jotai-state-tree 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NFJRKXCI.mjs → chunk-K2MLK6B7.mjs} +85 -30
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +149 -41
- package/dist/index.mjs +67 -12
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +4 -3
- package/dist/react.mjs +1 -1
- package/dist/{tree-S8buyIlj.d.mts → tree-C2ADWEka.d.mts} +3 -1
- package/dist/{tree-S8buyIlj.d.ts → tree-C2ADWEka.d.ts} +3 -1
- package/package.json +1 -1
- package/src/__tests__/index.test.ts +126 -0
- package/src/array.ts +10 -7
- package/src/lifecycle.ts +4 -0
- package/src/tree.ts +93 -34
- package/src/types.ts +1 -0
- package/src/undo.ts +58 -5
|
@@ -4,6 +4,13 @@ var lifecycleHookHandlers = {};
|
|
|
4
4
|
function setLifecycleHookHandlers(handlers) {
|
|
5
5
|
lifecycleHookHandlers = handlers;
|
|
6
6
|
}
|
|
7
|
+
var isApplyingSnapshotOrPatch = false;
|
|
8
|
+
function getIsApplyingSnapshotOrPatch() {
|
|
9
|
+
return isApplyingSnapshotOrPatch;
|
|
10
|
+
}
|
|
11
|
+
function setIsApplyingSnapshotOrPatch(value) {
|
|
12
|
+
isApplyingSnapshotOrPatch = value;
|
|
13
|
+
}
|
|
7
14
|
var globalStore = createStore();
|
|
8
15
|
function getGlobalStore() {
|
|
9
16
|
return globalStore;
|
|
@@ -69,6 +76,7 @@ var StateTreeNode = class {
|
|
|
69
76
|
this.$parent = null;
|
|
70
77
|
this.$path = "";
|
|
71
78
|
this.$isAlive = true;
|
|
79
|
+
this.$isApplyingHistory = false;
|
|
72
80
|
/** Child nodes - uses Map but children are explicitly destroyed */
|
|
73
81
|
this.children = /* @__PURE__ */ new Map();
|
|
74
82
|
/** Snapshot listeners */
|
|
@@ -126,11 +134,11 @@ var StateTreeNode = class {
|
|
|
126
134
|
return;
|
|
127
135
|
}
|
|
128
136
|
globalStore.set(this.valueAtom, value);
|
|
137
|
+
this.notifySnapshotChange();
|
|
129
138
|
this.notifyPatch(
|
|
130
139
|
{ op: "replace", path: this.$path, value },
|
|
131
140
|
{ op: "replace", path: this.$path, value: oldValue, oldValue }
|
|
132
141
|
);
|
|
133
|
-
this.notifySnapshotChange();
|
|
134
142
|
}
|
|
135
143
|
/** Add a child node */
|
|
136
144
|
addChild(key, child) {
|
|
@@ -221,9 +229,9 @@ var StateTreeNode = class {
|
|
|
221
229
|
}
|
|
222
230
|
/** Notify snapshot listeners */
|
|
223
231
|
notifySnapshotChange() {
|
|
224
|
-
this.invalidateSnapshot();
|
|
225
232
|
let current = this;
|
|
226
233
|
while (current) {
|
|
234
|
+
current.invalidateSnapshot();
|
|
227
235
|
const snapshot = getSnapshotFromNode(current);
|
|
228
236
|
current.snapshotListeners.forEach((listener) => listener(snapshot));
|
|
229
237
|
current = current.$parent;
|
|
@@ -232,11 +240,11 @@ var StateTreeNode = class {
|
|
|
232
240
|
/** Notify about a property change (for use by model proxy) */
|
|
233
241
|
notifyPropertyChange(propName, newValue, oldValue) {
|
|
234
242
|
const path = this.$path ? `${this.$path}/${propName}` : `/${propName}`;
|
|
243
|
+
this.notifySnapshotChange();
|
|
235
244
|
this.notifyPatch(
|
|
236
245
|
{ op: "replace", path, value: newValue },
|
|
237
246
|
{ op: "replace", path, value: oldValue, oldValue }
|
|
238
247
|
);
|
|
239
|
-
this.notifySnapshotChange();
|
|
240
248
|
}
|
|
241
249
|
/** Notify about a volatile state change (triggers snapshot listeners without patches) */
|
|
242
250
|
notifyVolatileChange() {
|
|
@@ -359,9 +367,19 @@ function applySnapshotToNode(node, snapshot) {
|
|
|
359
367
|
}
|
|
360
368
|
}
|
|
361
369
|
} else if (type._kind === "array" && Array.isArray(snapshot)) {
|
|
362
|
-
node.
|
|
370
|
+
const mstArray = node.getInstance();
|
|
371
|
+
if (mstArray) {
|
|
372
|
+
mstArray.replace(snapshot);
|
|
373
|
+
} else {
|
|
374
|
+
node.setValue(snapshot);
|
|
375
|
+
}
|
|
363
376
|
} else if (type._kind === "map" && typeof snapshot === "object" && snapshot !== null) {
|
|
364
|
-
node.
|
|
377
|
+
const mstMap = node.getInstance();
|
|
378
|
+
if (mstMap) {
|
|
379
|
+
mstMap.replace(snapshot);
|
|
380
|
+
} else {
|
|
381
|
+
node.setValue(snapshot);
|
|
382
|
+
}
|
|
365
383
|
} else {
|
|
366
384
|
node.setValue(snapshot);
|
|
367
385
|
}
|
|
@@ -522,7 +540,13 @@ function getSnapshot(target) {
|
|
|
522
540
|
}
|
|
523
541
|
function applySnapshot(target, snapshot) {
|
|
524
542
|
const node = getStateTreeNode(target);
|
|
525
|
-
|
|
543
|
+
const wasApplying = getIsApplyingSnapshotOrPatch();
|
|
544
|
+
setIsApplyingSnapshotOrPatch(true);
|
|
545
|
+
try {
|
|
546
|
+
applySnapshotToNode(node, snapshot);
|
|
547
|
+
} finally {
|
|
548
|
+
setIsApplyingSnapshotOrPatch(wasApplying);
|
|
549
|
+
}
|
|
526
550
|
}
|
|
527
551
|
function onSnapshot(target, listener) {
|
|
528
552
|
const node = getStateTreeNode(target);
|
|
@@ -535,8 +559,14 @@ function onPatch(target, listener) {
|
|
|
535
559
|
function applyPatch(target, patch) {
|
|
536
560
|
const patches = Array.isArray(patch) ? patch : [patch];
|
|
537
561
|
const rootNode = getStateTreeNode(target).getRoot();
|
|
538
|
-
|
|
539
|
-
|
|
562
|
+
const wasApplying = getIsApplyingSnapshotOrPatch();
|
|
563
|
+
setIsApplyingSnapshotOrPatch(true);
|
|
564
|
+
try {
|
|
565
|
+
for (const p of patches) {
|
|
566
|
+
applyPatchToNode(rootNode, p);
|
|
567
|
+
}
|
|
568
|
+
} finally {
|
|
569
|
+
setIsApplyingSnapshotOrPatch(wasApplying);
|
|
540
570
|
}
|
|
541
571
|
}
|
|
542
572
|
function applyPatchToNode(rootNode, patch) {
|
|
@@ -552,37 +582,61 @@ function applyPatchToNode(rootNode, patch) {
|
|
|
552
582
|
const key = pathParts[pathParts.length - 1];
|
|
553
583
|
switch (patch.op) {
|
|
554
584
|
case "replace": {
|
|
555
|
-
const
|
|
556
|
-
if (
|
|
557
|
-
|
|
585
|
+
const instance = node.getInstance();
|
|
586
|
+
if (instance && Array.isArray(instance)) {
|
|
587
|
+
const index = parseInt(key, 10);
|
|
588
|
+
instance[index] = patch.value;
|
|
589
|
+
} else if (instance && instance instanceof Map) {
|
|
590
|
+
instance.set(key, patch.value);
|
|
558
591
|
} else {
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
592
|
+
const childNode = node.getChild(key);
|
|
593
|
+
if (childNode) {
|
|
594
|
+
applySnapshotToNode(childNode, patch.value);
|
|
595
|
+
} else {
|
|
596
|
+
const currentValue = node.getValue();
|
|
597
|
+
currentValue[key] = patch.value;
|
|
598
|
+
node.setValue(currentValue);
|
|
599
|
+
}
|
|
562
600
|
}
|
|
563
601
|
break;
|
|
564
602
|
}
|
|
565
603
|
case "add": {
|
|
566
|
-
const
|
|
567
|
-
if (Array.isArray(
|
|
568
|
-
const index = key === "-" ?
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
node.
|
|
604
|
+
const instance = node.getInstance();
|
|
605
|
+
if (instance && Array.isArray(instance)) {
|
|
606
|
+
const index = key === "-" ? instance.length : parseInt(key, 10);
|
|
607
|
+
instance.splice(index, 0, patch.value);
|
|
608
|
+
} else if (instance && instance instanceof Map) {
|
|
609
|
+
instance.set(key, patch.value);
|
|
610
|
+
} else {
|
|
611
|
+
const currentValue = node.getValue();
|
|
612
|
+
if (Array.isArray(currentValue)) {
|
|
613
|
+
const index = key === "-" ? currentValue.length : parseInt(key, 10);
|
|
614
|
+
currentValue.splice(index, 0, patch.value);
|
|
615
|
+
node.setValue([...currentValue]);
|
|
616
|
+
} else if (typeof currentValue === "object" && currentValue !== null) {
|
|
617
|
+
currentValue[key] = patch.value;
|
|
618
|
+
node.setValue({ ...currentValue });
|
|
619
|
+
}
|
|
574
620
|
}
|
|
575
621
|
break;
|
|
576
622
|
}
|
|
577
623
|
case "remove": {
|
|
578
|
-
const
|
|
579
|
-
if (Array.isArray(
|
|
624
|
+
const instance = node.getInstance();
|
|
625
|
+
if (instance && Array.isArray(instance)) {
|
|
580
626
|
const index = parseInt(key, 10);
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
node.
|
|
627
|
+
instance.splice(index, 1);
|
|
628
|
+
} else if (instance && instance instanceof Map) {
|
|
629
|
+
instance.delete(key);
|
|
630
|
+
} else {
|
|
631
|
+
const currentValue = node.getValue();
|
|
632
|
+
if (Array.isArray(currentValue)) {
|
|
633
|
+
const index = parseInt(key, 10);
|
|
634
|
+
currentValue.splice(index, 1);
|
|
635
|
+
node.setValue([...currentValue]);
|
|
636
|
+
} else if (typeof currentValue === "object" && currentValue !== null) {
|
|
637
|
+
delete currentValue[key];
|
|
638
|
+
node.setValue({ ...currentValue });
|
|
639
|
+
}
|
|
586
640
|
}
|
|
587
641
|
break;
|
|
588
642
|
}
|
|
@@ -636,7 +690,7 @@ function isActionRunning() {
|
|
|
636
690
|
}
|
|
637
691
|
function trackAction(node, name, args, fn) {
|
|
638
692
|
const previousAction = currentAction;
|
|
639
|
-
currentAction = { name, args, tree: node };
|
|
693
|
+
currentAction = { name, args, tree: node, parent: previousAction };
|
|
640
694
|
try {
|
|
641
695
|
const result = fn();
|
|
642
696
|
const call = {
|
|
@@ -847,6 +901,7 @@ function unfreeze(target) {
|
|
|
847
901
|
|
|
848
902
|
export {
|
|
849
903
|
setLifecycleHookHandlers,
|
|
904
|
+
getIsApplyingSnapshotOrPatch,
|
|
850
905
|
getGlobalStore,
|
|
851
906
|
setGlobalStore,
|
|
852
907
|
resetGlobalStore,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-
|
|
2
|
-
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-
|
|
1
|
+
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-C2ADWEka.mjs';
|
|
2
|
+
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-C2ADWEka.mjs';
|
|
3
3
|
import 'jotai/vanilla/internals';
|
|
4
4
|
import 'jotai';
|
|
5
5
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-
|
|
2
|
-
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-
|
|
1
|
+
import { I as ISimpleType, a as IType, b as IIdentifierType, c as IIdentifierNumberType, d as ILiteralType, e as IEnumerationType, f as IFrozenType, M as ModelProperties, g as IModelType, h as MixinConfig, i as IMixin, j as IAnyType, k as IArrayType, l as IMapType, m as IOptionalType, n as IMaybeType, o as IMaybeNullType, p as IUnionType, U as UnionOptions, q as ILateType, r as IAnyModelType, R as ReferenceOptions, s as IReferenceType, t as ISafeReferenceType, u as IRefinementType, v as IDisposer, S as SnapshotIn, w as Instance, x as IReversibleJsonPatch } from './tree-C2ADWEka.js';
|
|
2
|
+
export { L as CustomTypeOptions, D as IAnyComplexType, E as IAnyMixin, G as IJsonPatch, z as IMSTArray, A as IMSTMap, y as IStateTreeNode, H as IValidationContext, K as IValidationError, J as IValidationResult, B as ModelInstance, F as ModelSelf, C as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, a8 as destroy, a9 as detach, am as findAll, an as findFirst, as as freeze, a2 as getEnv, ag as getGlobalStore, a4 as getIdentifier, af as getMembers, ar as getOrCreatePath, Y as getParent, $ as getParentOfType, a0 as getPath, a1 as getPathParts, av as getRegistryStats, aj as getRelativePath, X as getRoot, N as getSnapshot, ap as getTreeStats, a3 as getType, _ as hasParent, al as haveSameRoot, a5 as isAlive, ak as isAncestor, at as isFrozen, a6 as isRoot, a7 as isStateTreeNode, ao as isValidReference, W as onAction, ay as onLifecycleChange, Q as onPatch, P as onSnapshot, V as recordPatches, ai as resetGlobalStore, ae as resolveIdentifier, ac as resolvePath, ah as setGlobalStore, Z as tryGetParent, ad as tryResolve, au as unfreeze, ab as walk } from './tree-C2ADWEka.js';
|
|
3
3
|
import 'jotai/vanilla/internals';
|
|
4
4
|
import 'jotai';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -441,6 +441,13 @@ var lifecycleHookHandlers = {};
|
|
|
441
441
|
function setLifecycleHookHandlers(handlers) {
|
|
442
442
|
lifecycleHookHandlers = handlers;
|
|
443
443
|
}
|
|
444
|
+
var isApplyingSnapshotOrPatch = false;
|
|
445
|
+
function getIsApplyingSnapshotOrPatch() {
|
|
446
|
+
return isApplyingSnapshotOrPatch;
|
|
447
|
+
}
|
|
448
|
+
function setIsApplyingSnapshotOrPatch(value) {
|
|
449
|
+
isApplyingSnapshotOrPatch = value;
|
|
450
|
+
}
|
|
444
451
|
var globalStore = (0, import_jotai.createStore)();
|
|
445
452
|
function getGlobalStore() {
|
|
446
453
|
return globalStore;
|
|
@@ -500,6 +507,7 @@ var StateTreeNode = class {
|
|
|
500
507
|
this.$parent = null;
|
|
501
508
|
this.$path = "";
|
|
502
509
|
this.$isAlive = true;
|
|
510
|
+
this.$isApplyingHistory = false;
|
|
503
511
|
/** Child nodes - uses Map but children are explicitly destroyed */
|
|
504
512
|
this.children = /* @__PURE__ */ new Map();
|
|
505
513
|
/** Snapshot listeners */
|
|
@@ -557,11 +565,11 @@ var StateTreeNode = class {
|
|
|
557
565
|
return;
|
|
558
566
|
}
|
|
559
567
|
globalStore.set(this.valueAtom, value);
|
|
568
|
+
this.notifySnapshotChange();
|
|
560
569
|
this.notifyPatch(
|
|
561
570
|
{ op: "replace", path: this.$path, value },
|
|
562
571
|
{ op: "replace", path: this.$path, value: oldValue, oldValue }
|
|
563
572
|
);
|
|
564
|
-
this.notifySnapshotChange();
|
|
565
573
|
}
|
|
566
574
|
/** Add a child node */
|
|
567
575
|
addChild(key, child) {
|
|
@@ -652,9 +660,9 @@ var StateTreeNode = class {
|
|
|
652
660
|
}
|
|
653
661
|
/** Notify snapshot listeners */
|
|
654
662
|
notifySnapshotChange() {
|
|
655
|
-
this.invalidateSnapshot();
|
|
656
663
|
let current = this;
|
|
657
664
|
while (current) {
|
|
665
|
+
current.invalidateSnapshot();
|
|
658
666
|
const snapshot = getSnapshotFromNode(current);
|
|
659
667
|
current.snapshotListeners.forEach((listener) => listener(snapshot));
|
|
660
668
|
current = current.$parent;
|
|
@@ -663,11 +671,11 @@ var StateTreeNode = class {
|
|
|
663
671
|
/** Notify about a property change (for use by model proxy) */
|
|
664
672
|
notifyPropertyChange(propName, newValue, oldValue) {
|
|
665
673
|
const path = this.$path ? `${this.$path}/${propName}` : `/${propName}`;
|
|
674
|
+
this.notifySnapshotChange();
|
|
666
675
|
this.notifyPatch(
|
|
667
676
|
{ op: "replace", path, value: newValue },
|
|
668
677
|
{ op: "replace", path, value: oldValue, oldValue }
|
|
669
678
|
);
|
|
670
|
-
this.notifySnapshotChange();
|
|
671
679
|
}
|
|
672
680
|
/** Notify about a volatile state change (triggers snapshot listeners without patches) */
|
|
673
681
|
notifyVolatileChange() {
|
|
@@ -790,9 +798,19 @@ function applySnapshotToNode(node, snapshot) {
|
|
|
790
798
|
}
|
|
791
799
|
}
|
|
792
800
|
} else if (type._kind === "array" && Array.isArray(snapshot)) {
|
|
793
|
-
node.
|
|
801
|
+
const mstArray = node.getInstance();
|
|
802
|
+
if (mstArray) {
|
|
803
|
+
mstArray.replace(snapshot);
|
|
804
|
+
} else {
|
|
805
|
+
node.setValue(snapshot);
|
|
806
|
+
}
|
|
794
807
|
} else if (type._kind === "map" && typeof snapshot === "object" && snapshot !== null) {
|
|
795
|
-
node.
|
|
808
|
+
const mstMap = node.getInstance();
|
|
809
|
+
if (mstMap) {
|
|
810
|
+
mstMap.replace(snapshot);
|
|
811
|
+
} else {
|
|
812
|
+
node.setValue(snapshot);
|
|
813
|
+
}
|
|
796
814
|
} else {
|
|
797
815
|
node.setValue(snapshot);
|
|
798
816
|
}
|
|
@@ -953,7 +971,13 @@ function getSnapshot(target) {
|
|
|
953
971
|
}
|
|
954
972
|
function applySnapshot(target, snapshot) {
|
|
955
973
|
const node = getStateTreeNode(target);
|
|
956
|
-
|
|
974
|
+
const wasApplying = getIsApplyingSnapshotOrPatch();
|
|
975
|
+
setIsApplyingSnapshotOrPatch(true);
|
|
976
|
+
try {
|
|
977
|
+
applySnapshotToNode(node, snapshot);
|
|
978
|
+
} finally {
|
|
979
|
+
setIsApplyingSnapshotOrPatch(wasApplying);
|
|
980
|
+
}
|
|
957
981
|
}
|
|
958
982
|
function onSnapshot(target, listener) {
|
|
959
983
|
const node = getStateTreeNode(target);
|
|
@@ -966,8 +990,14 @@ function onPatch(target, listener) {
|
|
|
966
990
|
function applyPatch(target, patch) {
|
|
967
991
|
const patches = Array.isArray(patch) ? patch : [patch];
|
|
968
992
|
const rootNode = getStateTreeNode(target).getRoot();
|
|
969
|
-
|
|
970
|
-
|
|
993
|
+
const wasApplying = getIsApplyingSnapshotOrPatch();
|
|
994
|
+
setIsApplyingSnapshotOrPatch(true);
|
|
995
|
+
try {
|
|
996
|
+
for (const p of patches) {
|
|
997
|
+
applyPatchToNode(rootNode, p);
|
|
998
|
+
}
|
|
999
|
+
} finally {
|
|
1000
|
+
setIsApplyingSnapshotOrPatch(wasApplying);
|
|
971
1001
|
}
|
|
972
1002
|
}
|
|
973
1003
|
function applyPatchToNode(rootNode, patch) {
|
|
@@ -983,37 +1013,61 @@ function applyPatchToNode(rootNode, patch) {
|
|
|
983
1013
|
const key = pathParts[pathParts.length - 1];
|
|
984
1014
|
switch (patch.op) {
|
|
985
1015
|
case "replace": {
|
|
986
|
-
const
|
|
987
|
-
if (
|
|
988
|
-
|
|
1016
|
+
const instance = node.getInstance();
|
|
1017
|
+
if (instance && Array.isArray(instance)) {
|
|
1018
|
+
const index = parseInt(key, 10);
|
|
1019
|
+
instance[index] = patch.value;
|
|
1020
|
+
} else if (instance && instance instanceof Map) {
|
|
1021
|
+
instance.set(key, patch.value);
|
|
989
1022
|
} else {
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
1023
|
+
const childNode = node.getChild(key);
|
|
1024
|
+
if (childNode) {
|
|
1025
|
+
applySnapshotToNode(childNode, patch.value);
|
|
1026
|
+
} else {
|
|
1027
|
+
const currentValue = node.getValue();
|
|
1028
|
+
currentValue[key] = patch.value;
|
|
1029
|
+
node.setValue(currentValue);
|
|
1030
|
+
}
|
|
993
1031
|
}
|
|
994
1032
|
break;
|
|
995
1033
|
}
|
|
996
1034
|
case "add": {
|
|
997
|
-
const
|
|
998
|
-
if (Array.isArray(
|
|
999
|
-
const index = key === "-" ?
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
node.
|
|
1035
|
+
const instance = node.getInstance();
|
|
1036
|
+
if (instance && Array.isArray(instance)) {
|
|
1037
|
+
const index = key === "-" ? instance.length : parseInt(key, 10);
|
|
1038
|
+
instance.splice(index, 0, patch.value);
|
|
1039
|
+
} else if (instance && instance instanceof Map) {
|
|
1040
|
+
instance.set(key, patch.value);
|
|
1041
|
+
} else {
|
|
1042
|
+
const currentValue = node.getValue();
|
|
1043
|
+
if (Array.isArray(currentValue)) {
|
|
1044
|
+
const index = key === "-" ? currentValue.length : parseInt(key, 10);
|
|
1045
|
+
currentValue.splice(index, 0, patch.value);
|
|
1046
|
+
node.setValue([...currentValue]);
|
|
1047
|
+
} else if (typeof currentValue === "object" && currentValue !== null) {
|
|
1048
|
+
currentValue[key] = patch.value;
|
|
1049
|
+
node.setValue({ ...currentValue });
|
|
1050
|
+
}
|
|
1005
1051
|
}
|
|
1006
1052
|
break;
|
|
1007
1053
|
}
|
|
1008
1054
|
case "remove": {
|
|
1009
|
-
const
|
|
1010
|
-
if (Array.isArray(
|
|
1055
|
+
const instance = node.getInstance();
|
|
1056
|
+
if (instance && Array.isArray(instance)) {
|
|
1011
1057
|
const index = parseInt(key, 10);
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
node.
|
|
1058
|
+
instance.splice(index, 1);
|
|
1059
|
+
} else if (instance && instance instanceof Map) {
|
|
1060
|
+
instance.delete(key);
|
|
1061
|
+
} else {
|
|
1062
|
+
const currentValue = node.getValue();
|
|
1063
|
+
if (Array.isArray(currentValue)) {
|
|
1064
|
+
const index = parseInt(key, 10);
|
|
1065
|
+
currentValue.splice(index, 1);
|
|
1066
|
+
node.setValue([...currentValue]);
|
|
1067
|
+
} else if (typeof currentValue === "object" && currentValue !== null) {
|
|
1068
|
+
delete currentValue[key];
|
|
1069
|
+
node.setValue({ ...currentValue });
|
|
1070
|
+
}
|
|
1017
1071
|
}
|
|
1018
1072
|
break;
|
|
1019
1073
|
}
|
|
@@ -1067,7 +1121,7 @@ function isActionRunning() {
|
|
|
1067
1121
|
}
|
|
1068
1122
|
function trackAction(node, name, args, fn) {
|
|
1069
1123
|
const previousAction = currentAction;
|
|
1070
|
-
currentAction = { name, args, tree: node };
|
|
1124
|
+
currentAction = { name, args, tree: node, parent: previousAction };
|
|
1071
1125
|
try {
|
|
1072
1126
|
const result = fn();
|
|
1073
1127
|
const call = {
|
|
@@ -1623,6 +1677,9 @@ function canWrite(node) {
|
|
|
1623
1677
|
if (!node.$isAlive) {
|
|
1624
1678
|
return false;
|
|
1625
1679
|
}
|
|
1680
|
+
if (getIsApplyingSnapshotOrPatch()) {
|
|
1681
|
+
return true;
|
|
1682
|
+
}
|
|
1626
1683
|
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV === "production") {
|
|
1627
1684
|
return true;
|
|
1628
1685
|
}
|
|
@@ -2420,6 +2477,11 @@ var MSTArray = class _MSTArray extends Array {
|
|
|
2420
2477
|
syncToNode() {
|
|
2421
2478
|
const oldArray = this.node.getValue() || [];
|
|
2422
2479
|
const newArray = [...this];
|
|
2480
|
+
const oldSnapshots = /* @__PURE__ */ new Map();
|
|
2481
|
+
for (let i = 0; i < oldArray.length; i++) {
|
|
2482
|
+
const childNode = this.node.getChild(String(i));
|
|
2483
|
+
oldSnapshots.set(i, childNode ? getSnapshotFromNode(childNode) : oldArray[i]);
|
|
2484
|
+
}
|
|
2423
2485
|
const existingChildNodes = /* @__PURE__ */ new Set();
|
|
2424
2486
|
for (const [, child] of this.node.getChildren()) {
|
|
2425
2487
|
existingChildNodes.add(child);
|
|
@@ -2489,8 +2551,7 @@ var MSTArray = class _MSTArray extends Array {
|
|
|
2489
2551
|
}
|
|
2490
2552
|
} else if (newArray.length < oldArray.length && newArray.every((val, idx) => val === oldArray[idx])) {
|
|
2491
2553
|
for (let i = oldArray.length - 1; i >= newArray.length; i--) {
|
|
2492
|
-
const
|
|
2493
|
-
const oldValSnap = childNode ? getSnapshotFromNode(childNode) : oldArray[i];
|
|
2554
|
+
const oldValSnap = oldSnapshots.get(i);
|
|
2494
2555
|
patches.push({
|
|
2495
2556
|
op: "remove",
|
|
2496
2557
|
path: `${this.node.$path}/${i}`
|
|
@@ -2502,10 +2563,7 @@ var MSTArray = class _MSTArray extends Array {
|
|
|
2502
2563
|
});
|
|
2503
2564
|
}
|
|
2504
2565
|
} else {
|
|
2505
|
-
const oldSnap = oldArray.map((_, idx) =>
|
|
2506
|
-
const childNode = this.node.getChild(String(idx));
|
|
2507
|
-
return childNode ? getSnapshotFromNode(childNode) : oldArray[idx];
|
|
2508
|
-
});
|
|
2566
|
+
const oldSnap = oldArray.map((_, idx) => oldSnapshots.get(idx));
|
|
2509
2567
|
const newSnap = newArray.map((_, idx) => {
|
|
2510
2568
|
const childNode = this.node.getChild(String(idx));
|
|
2511
2569
|
return childNode ? getSnapshotFromNode(childNode) : newArray[idx];
|
|
@@ -2523,7 +2581,7 @@ var MSTArray = class _MSTArray extends Array {
|
|
|
2523
2581
|
}
|
|
2524
2582
|
const store = getGlobalStore();
|
|
2525
2583
|
store.set(this.node.valueAtom, newArray);
|
|
2526
|
-
this.node.
|
|
2584
|
+
this.node.notifySnapshotChange();
|
|
2527
2585
|
patches.forEach((patch, idx) => {
|
|
2528
2586
|
this.node.notifyPatch(patch, reversePatches[idx]);
|
|
2529
2587
|
});
|
|
@@ -3615,9 +3673,11 @@ var UndoManager = class {
|
|
|
3615
3673
|
this.isRedoing = false;
|
|
3616
3674
|
this.skipRecording = false;
|
|
3617
3675
|
this.grouping = false;
|
|
3676
|
+
this.actionGrouping = false;
|
|
3618
3677
|
this.currentGroup = [];
|
|
3619
3678
|
this.currentGroupInverse = [];
|
|
3620
3679
|
this.disposer = null;
|
|
3680
|
+
this.actionDisposer = null;
|
|
3621
3681
|
this.lastChangeTime = 0;
|
|
3622
3682
|
this.target = target;
|
|
3623
3683
|
this.options = {
|
|
@@ -3628,6 +3688,14 @@ var UndoManager = class {
|
|
|
3628
3688
|
this.disposer = onPatch(target, (patch, reversePatch) => {
|
|
3629
3689
|
this.recordPatch(patch, reversePatch);
|
|
3630
3690
|
});
|
|
3691
|
+
this.actionDisposer = onAction(target, () => {
|
|
3692
|
+
const current = getCurrentAction();
|
|
3693
|
+
if (current && !current.parent) {
|
|
3694
|
+
if (this.actionGrouping) {
|
|
3695
|
+
this.endGroup();
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
});
|
|
3631
3699
|
}
|
|
3632
3700
|
get canUndo() {
|
|
3633
3701
|
return this.currentIndex >= 0;
|
|
@@ -3651,16 +3719,31 @@ var UndoManager = class {
|
|
|
3651
3719
|
if (this.isUndoing || this.isRedoing || this.skipRecording) {
|
|
3652
3720
|
return;
|
|
3653
3721
|
}
|
|
3722
|
+
const node = getStateTreeNode(this.target);
|
|
3723
|
+
if (node.getRoot().$isApplyingHistory) {
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3654
3726
|
const now = Date.now();
|
|
3727
|
+
if (isActionRunning() && !this.grouping) {
|
|
3728
|
+
this.grouping = true;
|
|
3729
|
+
this.actionGrouping = true;
|
|
3730
|
+
this.currentGroup = [];
|
|
3731
|
+
this.currentGroupInverse = [];
|
|
3732
|
+
Promise.resolve().then(() => {
|
|
3733
|
+
if (this.actionGrouping) {
|
|
3734
|
+
this.endGroup();
|
|
3735
|
+
}
|
|
3736
|
+
});
|
|
3737
|
+
}
|
|
3655
3738
|
if (this.grouping) {
|
|
3656
3739
|
this.currentGroup.push(reversePatch);
|
|
3657
|
-
this.currentGroupInverse.
|
|
3740
|
+
this.currentGroupInverse.push({ ...patch });
|
|
3658
3741
|
return;
|
|
3659
3742
|
}
|
|
3660
3743
|
if (this.options.groupByTime && this.historyEntries.length > 0 && now - this.lastChangeTime < this.options.groupingWindow && this.currentIndex === this.historyEntries.length - 1) {
|
|
3661
3744
|
const lastEntry = this.historyEntries[this.currentIndex];
|
|
3662
3745
|
lastEntry.patches.push(reversePatch);
|
|
3663
|
-
lastEntry.inversePatches.
|
|
3746
|
+
lastEntry.inversePatches.push({ ...patch });
|
|
3664
3747
|
lastEntry.timestamp = now;
|
|
3665
3748
|
} else {
|
|
3666
3749
|
if (this.currentIndex < this.historyEntries.length - 1) {
|
|
@@ -3684,6 +3767,10 @@ var UndoManager = class {
|
|
|
3684
3767
|
if (!this.canUndo) {
|
|
3685
3768
|
return;
|
|
3686
3769
|
}
|
|
3770
|
+
const node = getStateTreeNode(this.target);
|
|
3771
|
+
const rootNode = node.getRoot();
|
|
3772
|
+
const wasApplying = rootNode.$isApplyingHistory;
|
|
3773
|
+
rootNode.$isApplyingHistory = true;
|
|
3687
3774
|
this.isUndoing = true;
|
|
3688
3775
|
try {
|
|
3689
3776
|
const entry = this.historyEntries[this.currentIndex];
|
|
@@ -3693,12 +3780,17 @@ var UndoManager = class {
|
|
|
3693
3780
|
this.currentIndex--;
|
|
3694
3781
|
} finally {
|
|
3695
3782
|
this.isUndoing = false;
|
|
3783
|
+
rootNode.$isApplyingHistory = wasApplying;
|
|
3696
3784
|
}
|
|
3697
3785
|
}
|
|
3698
3786
|
redo() {
|
|
3699
3787
|
if (!this.canRedo) {
|
|
3700
3788
|
return;
|
|
3701
3789
|
}
|
|
3790
|
+
const node = getStateTreeNode(this.target);
|
|
3791
|
+
const rootNode = node.getRoot();
|
|
3792
|
+
const wasApplying = rootNode.$isApplyingHistory;
|
|
3793
|
+
rootNode.$isApplyingHistory = true;
|
|
3702
3794
|
this.isRedoing = true;
|
|
3703
3795
|
try {
|
|
3704
3796
|
this.currentIndex++;
|
|
@@ -3708,6 +3800,7 @@ var UndoManager = class {
|
|
|
3708
3800
|
}
|
|
3709
3801
|
} finally {
|
|
3710
3802
|
this.isRedoing = false;
|
|
3803
|
+
rootNode.$isApplyingHistory = wasApplying;
|
|
3711
3804
|
}
|
|
3712
3805
|
}
|
|
3713
3806
|
clear() {
|
|
@@ -3716,9 +3809,11 @@ var UndoManager = class {
|
|
|
3716
3809
|
this.currentGroup = [];
|
|
3717
3810
|
this.currentGroupInverse = [];
|
|
3718
3811
|
this.grouping = false;
|
|
3812
|
+
this.actionGrouping = false;
|
|
3719
3813
|
}
|
|
3720
3814
|
startGroup() {
|
|
3721
3815
|
this.grouping = true;
|
|
3816
|
+
this.actionGrouping = false;
|
|
3722
3817
|
this.currentGroup = [];
|
|
3723
3818
|
this.currentGroupInverse = [];
|
|
3724
3819
|
}
|
|
@@ -3727,6 +3822,7 @@ var UndoManager = class {
|
|
|
3727
3822
|
return;
|
|
3728
3823
|
}
|
|
3729
3824
|
this.grouping = false;
|
|
3825
|
+
this.actionGrouping = false;
|
|
3730
3826
|
if (this.currentGroup.length > 0) {
|
|
3731
3827
|
if (this.currentIndex < this.historyEntries.length - 1) {
|
|
3732
3828
|
this.historyEntries.splice(this.currentIndex + 1);
|
|
@@ -3759,6 +3855,10 @@ var UndoManager = class {
|
|
|
3759
3855
|
this.disposer();
|
|
3760
3856
|
this.disposer = null;
|
|
3761
3857
|
}
|
|
3858
|
+
if (this.actionDisposer) {
|
|
3859
|
+
this.actionDisposer();
|
|
3860
|
+
this.actionDisposer = null;
|
|
3861
|
+
}
|
|
3762
3862
|
this.clear();
|
|
3763
3863
|
}
|
|
3764
3864
|
};
|
|
@@ -3777,9 +3877,12 @@ var TimeTravelManager = class {
|
|
|
3777
3877
|
this.record();
|
|
3778
3878
|
if (this.autoRecord) {
|
|
3779
3879
|
this.disposer = onPatch(target, () => {
|
|
3780
|
-
if (
|
|
3781
|
-
|
|
3880
|
+
if (this.isApplying) return;
|
|
3881
|
+
const node = getStateTreeNode(this.target);
|
|
3882
|
+
if (node.getRoot().$isApplyingHistory) {
|
|
3883
|
+
return;
|
|
3782
3884
|
}
|
|
3885
|
+
this.record();
|
|
3783
3886
|
});
|
|
3784
3887
|
}
|
|
3785
3888
|
}
|
|
@@ -3817,12 +3920,17 @@ var TimeTravelManager = class {
|
|
|
3817
3920
|
}
|
|
3818
3921
|
goTo(index) {
|
|
3819
3922
|
if (index < 0 || index >= this.snapshots.length) return;
|
|
3923
|
+
const node = getStateTreeNode(this.target);
|
|
3924
|
+
const rootNode = node.getRoot();
|
|
3925
|
+
const wasApplying = rootNode.$isApplyingHistory;
|
|
3926
|
+
rootNode.$isApplyingHistory = true;
|
|
3820
3927
|
this.isApplying = true;
|
|
3821
3928
|
try {
|
|
3822
3929
|
this.index = index;
|
|
3823
3930
|
applySnapshot(this.target, this.snapshots[index]);
|
|
3824
3931
|
} finally {
|
|
3825
3932
|
this.isApplying = false;
|
|
3933
|
+
rootNode.$isApplyingHistory = wasApplying;
|
|
3826
3934
|
}
|
|
3827
3935
|
}
|
|
3828
3936
|
getSnapshot(index) {
|