WIP - Implement dynamic prop types

TODO: Tests
This commit is contained in:
Aria Minaei 2022-10-06 14:05:04 +02:00 committed by Aria
parent e708463377
commit d260f74c06
9 changed files with 50 additions and 29 deletions

View file

@ -166,6 +166,7 @@ export default class SheetObject implements IdentityDerivationProvider {
const tracksToProcess = val(tracksToProcessD)
const valsAtom = new Atom<SheetObjectPropsValue>({})
const config = val(this.template.configPointer)
prism.effect(
'processTracks',
@ -175,7 +176,7 @@ export default class SheetObject implements IdentityDerivationProvider {
for (const {trackId, pathToProp} of tracksToProcess) {
const derivation = this._trackIdToDerivation(trackId)
const propConfig = getPropConfigByPath(
this.template.config,
config,
pathToProp,
)! as Extract<PropTypeConfig, {interpolate: $IntentionalAny}>
@ -222,7 +223,7 @@ export default class SheetObject implements IdentityDerivationProvider {
}
}
},
tracksToProcess,
[config, ...tracksToProcess],
)
return valsAtom.pointer

View file

@ -61,10 +61,14 @@ export default class SheetObjectTemplate {
readonly _cache = new SimpleCache()
readonly project: Project
get config() {
get staticConfig() {
return this._config.getState()
}
get configPointer() {
return this._config.pointer
}
constructor(
readonly sheetTemplate: SheetTemplate,
objectKey: ObjectAddressKey,
@ -95,7 +99,7 @@ export default class SheetObjectTemplate {
getDefaultValues(): IDerivation<SerializableMap> {
return this._cache.get('getDefaultValues()', () =>
prism(() => {
const config = val(this._config.pointer)
const config = val(this.configPointer)
return getPropDefaultsOfSheetObject(config)
}),
)
@ -119,7 +123,7 @@ export default class SheetObjectTemplate {
],
) ?? {}
const config = val(this._config.pointer)
const config = val(this.configPointer)
const deserialized = config.deserializeAndSanitize(json) || {}
return deserialized
}),
@ -154,12 +158,14 @@ export default class SheetObjectTemplate {
if (!trackIdByPropPath) return emptyArray as $IntentionalAny
const objectConfig = val(this.configPointer)
const _entries = Object.entries(trackIdByPropPath)
for (const [pathToPropInString, trackId] of _entries) {
const pathToProp = parsePathToProp(pathToPropInString)
if (!pathToProp) continue
const propConfig = getPropConfigByPath(this.config, pathToProp)
const propConfig = getPropConfigByPath(objectConfig, pathToProp)
const isSequencable = propConfig && isPropConfSequencable(propConfig)
@ -168,7 +174,7 @@ export default class SheetObjectTemplate {
arrayOfIds.push({pathToProp, trackId: trackId!})
}
const mapping = getOrderingOfPropTypeConfig(this.config)
const mapping = getOrderingOfPropTypeConfig(objectConfig)
arrayOfIds.sort((a, b) => {
const pathToPropA = a.pathToProp

View file

@ -45,6 +45,7 @@ export interface ISheet {
*
* @param key - Each object is identified by a key, which is a non-empty string
* @param props - The props of the object. See examples
* @param options - TODO
*
* @returns An Object
*
@ -68,6 +69,7 @@ export interface ISheet {
object<Props extends UnknownShorthandCompoundProps>(
key: string,
props: Props,
options?: {override?: boolean},
): ISheetObject<Props>
/**
@ -95,6 +97,7 @@ export default class TheatreSheet implements ISheet {
object<Props extends UnknownShorthandCompoundProps>(
key: string,
config: Props,
opts?: {override?: boolean},
): ISheetObject<Props> {
const internal = privateAPI(this)
const sanitizedPath = validateAndSanitiseSlashedPathOrThrow(
@ -118,11 +121,19 @@ export default class TheatreSheet implements ISheet {
const prevConfig = weakMapOfUnsanitizedProps.get(existingObject)
if (prevConfig) {
if (!deepEqual(config, prevConfig)) {
throw new Error(
`You seem to have called sheet.object("${key}", config) twice, with different values for \`config\`. ` +
`This is disallowed because changing the config of an object on the fly would make it difficult to reason about.\n\n` +
`You can fix this by either re-using the existing object, or calling sheet.object("${key}", config) with the same config.`,
)
if (opts?.override === true) {
const sanitizedConfig = compound(config)
existingObject.template.overrideConfig(sanitizedConfig)
weakMapOfUnsanitizedProps.set(existingObject, config)
return existingObject.publicApi as $IntentionalAny
} else {
throw new Error(
`You seem to have called sheet.object("${key}", config) twice, with different values for \`config\`. ` +
`This is disallowed because changing the config of an object on the fly would make it difficult to reason about.\n\n` +
`You can fix this by either re-using the existing object, or calling sheet.object("${key}", config) with the same config.\n\n` +
`If you mean to override the object's config, set \`{override: true}\` in sheet.object("${key}", config, {override: true})`,
)
}
}
}
}

View file

@ -89,7 +89,7 @@ export default function createTransactionPrivateApi(
.getMapOfValidSequenceTracks_forStudio()
.getValue()
const propConfig = getPropConfigByPath(root.template.config, path)
const propConfig = getPropConfigByPath(root.template.staticConfig, path)
if (!propConfig) {
throw new Error(
@ -205,7 +205,7 @@ export default function createTransactionPrivateApi(
)
const propConfig = getPropConfigByPath(
root.template.config,
root.template.staticConfig,
path,
) as PropTypeConfig

View file

@ -5,7 +5,6 @@ import type {
PropTypeConfig_AllSimples,
} from '@theatre/core/propTypes'
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
import {getPropTypeByPointer} from '@theatre/studio/propEditors/utils/getPropTypeByPointer'
import {simplePropEditorByPropType} from '@theatre/studio/propEditors/simpleEditors/simplePropEditorByPropType'
import type {PropConfigForType} from '@theatre/studio/propEditors/utils/PropConfigForType'
import type {ISimplePropEditorReactProps} from '@theatre/studio/propEditors/simpleEditors/ISimplePropEditorReactProps'
@ -24,16 +23,13 @@ import DetailSimplePropEditor from './DeterminePropEditorForDetail/DetailSimpleP
*/
const DeterminePropEditorForDetail: React.VFC<
IDeterminePropEditorForDetailProps<PropTypeConfig['type']>
> = (p) => {
const propConfig =
p.propConfig ?? getPropTypeByPointer(p.pointerToProp, p.obj)
> = ({propConfig, visualIndentation, pointerToProp, obj}) => {
if (propConfig.type === 'compound') {
return (
<DetailCompoundPropEditor
obj={p.obj}
visualIndentation={p.visualIndentation}
pointerToProp={p.pointerToProp}
obj={obj}
visualIndentation={visualIndentation}
pointerToProp={pointerToProp}
propConfig={propConfig}
/>
)
@ -50,9 +46,9 @@ const DeterminePropEditorForDetail: React.VFC<
ISimplePropEditorReactProps<PropTypeConfig_AllSimples>
>
}
obj={p.obj}
visualIndentation={p.visualIndentation}
pointerToProp={p.pointerToProp}
obj={obj}
visualIndentation={visualIndentation}
pointerToProp={pointerToProp}
propConfig={propConfig}
/>
)
@ -60,6 +56,7 @@ const DeterminePropEditorForDetail: React.VFC<
}
export default DeterminePropEditorForDetail
type IDeterminePropEditorForDetailProps<K extends PropTypeConfig['type']> =
IDetailEditablePropertyProps<K> & {
visualIndentation: number

View file

@ -3,6 +3,7 @@ import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
import type {Pointer} from '@theatre/dataverse'
import type {$FixMe} from '@theatre/shared/utils/types'
import DeterminePropEditorForDetail from './DeterminePropEditorForDetail'
import {useVal} from '@theatre/react'
const ObjectDetails: React.FC<{
/** TODO: add support for multiple objects (it would show their common props) */
@ -10,13 +11,14 @@ const ObjectDetails: React.FC<{
}> = ({objects}) => {
const obj = objects[0]
const key = useMemo(() => JSON.stringify(obj.address), [obj])
const config = useVal(obj.template.configPointer)
return (
<DeterminePropEditorForDetail
key={key}
obj={obj}
pointerToProp={obj.propsP as Pointer<$FixMe>}
propConfig={obj.template.config}
propConfig={config}
visualIndentation={1}
/>
)

View file

@ -18,6 +18,7 @@ import {
valueInProp,
} from '@theatre/shared/propTypes/utils'
import type {PropTypeConfig_AllSimples} from '@theatre/core/propTypes'
import {useVal} from '@theatre/react'
export type ExtremumSpace = {
fromValueSpace: (v: number) => number
@ -36,7 +37,7 @@ const BasicKeyframedTrack: React.VFC<{
}> = React.memo(
({layoutP, trackData, sheetObject, trackId, color, pathToProp}) => {
const propConfig = getPropConfigByPath(
sheetObject.template.config,
useVal(sheetObject.template.configPointer),
pathToProp,
)! as PropTypeConfig_AllSimples

View file

@ -157,6 +157,7 @@ export const calculateSequenceEditorTree = (
const trackSetups = val(
sheetObject.template.getMapOfValidSequenceTracks_forStudio(),
)
const objectConfig = val(sheetObject.template.configPointer)
if (Object.keys(trackSetups).length === 0) return
@ -192,7 +193,7 @@ export const calculateSequenceEditorTree = (
sheetObject,
trackSetups,
[],
sheetObject.template.config,
objectConfig,
row.children,
level + 1,
shouldRender && !isCollapsed,

View file

@ -3,6 +3,8 @@ import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
import {getPointerParts} from '@theatre/dataverse'
/**
* @deprecated because it uses obj.template.staticConfig
*
* Returns the PropTypeConfig by path. Assumes `path` is a valid prop path and that
* it exists in obj.
*
@ -20,7 +22,7 @@ export function getPropTypeByPointer(
pointerToProp: SheetObject['propsP'],
obj: SheetObject,
): PropTypeConfig {
const rootConf = obj.template.config
const rootConf = obj.template.staticConfig
const p = getPointerParts(pointerToProp).path
let conf = rootConf as PropTypeConfig