Make default and static overrides distinguishable
Right now it's easy for the user to distinguish between a sequenced prop and non-sequenced props. However, among the non-sequenced ones, it's not possible to distinguish between those that have a static override, and those that don't. The goal of this commit is to make it easy to distinguish between the two.
This commit is contained in:
parent
5c135a3cb9
commit
6f8e91ed5f
5 changed files with 85 additions and 79 deletions
|
@ -18,6 +18,7 @@ import type {
|
||||||
$FixMe,
|
$FixMe,
|
||||||
$IntentionalAny,
|
$IntentionalAny,
|
||||||
SerializableMap,
|
SerializableMap,
|
||||||
|
SerializablePrimitive,
|
||||||
SerializableValue,
|
SerializableValue,
|
||||||
} from '@theatre/shared/utils/types'
|
} from '@theatre/shared/utils/types'
|
||||||
import type {Prism, Pointer} from '@theatre/dataverse'
|
import type {Prism, Pointer} from '@theatre/dataverse'
|
||||||
|
@ -31,6 +32,7 @@ import {
|
||||||
isPropConfSequencable,
|
isPropConfSequencable,
|
||||||
} from '@theatre/shared/propTypes/utils'
|
} from '@theatre/shared/propTypes/utils'
|
||||||
import getOrderingOfPropTypeConfig from './getOrderingOfPropTypeConfig'
|
import getOrderingOfPropTypeConfig from './getOrderingOfPropTypeConfig'
|
||||||
|
import type {SheetState_Historic} from '@theatre/core/projects/store/types/SheetState_Historic'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an object like: `{transform: {type: 'absolute', position: {x: 0}}}`,
|
* Given an object like: `{transform: {type: 'absolute', position: {x: 0}}}`,
|
||||||
|
@ -64,6 +66,10 @@ export default class SheetObjectTemplate {
|
||||||
readonly _temp_actions_atom: Atom<SheetObjectActionsConfig>
|
readonly _temp_actions_atom: Atom<SheetObjectActionsConfig>
|
||||||
readonly _cache = new SimpleCache()
|
readonly _cache = new SimpleCache()
|
||||||
readonly project: Project
|
readonly project: Project
|
||||||
|
readonly pointerToSheetState: Pointer<SheetState_Historic | undefined>
|
||||||
|
readonly pointerToStaticOverrides: Pointer<
|
||||||
|
SerializableMap<SerializablePrimitive> | undefined
|
||||||
|
>
|
||||||
|
|
||||||
get staticConfig() {
|
get staticConfig() {
|
||||||
return this._config.get()
|
return this._config.get()
|
||||||
|
@ -92,6 +98,14 @@ export default class SheetObjectTemplate {
|
||||||
this._config = new Atom(config)
|
this._config = new Atom(config)
|
||||||
this._temp_actions_atom = new Atom(_temp_actions)
|
this._temp_actions_atom = new Atom(_temp_actions)
|
||||||
this.project = sheetTemplate.project
|
this.project = sheetTemplate.project
|
||||||
|
|
||||||
|
this.pointerToSheetState =
|
||||||
|
this.sheetTemplate.project.pointers.historic.sheetsById[
|
||||||
|
this.address.sheetId
|
||||||
|
]
|
||||||
|
|
||||||
|
this.pointerToStaticOverrides =
|
||||||
|
this.pointerToSheetState.staticOverrides.byObject[this.address.objectKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
createInstance(
|
createInstance(
|
||||||
|
@ -132,17 +146,7 @@ export default class SheetObjectTemplate {
|
||||||
getStaticValues(): Prism<SerializableMap> {
|
getStaticValues(): Prism<SerializableMap> {
|
||||||
return this._cache.get('getStaticValues', () =>
|
return this._cache.get('getStaticValues', () =>
|
||||||
prism(() => {
|
prism(() => {
|
||||||
const pointerToSheetState =
|
const json = val(this.pointerToStaticOverrides) ?? {}
|
||||||
this.sheetTemplate.project.pointers.historic.sheetsById[
|
|
||||||
this.address.sheetId
|
|
||||||
]
|
|
||||||
|
|
||||||
const json =
|
|
||||||
val(
|
|
||||||
pointerToSheetState.staticOverrides.byObject[
|
|
||||||
this.address.objectKey
|
|
||||||
],
|
|
||||||
) ?? {}
|
|
||||||
|
|
||||||
const config = val(this.configPointer)
|
const config = val(this.configPointer)
|
||||||
const deserialized = config.deserializeAndSanitize(json) || {}
|
const deserialized = config.deserializeAndSanitize(json) || {}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type {
|
||||||
} from '@theatre/core/propTypes'
|
} from '@theatre/core/propTypes'
|
||||||
import type {PathToProp} from '@theatre/shared/utils/addresses'
|
import type {PathToProp} from '@theatre/shared/utils/addresses'
|
||||||
import type {$IntentionalAny} from '@theatre/shared/utils/types'
|
import type {$IntentionalAny} from '@theatre/shared/utils/types'
|
||||||
|
import memoizeFn from '@theatre/shared/utils/memoizeFn'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Either compound or enum properties can be considered "composite"
|
* Either compound or enum properties can be considered "composite"
|
||||||
|
@ -70,35 +71,13 @@ export function isPropConfSequencable(
|
||||||
return !isPropConfigComposite(conf) // now all non-compounds are sequencable
|
return !isPropConfigComposite(conf) // now all non-compounds are sequencable
|
||||||
}
|
}
|
||||||
|
|
||||||
const compoundPropSequenceabilityCache = new WeakMap<
|
|
||||||
PropTypeConfig_Compound<{}> | PropTypeConfig_Enum,
|
|
||||||
boolean
|
|
||||||
>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See {@link compoundHasSimpleDescendantsImpl}
|
|
||||||
*/
|
|
||||||
export function compoundHasSimpleDescendants(
|
|
||||||
conf: PropTypeConfig_Compound<{}> | PropTypeConfig_Enum,
|
|
||||||
): boolean {
|
|
||||||
if (!compoundPropSequenceabilityCache.has(conf)) {
|
|
||||||
compoundPropSequenceabilityCache.set(
|
|
||||||
conf,
|
|
||||||
compoundHasSimpleDescendantsImpl(conf),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return compoundPropSequenceabilityCache.get(conf)!
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This basically checks of the compound prop has at least one simple prop in its descendants.
|
* This basically checks of the compound prop has at least one simple prop in its descendants.
|
||||||
* In other words, if the compound props has no subs, or its subs are only compounds that eventually
|
* In other words, if the compound props has no subs, or its subs are only compounds that eventually
|
||||||
* don't have simple subs, this will return false.
|
* don't have simple subs, this will return false.
|
||||||
*/
|
*/
|
||||||
function compoundHasSimpleDescendantsImpl(
|
export const compoundHasSimpleDescendants = memoizeFn(
|
||||||
conf: PropTypeConfig_Compound<{}> | PropTypeConfig_Enum,
|
(conf: PropTypeConfig_Compound<{}> | PropTypeConfig_Enum): boolean => {
|
||||||
): boolean {
|
|
||||||
if (conf.type === 'enum') {
|
if (conf.type === 'enum') {
|
||||||
throw new Error(`Not implemented yet for enums`)
|
throw new Error(`Not implemented yet for enums`)
|
||||||
}
|
}
|
||||||
|
@ -116,7 +95,8 @@ function compoundHasSimpleDescendantsImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
},
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates recursively over the simple props of a compound prop. Returns a generator.
|
* Iterates recursively over the simple props of a compound prop. Returns a generator.
|
||||||
|
|
|
@ -2,9 +2,9 @@ import {transparentize} from 'polished'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
export const theme = {
|
const theme = {
|
||||||
defaultState: {
|
defaultState: {
|
||||||
color: transparentize(0.85, `#C4C4C4`),
|
color: transparentize(0.95, `#C4C4C4`),
|
||||||
},
|
},
|
||||||
withStaticOverride: {
|
withStaticOverride: {
|
||||||
color: transparentize(0.85, `#C4C4C4`),
|
color: transparentize(0.85, `#C4C4C4`),
|
||||||
|
@ -28,24 +28,31 @@ const Rect = styled.rect`
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Icon = () => (
|
const DefaultIcon = styled.div`
|
||||||
<svg
|
width: 5px;
|
||||||
width="5"
|
height: 5px;
|
||||||
height="5"
|
border-radius: 1px;
|
||||||
viewBox="0 0 5 5"
|
/* border: 1px solid currentColor; */
|
||||||
fill="none"
|
background-color: currentColor;
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
`
|
||||||
>
|
|
||||||
<Rect width="5" height="5" />
|
const FilledIcon = styled.div`
|
||||||
</svg>
|
width: 5px;
|
||||||
)
|
height: 5px;
|
||||||
|
background-color: currentColor;
|
||||||
|
border-radius: 1px;
|
||||||
|
`
|
||||||
|
|
||||||
const DefaultOrStaticValueIndicator: React.FC<{hasStaticOverride: boolean}> = (
|
const DefaultOrStaticValueIndicator: React.FC<{hasStaticOverride: boolean}> = (
|
||||||
props,
|
props,
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<Container hasStaticOverride={props.hasStaticOverride}>
|
<Container hasStaticOverride={props.hasStaticOverride}>
|
||||||
<Icon />
|
{props.hasStaticOverride ? (
|
||||||
|
<FilledIcon title="The default value is overridden" />
|
||||||
|
) : (
|
||||||
|
<DefaultIcon title="This is the default value for this prop" />
|
||||||
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,13 @@ export function useEditingToolsForCompoundProp<T extends SerializablePrimitive>(
|
||||||
obj: SheetObject,
|
obj: SheetObject,
|
||||||
propConfig: PropTypeConfig_Compound<{}>,
|
propConfig: PropTypeConfig_Compound<{}>,
|
||||||
): Stuff {
|
): Stuff {
|
||||||
|
const pathToProp = getPointerParts(pointerToProp).path
|
||||||
|
|
||||||
|
const pointerToStaticOverrides = pointerDeep(
|
||||||
|
obj.template.pointerToStaticOverrides,
|
||||||
|
pathToProp,
|
||||||
|
)
|
||||||
|
|
||||||
return usePrism((): Stuff => {
|
return usePrism((): Stuff => {
|
||||||
// if the compound has no simple descendants, then there isn't much the user can do with it
|
// if the compound has no simple descendants, then there isn't much the user can do with it
|
||||||
if (!compoundHasSimpleDescendants(propConfig)) {
|
if (!compoundHasSimpleDescendants(propConfig)) {
|
||||||
|
@ -67,8 +74,6 @@ export function useEditingToolsForCompoundProp<T extends SerializablePrimitive>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathToProp = getPointerParts(pointerToProp).path
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO This implementation is wrong because {@link stateEditors.studio.ephemeral.projects.stateByProjectId.stateBySheetId.stateByObjectKey.propsBeingScrubbed.flag}
|
* TODO This implementation is wrong because {@link stateEditors.studio.ephemeral.projects.stateByProjectId.stateBySheetId.stateByObjectKey.propsBeingScrubbed.flag}
|
||||||
* does not prune empty objects
|
* does not prune empty objects
|
||||||
|
@ -96,6 +101,11 @@ export function useEditingToolsForCompoundProp<T extends SerializablePrimitive>(
|
||||||
obj.template.getMapOfValidSequenceTracks_forStudio(),
|
obj.template.getMapOfValidSequenceTracks_forStudio(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const staticOverrides = getDeep(
|
||||||
|
val(obj.template.getStaticValues()),
|
||||||
|
pathToProp,
|
||||||
|
)
|
||||||
|
|
||||||
const possibleSequenceTrackIds = getDeep(
|
const possibleSequenceTrackIds = getDeep(
|
||||||
validSequencedTracks,
|
validSequencedTracks,
|
||||||
pathToProp,
|
pathToProp,
|
||||||
|
@ -106,9 +116,8 @@ export function useEditingToolsForCompoundProp<T extends SerializablePrimitive>(
|
||||||
Object.keys(possibleSequenceTrackIds).length !== 0 // check if object is empty or undefined
|
Object.keys(possibleSequenceTrackIds).length !== 0 // check if object is empty or undefined
|
||||||
const listOfDescendantTrackIds: SequenceTrackId[] = []
|
const listOfDescendantTrackIds: SequenceTrackId[] = []
|
||||||
|
|
||||||
let hasOneOrMoreStatics = true
|
let hasOneOrMoreStatics = staticOverrides !== undefined
|
||||||
if (hasOneOrMoreSequencedTracks) {
|
if (hasOneOrMoreSequencedTracks) {
|
||||||
hasOneOrMoreStatics = false
|
|
||||||
for (const descendant of iteratePropType(propConfig, [])) {
|
for (const descendant of iteratePropType(propConfig, [])) {
|
||||||
if (isPropConfigComposite(descendant.conf)) continue
|
if (isPropConfigComposite(descendant.conf)) continue
|
||||||
const sequencedTrackIdBelongingToDescendant = getDeep(
|
const sequencedTrackIdBelongingToDescendant = getDeep(
|
||||||
|
@ -214,7 +223,9 @@ export function useEditingToolsForCompoundProp<T extends SerializablePrimitive>(
|
||||||
...common,
|
...common,
|
||||||
type: 'AllStatic',
|
type: 'AllStatic',
|
||||||
controlIndicators: (
|
controlIndicators: (
|
||||||
<DefaultOrStaticValueIndicator hasStaticOverride={false} />
|
<DefaultOrStaticValueIndicator
|
||||||
|
hasStaticOverride={hasOneOrMoreStatics}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,6 +272,11 @@ function createPrism<T extends SerializablePrimitive>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allStaticOverrides = val(obj.template.getStaticValues())
|
||||||
|
|
||||||
|
const staticOverride = getDeep(allStaticOverrides, pathToProp)
|
||||||
|
|
||||||
|
if (typeof staticOverride !== 'undefined') {
|
||||||
contextMenuItems.push({
|
contextMenuItems.push({
|
||||||
label: 'Reset to default',
|
label: 'Reset to default',
|
||||||
callback: () => {
|
callback: () => {
|
||||||
|
@ -280,6 +285,7 @@ function createPrism<T extends SerializablePrimitive>(
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (isSequencable) {
|
if (isSequencable) {
|
||||||
contextMenuItems.push({
|
contextMenuItems.push({
|
||||||
|
@ -297,9 +303,7 @@ function createPrism<T extends SerializablePrimitive>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const statics = val(obj.template.getStaticValues())
|
if (typeof staticOverride !== 'undefined') {
|
||||||
|
|
||||||
if (typeof getDeep(statics, pathToProp) !== 'undefined') {
|
|
||||||
const ret: EditingToolsStatic<T> = {
|
const ret: EditingToolsStatic<T> = {
|
||||||
...common,
|
...common,
|
||||||
type: 'Static',
|
type: 'Static',
|
||||||
|
|
Loading…
Reference in a new issue