jotai-state-tree 1.3.3 → 1.3.5
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-OAXK4KFM.mjs → chunk-E6MXYAAH.mjs} +84 -28
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +199 -33
- package/dist/index.mjs +120 -6
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +2 -1
- package/dist/react.mjs +1 -1
- package/dist/{tree-BV2K9utF.d.mts → tree-BMaFqD3f.d.mts} +3 -1
- package/dist/{tree-BV2K9utF.d.ts → tree-BMaFqD3f.d.ts} +3 -1
- package/package.json +1 -1
- package/src/__tests__/index.test.ts +171 -0
- package/src/array.ts +80 -2
- package/src/lifecycle.ts +4 -0
- package/src/tree.ts +89 -30
- 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 */
|
|
@@ -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;
|
|
@@ -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,
|
|
@@ -858,6 +913,7 @@ export {
|
|
|
858
913
|
$treenode,
|
|
859
914
|
getStateTreeNode,
|
|
860
915
|
hasStateTreeNode,
|
|
916
|
+
getSnapshotFromNode,
|
|
861
917
|
applySnapshotToNode,
|
|
862
918
|
resolveIdentifier,
|
|
863
919
|
getRegistryStats,
|
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-BMaFqD3f.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-BMaFqD3f.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-BMaFqD3f.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-BMaFqD3f.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 */
|
|
@@ -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;
|
|
@@ -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
|
}
|
|
@@ -2418,6 +2475,13 @@ var MSTArray = class _MSTArray extends Array {
|
|
|
2418
2475
|
return [...this];
|
|
2419
2476
|
}
|
|
2420
2477
|
syncToNode() {
|
|
2478
|
+
const oldArray = this.node.getValue() || [];
|
|
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
|
+
}
|
|
2421
2485
|
const existingChildNodes = /* @__PURE__ */ new Set();
|
|
2422
2486
|
for (const [, child] of this.node.getChildren()) {
|
|
2423
2487
|
existingChildNodes.add(child);
|
|
@@ -2469,7 +2533,59 @@ var MSTArray = class _MSTArray extends Array {
|
|
|
2469
2533
|
for (const [key, childNode] of newChildren) {
|
|
2470
2534
|
this.node.addChild(key, childNode);
|
|
2471
2535
|
}
|
|
2472
|
-
|
|
2536
|
+
const patches = [];
|
|
2537
|
+
const reversePatches = [];
|
|
2538
|
+
if (newArray.length > oldArray.length && oldArray.every((val, idx) => val === newArray[idx])) {
|
|
2539
|
+
for (let i = oldArray.length; i < newArray.length; i++) {
|
|
2540
|
+
const childNode = this.node.getChild(String(i));
|
|
2541
|
+
const valSnap = childNode ? getSnapshotFromNode(childNode) : newArray[i];
|
|
2542
|
+
patches.push({
|
|
2543
|
+
op: "add",
|
|
2544
|
+
path: `${this.node.$path}/${i}`,
|
|
2545
|
+
value: valSnap
|
|
2546
|
+
});
|
|
2547
|
+
reversePatches.push({
|
|
2548
|
+
op: "remove",
|
|
2549
|
+
path: `${this.node.$path}/${i}`
|
|
2550
|
+
});
|
|
2551
|
+
}
|
|
2552
|
+
} else if (newArray.length < oldArray.length && newArray.every((val, idx) => val === oldArray[idx])) {
|
|
2553
|
+
for (let i = oldArray.length - 1; i >= newArray.length; i--) {
|
|
2554
|
+
const oldValSnap = oldSnapshots.get(i);
|
|
2555
|
+
patches.push({
|
|
2556
|
+
op: "remove",
|
|
2557
|
+
path: `${this.node.$path}/${i}`
|
|
2558
|
+
});
|
|
2559
|
+
reversePatches.push({
|
|
2560
|
+
op: "add",
|
|
2561
|
+
path: `${this.node.$path}/${i}`,
|
|
2562
|
+
value: oldValSnap
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
} else {
|
|
2566
|
+
const oldSnap = oldArray.map((_, idx) => oldSnapshots.get(idx));
|
|
2567
|
+
const newSnap = newArray.map((_, idx) => {
|
|
2568
|
+
const childNode = this.node.getChild(String(idx));
|
|
2569
|
+
return childNode ? getSnapshotFromNode(childNode) : newArray[idx];
|
|
2570
|
+
});
|
|
2571
|
+
patches.push({
|
|
2572
|
+
op: "replace",
|
|
2573
|
+
path: this.node.$path,
|
|
2574
|
+
value: newSnap
|
|
2575
|
+
});
|
|
2576
|
+
reversePatches.push({
|
|
2577
|
+
op: "replace",
|
|
2578
|
+
path: this.node.$path,
|
|
2579
|
+
value: oldSnap
|
|
2580
|
+
});
|
|
2581
|
+
}
|
|
2582
|
+
const store = getGlobalStore();
|
|
2583
|
+
store.set(this.node.valueAtom, newArray);
|
|
2584
|
+
this.node.invalidateSnapshot();
|
|
2585
|
+
patches.forEach((patch, idx) => {
|
|
2586
|
+
this.node.notifyPatch(patch, reversePatches[idx]);
|
|
2587
|
+
});
|
|
2588
|
+
this.node.notifyVolatileChange();
|
|
2473
2589
|
}
|
|
2474
2590
|
};
|
|
2475
2591
|
var ArrayType = class {
|
|
@@ -3557,9 +3673,11 @@ var UndoManager = class {
|
|
|
3557
3673
|
this.isRedoing = false;
|
|
3558
3674
|
this.skipRecording = false;
|
|
3559
3675
|
this.grouping = false;
|
|
3676
|
+
this.actionGrouping = false;
|
|
3560
3677
|
this.currentGroup = [];
|
|
3561
3678
|
this.currentGroupInverse = [];
|
|
3562
3679
|
this.disposer = null;
|
|
3680
|
+
this.actionDisposer = null;
|
|
3563
3681
|
this.lastChangeTime = 0;
|
|
3564
3682
|
this.target = target;
|
|
3565
3683
|
this.options = {
|
|
@@ -3570,6 +3688,14 @@ var UndoManager = class {
|
|
|
3570
3688
|
this.disposer = onPatch(target, (patch, reversePatch) => {
|
|
3571
3689
|
this.recordPatch(patch, reversePatch);
|
|
3572
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
|
+
});
|
|
3573
3699
|
}
|
|
3574
3700
|
get canUndo() {
|
|
3575
3701
|
return this.currentIndex >= 0;
|
|
@@ -3593,16 +3719,31 @@ var UndoManager = class {
|
|
|
3593
3719
|
if (this.isUndoing || this.isRedoing || this.skipRecording) {
|
|
3594
3720
|
return;
|
|
3595
3721
|
}
|
|
3722
|
+
const node = getStateTreeNode(this.target);
|
|
3723
|
+
if (node.getRoot().$isApplyingHistory) {
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3596
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
|
+
}
|
|
3597
3738
|
if (this.grouping) {
|
|
3598
3739
|
this.currentGroup.push(reversePatch);
|
|
3599
|
-
this.currentGroupInverse.
|
|
3740
|
+
this.currentGroupInverse.push({ ...patch });
|
|
3600
3741
|
return;
|
|
3601
3742
|
}
|
|
3602
3743
|
if (this.options.groupByTime && this.historyEntries.length > 0 && now - this.lastChangeTime < this.options.groupingWindow && this.currentIndex === this.historyEntries.length - 1) {
|
|
3603
3744
|
const lastEntry = this.historyEntries[this.currentIndex];
|
|
3604
3745
|
lastEntry.patches.push(reversePatch);
|
|
3605
|
-
lastEntry.inversePatches.
|
|
3746
|
+
lastEntry.inversePatches.push({ ...patch });
|
|
3606
3747
|
lastEntry.timestamp = now;
|
|
3607
3748
|
} else {
|
|
3608
3749
|
if (this.currentIndex < this.historyEntries.length - 1) {
|
|
@@ -3626,6 +3767,10 @@ var UndoManager = class {
|
|
|
3626
3767
|
if (!this.canUndo) {
|
|
3627
3768
|
return;
|
|
3628
3769
|
}
|
|
3770
|
+
const node = getStateTreeNode(this.target);
|
|
3771
|
+
const rootNode = node.getRoot();
|
|
3772
|
+
const wasApplying = rootNode.$isApplyingHistory;
|
|
3773
|
+
rootNode.$isApplyingHistory = true;
|
|
3629
3774
|
this.isUndoing = true;
|
|
3630
3775
|
try {
|
|
3631
3776
|
const entry = this.historyEntries[this.currentIndex];
|
|
@@ -3635,12 +3780,17 @@ var UndoManager = class {
|
|
|
3635
3780
|
this.currentIndex--;
|
|
3636
3781
|
} finally {
|
|
3637
3782
|
this.isUndoing = false;
|
|
3783
|
+
rootNode.$isApplyingHistory = wasApplying;
|
|
3638
3784
|
}
|
|
3639
3785
|
}
|
|
3640
3786
|
redo() {
|
|
3641
3787
|
if (!this.canRedo) {
|
|
3642
3788
|
return;
|
|
3643
3789
|
}
|
|
3790
|
+
const node = getStateTreeNode(this.target);
|
|
3791
|
+
const rootNode = node.getRoot();
|
|
3792
|
+
const wasApplying = rootNode.$isApplyingHistory;
|
|
3793
|
+
rootNode.$isApplyingHistory = true;
|
|
3644
3794
|
this.isRedoing = true;
|
|
3645
3795
|
try {
|
|
3646
3796
|
this.currentIndex++;
|
|
@@ -3650,6 +3800,7 @@ var UndoManager = class {
|
|
|
3650
3800
|
}
|
|
3651
3801
|
} finally {
|
|
3652
3802
|
this.isRedoing = false;
|
|
3803
|
+
rootNode.$isApplyingHistory = wasApplying;
|
|
3653
3804
|
}
|
|
3654
3805
|
}
|
|
3655
3806
|
clear() {
|
|
@@ -3658,9 +3809,11 @@ var UndoManager = class {
|
|
|
3658
3809
|
this.currentGroup = [];
|
|
3659
3810
|
this.currentGroupInverse = [];
|
|
3660
3811
|
this.grouping = false;
|
|
3812
|
+
this.actionGrouping = false;
|
|
3661
3813
|
}
|
|
3662
3814
|
startGroup() {
|
|
3663
3815
|
this.grouping = true;
|
|
3816
|
+
this.actionGrouping = false;
|
|
3664
3817
|
this.currentGroup = [];
|
|
3665
3818
|
this.currentGroupInverse = [];
|
|
3666
3819
|
}
|
|
@@ -3669,6 +3822,7 @@ var UndoManager = class {
|
|
|
3669
3822
|
return;
|
|
3670
3823
|
}
|
|
3671
3824
|
this.grouping = false;
|
|
3825
|
+
this.actionGrouping = false;
|
|
3672
3826
|
if (this.currentGroup.length > 0) {
|
|
3673
3827
|
if (this.currentIndex < this.historyEntries.length - 1) {
|
|
3674
3828
|
this.historyEntries.splice(this.currentIndex + 1);
|
|
@@ -3701,6 +3855,10 @@ var UndoManager = class {
|
|
|
3701
3855
|
this.disposer();
|
|
3702
3856
|
this.disposer = null;
|
|
3703
3857
|
}
|
|
3858
|
+
if (this.actionDisposer) {
|
|
3859
|
+
this.actionDisposer();
|
|
3860
|
+
this.actionDisposer = null;
|
|
3861
|
+
}
|
|
3704
3862
|
this.clear();
|
|
3705
3863
|
}
|
|
3706
3864
|
};
|
|
@@ -3719,9 +3877,12 @@ var TimeTravelManager = class {
|
|
|
3719
3877
|
this.record();
|
|
3720
3878
|
if (this.autoRecord) {
|
|
3721
3879
|
this.disposer = onPatch(target, () => {
|
|
3722
|
-
if (
|
|
3723
|
-
|
|
3880
|
+
if (this.isApplying) return;
|
|
3881
|
+
const node = getStateTreeNode(this.target);
|
|
3882
|
+
if (node.getRoot().$isApplyingHistory) {
|
|
3883
|
+
return;
|
|
3724
3884
|
}
|
|
3885
|
+
this.record();
|
|
3725
3886
|
});
|
|
3726
3887
|
}
|
|
3727
3888
|
}
|
|
@@ -3759,12 +3920,17 @@ var TimeTravelManager = class {
|
|
|
3759
3920
|
}
|
|
3760
3921
|
goTo(index) {
|
|
3761
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;
|
|
3762
3927
|
this.isApplying = true;
|
|
3763
3928
|
try {
|
|
3764
3929
|
this.index = index;
|
|
3765
3930
|
applySnapshot(this.target, this.snapshots[index]);
|
|
3766
3931
|
} finally {
|
|
3767
3932
|
this.isApplying = false;
|
|
3933
|
+
rootNode.$isApplyingHistory = wasApplying;
|
|
3768
3934
|
}
|
|
3769
3935
|
}
|
|
3770
3936
|
getSnapshot(index) {
|