Unify Derivation and Prism 7/n
This commit is contained in:
parent
859cb40e0f
commit
acf34d393d
25 changed files with 134 additions and 141 deletions
|
@ -175,8 +175,8 @@ export const valueDerivation = <P extends PointerType<$IntentionalAny>>(
|
||||||
): IDerivation<P extends PointerType<infer T> ? T : void> => {
|
): IDerivation<P extends PointerType<infer T> ? T : void> => {
|
||||||
const meta = getPointerMeta(pointer)
|
const meta = getPointerMeta(pointer)
|
||||||
|
|
||||||
let derivation = identityDerivationWeakMap.get(meta)
|
let pr = identityDerivationWeakMap.get(meta)
|
||||||
if (!derivation) {
|
if (!pr) {
|
||||||
const root = meta.root
|
const root = meta.root
|
||||||
if (!(root instanceof Atom)) {
|
if (!(root instanceof Atom)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -184,13 +184,13 @@ export const valueDerivation = <P extends PointerType<$IntentionalAny>>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const {path} = meta
|
const {path} = meta
|
||||||
derivation = new DerivationFromSource<$IntentionalAny>(
|
pr = new DerivationFromSource<$IntentionalAny>(
|
||||||
(listener) => root.onPathValueChange(path, listener),
|
(listener) => root.onPathValueChange(path, listener),
|
||||||
() => root.getIn(path),
|
() => root.getIn(path),
|
||||||
)
|
)
|
||||||
identityDerivationWeakMap.set(meta, derivation)
|
identityDerivationWeakMap.set(meta, pr)
|
||||||
}
|
}
|
||||||
return derivation as $IntentionalAny
|
return pr as $IntentionalAny
|
||||||
}
|
}
|
||||||
|
|
||||||
export const val = <P>(
|
export const val = <P>(
|
||||||
|
|
|
@ -20,7 +20,7 @@ enum ValueTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for objects that can provide a derivation at a certain path.
|
* Interface for objects that can provide a prism at a certain path.
|
||||||
*/
|
*/
|
||||||
export interface IdentityPrismProvider {
|
export interface IdentityPrismProvider {
|
||||||
/**
|
/**
|
||||||
|
@ -30,9 +30,9 @@ export interface IdentityPrismProvider {
|
||||||
*/
|
*/
|
||||||
readonly $$isIdentityPrismProvider: true
|
readonly $$isIdentityPrismProvider: true
|
||||||
/**
|
/**
|
||||||
* Returns a derivation of the value at the provided path.
|
* Returns a prism of the value at the provided path.
|
||||||
*
|
*
|
||||||
* @param path - The path to create the derivation at.
|
* @param path - The path to create the prism at.
|
||||||
*/
|
*/
|
||||||
getIdentityPrism(path: Array<string | number>): Prism<unknown>
|
getIdentityPrism(path: Array<string | number>): Prism<unknown>
|
||||||
}
|
}
|
||||||
|
@ -240,9 +240,9 @@ export default class Atom<State extends {}> implements IdentityPrismProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new derivation of the value at the provided path.
|
* Returns a new prism of the value at the provided path.
|
||||||
*
|
*
|
||||||
* @param path - The path to create the derivation at.
|
* @param path - The path to create the prism at.
|
||||||
*/
|
*/
|
||||||
getIdentityPrism(path: Array<string | number>): Prism<unknown> {
|
getIdentityPrism(path: Array<string | number>): Prism<unknown> {
|
||||||
const subscribe = (listener: (val: unknown) => void) =>
|
const subscribe = (listener: (val: unknown) => void) =>
|
||||||
|
@ -259,18 +259,18 @@ export default class Atom<State extends {}> implements IdentityPrismProvider {
|
||||||
const identifyPrismWeakMap = new WeakMap<{}, Prism<unknown>>()
|
const identifyPrismWeakMap = new WeakMap<{}, Prism<unknown>>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a derivation of the value at the provided pointer. Derivations are
|
* Returns a prism of the value at the provided pointer. Prisms are
|
||||||
* cached per pointer.
|
* cached per pointer.
|
||||||
*
|
*
|
||||||
* @param pointer - The pointer to return the derivation at.
|
* @param pointer - The pointer to return the prism at.
|
||||||
*/
|
*/
|
||||||
export const pointerToPrism = <P extends PointerType<$IntentionalAny>>(
|
export const pointerToPrism = <P extends PointerType<$IntentionalAny>>(
|
||||||
pointer: P,
|
pointer: P,
|
||||||
): Prism<P extends PointerType<infer T> ? T : void> => {
|
): Prism<P extends PointerType<infer T> ? T : void> => {
|
||||||
const meta = getPointerMeta(pointer)
|
const meta = getPointerMeta(pointer)
|
||||||
|
|
||||||
let derivation = identifyPrismWeakMap.get(meta)
|
let prismInstance = identifyPrismWeakMap.get(meta)
|
||||||
if (!derivation) {
|
if (!prismInstance) {
|
||||||
const root = meta.root
|
const root = meta.root
|
||||||
if (!isIdentityPrismProvider(root)) {
|
if (!isIdentityPrismProvider(root)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -278,10 +278,10 @@ export const pointerToPrism = <P extends PointerType<$IntentionalAny>>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const {path} = meta
|
const {path} = meta
|
||||||
derivation = root.getIdentityPrism(path)
|
prismInstance = root.getIdentityPrism(path)
|
||||||
identifyPrismWeakMap.set(meta, derivation)
|
identifyPrismWeakMap.set(meta, prismInstance)
|
||||||
}
|
}
|
||||||
return derivation as $IntentionalAny
|
return prismInstance as $IntentionalAny
|
||||||
}
|
}
|
||||||
|
|
||||||
function isIdentityPrismProvider(val: unknown): val is IdentityPrismProvider {
|
function isIdentityPrismProvider(val: unknown): val is IdentityPrismProvider {
|
||||||
|
@ -294,10 +294,10 @@ function isIdentityPrismProvider(val: unknown): val is IdentityPrismProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function that returns a plain value from its argument, whether it
|
* Convenience function that returns a plain value from its argument, whether it
|
||||||
* is a pointer, a derivation or a plain value itself.
|
* is a pointer, a prism or a plain value itself.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* For pointers, the value is returned by first creating a derivation, so it is
|
* For pointers, the value is returned by first creating a prism, so it is
|
||||||
* reactive e.g. when used in a `prism`.
|
* reactive e.g. when used in a `prism`.
|
||||||
*
|
*
|
||||||
* @param input - The argument to return a value from.
|
* @param input - The argument to return a value from.
|
||||||
|
|
|
@ -17,24 +17,23 @@ export interface IBox<V> {
|
||||||
* Gets the value of the Box.
|
* Gets the value of the Box.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* Usages of `get()` aren't tracked, they are only for retrieving the value. To track changes, you need to
|
* Usages of `get()` aren't tracked, they are only for retrieving the value. To track changes, you need use a prism.
|
||||||
* create a derivation.
|
|
||||||
*
|
*
|
||||||
* @see derivation
|
* @see prism
|
||||||
*/
|
*/
|
||||||
get(): V
|
get(): V
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a derivation of the Box that you can use to track changes to it.
|
* Returns a prism of the Box that you can use to track changes to it.
|
||||||
*/
|
*/
|
||||||
derivation: Prism<V>
|
prism: Prism<V>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a single value.
|
* Wraps a single value.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* Derivations created with {@link Box.derivation} update based on strict equality (`===`) of the old value and the new one.
|
* Derivations created with {@link Box.prism} update based on strict equality (`===`) of the old value and the new one.
|
||||||
* This also means that property-changes of objects won't be tracked, and that for objects, updates will trigger on changes of
|
* This also means that property-changes of objects won't be tracked, and that for objects, updates will trigger on changes of
|
||||||
* reference even if the objects are structurally equal.
|
* reference even if the objects are structurally equal.
|
||||||
*/
|
*/
|
||||||
|
@ -74,18 +73,18 @@ export default class Box<V> implements IBox<V> {
|
||||||
* Gets the value of the Box.
|
* Gets the value of the Box.
|
||||||
*
|
*
|
||||||
* Note: usages of `get()` aren't tracked, they are only for retrieving the value. To track changes, you need to
|
* Note: usages of `get()` aren't tracked, they are only for retrieving the value. To track changes, you need to
|
||||||
* create a derivation.
|
* use a prism.
|
||||||
*
|
*
|
||||||
* @see Box.derivation
|
* @see Box.prism
|
||||||
*/
|
*/
|
||||||
get() {
|
get() {
|
||||||
return this._value
|
return this._value
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a derivation of the Box that you can use to track changes to it.
|
* Returns a prism of the Box that you can use to track changes to it.
|
||||||
*/
|
*/
|
||||||
get derivation() {
|
get prism() {
|
||||||
return this._publicDerivation
|
return this._publicDerivation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,13 +44,13 @@ export default class PointerProxy<O extends {}>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a derivation of the value at the provided sub-path of the proxied pointer.
|
* Returns a prism of the value at the provided sub-path of the proxied pointer.
|
||||||
*
|
*
|
||||||
* @param path - The path to create the derivation at.
|
* @param path - The path to create the prism at.
|
||||||
*/
|
*/
|
||||||
getIdentityPrism(path: Array<string | number>) {
|
getIdentityPrism(path: Array<string | number>) {
|
||||||
return prism(() => {
|
return prism(() => {
|
||||||
const currentPointer = this._currentPointerBox.derivation.getValue()
|
const currentPointer = this._currentPointerBox.prism.getValue()
|
||||||
const subPointer = path.reduce(
|
const subPointer = path.reduce(
|
||||||
(pointerSoFar, pathItem) => (pointerSoFar as $IntentionalAny)[pathItem],
|
(pointerSoFar, pathItem) => (pointerSoFar as $IntentionalAny)[pathItem],
|
||||||
currentPointer,
|
currentPointer,
|
||||||
|
|
|
@ -4,16 +4,16 @@ import type {$IntentionalAny, VoidFn} from '../types'
|
||||||
type IDependent = (msgComingFrom: Prism<$IntentionalAny>) => void
|
type IDependent = (msgComingFrom: Prism<$IntentionalAny>) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common interface for derivations.
|
* Common interface for prisms.
|
||||||
*/
|
*/
|
||||||
export interface Prism<V> {
|
export interface Prism<V> {
|
||||||
/**
|
/**
|
||||||
* Whether the object is a derivation.
|
* Whether the object is a prism.
|
||||||
*/
|
*/
|
||||||
isPrism: true
|
isPrism: true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the derivation is hot.
|
* Whether the prism is hot.
|
||||||
*/
|
*/
|
||||||
isHot: boolean
|
isHot: boolean
|
||||||
|
|
||||||
|
@ -29,14 +29,14 @@ export interface Prism<V> {
|
||||||
onStale(cb: () => void): VoidFn
|
onStale(cb: () => void): VoidFn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep the derivation hot, even if there are no tappers (subscribers).
|
* Keep the prism hot, even if there are no tappers (subscribers).
|
||||||
*/
|
*/
|
||||||
keepHot(): VoidFn
|
keepHot(): VoidFn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a derivation as a dependent of this derivation.
|
* Add a prism as a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @param d - The derivation to be made a dependent of this derivation.
|
* @param d - The prism to be made a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @see _removeDependent
|
* @see _removeDependent
|
||||||
*
|
*
|
||||||
|
@ -45,9 +45,9 @@ export interface Prism<V> {
|
||||||
_addDependent(d: IDependent): void
|
_addDependent(d: IDependent): void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a derivation as a dependent of this derivation.
|
* Remove a prism as a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @param d - The derivation to be removed from as a dependent of this derivation.
|
* @param d - The prism to be removed from as a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @see _addDependent
|
* @see _addDependent
|
||||||
* @internal
|
* @internal
|
||||||
|
@ -55,13 +55,13 @@ export interface Prism<V> {
|
||||||
_removeDependent(d: IDependent): void
|
_removeDependent(d: IDependent): void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current value of the derivation. If the value is stale, it causes the derivation to freshen.
|
* Gets the current value of the prism. If the value is stale, it causes the prism to freshen.
|
||||||
*/
|
*/
|
||||||
getValue(): V
|
getValue(): V
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether `d` is a derivation.
|
* Returns whether `d` is a prism.
|
||||||
*/
|
*/
|
||||||
export function isPrism(d: any): d is Prism<unknown> {
|
export function isPrism(d: any): d is Prism<unknown> {
|
||||||
return d && d.isPrism && d.isPrism === true
|
return d && d.isPrism && d.isPrism === true
|
||||||
|
|
|
@ -93,7 +93,7 @@ describe('prism', () => {
|
||||||
|
|
||||||
const a = new Atom({letter: 'a'})
|
const a = new Atom({letter: 'a'})
|
||||||
|
|
||||||
const derivation = prism(() => {
|
const prsm = prism(() => {
|
||||||
const n = val(a.pointer.letter)
|
const n = val(a.pointer.letter)
|
||||||
const iterationAtTimeOfCall = iteration
|
const iterationAtTimeOfCall = iteration
|
||||||
sequence.push({derivationCall: iterationAtTimeOfCall})
|
sequence.push({derivationCall: iterationAtTimeOfCall})
|
||||||
|
@ -112,7 +112,7 @@ describe('prism', () => {
|
||||||
return n
|
return n
|
||||||
})
|
})
|
||||||
|
|
||||||
const untap = derivation.onChange(ticker, (change) => {
|
const untap = prsm.onChange(ticker, (change) => {
|
||||||
sequence.push({change})
|
sequence.push({change})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ describe('prism', () => {
|
||||||
|
|
||||||
const a = new Atom({letter: 'a'})
|
const a = new Atom({letter: 'a'})
|
||||||
|
|
||||||
const derivation = prism(() => {
|
const prsm = prism(() => {
|
||||||
const n = val(a.pointer.letter)
|
const n = val(a.pointer.letter)
|
||||||
const iterationAtTimeOfCall = iteration
|
const iterationAtTimeOfCall = iteration
|
||||||
sequence.push({derivationCall: iterationAtTimeOfCall})
|
sequence.push({derivationCall: iterationAtTimeOfCall})
|
||||||
|
@ -172,7 +172,7 @@ describe('prism', () => {
|
||||||
return n
|
return n
|
||||||
})
|
})
|
||||||
|
|
||||||
const untap = derivation.onChange(ticker, (change) => {
|
const untap = prsm.onChange(ticker, (change) => {
|
||||||
sequence.push({change})
|
sequence.push({change})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ class HotHandle<V> {
|
||||||
protected _lastValue: undefined | V = undefined
|
protected _lastValue: undefined | V = undefined
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the derivation is stale even though its dependencies aren't
|
* If true, the prism is stale even though its dependencies aren't
|
||||||
* marked as such. This is used by `prism.source()` and `prism.state()`
|
* marked as such. This is used by `prism.source()` and `prism.state()`
|
||||||
* to mark the prism as stale.
|
* to mark the prism as stale.
|
||||||
*/
|
*/
|
||||||
|
@ -200,7 +200,7 @@ const emptyObject = {}
|
||||||
|
|
||||||
class PrismDerivation<V> implements Prism<V> {
|
class PrismDerivation<V> implements Prism<V> {
|
||||||
/**
|
/**
|
||||||
* Whether the object is a derivation.
|
* Whether the object is a prism.
|
||||||
*/
|
*/
|
||||||
readonly isPrism: true = true
|
readonly isPrism: true = true
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ class PrismDerivation<V> implements Prism<V> {
|
||||||
constructor(private readonly _fn: () => V) {}
|
constructor(private readonly _fn: () => V) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the derivation is hot.
|
* Whether the prism is hot.
|
||||||
*/
|
*/
|
||||||
get isHot(): boolean {
|
get isHot(): boolean {
|
||||||
return this._state.hot
|
return this._state.hot
|
||||||
|
@ -266,16 +266,16 @@ class PrismDerivation<V> implements Prism<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep the derivation hot, even if there are no tappers (subscribers).
|
* Keep the prism hot, even if there are no tappers (subscribers).
|
||||||
*/
|
*/
|
||||||
keepHot() {
|
keepHot() {
|
||||||
return this.onStale(() => {})
|
return this.onStale(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a derivation as a dependent of this derivation.
|
* Add a prism as a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @param d - The derivation to be made a dependent of this derivation.
|
* @param d - The prism to be made a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @see _removeDependent
|
* @see _removeDependent
|
||||||
*/
|
*/
|
||||||
|
@ -295,9 +295,9 @@ class PrismDerivation<V> implements Prism<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a derivation as a dependent of this derivation.
|
* Remove a prism as a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @param d - The derivation to be removed from as a dependent of this derivation.
|
* @param d - The prism to be removed from as a dependent of this prism.
|
||||||
*
|
*
|
||||||
* @see _addDependent
|
* @see _addDependent
|
||||||
*/
|
*/
|
||||||
|
@ -315,23 +315,23 @@ class PrismDerivation<V> implements Prism<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current value of the derivation. If the value is stale, it causes the derivation to freshen.
|
* Gets the current value of the prism. If the value is stale, it causes the prism to freshen.
|
||||||
*/
|
*/
|
||||||
getValue(): V {
|
getValue(): V {
|
||||||
/**
|
/**
|
||||||
* TODO We should prevent (or warn about) a common mistake users make, which is reading the value of
|
* TODO We should prevent (or warn about) a common mistake users make, which is reading the value of
|
||||||
* a derivation in the body of a react component (e.g. `der.getValue()` (often via `val()`) instead of `useVal()`
|
* a prism in the body of a react component (e.g. `der.getValue()` (often via `val()`) instead of `useVal()`
|
||||||
* or `uesPrism()`).
|
* or `uesPrism()`).
|
||||||
*
|
*
|
||||||
* Although that's the most common example of this mistake, you can also find it outside of react components.
|
* Although that's the most common example of this mistake, you can also find it outside of react components.
|
||||||
* Basically the user runs `der.getValue()` assuming the read is detected by a wrapping prism when it's not.
|
* Basically the user runs `der.getValue()` assuming the read is detected by a wrapping prism when it's not.
|
||||||
*
|
*
|
||||||
* Sometiems the derivation isn't even hot when the user assumes it is.
|
* Sometiems the prism isn't even hot when the user assumes it is.
|
||||||
*
|
*
|
||||||
* We can fix this type of mistake by:
|
* We can fix this type of mistake by:
|
||||||
* 1. Warning the user when they call `getValue()` on a cold derivation.
|
* 1. Warning the user when they call `getValue()` on a cold prism.
|
||||||
* 2. Warning the user about calling `getValue()` on a hot-but-stale derivation
|
* 2. Warning the user about calling `getValue()` on a hot-but-stale prism
|
||||||
* if `getValue()` isn't called by a known mechanism like a `DerivationEmitter`.
|
* if `getValue()` isn't called by a known mechanism like a `PrismEmitter`.
|
||||||
*
|
*
|
||||||
* Design constraints:
|
* Design constraints:
|
||||||
* - This fix should not have a perf-penalty in production. Perhaps use a global flag + `process.env.NODE_ENV !== 'production'`
|
* - This fix should not have a perf-penalty in production. Perhaps use a global flag + `process.env.NODE_ENV !== 'production'`
|
||||||
|
@ -616,7 +616,7 @@ function memo<T>(
|
||||||
* ```ts
|
* ```ts
|
||||||
* import {prism} from 'dataverse'
|
* import {prism} from 'dataverse'
|
||||||
*
|
*
|
||||||
* // This derivation holds the current mouse position and updates when the mouse moves
|
* // This prism holds the current mouse position and updates when the mouse moves
|
||||||
* const mousePositionD = prism(() => {
|
* const mousePositionD = prism(() => {
|
||||||
* const [pos, setPos] = prism.state<[x: number, y: number]>('pos', [0, 0])
|
* const [pos, setPos] = prism.state<[x: number, y: number]>('pos', [0, 0])
|
||||||
*
|
*
|
||||||
|
@ -736,10 +736,10 @@ type IPrismFn = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a derivation from the passed function that adds all derivations referenced
|
* Creates a prism from the passed function that adds all prisms referenced
|
||||||
* in it as dependencies, and reruns the function when these change.
|
* in it as dependencies, and reruns the function when these change.
|
||||||
*
|
*
|
||||||
* @param fn - The function to rerun when the derivations referenced in it change.
|
* @param fn - The function to rerun when the prisms referenced in it change.
|
||||||
*/
|
*/
|
||||||
const prism: IPrismFn = (fn) => {
|
const prism: IPrismFn = (fn) => {
|
||||||
return new PrismDerivation(fn)
|
return new PrismDerivation(fn)
|
||||||
|
|
|
@ -153,7 +153,7 @@ export const getPointerParts = <_>(
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* // Here, sum is a derivation that updates whenever the a or b prop of someAtom does.
|
* // Here, sum is a prism that updates whenever the a or b prop of someAtom does.
|
||||||
* const sum = prism(() => {
|
* const sum = prism(() => {
|
||||||
* return val(pointer({root: someAtom, path: ['a']})) + val(pointer({root: someAtom, path: ['b']}));
|
* return val(pointer({root: someAtom, path: ['a']})) + val(pointer({root: someAtom, path: ['b']}));
|
||||||
* });
|
* });
|
||||||
|
|
|
@ -31,7 +31,7 @@ studio.extend({
|
||||||
const untapFn = prism<ToolsetConfig>(() => [
|
const untapFn = prism<ToolsetConfig>(() => [
|
||||||
{
|
{
|
||||||
type: 'Switch',
|
type: 'Switch',
|
||||||
value: val(exampleBox.derivation),
|
value: val(exampleBox.prism),
|
||||||
onChange: (value) => exampleBox.set(value),
|
onChange: (value) => exampleBox.set(value),
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ studio.extend({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
// listen to changes to this derivation using the requestAnimationFrame shared ticker
|
// listen to changes to this prism using the requestAnimationFrame shared ticker
|
||||||
.onChange(
|
.onChange(
|
||||||
Ticker.raf,
|
Ticker.raf,
|
||||||
(value) => {
|
(value) => {
|
||||||
|
|
|
@ -65,16 +65,16 @@ export function usePrism<T>(
|
||||||
boxRef.current.set(fnAsCallback)
|
boxRef.current.set(fnAsCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
const derivation = useMemo(
|
const pr = useMemo(
|
||||||
() =>
|
() =>
|
||||||
prism(() => {
|
prism(() => {
|
||||||
const fn = boxRef.current.derivation.getValue()
|
const fn = boxRef.current.prism.getValue()
|
||||||
return fn()
|
return fn()
|
||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
||||||
return useDerivation(derivation, debugLabel)
|
return useDerivation(pr, debugLabel)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useVal: typeof val = (p: $IntentionalAny, debugLabel?: string) => {
|
export const useVal: typeof val = (p: $IntentionalAny, debugLabel?: string) => {
|
||||||
|
@ -88,9 +88,9 @@ export const useVal: typeof val = (p: $IntentionalAny, debugLabel?: string) => {
|
||||||
let lastOrder = 0
|
let lastOrder = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sorted array of derivations that need to be refreshed. The derivations are sorted
|
* A sorted array of prisms that need to be refreshed. The prisms are sorted
|
||||||
* by their order, which means a parent derivation always gets priority to children
|
* by their order, which means a parent prism always gets priority to children
|
||||||
* and descendents. Ie. we refresh the derivations top to bottom.
|
* and descendents. Ie. we refresh the prisms top to bottom.
|
||||||
*/
|
*/
|
||||||
const queue: QueueItem[] = []
|
const queue: QueueItem[] = []
|
||||||
const setOfQueuedItems = new Set<QueueItem>()
|
const setOfQueuedItems = new Set<QueueItem>()
|
||||||
|
@ -99,7 +99,7 @@ type QueueItem<T = unknown> = {
|
||||||
order: number
|
order: number
|
||||||
/**
|
/**
|
||||||
* runUpdate() is the equivalent of a forceUpdate() call. It would only be called
|
* runUpdate() is the equivalent of a forceUpdate() call. It would only be called
|
||||||
* if the value of the inner derivation has _actually_ changed.
|
* if the value of the inner prism has _actually_ changed.
|
||||||
*/
|
*/
|
||||||
runUpdate: VoidFn
|
runUpdate: VoidFn
|
||||||
/**
|
/**
|
||||||
|
@ -142,11 +142,11 @@ type QueueItem<T = unknown> = {
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* A reference to the derivation
|
* A reference to the prism
|
||||||
*/
|
*/
|
||||||
der: Prism<T>
|
der: Prism<T>
|
||||||
/**
|
/**
|
||||||
* The last value of this derivation.
|
* The last value of this prism.
|
||||||
*/
|
*/
|
||||||
lastValue: T
|
lastValue: T
|
||||||
/**
|
/**
|
||||||
|
@ -246,17 +246,17 @@ function queueIfNeeded() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* A React hook that returns the value of the derivation that it received as the first argument.
|
* A React hook that returns the value of the prism that it received as the first argument.
|
||||||
* It works like an implementation of Dataverse's Ticker, except that it runs the side effects in
|
* It works like an implementation of Dataverse's Ticker, except that it runs the side effects in
|
||||||
* an order where a component's derivation is guaranteed to run before any of its descendents' derivations.
|
* an order where a component's prism is guaranteed to run before any of its descendents' prisms.
|
||||||
*
|
*
|
||||||
* @param der - The derivation
|
* @param der - The prism
|
||||||
* @param debugLabel - The label used by the debugger
|
* @param debugLabel - The label used by the debugger
|
||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* It looks like this new implementation of useDerivation() manages to:
|
* It looks like this new implementation of usePrism() manages to:
|
||||||
* 1. Not over-calculate the derivations
|
* 1. Not over-calculate the prisms
|
||||||
* 2. Render derivation in ancestor -\> descendent order
|
* 2. Render prism in ancestor -\> descendent order
|
||||||
* 3. Not set off React's concurrent mode alarms
|
* 3. Not set off React's concurrent mode alarms
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -266,21 +266,21 @@ function queueIfNeeded() {
|
||||||
*
|
*
|
||||||
* Notes on the latest implementation:
|
* Notes on the latest implementation:
|
||||||
*
|
*
|
||||||
* # Remove cold derivation reads
|
* # Remove cold prism reads
|
||||||
*
|
*
|
||||||
* Prior to the latest change, the first render of every `useDerivation()` resulted in a cold read of its inner derivation.
|
* Prior to the latest change, the first render of every `useDerivation()` resulted in a cold read of its inner prism.
|
||||||
* Cold reads are predictably slow. The reason we'd run cold reads was to comply with react's rule of not running side-effects
|
* Cold reads are predictably slow. The reason we'd run cold reads was to comply with react's rule of not running side-effects
|
||||||
* during render. (Turning a derivation hot is _technically_ a side-effect).
|
* during render. (Turning a prism hot is _technically_ a side-effect).
|
||||||
*
|
*
|
||||||
* However, now that users are animating scenes with hundreds of objects in the same sequence, the lag started to be noticable.
|
* However, now that users are animating scenes with hundreds of objects in the same sequence, the lag started to be noticable.
|
||||||
*
|
*
|
||||||
* This commit changes `useDerivation()` so that it turns its derivation hot before rendering them.
|
* This commit changes `useDerivation()` so that it turns its prism hot before rendering them.
|
||||||
*
|
*
|
||||||
* # Freshen derivations before render
|
* # Freshen prisms before render
|
||||||
*
|
*
|
||||||
* Previously in order to avoid the zombie child problem (https://kaihao.dev/posts/stale-props-and-zombie-children-in-redux)
|
* Previously in order to avoid the zombie child problem (https://kaihao.dev/posts/stale-props-and-zombie-children-in-redux)
|
||||||
* we deferred freshening the derivations to the render phase of components. This meant that if a derivation's dependencies
|
* we deferred freshening the prisms to the render phase of components. This meant that if a prism's dependencies
|
||||||
* changed, `useDerivation()` would schedule a re-render, regardless of whether that change actually affected the derivation's
|
* changed, `useDerivation()` would schedule a re-render, regardless of whether that change actually affected the prism's
|
||||||
* value. Here is a contrived example:
|
* value. Here is a contrived example:
|
||||||
*
|
*
|
||||||
* ```ts
|
* ```ts
|
||||||
|
@ -294,10 +294,10 @@ function queueIfNeeded() {
|
||||||
* num.set(2) // would cause Comp to re-render- even though 1 is still a positive number
|
* num.set(2) // would cause Comp to re-render- even though 1 is still a positive number
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* We now avoid this problem by freshening the derivation (i.e. calling `der.getValue()`) inside `runQueue()`,
|
* We now avoid this problem by freshening the prism (i.e. calling `der.getValue()`) inside `runQueue()`,
|
||||||
* and then only causing a re-render if the derivation's value is actually changed.
|
* and then only causing a re-render if the prism's value is actually changed.
|
||||||
*
|
*
|
||||||
* This still avoids the zombie-child problem because `runQueue` reads the derivations in-order of their position in
|
* This still avoids the zombie-child problem because `runQueue` reads the prisms in-order of their position in
|
||||||
* the mounting tree.
|
* the mounting tree.
|
||||||
*
|
*
|
||||||
* On the off-chance that one of them still turns out to be a zombile child, `runQueue` will defer that particular
|
* On the off-chance that one of them still turns out to be a zombile child, `runQueue` will defer that particular
|
||||||
|
@ -374,29 +374,29 @@ export function useDerivation<T>(der: Prism<T>, debugLabel?: string): T {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This makes sure the prism derivation remains hot as long as the
|
* This makes sure the prism prism remains hot as long as the
|
||||||
* component calling the hook is alive, but it does not
|
* component calling the hook is alive, but it does not
|
||||||
* return the value of the derivation, and it does not
|
* return the value of the prism, and it does not
|
||||||
* re-render the component if the value of the derivation changes.
|
* re-render the component if the value of the prism changes.
|
||||||
*
|
*
|
||||||
* Use this hook if you plan to read a derivation in a
|
* Use this hook if you plan to read a prism in a
|
||||||
* useEffect() call, without the derivation causing your
|
* useEffect() call, without the prism causing your
|
||||||
* element to re-render.
|
* element to re-render.
|
||||||
*/
|
*/
|
||||||
export function usePrismWithoutReRender<T>(
|
export function usePrismWithoutReRender<T>(
|
||||||
fn: () => T,
|
fn: () => T,
|
||||||
deps: unknown[],
|
deps: unknown[],
|
||||||
): Prism<T> {
|
): Prism<T> {
|
||||||
const derivation = useMemo(() => prism(fn), deps)
|
const pr = useMemo(() => prism(fn), deps)
|
||||||
|
|
||||||
return useDerivationWithoutReRender(derivation)
|
return useDerivationWithoutReRender(pr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This makes sure the derivation remains hot as long as the
|
* This makes sure the prism remains hot as long as the
|
||||||
* component calling the hook is alive, but it does not
|
* component calling the hook is alive, but it does not
|
||||||
* return the value of the derivation, and it does not
|
* return the value of the prism, and it does not
|
||||||
* re-render the component if the value of the derivation changes.
|
* re-render the component if the value of the prism changes.
|
||||||
*/
|
*/
|
||||||
export function useDerivationWithoutReRender<T>(der: Prism<T>): Prism<T> {
|
export function useDerivationWithoutReRender<T>(der: Prism<T>): Prism<T> {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -155,17 +155,13 @@ export function onChange<P extends PointerType<$IntentionalAny>>(
|
||||||
callback: (value: P extends PointerType<infer T> ? T : unknown) => void,
|
callback: (value: P extends PointerType<infer T> ? T : unknown) => void,
|
||||||
): VoidFn {
|
): VoidFn {
|
||||||
if (isPointer(pointer)) {
|
if (isPointer(pointer)) {
|
||||||
const derivation = pointerToPrism(pointer)
|
const pr = pointerToPrism(pointer)
|
||||||
return derivation.onChange(
|
return pr.onChange(getCoreTicker(), callback as $IntentionalAny, true)
|
||||||
getCoreTicker(),
|
|
||||||
callback as $IntentionalAny,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
} else if (isPrism(pointer)) {
|
} else if (isPrism(pointer)) {
|
||||||
return pointer.onChange(getCoreTicker(), callback as $IntentionalAny, true)
|
return pointer.onChange(getCoreTicker(), callback as $IntentionalAny, true)
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Called onChange(p) where p is neither a pointer nor a derivation.`,
|
`Called onChange(p) where p is neither a pointer nor a prism.`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import globals from '@theatre/shared/globals'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @remarks
|
* @remarks
|
||||||
* TODO this could be turned into a simple derivation, like:
|
* TODO this could be turned into a simple prism, like:
|
||||||
* `editor.isReady: Prism<{isReady: true} | {isReady: false, reason: 'conflictBetweenDiskStateAndBrowserState'}>`
|
* `editor.isReady: Prism<{isReady: true} | {isReady: false, reason: 'conflictBetweenDiskStateAndBrowserState'}>`
|
||||||
*/
|
*/
|
||||||
export default async function initialiseProjectState(
|
export default async function initialiseProjectState(
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default class Sequence {
|
||||||
)
|
)
|
||||||
|
|
||||||
this._statePointerDerivation = prism(
|
this._statePointerDerivation = prism(
|
||||||
() => this._playbackControllerBox.derivation.getValue().statePointer,
|
() => this._playbackControllerBox.prism.getValue().statePointer,
|
||||||
)
|
)
|
||||||
|
|
||||||
this._positionD = prism(() => {
|
this._positionD = prism(() => {
|
||||||
|
@ -189,7 +189,7 @@ export default class Sequence {
|
||||||
* @remarks
|
* @remarks
|
||||||
* One use case for this is to play the playback within the focus range.
|
* One use case for this is to play the playback within the focus range.
|
||||||
*
|
*
|
||||||
* @param rangeD - The derivation that contains the range that will be used for the playback
|
* @param rangeD - The prism that contains the range that will be used for the playback
|
||||||
*
|
*
|
||||||
* @returns a promise that gets rejected if the playback stopped for whatever reason
|
* @returns a promise that gets rejected if the playback stopped for whatever reason
|
||||||
*
|
*
|
||||||
|
|
|
@ -31,7 +31,7 @@ export interface IPlaybackController {
|
||||||
* @remarks
|
* @remarks
|
||||||
* One use case for this is to play the playback within the focus range.
|
* One use case for this is to play the playback within the focus range.
|
||||||
*
|
*
|
||||||
* @param rangeD - The derivation that contains the range that will be used for the playback
|
* @param rangeD - The prism that contains the range that will be used for the playback
|
||||||
*
|
*
|
||||||
* @returns a promise that gets rejected if the playback stopped for whatever reason
|
* @returns a promise that gets rejected if the playback stopped for whatever reason
|
||||||
*
|
*
|
||||||
|
|
|
@ -70,8 +70,8 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
getValues(): Prism<Pointer<SheetObjectPropsValue>> {
|
getValues(): Prism<Pointer<SheetObjectPropsValue>> {
|
||||||
// Cache the derivation because only one is needed per SheetObject.
|
// Cache the prism because only one is needed per SheetObject.
|
||||||
// Also, if `onValuesChange()` is unsubscribed from, this derivation will go cold
|
// Also, if `onValuesChange()` is unsubscribed from, this prism will go cold
|
||||||
// and free its resources. So it's no problem to still keep it on the cache.
|
// and free its resources. So it's no problem to still keep it on the cache.
|
||||||
return this._cache.get('getValues()', () =>
|
return this._cache.get('getValues()', () =>
|
||||||
prism(() => {
|
prism(() => {
|
||||||
|
@ -107,7 +107,7 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The lowest layer is the default value of the root prop. Since an object's config
|
* The lowest layer is the default value of the root prop. Since an object's config
|
||||||
* _could_ change, we read it as a derivation. Otherwise, we could have just `getDefaultsOfPropTypeConfig(this.template.staticConfig)`.
|
* _could_ change, we read it as a prism. Otherwise, we could have just `getDefaultsOfPropTypeConfig(this.template.staticConfig)`.
|
||||||
*
|
*
|
||||||
* Note: If studio is not present, there is no known use-case for the config of an object to change on the fly, so
|
* Note: If studio is not present, there is no known use-case for the config of an object to change on the fly, so
|
||||||
* we could read this value statically.
|
* we could read this value statically.
|
||||||
|
@ -168,7 +168,7 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
let sequenced
|
let sequenced
|
||||||
|
|
||||||
{
|
{
|
||||||
// NOTE: we're reading the sequenced values as a derivation to a pointer. This should be refactored
|
// NOTE: we're reading the sequenced values as a prism to a pointer. This should be refactored
|
||||||
// to a simple pointer.
|
// to a simple pointer.
|
||||||
const pointerToSequencedValuesD = prism.memo(
|
const pointerToSequencedValuesD = prism.memo(
|
||||||
'seq',
|
'seq',
|
||||||
|
@ -185,7 +185,7 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
)
|
)
|
||||||
|
|
||||||
// read the sequenced values
|
// read the sequenced values
|
||||||
// (val(val(x))) unwraps the pointer and the derivation
|
// (val(val(x))) unwraps the pointer and the prism
|
||||||
sequenced = val(val(pointerToSequencedValuesD))
|
sequenced = val(val(pointerToSequencedValuesD))
|
||||||
|
|
||||||
// deep-merge the sequenced values with the previous layer
|
// deep-merge the sequenced values with the previous layer
|
||||||
|
@ -243,7 +243,7 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
const untaps: Array<() => void> = []
|
const untaps: Array<() => void> = []
|
||||||
|
|
||||||
for (const {trackId, pathToProp} of tracksToProcess) {
|
for (const {trackId, pathToProp} of tracksToProcess) {
|
||||||
const derivation = this._trackIdToDerivation(trackId)
|
const pr = this._trackIdToPrism(trackId)
|
||||||
const propConfig = getPropConfigByPath(
|
const propConfig = getPropConfigByPath(
|
||||||
config,
|
config,
|
||||||
pathToProp,
|
pathToProp,
|
||||||
|
@ -254,7 +254,7 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
propConfig.interpolate! as Interpolator<$IntentionalAny>
|
propConfig.interpolate! as Interpolator<$IntentionalAny>
|
||||||
|
|
||||||
const updateSequenceValueFromItsDerivation = () => {
|
const updateSequenceValueFromItsDerivation = () => {
|
||||||
const triple = derivation.getValue()
|
const triple = pr.getValue()
|
||||||
|
|
||||||
if (!triple) return valsAtom.setIn(pathToProp, undefined)
|
if (!triple) return valsAtom.setIn(pathToProp, undefined)
|
||||||
|
|
||||||
|
@ -279,9 +279,7 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
interpolate(left, right, triple.progression),
|
interpolate(left, right, triple.progression),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const untap = derivation.onStale(
|
const untap = pr.onStale(updateSequenceValueFromItsDerivation)
|
||||||
updateSequenceValueFromItsDerivation,
|
|
||||||
)
|
|
||||||
|
|
||||||
updateSequenceValueFromItsDerivation()
|
updateSequenceValueFromItsDerivation()
|
||||||
untaps.push(untap)
|
untaps.push(untap)
|
||||||
|
@ -299,7 +297,7 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _trackIdToDerivation(
|
protected _trackIdToPrism(
|
||||||
trackId: SequenceTrackId,
|
trackId: SequenceTrackId,
|
||||||
): Prism<InterpolationTriple | undefined> {
|
): Prism<InterpolationTriple | undefined> {
|
||||||
const trackP =
|
const trackP =
|
||||||
|
|
|
@ -147,7 +147,7 @@ export default class TheatreSheetObject<
|
||||||
return {...privateAPI(this).address}
|
return {...privateAPI(this).address}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _valuesDerivation(): Prism<this['value']> {
|
private _valuesPrism(): Prism<this['value']> {
|
||||||
return this._cache.get('onValuesChangeDerivation', () => {
|
return this._cache.get('onValuesChangeDerivation', () => {
|
||||||
const sheetObject = privateAPI(this)
|
const sheetObject = privateAPI(this)
|
||||||
const d: Prism<PropsValue<Props>> = prism(() => {
|
const d: Prism<PropsValue<Props>> = prism(() => {
|
||||||
|
@ -158,15 +158,15 @@ export default class TheatreSheetObject<
|
||||||
}
|
}
|
||||||
|
|
||||||
onValuesChange(fn: (values: this['value']) => void): VoidFn {
|
onValuesChange(fn: (values: this['value']) => void): VoidFn {
|
||||||
return this._valuesDerivation().onChange(getCoreTicker(), fn, true)
|
return this._valuesPrism().onChange(getCoreTicker(), fn, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal: Make the deviration keepHot if directly read
|
// internal: Make the deviration keepHot if directly read
|
||||||
get value(): PropsValue<Props> {
|
get value(): PropsValue<Props> {
|
||||||
const der = this._valuesDerivation()
|
const der = this._valuesPrism()
|
||||||
if (KEEP_HOT_FOR_MS != null) {
|
if (KEEP_HOT_FOR_MS != null) {
|
||||||
if (!der.isHot) {
|
if (!der.isHot) {
|
||||||
// derivation not hot, so keep it hot and set up `_keepHotUntapDebounce`
|
// prism not hot, so keep it hot and set up `_keepHotUntapDebounce`
|
||||||
if (this._keepHotUntapDebounce != null) {
|
if (this._keepHotUntapDebounce != null) {
|
||||||
// defensive checks
|
// defensive checks
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default function useKeyboardShortcuts() {
|
||||||
const {projectId, sheetId} = seq.address
|
const {projectId, sheetId} = seq.address
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The value of this derivation is an array that contains the
|
* The value of this prism is an array that contains the
|
||||||
* range of the playback (start and end), and a boolean that is
|
* range of the playback (start and end), and a boolean that is
|
||||||
* `true` if the playback should be played within that range.
|
* `true` if the playback should be played within that range.
|
||||||
*/
|
*/
|
||||||
|
@ -162,7 +162,7 @@ const getPlaybackStateBox = memoizeFn(
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A memoized function that returns a derivation with a boolean value.
|
* A memoized function that returns a prism with a boolean value.
|
||||||
* This value is set to `true` if:
|
* This value is set to `true` if:
|
||||||
* 1. the playback is playing and using the focus range instead of the whole sequence
|
* 1. the playback is playing and using the focus range instead of the whole sequence
|
||||||
* 2. the playback is stopped, but would use the focus range if it were started.
|
* 2. the playback is stopped, but would use the focus range if it were started.
|
||||||
|
@ -171,7 +171,7 @@ export const getIsPlayheadAttachedToFocusRange = memoizeFn(
|
||||||
(sequence: Sequence) =>
|
(sequence: Sequence) =>
|
||||||
prism<boolean>(() => {
|
prism<boolean>(() => {
|
||||||
const controlledPlaybackState =
|
const controlledPlaybackState =
|
||||||
getPlaybackStateBox(sequence).derivation.getValue()
|
getPlaybackStateBox(sequence).prism.getValue()
|
||||||
if (controlledPlaybackState) {
|
if (controlledPlaybackState) {
|
||||||
return controlledPlaybackState.getValue().isFollowingARange
|
return controlledPlaybackState.getValue().isFollowingARange
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -199,8 +199,8 @@ const isDetailPanelHotspotActiveB = new Box<boolean>(false)
|
||||||
const isDetailPanelHoveredB = new Box<boolean>(false)
|
const isDetailPanelHoveredB = new Box<boolean>(false)
|
||||||
|
|
||||||
export const shouldShowDetailD = prism<boolean>(() => {
|
export const shouldShowDetailD = prism<boolean>(() => {
|
||||||
const isHovered = val(isDetailPanelHoveredB.derivation)
|
const isHovered = val(isDetailPanelHoveredB.prism)
|
||||||
const isHotspotActive = val(isDetailPanelHotspotActiveB.derivation)
|
const isHotspotActive = val(isDetailPanelHotspotActiveB.prism)
|
||||||
|
|
||||||
return isHovered || isHotspotActive
|
return isHovered || isHotspotActive
|
||||||
})
|
})
|
||||||
|
|
|
@ -83,8 +83,8 @@ const isOutlinePanelHotspotActiveB = new Box<boolean>(false)
|
||||||
const isOutlinePanelHoveredB = new Box<boolean>(false)
|
const isOutlinePanelHoveredB = new Box<boolean>(false)
|
||||||
|
|
||||||
export const shouldShowOutlineD = prism<boolean>(() => {
|
export const shouldShowOutlineD = prism<boolean>(() => {
|
||||||
const isHovered = val(isOutlinePanelHoveredB.derivation)
|
const isHovered = val(isOutlinePanelHoveredB.prism)
|
||||||
const isHotspotActive = val(isOutlinePanelHotspotActiveB.derivation)
|
const isHotspotActive = val(isOutlinePanelHotspotActiveB.prism)
|
||||||
|
|
||||||
return isHovered || isHotspotActive
|
return isHovered || isHotspotActive
|
||||||
})
|
})
|
||||||
|
|
|
@ -545,12 +545,12 @@ const {isCurveEditorOpenD, isConnectionEditingInCurvePopover, getLock} =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isCurveEditorOpenD: prism(() => {
|
isCurveEditorOpenD: prism(() => {
|
||||||
return connectionsInCurvePopoverEdit.derivation.getValue().length > 0
|
return connectionsInCurvePopoverEdit.prism.getValue().length > 0
|
||||||
}),
|
}),
|
||||||
// must be run in a prism
|
// must be run in a prism
|
||||||
isConnectionEditingInCurvePopover(con: KeyframeConnectionWithAddress) {
|
isConnectionEditingInCurvePopover(con: KeyframeConnectionWithAddress) {
|
||||||
prism.ensurePrism()
|
prism.ensurePrism()
|
||||||
return connectionsInCurvePopoverEdit.derivation
|
return connectionsInCurvePopoverEdit.prism
|
||||||
.getValue()
|
.getValue()
|
||||||
.some(
|
.some(
|
||||||
({left, right}) =>
|
({left, right}) =>
|
||||||
|
|
|
@ -78,7 +78,7 @@ const stateB = new Box<
|
||||||
}
|
}
|
||||||
>({mode: 'snapToNone'})
|
>({mode: 'snapToNone'})
|
||||||
|
|
||||||
export const snapPositionsStateD = stateB.derivation
|
export const snapPositionsStateD = stateB.prism
|
||||||
|
|
||||||
export function snapToAll() {
|
export function snapToAll() {
|
||||||
stateB.set({mode: 'snapToAll'})
|
stateB.set({mode: 'snapToAll'})
|
||||||
|
|
|
@ -40,7 +40,7 @@ const ExtensionToolsetRender: React.FC<{
|
||||||
if (typeof detach === 'function') return detach
|
if (typeof detach === 'function') return detach
|
||||||
}, [extension, toolbarId])
|
}, [extension, toolbarId])
|
||||||
|
|
||||||
const config = useVal(toolsetConfigBox.derivation)
|
const config = useVal(toolsetConfigBox.prism)
|
||||||
|
|
||||||
return <Toolset config={config} />
|
return <Toolset config={config} />
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ export const useTooltipOpenState = (): [
|
||||||
|
|
||||||
const TooltipContext: React.FC<{}> = ({children}) => {
|
const TooltipContext: React.FC<{}> = ({children}) => {
|
||||||
const currentTooltipId = useMemo(() => new Box(-1), [])
|
const currentTooltipId = useMemo(() => new Box(-1), [])
|
||||||
const cur = currentTooltipId.derivation
|
const cur = currentTooltipId.prism
|
||||||
|
|
||||||
const set = useMemo(() => {
|
const set = useMemo(() => {
|
||||||
let lastTimeout: NodeJS.Timeout | undefined = undefined
|
let lastTimeout: NodeJS.Timeout | undefined = undefined
|
||||||
|
|
|
@ -68,7 +68,7 @@ function createPresenceContext(options: {
|
||||||
const focusD = useMemo(() => {
|
const focusD = useMemo(() => {
|
||||||
if (!itemKey) return undefinedD
|
if (!itemKey) return undefinedD
|
||||||
// this is the thing being hovered
|
// this is the thing being hovered
|
||||||
const currentD = currentUserHoverItemB.derivation
|
const currentD = currentUserHoverItemB.prism
|
||||||
const primaryFocusDer = pointerToPrism(
|
const primaryFocusDer = pointerToPrism(
|
||||||
currentUserHoverFlagItemsAtom.pointer[itemKey],
|
currentUserHoverFlagItemsAtom.pointer[itemKey],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {prism} from '@theatre/dataverse'
|
import {prism} from '@theatre/dataverse'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A derivation that holds the current mouse position.
|
* A prism that holds the current mouse position.
|
||||||
*/
|
*/
|
||||||
const mousePositionD = prism(() => {
|
const mousePositionD = prism(() => {
|
||||||
const [pos, setPos] = prism.state<MouseEvent | null>('pos', null)
|
const [pos, setPos] = prism.state<MouseEvent | null>('pos', null)
|
||||||
|
|
Loading…
Reference in a new issue