Replace Atom.setIn()
and Atom.reduceIn()
with the type-safe Atom.setByPointer()
and Atom.reduceByPointer()
This commit is contained in:
parent
5b6306bde9
commit
ac9d8b4481
15 changed files with 82 additions and 223 deletions
|
@ -4,10 +4,10 @@ import last from 'lodash-es/last'
|
||||||
import type {Prism} from './prism/Interface'
|
import type {Prism} from './prism/Interface'
|
||||||
import {isPrism} from './prism/Interface'
|
import {isPrism} from './prism/Interface'
|
||||||
import type {Pointer, PointerType} from './pointer'
|
import type {Pointer, PointerType} from './pointer'
|
||||||
|
import {getPointerParts} from './pointer'
|
||||||
import {isPointer} from './pointer'
|
import {isPointer} from './pointer'
|
||||||
import pointer, {getPointerMeta} from './pointer'
|
import pointer, {getPointerMeta} from './pointer'
|
||||||
import type {$FixMe, $IntentionalAny} from './types'
|
import type {$FixMe, $IntentionalAny} from './types'
|
||||||
import type {PathBasedReducer} from './utils/PathBasedReducer'
|
|
||||||
import updateDeep from './utils/updateDeep'
|
import updateDeep from './utils/updateDeep'
|
||||||
import prism from './prism/prism'
|
import prism from './prism/prism'
|
||||||
|
|
||||||
|
@ -176,39 +176,22 @@ export default class Atom<State> implements IdentityPrismProvider {
|
||||||
return path.length === 0 ? this.getState() : get(this.getState(), path)
|
return path.length === 0 ? this.getState() : get(this.getState(), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
reduce(fn: (state: State) => State) {
|
||||||
* Creates a new state object from the current one, where the value at `path`
|
this.set(fn(this.get()))
|
||||||
* is replaced by the return value of `reducer`, then sets it.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Doesn't mutate the old state, and preserves referential equality between
|
|
||||||
* values of the old state and the new state where possible.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* someAtom.getIn(['a']) // 1
|
|
||||||
* someAtom.reduceState(['a'], (state) => state + 1);
|
|
||||||
* someAtom.getIn(['a']) // 2
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param path - The path to call the reducer at.
|
|
||||||
* @param reducer - The function to use for creating the new state.
|
|
||||||
*/
|
|
||||||
// TODO: Why is this a property and not a method?
|
|
||||||
reduceState: PathBasedReducer<State, State> = (
|
|
||||||
path: $IntentionalAny[],
|
|
||||||
reducer: $IntentionalAny,
|
|
||||||
) => {
|
|
||||||
const newState = updateDeep(this.getState(), path, reducer)
|
|
||||||
this.setState(newState)
|
|
||||||
return newState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
reduceByPointer<S>(
|
||||||
* Sets the state of the atom at `path`.
|
fn: (p: Pointer<State>) => Pointer<S>,
|
||||||
*/
|
reducer: (s: S) => S,
|
||||||
setIn(path: $FixMe[], val: $FixMe) {
|
) {
|
||||||
return this.reduceState(path, () => val)
|
const pointer = fn(this.pointer)
|
||||||
|
const path = getPointerParts(pointer).path
|
||||||
|
const newState = updateDeep(this.get(), path, reducer)
|
||||||
|
this.set(newState)
|
||||||
|
}
|
||||||
|
|
||||||
|
setByPointer<S>(fn: (p: Pointer<State>) => Pointer<S>, val: S) {
|
||||||
|
this.reduceByPointer(fn, () => val)
|
||||||
}
|
}
|
||||||
|
|
||||||
private _checkUpdates(scope: Scope, oldState: unknown, newState: unknown) {
|
private _checkUpdates(scope: Scope, oldState: unknown, newState: unknown) {
|
||||||
|
|
|
@ -6,16 +6,16 @@ import iterateOver from './iterateOver'
|
||||||
|
|
||||||
describe(`iterateOver()`, () => {
|
describe(`iterateOver()`, () => {
|
||||||
test('it should work', () => {
|
test('it should work', () => {
|
||||||
const a = new Atom({a: 0})
|
const a = new Atom(0)
|
||||||
let iter = iterateOver(a.pointer.a)
|
let iter = iterateOver(a.pointer)
|
||||||
expect(iter.next().value).toEqual(0)
|
expect(iter.next().value).toEqual(0)
|
||||||
a.setIn(['a'], 1)
|
a.set(1)
|
||||||
a.setIn(['a'], 2)
|
a.set(2)
|
||||||
expect(iter.next()).toMatchObject({value: 2, done: false})
|
expect(iter.next()).toMatchObject({value: 2, done: false})
|
||||||
iter.return()
|
iter.return()
|
||||||
iter = iterateOver(a.pointer.a)
|
iter = iterateOver(a.pointer)
|
||||||
expect(iter.next().value).toEqual(2)
|
expect(iter.next().value).toEqual(2)
|
||||||
a.setIn(['a'], 3)
|
a.set(3)
|
||||||
expect(iter.next()).toMatchObject({done: false, value: 3})
|
expect(iter.next()).toMatchObject({done: false, value: 3})
|
||||||
iter.return()
|
iter.return()
|
||||||
})
|
})
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe('prism', () => {
|
||||||
changes.push(c)
|
changes.push(c)
|
||||||
})
|
})
|
||||||
|
|
||||||
o.reduceState(['foo'], () => 'foo2')
|
o.reduce(({foo}) => ({foo: 'foo2'}))
|
||||||
ticker.tick()
|
ticker.tick()
|
||||||
expect(changes).toMatchObject(['foo2boo'])
|
expect(changes).toMatchObject(['foo2boo'])
|
||||||
})
|
})
|
||||||
|
@ -43,11 +43,11 @@ describe('prism', () => {
|
||||||
|
|
||||||
describe('prism.ref()', () => {
|
describe('prism.ref()', () => {
|
||||||
it('should work', () => {
|
it('should work', () => {
|
||||||
const theAtom: Atom<{n: number}> = new Atom({n: 2})
|
const theAtom: Atom<number> = new Atom(2)
|
||||||
|
|
||||||
const isEvenD = prism((): {isEven: boolean} => {
|
const isEvenD = prism((): {isEven: boolean} => {
|
||||||
const ref = prism.ref<{isEven: boolean} | undefined>('cache', undefined)
|
const ref = prism.ref<{isEven: boolean} | undefined>('cache', undefined)
|
||||||
const currentN = val(theAtom.pointer.n)
|
const currentN = val(theAtom.pointer)
|
||||||
|
|
||||||
const isEven = currentN % 2 === 0
|
const isEven = currentN % 2 === 0
|
||||||
if (ref.current && ref.current.isEven === isEven) {
|
if (ref.current && ref.current.isEven === isEven) {
|
||||||
|
@ -60,20 +60,20 @@ describe('prism', () => {
|
||||||
|
|
||||||
const iterator = iterateAndCountTicks(isEvenD)
|
const iterator = iterateAndCountTicks(isEvenD)
|
||||||
|
|
||||||
theAtom.reduceState(['n'], () => 3)
|
theAtom.reduce(() => 3)
|
||||||
|
|
||||||
expect(iterator.next().value).toMatchObject({
|
expect(iterator.next().value).toMatchObject({
|
||||||
value: {isEven: false},
|
value: {isEven: false},
|
||||||
ticks: 0,
|
ticks: 0,
|
||||||
})
|
})
|
||||||
theAtom.reduceState(['n'], () => 5)
|
theAtom.reduce(() => 5)
|
||||||
theAtom.reduceState(['n'], () => 7)
|
theAtom.reduce(() => 7)
|
||||||
expect(iterator.next().value).toMatchObject({
|
expect(iterator.next().value).toMatchObject({
|
||||||
value: {isEven: false},
|
value: {isEven: false},
|
||||||
ticks: 1,
|
ticks: 1,
|
||||||
})
|
})
|
||||||
theAtom.reduceState(['n'], () => 2)
|
theAtom.reduce(() => 2)
|
||||||
theAtom.reduceState(['n'], () => 4)
|
theAtom.reduce(() => 4)
|
||||||
expect(iterator.next().value).toMatchObject({
|
expect(iterator.next().value).toMatchObject({
|
||||||
value: {isEven: true},
|
value: {isEven: true},
|
||||||
ticks: 1,
|
ticks: 1,
|
||||||
|
@ -91,10 +91,10 @@ describe('prism', () => {
|
||||||
const sequence: unknown[] = []
|
const sequence: unknown[] = []
|
||||||
let deps: unknown[] = []
|
let deps: unknown[] = []
|
||||||
|
|
||||||
const a = new Atom({letter: 'a'})
|
const a = new Atom('a')
|
||||||
|
|
||||||
const prsm = prism(() => {
|
const prsm = prism(() => {
|
||||||
const n = val(a.pointer.letter)
|
const n = val(a.pointer)
|
||||||
const iterationAtTimeOfCall = iteration
|
const iterationAtTimeOfCall = iteration
|
||||||
sequence.push({prismCall: iterationAtTimeOfCall})
|
sequence.push({prismCall: iterationAtTimeOfCall})
|
||||||
|
|
||||||
|
@ -120,14 +120,14 @@ describe('prism', () => {
|
||||||
sequence.length = 0
|
sequence.length = 0
|
||||||
|
|
||||||
iteration++
|
iteration++
|
||||||
a.setIn(['letter'], 'b')
|
a.set('b')
|
||||||
ticker.tick()
|
ticker.tick()
|
||||||
expect(sequence).toMatchObject([{prismCall: 1}, {change: 'b'}])
|
expect(sequence).toMatchObject([{prismCall: 1}, {change: 'b'}])
|
||||||
sequence.length = 0
|
sequence.length = 0
|
||||||
|
|
||||||
deps = [1]
|
deps = [1]
|
||||||
iteration++
|
iteration++
|
||||||
a.setIn(['letter'], 'c')
|
a.set('c')
|
||||||
ticker.tick()
|
ticker.tick()
|
||||||
expect(sequence).toMatchObject([
|
expect(sequence).toMatchObject([
|
||||||
{prismCall: 2},
|
{prismCall: 2},
|
||||||
|
@ -151,10 +151,10 @@ describe('prism', () => {
|
||||||
const sequence: unknown[] = []
|
const sequence: unknown[] = []
|
||||||
let deps: unknown[] = []
|
let deps: unknown[] = []
|
||||||
|
|
||||||
const a = new Atom({letter: 'a'})
|
const a = new Atom('a')
|
||||||
|
|
||||||
const prsm = prism(() => {
|
const prsm = prism(() => {
|
||||||
const n = val(a.pointer.letter)
|
const n = val(a.pointer)
|
||||||
const iterationAtTimeOfCall = iteration
|
const iterationAtTimeOfCall = iteration
|
||||||
sequence.push({prismCall: iterationAtTimeOfCall})
|
sequence.push({prismCall: iterationAtTimeOfCall})
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ describe('prism', () => {
|
||||||
sequence.length = 0
|
sequence.length = 0
|
||||||
|
|
||||||
iteration++
|
iteration++
|
||||||
a.setIn(['letter'], 'b')
|
a.set('b')
|
||||||
ticker.tick()
|
ticker.tick()
|
||||||
expect(sequence).toMatchObject([
|
expect(sequence).toMatchObject([
|
||||||
{prismCall: 1},
|
{prismCall: 1},
|
||||||
|
@ -195,7 +195,7 @@ describe('prism', () => {
|
||||||
|
|
||||||
deps = [1]
|
deps = [1]
|
||||||
iteration++
|
iteration++
|
||||||
a.setIn(['letter'], 'c')
|
a.set('c')
|
||||||
ticker.tick()
|
ticker.tick()
|
||||||
expect(sequence).toMatchObject([
|
expect(sequence).toMatchObject([
|
||||||
{prismCall: 2},
|
{prismCall: 2},
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
export type PathBasedReducer<S, ReturnType> = {
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
A4 extends keyof S[A0][A1][A2][A3],
|
|
||||||
A5 extends keyof S[A0][A1][A2][A3][A4],
|
|
||||||
A6 extends keyof S[A0][A1][A2][A3][A4][A5],
|
|
||||||
A7 extends keyof S[A0][A1][A2][A3][A4][A5][A6],
|
|
||||||
A8 extends keyof S[A0][A1][A2][A3][A4][A5][A6][A7],
|
|
||||||
A9 extends keyof S[A0][A1][A2][A3][A4][A5][A6][A7][A8],
|
|
||||||
A10 extends keyof S[A0][A1][A2][A3][A4][A5][A6][A7][A8][A9],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10],
|
|
||||||
reducer: (
|
|
||||||
d: S[A0][A1][A2][A3][A4][A5][A6][A7][A8][A9][A10],
|
|
||||||
) => S[A0][A1][A2][A3][A4][A5][A6][A7][A8][A9][A10],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
A4 extends keyof S[A0][A1][A2][A3],
|
|
||||||
A5 extends keyof S[A0][A1][A2][A3][A4],
|
|
||||||
A6 extends keyof S[A0][A1][A2][A3][A4][A5],
|
|
||||||
A7 extends keyof S[A0][A1][A2][A3][A4][A5][A6],
|
|
||||||
A8 extends keyof S[A0][A1][A2][A3][A4][A5][A6][A7],
|
|
||||||
A9 extends keyof S[A0][A1][A2][A3][A4][A5][A6][A7][A8],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3, A4, A5, A6, A7, A8, A9],
|
|
||||||
reducer: (
|
|
||||||
d: S[A0][A1][A2][A3][A4][A5][A6][A7][A8][A9],
|
|
||||||
) => S[A0][A1][A2][A3][A4][A5][A6][A7][A8][A9],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
A4 extends keyof S[A0][A1][A2][A3],
|
|
||||||
A5 extends keyof S[A0][A1][A2][A3][A4],
|
|
||||||
A6 extends keyof S[A0][A1][A2][A3][A4][A5],
|
|
||||||
A7 extends keyof S[A0][A1][A2][A3][A4][A5][A6],
|
|
||||||
A8 extends keyof S[A0][A1][A2][A3][A4][A5][A6][A7],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3, A4, A5, A6, A7, A8],
|
|
||||||
reducer: (
|
|
||||||
d: S[A0][A1][A2][A3][A4][A5][A6][A7][A8],
|
|
||||||
) => S[A0][A1][A2][A3][A4][A5][A6][A7][A8],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
A4 extends keyof S[A0][A1][A2][A3],
|
|
||||||
A5 extends keyof S[A0][A1][A2][A3][A4],
|
|
||||||
A6 extends keyof S[A0][A1][A2][A3][A4][A5],
|
|
||||||
A7 extends keyof S[A0][A1][A2][A3][A4][A5][A6],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3, A4, A5, A6, A7],
|
|
||||||
reducer: (
|
|
||||||
d: S[A0][A1][A2][A3][A4][A5][A6][A7],
|
|
||||||
) => S[A0][A1][A2][A3][A4][A5][A6][A7],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
A4 extends keyof S[A0][A1][A2][A3],
|
|
||||||
A5 extends keyof S[A0][A1][A2][A3][A4],
|
|
||||||
A6 extends keyof S[A0][A1][A2][A3][A4][A5],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3, A4, A5, A6],
|
|
||||||
reducer: (
|
|
||||||
d: S[A0][A1][A2][A3][A4][A5][A6],
|
|
||||||
) => S[A0][A1][A2][A3][A4][A5][A6],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
A4 extends keyof S[A0][A1][A2][A3],
|
|
||||||
A5 extends keyof S[A0][A1][A2][A3][A4],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3, A4, A5],
|
|
||||||
reducer: (d: S[A0][A1][A2][A3][A4][A5]) => S[A0][A1][A2][A3][A4][A5],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
A4 extends keyof S[A0][A1][A2][A3],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3, A4],
|
|
||||||
reducer: (d: S[A0][A1][A2][A3][A4]) => S[A0][A1][A2][A3][A4],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<
|
|
||||||
A0 extends keyof S,
|
|
||||||
A1 extends keyof S[A0],
|
|
||||||
A2 extends keyof S[A0][A1],
|
|
||||||
A3 extends keyof S[A0][A1][A2],
|
|
||||||
>(
|
|
||||||
addr: [A0, A1, A2, A3],
|
|
||||||
reducer: (d: S[A0][A1][A2][A3]) => S[A0][A1][A2][A3],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<A0 extends keyof S, A1 extends keyof S[A0], A2 extends keyof S[A0][A1]>(
|
|
||||||
addr: [A0, A1, A2],
|
|
||||||
reducer: (d: S[A0][A1][A2]) => S[A0][A1][A2],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<A0 extends keyof S, A1 extends keyof S[A0]>(
|
|
||||||
addr: [A0, A1],
|
|
||||||
reducer: (d: S[A0][A1]) => S[A0][A1],
|
|
||||||
): ReturnType
|
|
||||||
|
|
||||||
<A0 extends keyof S>(addr: [A0], reducer: (d: S[A0]) => S[A0]): ReturnType
|
|
||||||
|
|
||||||
(addr: undefined[], reducer: (d: S) => S): ReturnType
|
|
||||||
}
|
|
|
@ -240,11 +240,11 @@ export default class Project {
|
||||||
sheetId: SheetId,
|
sheetId: SheetId,
|
||||||
instanceId: SheetInstanceId = 'default' as SheetInstanceId,
|
instanceId: SheetInstanceId = 'default' as SheetInstanceId,
|
||||||
): Sheet {
|
): Sheet {
|
||||||
let template = this._sheetTemplates.getState()[sheetId]
|
let template = this._sheetTemplates.get()[sheetId]
|
||||||
|
|
||||||
if (!template) {
|
if (!template) {
|
||||||
template = new SheetTemplate(this, sheetId)
|
template = new SheetTemplate(this, sheetId)
|
||||||
this._sheetTemplates.setIn([sheetId], template)
|
this._sheetTemplates.reduce((s) => ({...s, [sheetId]: template}))
|
||||||
}
|
}
|
||||||
|
|
||||||
return template.getInstance(instanceId)
|
return template.getInstance(instanceId)
|
||||||
|
|
|
@ -14,11 +14,11 @@ class ProjectsSingleton {
|
||||||
* We're trusting here that each project id is unique
|
* We're trusting here that each project id is unique
|
||||||
*/
|
*/
|
||||||
add(id: ProjectId, project: Project) {
|
add(id: ProjectId, project: Project) {
|
||||||
this.atom.reduceState(['projects', id], () => project)
|
this.atom.setByPointer((p) => p.projects[id], project)
|
||||||
}
|
}
|
||||||
|
|
||||||
get(id: ProjectId): Project | undefined {
|
get(id: ProjectId): Project | undefined {
|
||||||
return this.atom.getState().projects[id]
|
return this.atom.get().projects[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
has(id: ProjectId) {
|
has(id: ProjectId) {
|
||||||
|
|
|
@ -120,11 +120,11 @@ export default class AudioPlaybackController implements IPlaybackController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _playing() {
|
private get _playing() {
|
||||||
return this._state.getState().playing
|
return this._state.get().playing
|
||||||
}
|
}
|
||||||
|
|
||||||
private set _playing(playing: boolean) {
|
private set _playing(playing: boolean) {
|
||||||
this._state.setIn(['playing'], playing)
|
this._state.setByPointer((p) => p.playing, playing)
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {}
|
destroy() {}
|
||||||
|
@ -140,11 +140,11 @@ export default class AudioPlaybackController implements IPlaybackController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updatePositionInState(time: number) {
|
private _updatePositionInState(time: number) {
|
||||||
this._state.reduceState(['position'], () => time)
|
this._state.reduce((s) => ({...s, position: time}))
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentPosition() {
|
getCurrentPosition() {
|
||||||
return this._state.getState().position
|
return this._state.get().position
|
||||||
}
|
}
|
||||||
|
|
||||||
play(
|
play(
|
||||||
|
|
|
@ -66,19 +66,19 @@ export default class DefaultPlaybackController implements IPlaybackController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updatePositionInState(time: number) {
|
private _updatePositionInState(time: number) {
|
||||||
this._state.reduceState(['position'], () => time)
|
this._state.setByPointer((p) => p.position, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentPosition() {
|
getCurrentPosition() {
|
||||||
return this._state.getState().position
|
return this._state.get().position
|
||||||
}
|
}
|
||||||
|
|
||||||
get playing() {
|
get playing() {
|
||||||
return this._state.getState().playing
|
return this._state.get().playing
|
||||||
}
|
}
|
||||||
|
|
||||||
set playing(playing: boolean) {
|
set playing(playing: boolean) {
|
||||||
this._state.setIn(['playing'], playing)
|
this._state.setByPointer((p) => p.playing, playing)
|
||||||
}
|
}
|
||||||
|
|
||||||
play(
|
play(
|
||||||
|
|
|
@ -256,7 +256,11 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
const updateSequenceValueFromItsPrism = () => {
|
const updateSequenceValueFromItsPrism = () => {
|
||||||
const triple = pr.getValue()
|
const triple = pr.getValue()
|
||||||
|
|
||||||
if (!triple) return valsAtom.setIn(pathToProp, undefined)
|
if (!triple)
|
||||||
|
return valsAtom.setByPointer(
|
||||||
|
(p) => pointerDeep(p, pathToProp),
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
|
|
||||||
const leftDeserialized = deserializeAndSanitize(triple.left)
|
const leftDeserialized = deserializeAndSanitize(triple.left)
|
||||||
|
|
||||||
|
@ -266,7 +270,10 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
: leftDeserialized
|
: leftDeserialized
|
||||||
|
|
||||||
if (triple.right === undefined)
|
if (triple.right === undefined)
|
||||||
return valsAtom.setIn(pathToProp, left)
|
return valsAtom.setByPointer(
|
||||||
|
(p) => pointerDeep(p, pathToProp),
|
||||||
|
left,
|
||||||
|
)
|
||||||
|
|
||||||
const rightDeserialized = deserializeAndSanitize(triple.right)
|
const rightDeserialized = deserializeAndSanitize(triple.right)
|
||||||
const right =
|
const right =
|
||||||
|
@ -274,8 +281,8 @@ export default class SheetObject implements IdentityPrismProvider {
|
||||||
? propConfig.default
|
? propConfig.default
|
||||||
: rightDeserialized
|
: rightDeserialized
|
||||||
|
|
||||||
return valsAtom.setIn(
|
return valsAtom.setByPointer(
|
||||||
pathToProp,
|
(p) => pointerDeep(p, pathToProp),
|
||||||
interpolate(left, right, triple.progression),
|
interpolate(left, right, triple.progression),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ export default class Sheet {
|
||||||
|
|
||||||
const object = objTemplate.createInstance(this, nativeObject, config)
|
const object = objTemplate.createInstance(this, nativeObject, config)
|
||||||
|
|
||||||
this._objects.setIn([objectKey], object)
|
this._objects.setByPointer((p) => p[objectKey], object)
|
||||||
|
|
||||||
return object
|
return object
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ export default class Sheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteObject(objectKey: ObjectAddressKey) {
|
deleteObject(objectKey: ObjectAddressKey) {
|
||||||
this._objects.reduceState([], (state) => {
|
this._objects.reduce((state) => {
|
||||||
const newState = {...state}
|
const newState = {...state}
|
||||||
delete newState[objectKey]
|
delete newState[objectKey]
|
||||||
return newState
|
return newState
|
||||||
|
|
|
@ -43,7 +43,7 @@ export default class SheetTemplate {
|
||||||
|
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
inst = new Sheet(this, instanceId)
|
inst = new Sheet(this, instanceId)
|
||||||
this._instances.setIn([instanceId], inst)
|
this._instances.setByPointer((p) => p[instanceId], inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
return inst
|
return inst
|
||||||
|
@ -65,7 +65,7 @@ export default class SheetTemplate {
|
||||||
config,
|
config,
|
||||||
actions,
|
actions,
|
||||||
)
|
)
|
||||||
this._objectTemplates.setIn([objectKey], template)
|
this._objectTemplates.setByPointer((p) => p[objectKey], template)
|
||||||
}
|
}
|
||||||
|
|
||||||
return template
|
return template
|
||||||
|
|
|
@ -188,7 +188,7 @@ export class Studio {
|
||||||
|
|
||||||
setCoreBits(coreBits: CoreBits) {
|
setCoreBits(coreBits: CoreBits) {
|
||||||
this._corePrivateApi = coreBits.privateAPI
|
this._corePrivateApi = coreBits.privateAPI
|
||||||
this._coreAtom.setIn(['core'], coreBits.coreExports)
|
this._coreAtom.setByPointer((p) => p.core, coreBits.coreExports)
|
||||||
this._setProjectsP(coreBits.projectsP)
|
this._setProjectsP(coreBits.projectsP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ let lastLockId = 0
|
||||||
const FrameStampPositionProvider: React.FC<{
|
const FrameStampPositionProvider: React.FC<{
|
||||||
layoutP: Pointer<SequenceEditorPanelLayout>
|
layoutP: Pointer<SequenceEditorPanelLayout>
|
||||||
}> = ({children, layoutP}) => {
|
}> = ({children, layoutP}) => {
|
||||||
const locksAtom = useMemo(() => new Atom<{list: LockItem[]}>({list: []}), [])
|
const locksAtom = useMemo(() => new Atom<LockItem[]>([]), [])
|
||||||
const currentD = useMemo(
|
const currentD = useMemo(
|
||||||
() =>
|
() =>
|
||||||
prism(() => {
|
prism(() => {
|
||||||
|
@ -57,7 +57,7 @@ const FrameStampPositionProvider: React.FC<{
|
||||||
.memo('p', () => pointerPositionInUnitSpace(layoutP), [layoutP])
|
.memo('p', () => pointerPositionInUnitSpace(layoutP), [layoutP])
|
||||||
.getValue()
|
.getValue()
|
||||||
|
|
||||||
const locks = val(locksAtom.pointer.list)
|
const locks = val(locksAtom.pointer)
|
||||||
|
|
||||||
if (locks.length > 0) {
|
if (locks.length > 0) {
|
||||||
return last(locks)!.position
|
return last(locks)!.position
|
||||||
|
@ -69,7 +69,7 @@ const FrameStampPositionProvider: React.FC<{
|
||||||
)
|
)
|
||||||
const getLock = useCallback(() => {
|
const getLock = useCallback(() => {
|
||||||
const id = lastLockId++
|
const id = lastLockId++
|
||||||
locksAtom.reduceState(['list'], (list) => [
|
locksAtom.reduce((list) => [
|
||||||
...list,
|
...list,
|
||||||
{
|
{
|
||||||
id,
|
id,
|
||||||
|
@ -78,13 +78,11 @@ const FrameStampPositionProvider: React.FC<{
|
||||||
])
|
])
|
||||||
|
|
||||||
const unlock = () => {
|
const unlock = () => {
|
||||||
locksAtom.reduceState(['list'], (list) =>
|
locksAtom.reduce((list) => list.filter((lock) => lock.id !== id))
|
||||||
list.filter((lock) => lock.id !== id),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const set = (posInUnitSpace: number) => {
|
const set = (posInUnitSpace: number) => {
|
||||||
locksAtom.reduceState(['list'], (list) => {
|
locksAtom.reduce((list) => {
|
||||||
const index = list.findIndex((lock) => lock.id === id)
|
const index = list.findIndex((lock) => lock.id === id)
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
console.warn(`Lock is already freed. This is a bug.`)
|
console.warn(`Lock is already freed. This is a bug.`)
|
||||||
|
|
|
@ -7,6 +7,7 @@ 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'
|
||||||
|
import pointerDeep from '@theatre/shared/utils/pointerDeep'
|
||||||
|
|
||||||
/** To mean the presence value */
|
/** To mean the presence value */
|
||||||
export enum PresenceFlag {
|
export enum PresenceFlag {
|
||||||
|
@ -53,12 +54,15 @@ function createPresenceContext(options: {
|
||||||
flag: rel.flag,
|
flag: rel.flag,
|
||||||
}
|
}
|
||||||
const path = [rel.affects, itemKey, relationId]
|
const path = [rel.affects, itemKey, relationId]
|
||||||
relationsAtom.setIn(path, presence)
|
relationsAtom.setByPointer((p) => pointerDeep(p, path), presence)
|
||||||
return path
|
return path
|
||||||
})
|
})
|
||||||
return () => {
|
return () => {
|
||||||
for (const pathToUndo of undoAtPaths) {
|
for (const pathToUndo of undoAtPaths) {
|
||||||
relationsAtom.setIn(pathToUndo, undefined)
|
relationsAtom.setByPointer(
|
||||||
|
(p) => pointerDeep(p, pathToUndo),
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -98,16 +102,16 @@ function createPresenceContext(options: {
|
||||||
return usePrismInstance(focusD)
|
return usePrismInstance(focusD)
|
||||||
},
|
},
|
||||||
setUserHover(itemKeyOpt) {
|
setUserHover(itemKeyOpt) {
|
||||||
const prev = currentUserHoverItemB.getState()
|
const prev = currentUserHoverItemB.get()
|
||||||
if (prev === itemKeyOpt) {
|
if (prev === itemKeyOpt) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (prev) {
|
if (prev) {
|
||||||
currentUserHoverFlagItemsAtom.setIn([prev], false)
|
currentUserHoverFlagItemsAtom.setByPointer((p) => p[prev], false)
|
||||||
}
|
}
|
||||||
currentUserHoverItemB.setState(itemKeyOpt)
|
currentUserHoverItemB.set(itemKeyOpt)
|
||||||
if (itemKeyOpt) {
|
if (itemKeyOpt) {
|
||||||
currentUserHoverFlagItemsAtom.setIn([itemKeyOpt], true)
|
currentUserHoverFlagItemsAtom.setByPointer((p) => p[itemKeyOpt], true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const getMounter = () => {
|
||||||
props: Props,
|
props: Props,
|
||||||
portalNode: HTMLElement,
|
portalNode: HTMLElement,
|
||||||
) {
|
) {
|
||||||
theAtom.reduceState([], (s) => {
|
theAtom.reduce((s) => {
|
||||||
return {
|
return {
|
||||||
byId: {...s.byId, [id]: {comp, props, portalNode}},
|
byId: {...s.byId, [id]: {comp, props, portalNode}},
|
||||||
set: {...s.set, [id]: true},
|
set: {...s.set, [id]: true},
|
||||||
|
@ -36,7 +36,7 @@ export const getMounter = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function unmount() {
|
function unmount() {
|
||||||
theAtom.reduceState([], (s) => {
|
theAtom.reduce((s) => {
|
||||||
const set = {...s.set}
|
const set = {...s.set}
|
||||||
const byId = {...s.byId}
|
const byId = {...s.byId}
|
||||||
delete set[id]
|
delete set[id]
|
||||||
|
|
Loading…
Reference in a new issue