Remove Box in favor of Atom

This commit is contained in:
Aria Minaei 2022-12-01 15:37:19 +01:00
parent 2bd1dc85a9
commit c354a602a4
13 changed files with 63 additions and 49 deletions

View file

@ -115,7 +115,7 @@ class Scope {
/** /**
* Wraps an object whose (sub)properties can be individually tracked. * Wraps an object whose (sub)properties can be individually tracked.
*/ */
export default class Atom<State extends {}> implements IdentityPrismProvider { export default class Atom<State> implements IdentityPrismProvider {
private _currentState: State private _currentState: State
/** /**
* @internal * @internal
@ -130,6 +130,8 @@ export default class Atom<State extends {}> implements IdentityPrismProvider {
*/ */
readonly pointer: Pointer<State> readonly pointer: Pointer<State>
readonly prism: Prism<State> = this.getIdentityPrism([]) as $IntentionalAny
constructor(initialState: State) { constructor(initialState: State) {
this._currentState = initialState this._currentState = initialState
this._rootScope = new Scope(undefined, []) this._rootScope = new Scope(undefined, [])
@ -141,7 +143,7 @@ export default class Atom<State extends {}> implements IdentityPrismProvider {
* *
* @param newState - The new state of the atom. * @param newState - The new state of the atom.
*/ */
setState(newState: State) { set(newState: State) {
const oldState = this._currentState const oldState = this._currentState
this._currentState = newState this._currentState = newState
@ -150,11 +152,23 @@ export default class Atom<State extends {}> implements IdentityPrismProvider {
/** /**
* Gets the current state of the atom. * Gets the current state of the atom.
* @deprecated
*/ */
getState() { getState() {
return this._currentState return this._currentState
} }
get() {
return this.getState()
}
/**
* @deprecated
*/
setState(newState: State) {
this.set(newState)
}
/** /**
* Gets the state of the atom at `path`. * Gets the state of the atom at `path`.
*/ */

View file

@ -6,8 +6,6 @@
export type {IdentityPrismProvider} from './Atom' export type {IdentityPrismProvider} from './Atom'
export {default as Atom, val, pointerToPrism} from './Atom' export {default as Atom, val, pointerToPrism} from './Atom'
export {default as Box} from './Box'
export type {IBox} from './Box'
export {isPrism} from './prism/Interface' export {isPrism} from './prism/Interface'
export type {Prism} from './prism/Interface' export type {Prism} from './prism/Interface'
export {default as iterateAndCountTicks} from './prism/iterateAndCountTicks' export {default as iterateAndCountTicks} from './prism/iterateAndCountTicks'

View file

@ -4,7 +4,7 @@ import App from './App'
import type {ToolsetConfig} from '@theatre/studio' import type {ToolsetConfig} from '@theatre/studio'
import studio from '@theatre/studio' import studio from '@theatre/studio'
import extension from '@theatre/r3f/dist/extension' import extension from '@theatre/r3f/dist/extension'
import {Box, prism, Ticker, val} from '@theatre/dataverse' import {Atom, prism, Ticker, val} from '@theatre/dataverse'
/** /**
* Let's take a look at how we can use `prism`, `Ticker`, and `val` from Theatre.js's Dataverse library * Let's take a look at how we can use `prism`, `Ticker`, and `val` from Theatre.js's Dataverse library
@ -26,7 +26,7 @@ studio.extend({
id: '@theatre/hello-world-extension', id: '@theatre/hello-world-extension',
toolbars: { toolbars: {
global(set, studio) { global(set, studio) {
const exampleBox = new Box('mobile') const exampleBox = new Atom('mobile')
const untapFn = prism<ToolsetConfig>(() => [ const untapFn = prism<ToolsetConfig>(() => [
{ {

View file

@ -4,8 +4,8 @@
* @packageDocumentation * @packageDocumentation
*/ */
import type {Prism} from '@theatre/dataverse' import type { Prism} from '@theatre/dataverse';
import {Box} from '@theatre/dataverse' import {Atom} from '@theatre/dataverse'
import {prism, val} from '@theatre/dataverse' import {prism, val} from '@theatre/dataverse'
import {findIndex} from 'lodash-es' import {findIndex} from 'lodash-es'
import queueMicrotask from 'queue-microtask' import queueMicrotask from 'queue-microtask'
@ -58,17 +58,17 @@ export function usePrism<T>(
debugLabel?: string, debugLabel?: string,
): T { ): T {
const fnAsCallback = useCallback(fn, deps) const fnAsCallback = useCallback(fn, deps)
const boxRef = useRef<Box<typeof fn>>(null as $IntentionalAny) const atomRef = useRef<Atom<typeof fn>>(null as $IntentionalAny)
if (!boxRef.current) { if (!atomRef.current) {
boxRef.current = new Box(fnAsCallback) atomRef.current = new Atom(fnAsCallback)
} else { } else {
boxRef.current.set(fnAsCallback) atomRef.current.setState(fnAsCallback)
} }
const prsm = useMemo( const prsm = useMemo(
() => () =>
prism(() => { prism(() => {
const fn = boxRef.current.prism.getValue() const fn = atomRef.current.prism.getValue()
return fn() return fn()
}), }),
[], [],

View file

@ -3,9 +3,10 @@ import type Sheet from '@theatre/core/sheets/Sheet'
import type {SequenceAddress} from '@theatre/shared/utils/addresses' import type {SequenceAddress} from '@theatre/shared/utils/addresses'
import didYouMean from '@theatre/shared/utils/didYouMean' import didYouMean from '@theatre/shared/utils/didYouMean'
import {InvalidArgumentError} from '@theatre/shared/utils/errors' import {InvalidArgumentError} from '@theatre/shared/utils/errors'
import type {IBox, Prism, Pointer} from '@theatre/dataverse' import type {Prism, Pointer} from '@theatre/dataverse'
import {Atom} from '@theatre/dataverse'
import {pointer} from '@theatre/dataverse' import {pointer} from '@theatre/dataverse'
import {Box, prism, val} from '@theatre/dataverse' import {prism, val} from '@theatre/dataverse'
import {padStart} from 'lodash-es' import {padStart} from 'lodash-es'
import type { import type {
IPlaybackController, IPlaybackController,
@ -37,7 +38,7 @@ export default class Sequence {
public readonly address: SequenceAddress public readonly address: SequenceAddress
publicApi: TheatreSequence publicApi: TheatreSequence
private _playbackControllerBox: IBox<IPlaybackController> private _playbackControllerBox: Atom<IPlaybackController>
private _prismOfStatePointer: Prism<Pointer<IPlaybackState>> private _prismOfStatePointer: Prism<Pointer<IPlaybackState>>
private _positionD: Prism<number> private _positionD: Prism<number>
private _positionFormatterD: Prism<ISequencePositionFormatter> private _positionFormatterD: Prism<ISequencePositionFormatter>
@ -62,7 +63,7 @@ export default class Sequence {
this.publicApi = new TheatreSequence(this) this.publicApi = new TheatreSequence(this)
this._playbackControllerBox = new Box( this._playbackControllerBox = new Atom(
playbackController ?? new DefaultPlaybackController(getCoreTicker()), playbackController ?? new DefaultPlaybackController(getCoreTicker()),
) )
@ -123,7 +124,7 @@ export default class Sequence {
} }
get position() { get position() {
return this._playbackControllerBox.get().getCurrentPosition() return this._playbackControllerBox.getState().getCurrentPosition()
} }
get subUnitsPerUnit(): number { get subUnitsPerUnit(): number {
@ -165,7 +166,7 @@ export default class Sequence {
} }
const dur = this.length const dur = this.length
this._playbackControllerBox this._playbackControllerBox
.get() .getState()
.gotoPosition(position > dur ? dur : position) .gotoPosition(position > dur ? dur : position)
} }
@ -174,7 +175,7 @@ export default class Sequence {
} }
get playing() { get playing() {
return val(this._playbackControllerBox.get().statePointer.playing) return val(this._playbackControllerBox.getState().statePointer.playing)
} }
_makeRangeFromSequenceTemplate(): Prism<IPlaybackRange> { _makeRangeFromSequenceTemplate(): Prism<IPlaybackRange> {
@ -195,7 +196,7 @@ export default class Sequence {
* *
*/ */
playDynamicRange(rangeD: Prism<IPlaybackRange>): Promise<unknown> { playDynamicRange(rangeD: Prism<IPlaybackRange>): Promise<unknown> {
return this._playbackControllerBox.get().playDynamicRange(rangeD) return this._playbackControllerBox.getState().playDynamicRange(rangeD)
} }
async play( async play(
@ -329,18 +330,18 @@ To fix this, either set \`conf.range[1]\` to be less the duration of the sequenc
direction: IPlaybackDirection, direction: IPlaybackDirection,
): Promise<boolean> { ): Promise<boolean> {
return this._playbackControllerBox return this._playbackControllerBox
.get() .getState()
.play(iterationCount, range, rate, direction) .play(iterationCount, range, rate, direction)
} }
pause() { pause() {
this._playbackControllerBox.get().pause() this._playbackControllerBox.getState().pause()
} }
replacePlaybackController(playbackController: IPlaybackController) { replacePlaybackController(playbackController: IPlaybackController) {
this.pause() this.pause()
const oldController = this._playbackControllerBox.get() const oldController = this._playbackControllerBox.getState()
this._playbackControllerBox.set(playbackController) this._playbackControllerBox.setState(playbackController)
const time = oldController.getCurrentPosition() const time = oldController.getCurrentPosition()
oldController.destroy() oldController.destroy()

View file

@ -4,7 +4,7 @@ import {cmdIsDown} from '@theatre/studio/utils/keyboardUtils'
import {getSelectedSequence} from '@theatre/studio/selectors' import {getSelectedSequence} from '@theatre/studio/selectors'
import type {$IntentionalAny} from '@theatre/shared/utils/types' import type {$IntentionalAny} from '@theatre/shared/utils/types'
import type {Prism} from '@theatre/dataverse' import type {Prism} from '@theatre/dataverse'
import {Box, prism, val} from '@theatre/dataverse' import {Atom, prism, val} from '@theatre/dataverse'
import type {IPlaybackRange} from '@theatre/core/sequences/Sequence' import type {IPlaybackRange} from '@theatre/core/sequences/Sequence'
import type Sequence from '@theatre/core/sequences/Sequence' import type Sequence from '@theatre/core/sequences/Sequence'
import memoizeFn from '@theatre/shared/utils/memoizeFn' import memoizeFn from '@theatre/shared/utils/memoizeFn'
@ -150,13 +150,13 @@ export default function useKeyboardShortcuts() {
}, []) }, [])
} }
type ControlledPlaybackStateBox = Box< type ControlledPlaybackStateBox = Atom<
undefined | Prism<{range: IPlaybackRange; isFollowingARange: boolean}> undefined | Prism<{range: IPlaybackRange; isFollowingARange: boolean}>
> >
const getPlaybackStateBox = memoizeFn( const getPlaybackStateBox = memoizeFn(
(sequence: Sequence): ControlledPlaybackStateBox => { (sequence: Sequence): ControlledPlaybackStateBox => {
const box = new Box(undefined) as ControlledPlaybackStateBox const box = new Atom(undefined) as ControlledPlaybackStateBox
return box return box
}, },
) )

View file

@ -19,7 +19,7 @@ import ObjectDetails from './ObjectDetails'
import ProjectDetails from './ProjectDetails' import ProjectDetails from './ProjectDetails'
import getStudio from '@theatre/studio/getStudio' import getStudio from '@theatre/studio/getStudio'
import useHotspot from '@theatre/studio/uiComponents/useHotspot' import useHotspot from '@theatre/studio/uiComponents/useHotspot'
import {Box, prism, val} from '@theatre/dataverse' import {Atom, prism, val} from '@theatre/dataverse'
import EmptyState from './EmptyState' import EmptyState from './EmptyState'
import useLockSet from '@theatre/studio/uiComponents/useLockSet' import useLockSet from '@theatre/studio/uiComponents/useLockSet'
import {usePresenceListenersOnRootElement} from '@theatre/studio/uiComponents/usePresence' import {usePresenceListenersOnRootElement} from '@theatre/studio/uiComponents/usePresence'
@ -195,8 +195,8 @@ export default () => {
) )
} }
const isDetailPanelHotspotActiveB = new Box<boolean>(false) const isDetailPanelHotspotActiveB = new Atom<boolean>(false)
const isDetailPanelHoveredB = new Box<boolean>(false) const isDetailPanelHoveredB = new Atom<boolean>(false)
export const shouldShowDetailD = prism<boolean>(() => { export const shouldShowDetailD = prism<boolean>(() => {
const isHovered = val(isDetailPanelHoveredB.prism) const isHovered = val(isDetailPanelHoveredB.prism)

View file

@ -5,7 +5,7 @@ import ProjectsList from './ProjectsList/ProjectsList'
import {useVal} from '@theatre/react' import {useVal} from '@theatre/react'
import getStudio from '@theatre/studio/getStudio' import getStudio from '@theatre/studio/getStudio'
import useHotspot from '@theatre/studio/uiComponents/useHotspot' import useHotspot from '@theatre/studio/uiComponents/useHotspot'
import {Box, prism, val} from '@theatre/dataverse' import {Atom, prism, val} from '@theatre/dataverse'
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css' import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
const headerHeight = `44px` const headerHeight = `44px`
@ -79,8 +79,8 @@ const OutlinePanel: React.FC<{}> = () => {
export default OutlinePanel export default OutlinePanel
const isOutlinePanelHotspotActiveB = new Box<boolean>(false) const isOutlinePanelHotspotActiveB = new Atom<boolean>(false)
const isOutlinePanelHoveredB = new Box<boolean>(false) const isOutlinePanelHoveredB = new Atom<boolean>(false)
export const shouldShowOutlineD = prism<boolean>(() => { export const shouldShowOutlineD = prism<boolean>(() => {
const isHovered = val(isOutlinePanelHoveredB.prism) const isHovered = val(isOutlinePanelHoveredB.prism)

View file

@ -1,4 +1,4 @@
import {Box, prism} from '@theatre/dataverse' import {Atom, prism} from '@theatre/dataverse'
import type {KeyboardEvent} from 'react' import type {KeyboardEvent} from 'react'
import React, { import React, {
useEffect, useEffect,
@ -532,7 +532,7 @@ function areConnectedKeyframesTheSameAs({
const {isCurveEditorOpenD, isConnectionEditingInCurvePopover, getLock} = const {isCurveEditorOpenD, isConnectionEditingInCurvePopover, getLock} =
(() => { (() => {
const connectionsInCurvePopoverEdit = new Box< const connectionsInCurvePopoverEdit = new Atom<
Array<KeyframeConnectionWithAddress> Array<KeyframeConnectionWithAddress>
>([]) >([])

View file

@ -1,6 +1,7 @@
import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout' import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout'
import type {Pointer} from '@theatre/dataverse' import type { Pointer} from '@theatre/dataverse';
import {Box, val} from '@theatre/dataverse' import {Atom} from '@theatre/dataverse'
import {val} from '@theatre/dataverse'
import React from 'react' import React from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import {DopeSnapHitZoneUI} from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnapHitZoneUI' import {DopeSnapHitZoneUI} from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnapHitZoneUI'
@ -62,7 +63,7 @@ export type KeyframeSnapPositions = {
} }
} }
const stateB = new Box< const stateB = new Atom<
| { | {
// all keyframes must be snap targets // all keyframes must be snap targets
mode: 'snapToAll' mode: 'snapToAll'

View file

@ -1,4 +1,4 @@
import {Box} from '@theatre/dataverse' import {Atom} from '@theatre/dataverse'
import {useVal} from '@theatre/react' import {useVal} from '@theatre/react'
import type {IExtension} from '@theatre/studio' import type {IExtension} from '@theatre/studio'
import getStudio from '@theatre/studio/getStudio' import getStudio from '@theatre/studio/getStudio'
@ -29,11 +29,11 @@ const ExtensionToolsetRender: React.FC<{
extension: IExtension extension: IExtension
toolbarId: string toolbarId: string
}> = ({extension, toolbarId}) => { }> = ({extension, toolbarId}) => {
const toolsetConfigBox = useMemo(() => new Box<ToolsetConfig>([]), []) const toolsetConfigBox = useMemo(() => new Atom<ToolsetConfig>([]), [])
useLayoutEffect(() => { useLayoutEffect(() => {
const detach = extension.toolbars?.[toolbarId]?.( const detach = extension.toolbars?.[toolbarId]?.(
toolsetConfigBox.set.bind(toolsetConfigBox), toolsetConfigBox.setState.bind(toolsetConfigBox),
getStudio()!.publicApi, getStudio()!.publicApi,
) )

View file

@ -1,5 +1,5 @@
import type {Prism} from '@theatre/dataverse' import type { Prism} from '@theatre/dataverse';
import {Box} from '@theatre/dataverse' import {Atom} from '@theatre/dataverse'
import useRefAndState from '@theatre/studio/utils/useRefAndState' import useRefAndState from '@theatre/studio/utils/useRefAndState'
import React, { import React, {
createContext, createContext,
@ -40,7 +40,7 @@ export const useTooltipOpenState = (): [
} }
const TooltipContext: React.FC<{}> = ({children}) => { const TooltipContext: React.FC<{}> = ({children}) => {
const currentTooltipId = useMemo(() => new Box(-1), []) const currentTooltipId = useMemo(() => new Atom(-1), [])
const cur = currentTooltipId.prism const cur = currentTooltipId.prism
const set = useMemo(() => { const set = useMemo(() => {

View file

@ -3,7 +3,7 @@ import type {StrictRecord} from '@theatre/shared/utils/types'
import React, {useMemo} from 'react' import React, {useMemo} from 'react'
import {useEffect} from 'react' import {useEffect} from 'react'
import {useLogger} from './useLogger' import {useLogger} from './useLogger'
import {Box, prism, pointerToPrism} from '@theatre/dataverse' import {prism, pointerToPrism} from '@theatre/dataverse'
import {Atom} from '@theatre/dataverse' import {Atom} from '@theatre/dataverse'
import {usePrismInstance} from '@theatre/react' import {usePrismInstance} from '@theatre/react'
import {selectClosestHTMLAncestor} from '@theatre/studio/utils/selectClosestHTMLAncestor' import {selectClosestHTMLAncestor} from '@theatre/studio/utils/selectClosestHTMLAncestor'
@ -24,7 +24,7 @@ undefinedD.keepHot() // constant anyway...
function createPresenceContext(options: { function createPresenceContext(options: {
enabled: boolean enabled: boolean
}): InternalPresenceContext { }): InternalPresenceContext {
const currentUserHoverItemB = new Box<StudioSheetItemKey | undefined>( const currentUserHoverItemB = new Atom<StudioSheetItemKey | undefined>(
undefined, undefined,
) )
const currentUserHoverFlagItemsAtom = new Atom( const currentUserHoverFlagItemsAtom = new Atom(
@ -98,14 +98,14 @@ function createPresenceContext(options: {
return usePrismInstance(focusD) return usePrismInstance(focusD)
}, },
setUserHover(itemKeyOpt) { setUserHover(itemKeyOpt) {
const prev = currentUserHoverItemB.get() const prev = currentUserHoverItemB.getState()
if (prev === itemKeyOpt) { if (prev === itemKeyOpt) {
return return
} }
if (prev) { if (prev) {
currentUserHoverFlagItemsAtom.setIn([prev], false) currentUserHoverFlagItemsAtom.setIn([prev], false)
} }
currentUserHoverItemB.set(itemKeyOpt) currentUserHoverItemB.setState(itemKeyOpt)
if (itemKeyOpt) { if (itemKeyOpt) {
currentUserHoverFlagItemsAtom.setIn([itemKeyOpt], true) currentUserHoverFlagItemsAtom.setIn([itemKeyOpt], true)
} }