Fix the bugs in assetStorage
This commit is contained in:
parent
33235e9cd7
commit
2b10e46441
11 changed files with 176 additions and 32 deletions
|
@ -8,12 +8,12 @@ import React, {useEffect, useState} from 'react'
|
|||
import {render} from 'react-dom'
|
||||
import styled from 'styled-components'
|
||||
|
||||
studio.initialize()
|
||||
const project = getProject('Image type playground', {
|
||||
assets: {
|
||||
baseUrl: 'http://localhost:3000',
|
||||
baseUrl: '/',
|
||||
},
|
||||
})
|
||||
studio.initialize()
|
||||
const sheet = project.sheet('Image type')
|
||||
|
||||
const Wrapper = styled.div`
|
||||
|
@ -35,6 +35,7 @@ const ImageTypeExample: React.FC<{}> = (props) => {
|
|||
image2: types.image('', {
|
||||
label: 'another texture',
|
||||
}),
|
||||
// audio: types.__genericAsset(''),
|
||||
something: 'asdf',
|
||||
color: types.rgba(),
|
||||
})
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
"@types/react-dom": "^17.0.6",
|
||||
"esbuild": "^0.12.15",
|
||||
"esbuild-register": "^2.5.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^4.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type {
|
||||
IProject,
|
||||
IProjectConfig,
|
||||
ISheetObject,
|
||||
UnknownShorthandCompoundProps,
|
||||
|
@ -45,14 +46,37 @@ function equalityCheckWithFunctionsAlwaysEqual(
|
|||
}
|
||||
}
|
||||
|
||||
export function initialize(config: IProjectConfig) {
|
||||
if (_projectConfig !== undefined) {
|
||||
export function initialize(config: IProjectConfig): Promise<void> {
|
||||
if (_project) {
|
||||
console.warn(
|
||||
'Theatric has already been initialized, either through another initialize call, or by calling useControls() before calling initialize().',
|
||||
)
|
||||
return
|
||||
return _project.ready.then(() => {})
|
||||
}
|
||||
_projectConfig = config
|
||||
const project = callGetProject()
|
||||
return project.ready.then(() => {})
|
||||
}
|
||||
|
||||
export function getAssetUrl(asset: {
|
||||
type: 'image'
|
||||
id: string | undefined
|
||||
}): string | undefined {
|
||||
if (!_project) {
|
||||
throw new Error(
|
||||
'Theatric has not been initialized yet. Please call initialize() before calling getAssetUrl().',
|
||||
)
|
||||
}
|
||||
if (!_project.isReady) {
|
||||
throw new Error(
|
||||
'Calling `getAssetUrl()` before `initialize()` is resolved.\n' +
|
||||
'The best way to solve this is to delay rendering your react app until `project.ready` is resolved, like this: \n\n' +
|
||||
'```\n' +
|
||||
'project.ready.then(() => {ReactDom.render(...)})\n' +
|
||||
'```',
|
||||
)
|
||||
}
|
||||
return _project.getAssetUrl(asset)
|
||||
}
|
||||
|
||||
const allProps: Record<string, UnknownShorthandCompoundProps[]> = {}
|
||||
|
@ -171,10 +195,8 @@ export function useControls<Config extends ControlsAndButtons>(
|
|||
[buttons, folder],
|
||||
)
|
||||
|
||||
const sheet = useMemo(
|
||||
() => getProject('Theatric', _projectConfig ?? undefined).sheet('Panels'),
|
||||
[],
|
||||
)
|
||||
const sheet = useMemo(() => callGetProject().sheet('Panels'), [])
|
||||
|
||||
const panel = options.panel ?? 'Default panel'
|
||||
const allPanelProps = allProps[panel] ?? (allProps[panel] = [])
|
||||
const allPanelActions = allActions[panel] ?? (allActions[panel] = [])
|
||||
|
@ -298,3 +320,11 @@ export const button = (onClick: Button['onClick']) => {
|
|||
onClick,
|
||||
}
|
||||
}
|
||||
|
||||
let _project: undefined | IProject
|
||||
|
||||
function callGetProject() {
|
||||
if (_project) return _project
|
||||
_project = getProject('Theatric', _projectConfig ?? undefined)
|
||||
return _project
|
||||
}
|
||||
|
|
|
@ -107,6 +107,15 @@ export default class TheatreProject implements IProject {
|
|||
}
|
||||
|
||||
getAssetUrl(asset: Asset): string | undefined {
|
||||
// probably should put this in project.getAssetUrl but this will do for now
|
||||
if (!this.isReady) {
|
||||
console.error(
|
||||
'Calling `project.getAssetUrl()` before `project.ready` is resolved, will always return `undefined`. ' +
|
||||
'Either use `project.ready.then(() => project.getAssetUrl())` or `await project.ready` before calling `project.getAssetUrl()`.',
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
|
||||
return asset.id
|
||||
? privateAPI(this).assetStorage.getAssetUrl(asset.id)
|
||||
: undefined
|
||||
|
|
|
@ -1,19 +1,32 @@
|
|||
import type Project from '@theatre/core/projects/Project'
|
||||
import {val} from '@theatre/dataverse'
|
||||
import forEachPropDeep from './forEachDeep'
|
||||
import type {$IntentionalAny} from './types'
|
||||
|
||||
export function getAllPossibleAssetIDs(project: Project, type?: string) {
|
||||
// Apparently the value returned by val() can be undefined. Should fix TS.
|
||||
const sheets = Object.values(val(project.pointers.historic.sheetsById) ?? {})
|
||||
const staticValues = sheets
|
||||
.flatMap((sheet) => Object.values(sheet?.staticOverrides.byObject ?? {}))
|
||||
.flatMap((overrides) => Object.values(overrides ?? {}))
|
||||
|
||||
const keyframeValues = sheets
|
||||
.flatMap((sheet) => Object.values(sheet?.sequence?.tracksByObject ?? {}))
|
||||
.flatMap((tracks) => Object.values(tracks?.trackData ?? {}))
|
||||
.flatMap((track) => track?.keyframes)
|
||||
.map((keyframe) => keyframe?.value)
|
||||
|
||||
const allAssets = [...staticValues, ...keyframeValues]
|
||||
const allValues = [...keyframeValues]
|
||||
staticValues.forEach((value) => {
|
||||
forEachPropDeep(
|
||||
value,
|
||||
(v) => {
|
||||
allValues.push(v as $IntentionalAny)
|
||||
},
|
||||
[],
|
||||
)
|
||||
})
|
||||
|
||||
const allAssets = allValues
|
||||
// value is Asset of the type provided
|
||||
.filter((value) => {
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import type {
|
||||
PropTypeConfig_AllSimples,
|
||||
PropTypeConfig_Compound,
|
||||
} from '@theatre/core/propTypes'
|
||||
import type {PathToProp} from './addresses'
|
||||
import type {$IntentionalAny, SerializableMap} from './types'
|
||||
import type {$IntentionalAny} from './types'
|
||||
|
||||
/**
|
||||
* Iterates recursively over all props of an object (which should be a {@link SerializableMap}) and runs `fn`
|
||||
|
@ -24,16 +28,28 @@ import type {$IntentionalAny, SerializableMap} from './types'
|
|||
* // Also note that `a` is also skippped, because it's not a primitive value.
|
||||
* ```
|
||||
*/
|
||||
export default function forEachDeep<
|
||||
Primitive extends string | number | boolean,
|
||||
export default function forEachPropDeep<
|
||||
Primitive extends
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| PropTypeConfig_AllSimples['valueType'],
|
||||
>(
|
||||
m: SerializableMap<Primitive> | Primitive | undefined | unknown,
|
||||
m:
|
||||
| PropTypeConfig_Compound<$IntentionalAny>['valueType']
|
||||
| Primitive
|
||||
| undefined
|
||||
| unknown,
|
||||
fn: (value: Primitive, path: PathToProp) => void,
|
||||
startingPath: PathToProp = [],
|
||||
): void {
|
||||
if (typeof m === 'object' && m) {
|
||||
if (isImage(m) || isRGBA(m)) {
|
||||
fn(m as $IntentionalAny as Primitive, startingPath)
|
||||
return
|
||||
}
|
||||
for (const [key, value] of Object.entries(m)) {
|
||||
forEachDeep(value!, fn, [...startingPath, key])
|
||||
forEachPropDeep(value!, fn, [...startingPath, key])
|
||||
}
|
||||
} else if (m === undefined || m === null) {
|
||||
return
|
||||
|
@ -41,3 +57,39 @@ export default function forEachDeep<
|
|||
fn(m as $IntentionalAny as Primitive, startingPath)
|
||||
}
|
||||
}
|
||||
|
||||
const isImage = (value: unknown): value is {type: 'image'; id: string} => {
|
||||
return (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
Object.hasOwnProperty.call(value, 'type') &&
|
||||
// @ts-ignore
|
||||
value.type === 'image' &&
|
||||
Object.hasOwnProperty.call(value, 'id') &&
|
||||
// @ts-ignore
|
||||
typeof value.id === 'string' &&
|
||||
// @ts-ignore
|
||||
value.id !== ''
|
||||
)
|
||||
}
|
||||
|
||||
const isRGBA = (
|
||||
value: unknown,
|
||||
): value is {r: number; g: number; b: number; a: number} => {
|
||||
return (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
Object.hasOwnProperty.call(value, 'r') &&
|
||||
Object.hasOwnProperty.call(value, 'g') &&
|
||||
Object.hasOwnProperty.call(value, 'b') &&
|
||||
Object.hasOwnProperty.call(value, 'a') &&
|
||||
// @ts-ignore
|
||||
typeof value.r === 'number' &&
|
||||
// @ts-ignore
|
||||
typeof value.g === 'number' &&
|
||||
// @ts-ignore
|
||||
typeof value.b === 'number' &&
|
||||
// @ts-ignore
|
||||
typeof value.a === 'number'
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import forEachDeep from '@theatre/shared/utils/forEachDeep'
|
||||
import forEachPropDeep from '@theatre/shared/utils/forEachDeep'
|
||||
import type {$FixMe} from '@theatre/shared/utils/types'
|
||||
import type {Pointer} from '@theatre/dataverse'
|
||||
import {getPointerParts} from '@theatre/dataverse'
|
||||
|
@ -213,7 +213,7 @@ export default class Scrub implements IScrub {
|
|||
|
||||
const defaultValueOfProp = root.template.getDefaultsAtPointer(pointer)
|
||||
|
||||
forEachDeep(
|
||||
forEachPropDeep(
|
||||
defaultValueOfProp,
|
||||
(val, pathToProp) => {
|
||||
stateEditors.studio.ephemeral.projects.stateByProjectId.stateBySheetId.stateByObjectKey.propsBeingScrubbed.flag(
|
||||
|
|
|
@ -3,7 +3,7 @@ import {isSheetObject} from '@theatre/shared/instanceTypes'
|
|||
import type {$FixMe, $IntentionalAny} from '@theatre/shared/utils/types'
|
||||
import get from 'lodash-es/get'
|
||||
import type {ITransactionPrivateApi} from './StudioStore'
|
||||
import forEachDeep from '@theatre/shared/utils/forEachDeep'
|
||||
import forEachPropDeep from '@theatre/shared/utils/forEachDeep'
|
||||
import getDeep from '@theatre/shared/utils/getDeep'
|
||||
import type {SequenceTrackId} from '@theatre/shared/utils/ids'
|
||||
import {getPointerParts} from '@theatre/dataverse'
|
||||
|
@ -233,7 +233,7 @@ export default function createTransactionPrivateApi(
|
|||
}
|
||||
|
||||
if (propConfig.type === 'compound') {
|
||||
forEachDeep(
|
||||
forEachPropDeep(
|
||||
defaultValue,
|
||||
(v, pathToProp) => {
|
||||
unsetStaticOrKeyframeProp(v, pathToProp)
|
||||
|
|
|
@ -60,7 +60,7 @@ const InputLabel = styled.label<{empty: boolean}>`
|
|||
`
|
||||
|
||||
// file input
|
||||
const Input = styled.input.attrs({type: 'file', accept: 'image/*'})`
|
||||
const Input = styled.input.attrs({type: 'file'})`
|
||||
display: none;
|
||||
`
|
||||
|
||||
|
@ -145,7 +145,7 @@ function ImagePropEditor({
|
|||
<Input
|
||||
type="file"
|
||||
onChange={onChange}
|
||||
accept="image/*"
|
||||
accept="image/*,.hdr"
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
{previewUrl ? <Preview src={previewUrl} /> : <AddImage />}
|
||||
|
|
|
@ -34,7 +34,7 @@ interface EditingToolsCommon<T> {
|
|||
permanentlySetValue(v: T): void
|
||||
|
||||
getAssetUrl: (asset: Asset) => string | undefined
|
||||
createAsset(asset: Blob): Promise<string | null>
|
||||
createAsset(asset: File): Promise<string | null>
|
||||
}
|
||||
|
||||
interface EditingToolsDefault<T> extends EditingToolsCommon<T> {
|
||||
|
@ -114,7 +114,8 @@ function createPrism<T extends SerializablePrimitive>(
|
|||
)
|
||||
|
||||
const editAssets = {
|
||||
createAsset: obj.sheet.project.assetStorage.createAsset,
|
||||
createAsset: (asset: File): Promise<string | null> =>
|
||||
obj.sheet.project.assetStorage.createAsset(asset),
|
||||
getAssetUrl: (asset: Asset) =>
|
||||
asset.id
|
||||
? obj.sheet.project.assetStorage.getAssetUrl(asset.id)
|
||||
|
|
52
yarn.lock
52
yarn.lock
|
@ -5429,7 +5429,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.0":
|
||||
"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.14.0":
|
||||
version: 7.14.0
|
||||
resolution: "@babel/runtime@npm:7.14.0"
|
||||
dependencies:
|
||||
|
@ -5447,6 +5447,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.13.10":
|
||||
version: 7.20.13
|
||||
resolution: "@babel/runtime@npm:7.20.13"
|
||||
dependencies:
|
||||
regenerator-runtime: ^0.13.11
|
||||
checksum: 09b7a97a05c80540db6c9e4ddf8c5d2ebb06cae5caf3a87e33c33f27f8c4d49d9c67a2d72f1570e796045288fad569f98a26ceba0c4f5fad2af84b6ad855c4fb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.9.2":
|
||||
version: 7.14.8
|
||||
resolution: "@babel/runtime@npm:7.14.8"
|
||||
|
@ -7613,14 +7622,15 @@ __metadata:
|
|||
linkType: hard
|
||||
|
||||
"@react-three/fiber@npm:^7.0.6":
|
||||
version: 7.0.6
|
||||
resolution: "@react-three/fiber@npm:7.0.6"
|
||||
version: 7.0.29
|
||||
resolution: "@react-three/fiber@npm:7.0.29"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.13.10
|
||||
"@types/react-reconciler": ^0.26.2
|
||||
react-merge-refs: ^1.1.0
|
||||
react-reconciler: ^0.26.2
|
||||
react-three-fiber: 0.0.0-deprecated
|
||||
react-use-measure: ^2.0.4
|
||||
react-use-measure: ^2.1.1
|
||||
resize-observer-polyfill: ^1.5.1
|
||||
scheduler: ^0.20.2
|
||||
use-asset: ^1.0.4
|
||||
|
@ -7629,11 +7639,11 @@ __metadata:
|
|||
peerDependencies:
|
||||
react: ">=17.0"
|
||||
react-dom: ">=17.0"
|
||||
three: ">=0.126"
|
||||
three: ">=0.133"
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
checksum: f213eef29a600688f03d3ffd2f41ea2ce4da9608326921f3fea15621f86bebbc8154ce5eca071188a78f9684751c7ee824353711e59affb9967f3f7fdeaf2f20
|
||||
checksum: 79b760b41c4076666b4546c9ee6713cdd815e6cb9e05a90702ba911306180f3968a31cb7ac024cc7683bc6e2af7dd0e55125db26b0dc238647628ad5d9dbd877
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -8869,6 +8879,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-reconciler@npm:^0.26.2":
|
||||
version: 0.26.7
|
||||
resolution: "@types/react-reconciler@npm:0.26.7"
|
||||
dependencies:
|
||||
"@types/react": "*"
|
||||
checksum: 4122d2b08580f775d0aeae9bd10b68248f894096ed14c0ebbc143ef712e21b159e89d0c628bd95dd3329947fc1ee94a0cb1d2d32b32b1d5d225e70030e91e58f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:^17.0.9":
|
||||
version: 17.0.9
|
||||
resolution: "@types/react@npm:17.0.9"
|
||||
|
@ -14174,7 +14193,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"debounce@npm:^1.2.0":
|
||||
"debounce@npm:^1.2.0, debounce@npm:^1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "debounce@npm:1.2.1"
|
||||
checksum: 682a89506d9e54fb109526f4da255c5546102fbb8e3ae75eef3b04effaf5d4853756aee97475cd4650641869794e44f410eeb20ace2b18ea592287ab2038519e
|
||||
|
@ -27998,6 +28017,18 @@ fsevents@^1.2.7:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-use-measure@npm:^2.1.1":
|
||||
version: 2.1.1
|
||||
resolution: "react-use-measure@npm:2.1.1"
|
||||
dependencies:
|
||||
debounce: ^1.2.1
|
||||
peerDependencies:
|
||||
react: ">=16.13"
|
||||
react-dom: ">=16.13"
|
||||
checksum: b8e8939229d463c3c505f7b617925c0228efae0cd6f651371f463846417b06c9170be57df51293a61027c41770f8a090fdb8a08717c4e36290ccb496e0318f1f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-use@npm:^15.3.3":
|
||||
version: 15.3.8
|
||||
resolution: "react-use@npm:15.3.8"
|
||||
|
@ -28296,6 +28327,13 @@ fsevents@^1.2.7:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regenerator-runtime@npm:^0.13.11":
|
||||
version: 0.13.11
|
||||
resolution: "regenerator-runtime@npm:0.13.11"
|
||||
checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regenerator-runtime@npm:^0.13.4":
|
||||
version: 0.13.8
|
||||
resolution: "regenerator-runtime@npm:0.13.8"
|
||||
|
|
Loading…
Reference in a new issue