jotai-state-tree 1.4.0 → 1.4.2
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-MSLAD5CJ.mjs → chunk-Q6QPBXHH.mjs} +88 -7
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +90 -7
- package/dist/index.mjs +4 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +108 -23
- package/dist/react.mjs +26 -18
- package/dist/{undo-BcBI_BQM.d.mts → undo-DL1pyOkT.d.mts} +2 -0
- package/dist/{undo-BcBI_BQM.d.ts → undo-DL1pyOkT.d.ts} +2 -0
- package/package.json +1 -1
- package/src/__tests__/app_example.test.tsx +1 -1
- package/src/__tests__/examples/dashboard-live-telemetry.test.tsx +107 -0
- package/src/__tests__/examples/form-builder-dynamic.test.tsx +187 -0
- package/src/__tests__/examples/kanban-board-references.test.tsx +130 -0
- package/src/__tests__/examples/note-taking-ssr.test.tsx +100 -0
- package/src/__tests__/examples/shopping-cart-views.test.tsx +181 -0
- package/src/__tests__/examples/todo-list-time-travel.test.tsx +223 -0
- package/src/__tests__/history_repro.test.ts +3 -4
- package/src/__tests__/index.test.ts +3 -2
- package/src/model.ts +3 -0
- package/src/react.ts +28 -16
- package/src/tree.ts +67 -8
- package/src/undo.ts +42 -0
|
@@ -42,9 +42,12 @@ var identifierFinalizationRegistry = new FinalizationRegistry(
|
|
|
42
42
|
(info) => {
|
|
43
43
|
const typeMap = identifierRegistry.get(info.typeName);
|
|
44
44
|
if (typeMap) {
|
|
45
|
-
typeMap.
|
|
46
|
-
if (
|
|
47
|
-
|
|
45
|
+
const ref = typeMap.get(info.identifier);
|
|
46
|
+
if (!ref || ref.deref() === void 0) {
|
|
47
|
+
typeMap.delete(info.identifier);
|
|
48
|
+
if (typeMap.size === 0) {
|
|
49
|
+
identifierRegistry.delete(info.typeName);
|
|
50
|
+
}
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
}
|
|
@@ -71,6 +74,35 @@ function notifyLifecycleChange(node, isAlive2) {
|
|
|
71
74
|
listeners.forEach((listener) => listener(isAlive2));
|
|
72
75
|
}
|
|
73
76
|
}
|
|
77
|
+
function cloneAndSerialize(value) {
|
|
78
|
+
if (value === null || value === void 0) {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
if (hasStateTreeNode(value)) {
|
|
82
|
+
return getSnapshotFromNode(getStateTreeNode(value));
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
return value.map(cloneAndSerialize);
|
|
86
|
+
}
|
|
87
|
+
if (typeof value === "object") {
|
|
88
|
+
if (value instanceof Map) {
|
|
89
|
+
const res = {};
|
|
90
|
+
for (const [k, v] of value.entries()) {
|
|
91
|
+
res[k] = cloneAndSerialize(v);
|
|
92
|
+
}
|
|
93
|
+
return res;
|
|
94
|
+
}
|
|
95
|
+
const proto = Object.getPrototypeOf(value);
|
|
96
|
+
if (proto === null || proto === Object.prototype) {
|
|
97
|
+
const res = {};
|
|
98
|
+
for (const [k, v] of Object.entries(value)) {
|
|
99
|
+
res[k] = cloneAndSerialize(v);
|
|
100
|
+
}
|
|
101
|
+
return res;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
74
106
|
var StateTreeNode = class {
|
|
75
107
|
constructor(type, initialValue, env, parent, pathSegment) {
|
|
76
108
|
this.$parent = null;
|
|
@@ -88,6 +120,8 @@ var StateTreeNode = class {
|
|
|
88
120
|
/** Cached snapshot for structural sharing optimization */
|
|
89
121
|
this.cachedSnapshot = void 0;
|
|
90
122
|
this.isSnapshotDirty = true;
|
|
123
|
+
/** Strong reference to the instance proxy to prevent GC of active nodes */
|
|
124
|
+
this.instance = null;
|
|
91
125
|
this.$id = generateNodeId();
|
|
92
126
|
this.$type = type;
|
|
93
127
|
this.$env = env ?? parent?.$env;
|
|
@@ -108,6 +142,7 @@ var StateTreeNode = class {
|
|
|
108
142
|
}
|
|
109
143
|
/** Set the instance reference */
|
|
110
144
|
setInstance(instance) {
|
|
145
|
+
this.instance = instance;
|
|
111
146
|
const entry = nodeRegistry.get(this.$id);
|
|
112
147
|
if (entry && instance && typeof instance === "object") {
|
|
113
148
|
entry.instance = new WeakRef(instance);
|
|
@@ -115,8 +150,7 @@ var StateTreeNode = class {
|
|
|
115
150
|
}
|
|
116
151
|
/** Get the instance */
|
|
117
152
|
getInstance() {
|
|
118
|
-
|
|
119
|
-
return entry?.instance?.deref() ?? null;
|
|
153
|
+
return this.instance;
|
|
120
154
|
}
|
|
121
155
|
/** Get current value from atom */
|
|
122
156
|
getValue() {
|
|
@@ -222,9 +256,27 @@ var StateTreeNode = class {
|
|
|
222
256
|
}
|
|
223
257
|
/** Notify patch listeners */
|
|
224
258
|
notifyPatch(patch, reversePatch) {
|
|
225
|
-
|
|
259
|
+
const serializedPatch = {
|
|
260
|
+
...patch,
|
|
261
|
+
value: "value" in patch ? cloneAndSerialize(patch.value) : void 0
|
|
262
|
+
};
|
|
263
|
+
if (!("value" in patch)) {
|
|
264
|
+
delete serializedPatch.value;
|
|
265
|
+
}
|
|
266
|
+
const serializedReversePatch = {
|
|
267
|
+
...reversePatch,
|
|
268
|
+
value: "value" in reversePatch ? cloneAndSerialize(reversePatch.value) : void 0,
|
|
269
|
+
oldValue: "oldValue" in reversePatch ? cloneAndSerialize(reversePatch.oldValue) : void 0
|
|
270
|
+
};
|
|
271
|
+
if (!("value" in reversePatch)) {
|
|
272
|
+
delete serializedReversePatch.value;
|
|
273
|
+
}
|
|
274
|
+
if (!("oldValue" in reversePatch)) {
|
|
275
|
+
delete serializedReversePatch.oldValue;
|
|
276
|
+
}
|
|
277
|
+
this.patchListeners.forEach((listener) => listener(serializedPatch, serializedReversePatch));
|
|
226
278
|
if (this.$parent) {
|
|
227
|
-
this.$parent.notifyPatch(
|
|
279
|
+
this.$parent.notifyPatch(serializedPatch, serializedReversePatch);
|
|
228
280
|
}
|
|
229
281
|
}
|
|
230
282
|
/** Notify snapshot listeners */
|
|
@@ -261,6 +313,7 @@ var StateTreeNode = class {
|
|
|
261
313
|
/** Destroy this node and all children */
|
|
262
314
|
destroy() {
|
|
263
315
|
if (!this.$isAlive) return;
|
|
316
|
+
this.instance = null;
|
|
264
317
|
lifecycleHookHandlers.runBeforeDestroy?.(this);
|
|
265
318
|
this.children.forEach((child) => child.destroy());
|
|
266
319
|
this.children.clear();
|
|
@@ -900,6 +953,8 @@ function unfreeze(target) {
|
|
|
900
953
|
}
|
|
901
954
|
|
|
902
955
|
// src/undo.ts
|
|
956
|
+
var undoManagersRegistry = /* @__PURE__ */ new WeakMap();
|
|
957
|
+
var timeTravelManagersRegistry = /* @__PURE__ */ new WeakMap();
|
|
903
958
|
var UndoManager = class {
|
|
904
959
|
constructor(target, options = {}) {
|
|
905
960
|
this.historyEntries = [];
|
|
@@ -920,6 +975,7 @@ var UndoManager = class {
|
|
|
920
975
|
groupByTime: options.groupByTime ?? false,
|
|
921
976
|
groupingWindow: options.groupingWindow ?? 200
|
|
922
977
|
};
|
|
978
|
+
undoManagersRegistry.set(target, this);
|
|
923
979
|
this.disposer = onPatch(target, (patch, reversePatch) => {
|
|
924
980
|
this.recordPatch(patch, reversePatch);
|
|
925
981
|
});
|
|
@@ -1013,6 +1069,13 @@ var UndoManager = class {
|
|
|
1013
1069
|
applyPatch(this.target, entry.patches[i]);
|
|
1014
1070
|
}
|
|
1015
1071
|
this.currentIndex--;
|
|
1072
|
+
const tt = timeTravelManagersRegistry.get(this.target);
|
|
1073
|
+
if (tt) {
|
|
1074
|
+
const N = tt.snapshots.length;
|
|
1075
|
+
const M = this.historyEntries.length;
|
|
1076
|
+
const ttIndex = this.currentIndex + 1 + (N - 1 - M);
|
|
1077
|
+
tt.index = Math.max(0, Math.min(N - 1, ttIndex));
|
|
1078
|
+
}
|
|
1016
1079
|
} finally {
|
|
1017
1080
|
this.isUndoing = false;
|
|
1018
1081
|
rootNode.$isApplyingHistory = wasApplying;
|
|
@@ -1033,6 +1096,13 @@ var UndoManager = class {
|
|
|
1033
1096
|
for (const patch of entry.inversePatches) {
|
|
1034
1097
|
applyPatch(this.target, patch);
|
|
1035
1098
|
}
|
|
1099
|
+
const tt = timeTravelManagersRegistry.get(this.target);
|
|
1100
|
+
if (tt) {
|
|
1101
|
+
const N = tt.snapshots.length;
|
|
1102
|
+
const M = this.historyEntries.length;
|
|
1103
|
+
const ttIndex = this.currentIndex + 1 + (N - 1 - M);
|
|
1104
|
+
tt.index = Math.max(0, Math.min(N - 1, ttIndex));
|
|
1105
|
+
}
|
|
1036
1106
|
} finally {
|
|
1037
1107
|
this.isRedoing = false;
|
|
1038
1108
|
rootNode.$isApplyingHistory = wasApplying;
|
|
@@ -1086,6 +1156,7 @@ var UndoManager = class {
|
|
|
1086
1156
|
}
|
|
1087
1157
|
}
|
|
1088
1158
|
dispose() {
|
|
1159
|
+
undoManagersRegistry.delete(this.target);
|
|
1089
1160
|
if (this.disposer) {
|
|
1090
1161
|
this.disposer();
|
|
1091
1162
|
this.disposer = null;
|
|
@@ -1112,6 +1183,7 @@ var TimeTravelManager = class {
|
|
|
1112
1183
|
this.target = target;
|
|
1113
1184
|
this.maxSnapshots = options.maxSnapshots ?? 50;
|
|
1114
1185
|
this.autoRecord = options.autoRecord ?? false;
|
|
1186
|
+
timeTravelManagersRegistry.set(target, this);
|
|
1115
1187
|
this.record();
|
|
1116
1188
|
if (this.autoRecord) {
|
|
1117
1189
|
this.disposer = onPatch(target, () => {
|
|
@@ -1193,6 +1265,13 @@ var TimeTravelManager = class {
|
|
|
1193
1265
|
try {
|
|
1194
1266
|
this.index = index;
|
|
1195
1267
|
applySnapshot(this.target, this.snapshots[index]);
|
|
1268
|
+
const undo = undoManagersRegistry.get(this.target);
|
|
1269
|
+
if (undo) {
|
|
1270
|
+
const N = this.snapshots.length;
|
|
1271
|
+
const M = undo.historyEntries.length;
|
|
1272
|
+
const undoIndex = this.index - 1 - (N - 1 - M);
|
|
1273
|
+
undo.currentIndex = Math.max(-1, Math.min(M - 1, undoIndex));
|
|
1274
|
+
}
|
|
1196
1275
|
} finally {
|
|
1197
1276
|
this.isApplying = false;
|
|
1198
1277
|
rootNode.$isApplyingHistory = wasApplying;
|
|
@@ -1210,6 +1289,7 @@ var TimeTravelManager = class {
|
|
|
1210
1289
|
this.record();
|
|
1211
1290
|
}
|
|
1212
1291
|
dispose() {
|
|
1292
|
+
timeTravelManagersRegistry.delete(this.target);
|
|
1213
1293
|
if (this.disposer) {
|
|
1214
1294
|
this.disposer();
|
|
1215
1295
|
this.disposer = null;
|
|
@@ -1302,6 +1382,7 @@ function createActionRecorder(target) {
|
|
|
1302
1382
|
export {
|
|
1303
1383
|
setLifecycleHookHandlers,
|
|
1304
1384
|
getIsApplyingSnapshotOrPatch,
|
|
1385
|
+
setIsApplyingSnapshotOrPatch,
|
|
1305
1386
|
getGlobalStore,
|
|
1306
1387
|
setGlobalStore,
|
|
1307
1388
|
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 } from './undo-
|
|
2
|
-
export { L as CustomTypeOptions, aG as IActionRecorder, aH as IActionRecording, C as IAnyComplexType, D as IAnyMixin, aE as IHistoryEntry, F as IJsonPatch, y as IMSTArray, z as IMSTMap, G as IReversibleJsonPatch, x as IStateTreeNode, aF as ITimeTravelManager, aC as IUndoManager, aD as IUndoManagerOptions, H as IValidationContext, K as IValidationError, J as IValidationResult, A as ModelInstance, E as ModelSelf, B as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, aB as createActionRecorder, aA as createTimeTravelManager, az as createUndoManager, 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 './undo-
|
|
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 } from './undo-DL1pyOkT.mjs';
|
|
2
|
+
export { L as CustomTypeOptions, aG as IActionRecorder, aH as IActionRecording, C as IAnyComplexType, D as IAnyMixin, aE as IHistoryEntry, F as IJsonPatch, y as IMSTArray, z as IMSTMap, G as IReversibleJsonPatch, x as IStateTreeNode, aF as ITimeTravelManager, aC as IUndoManager, aD as IUndoManagerOptions, H as IValidationContext, K as IValidationError, J as IValidationResult, A as ModelInstance, E as ModelSelf, B as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, aB as createActionRecorder, aA as createTimeTravelManager, az as createUndoManager, 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 './undo-DL1pyOkT.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 } from './undo-
|
|
2
|
-
export { L as CustomTypeOptions, aG as IActionRecorder, aH as IActionRecording, C as IAnyComplexType, D as IAnyMixin, aE as IHistoryEntry, F as IJsonPatch, y as IMSTArray, z as IMSTMap, G as IReversibleJsonPatch, x as IStateTreeNode, aF as ITimeTravelManager, aC as IUndoManager, aD as IUndoManagerOptions, H as IValidationContext, K as IValidationError, J as IValidationResult, A as ModelInstance, E as ModelSelf, B as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, aB as createActionRecorder, aA as createTimeTravelManager, az as createUndoManager, 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 './undo-
|
|
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 } from './undo-DL1pyOkT.js';
|
|
2
|
+
export { L as CustomTypeOptions, aG as IActionRecorder, aH as IActionRecording, C as IAnyComplexType, D as IAnyMixin, aE as IHistoryEntry, F as IJsonPatch, y as IMSTArray, z as IMSTMap, G as IReversibleJsonPatch, x as IStateTreeNode, aF as ITimeTravelManager, aC as IUndoManager, aD as IUndoManagerOptions, H as IValidationContext, K as IValidationError, J as IValidationResult, A as ModelInstance, E as ModelSelf, B as SnapshotOut, T as applyPatch, O as applySnapshot, aw as cleanupStaleEntries, ax as clearAllRegistries, aa as clone, aq as cloneDeep, aB as createActionRecorder, aA as createTimeTravelManager, az as createUndoManager, 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 './undo-DL1pyOkT.js';
|
|
3
3
|
import 'jotai/vanilla/internals';
|
|
4
4
|
import 'jotai';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -473,9 +473,12 @@ var identifierFinalizationRegistry = new FinalizationRegistry(
|
|
|
473
473
|
(info) => {
|
|
474
474
|
const typeMap = identifierRegistry.get(info.typeName);
|
|
475
475
|
if (typeMap) {
|
|
476
|
-
typeMap.
|
|
477
|
-
if (
|
|
478
|
-
|
|
476
|
+
const ref = typeMap.get(info.identifier);
|
|
477
|
+
if (!ref || ref.deref() === void 0) {
|
|
478
|
+
typeMap.delete(info.identifier);
|
|
479
|
+
if (typeMap.size === 0) {
|
|
480
|
+
identifierRegistry.delete(info.typeName);
|
|
481
|
+
}
|
|
479
482
|
}
|
|
480
483
|
}
|
|
481
484
|
}
|
|
@@ -502,6 +505,35 @@ function notifyLifecycleChange(node, isAlive2) {
|
|
|
502
505
|
listeners.forEach((listener) => listener(isAlive2));
|
|
503
506
|
}
|
|
504
507
|
}
|
|
508
|
+
function cloneAndSerialize(value) {
|
|
509
|
+
if (value === null || value === void 0) {
|
|
510
|
+
return value;
|
|
511
|
+
}
|
|
512
|
+
if (hasStateTreeNode(value)) {
|
|
513
|
+
return getSnapshotFromNode(getStateTreeNode(value));
|
|
514
|
+
}
|
|
515
|
+
if (Array.isArray(value)) {
|
|
516
|
+
return value.map(cloneAndSerialize);
|
|
517
|
+
}
|
|
518
|
+
if (typeof value === "object") {
|
|
519
|
+
if (value instanceof Map) {
|
|
520
|
+
const res = {};
|
|
521
|
+
for (const [k, v] of value.entries()) {
|
|
522
|
+
res[k] = cloneAndSerialize(v);
|
|
523
|
+
}
|
|
524
|
+
return res;
|
|
525
|
+
}
|
|
526
|
+
const proto = Object.getPrototypeOf(value);
|
|
527
|
+
if (proto === null || proto === Object.prototype) {
|
|
528
|
+
const res = {};
|
|
529
|
+
for (const [k, v] of Object.entries(value)) {
|
|
530
|
+
res[k] = cloneAndSerialize(v);
|
|
531
|
+
}
|
|
532
|
+
return res;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return value;
|
|
536
|
+
}
|
|
505
537
|
var StateTreeNode = class {
|
|
506
538
|
constructor(type, initialValue, env, parent, pathSegment) {
|
|
507
539
|
this.$parent = null;
|
|
@@ -519,6 +551,8 @@ var StateTreeNode = class {
|
|
|
519
551
|
/** Cached snapshot for structural sharing optimization */
|
|
520
552
|
this.cachedSnapshot = void 0;
|
|
521
553
|
this.isSnapshotDirty = true;
|
|
554
|
+
/** Strong reference to the instance proxy to prevent GC of active nodes */
|
|
555
|
+
this.instance = null;
|
|
522
556
|
this.$id = generateNodeId();
|
|
523
557
|
this.$type = type;
|
|
524
558
|
this.$env = env ?? parent?.$env;
|
|
@@ -539,6 +573,7 @@ var StateTreeNode = class {
|
|
|
539
573
|
}
|
|
540
574
|
/** Set the instance reference */
|
|
541
575
|
setInstance(instance) {
|
|
576
|
+
this.instance = instance;
|
|
542
577
|
const entry = nodeRegistry.get(this.$id);
|
|
543
578
|
if (entry && instance && typeof instance === "object") {
|
|
544
579
|
entry.instance = new WeakRef(instance);
|
|
@@ -546,8 +581,7 @@ var StateTreeNode = class {
|
|
|
546
581
|
}
|
|
547
582
|
/** Get the instance */
|
|
548
583
|
getInstance() {
|
|
549
|
-
|
|
550
|
-
return entry?.instance?.deref() ?? null;
|
|
584
|
+
return this.instance;
|
|
551
585
|
}
|
|
552
586
|
/** Get current value from atom */
|
|
553
587
|
getValue() {
|
|
@@ -653,9 +687,27 @@ var StateTreeNode = class {
|
|
|
653
687
|
}
|
|
654
688
|
/** Notify patch listeners */
|
|
655
689
|
notifyPatch(patch, reversePatch) {
|
|
656
|
-
|
|
690
|
+
const serializedPatch = {
|
|
691
|
+
...patch,
|
|
692
|
+
value: "value" in patch ? cloneAndSerialize(patch.value) : void 0
|
|
693
|
+
};
|
|
694
|
+
if (!("value" in patch)) {
|
|
695
|
+
delete serializedPatch.value;
|
|
696
|
+
}
|
|
697
|
+
const serializedReversePatch = {
|
|
698
|
+
...reversePatch,
|
|
699
|
+
value: "value" in reversePatch ? cloneAndSerialize(reversePatch.value) : void 0,
|
|
700
|
+
oldValue: "oldValue" in reversePatch ? cloneAndSerialize(reversePatch.oldValue) : void 0
|
|
701
|
+
};
|
|
702
|
+
if (!("value" in reversePatch)) {
|
|
703
|
+
delete serializedReversePatch.value;
|
|
704
|
+
}
|
|
705
|
+
if (!("oldValue" in reversePatch)) {
|
|
706
|
+
delete serializedReversePatch.oldValue;
|
|
707
|
+
}
|
|
708
|
+
this.patchListeners.forEach((listener) => listener(serializedPatch, serializedReversePatch));
|
|
657
709
|
if (this.$parent) {
|
|
658
|
-
this.$parent.notifyPatch(
|
|
710
|
+
this.$parent.notifyPatch(serializedPatch, serializedReversePatch);
|
|
659
711
|
}
|
|
660
712
|
}
|
|
661
713
|
/** Notify snapshot listeners */
|
|
@@ -692,6 +744,7 @@ var StateTreeNode = class {
|
|
|
692
744
|
/** Destroy this node and all children */
|
|
693
745
|
destroy() {
|
|
694
746
|
if (!this.$isAlive) return;
|
|
747
|
+
this.instance = null;
|
|
695
748
|
lifecycleHookHandlers.runBeforeDestroy?.(this);
|
|
696
749
|
this.children.forEach((child) => child.destroy());
|
|
697
750
|
this.children.clear();
|
|
@@ -1883,6 +1936,9 @@ var ModelType = class _ModelType {
|
|
|
1883
1936
|
}
|
|
1884
1937
|
return descriptor.value;
|
|
1885
1938
|
}
|
|
1939
|
+
if (propStr === "toggle") {
|
|
1940
|
+
console.log("PROXY GET toggle:", propStr, "in allActions:", propStr in allActions, "keys:", Object.keys(allActions), "node alive:", node.$isAlive);
|
|
1941
|
+
}
|
|
1886
1942
|
if (propStr in allActions) {
|
|
1887
1943
|
return allActions[propStr];
|
|
1888
1944
|
}
|
|
@@ -3713,6 +3769,8 @@ function createWithDefaults(type, snapshot = {}, env) {
|
|
|
3713
3769
|
}
|
|
3714
3770
|
|
|
3715
3771
|
// src/undo.ts
|
|
3772
|
+
var undoManagersRegistry = /* @__PURE__ */ new WeakMap();
|
|
3773
|
+
var timeTravelManagersRegistry = /* @__PURE__ */ new WeakMap();
|
|
3716
3774
|
var UndoManager = class {
|
|
3717
3775
|
constructor(target, options = {}) {
|
|
3718
3776
|
this.historyEntries = [];
|
|
@@ -3733,6 +3791,7 @@ var UndoManager = class {
|
|
|
3733
3791
|
groupByTime: options.groupByTime ?? false,
|
|
3734
3792
|
groupingWindow: options.groupingWindow ?? 200
|
|
3735
3793
|
};
|
|
3794
|
+
undoManagersRegistry.set(target, this);
|
|
3736
3795
|
this.disposer = onPatch(target, (patch, reversePatch) => {
|
|
3737
3796
|
this.recordPatch(patch, reversePatch);
|
|
3738
3797
|
});
|
|
@@ -3826,6 +3885,13 @@ var UndoManager = class {
|
|
|
3826
3885
|
applyPatch(this.target, entry.patches[i]);
|
|
3827
3886
|
}
|
|
3828
3887
|
this.currentIndex--;
|
|
3888
|
+
const tt = timeTravelManagersRegistry.get(this.target);
|
|
3889
|
+
if (tt) {
|
|
3890
|
+
const N = tt.snapshots.length;
|
|
3891
|
+
const M = this.historyEntries.length;
|
|
3892
|
+
const ttIndex = this.currentIndex + 1 + (N - 1 - M);
|
|
3893
|
+
tt.index = Math.max(0, Math.min(N - 1, ttIndex));
|
|
3894
|
+
}
|
|
3829
3895
|
} finally {
|
|
3830
3896
|
this.isUndoing = false;
|
|
3831
3897
|
rootNode.$isApplyingHistory = wasApplying;
|
|
@@ -3846,6 +3912,13 @@ var UndoManager = class {
|
|
|
3846
3912
|
for (const patch of entry.inversePatches) {
|
|
3847
3913
|
applyPatch(this.target, patch);
|
|
3848
3914
|
}
|
|
3915
|
+
const tt = timeTravelManagersRegistry.get(this.target);
|
|
3916
|
+
if (tt) {
|
|
3917
|
+
const N = tt.snapshots.length;
|
|
3918
|
+
const M = this.historyEntries.length;
|
|
3919
|
+
const ttIndex = this.currentIndex + 1 + (N - 1 - M);
|
|
3920
|
+
tt.index = Math.max(0, Math.min(N - 1, ttIndex));
|
|
3921
|
+
}
|
|
3849
3922
|
} finally {
|
|
3850
3923
|
this.isRedoing = false;
|
|
3851
3924
|
rootNode.$isApplyingHistory = wasApplying;
|
|
@@ -3899,6 +3972,7 @@ var UndoManager = class {
|
|
|
3899
3972
|
}
|
|
3900
3973
|
}
|
|
3901
3974
|
dispose() {
|
|
3975
|
+
undoManagersRegistry.delete(this.target);
|
|
3902
3976
|
if (this.disposer) {
|
|
3903
3977
|
this.disposer();
|
|
3904
3978
|
this.disposer = null;
|
|
@@ -3925,6 +3999,7 @@ var TimeTravelManager = class {
|
|
|
3925
3999
|
this.target = target;
|
|
3926
4000
|
this.maxSnapshots = options.maxSnapshots ?? 50;
|
|
3927
4001
|
this.autoRecord = options.autoRecord ?? false;
|
|
4002
|
+
timeTravelManagersRegistry.set(target, this);
|
|
3928
4003
|
this.record();
|
|
3929
4004
|
if (this.autoRecord) {
|
|
3930
4005
|
this.disposer = onPatch(target, () => {
|
|
@@ -4006,6 +4081,13 @@ var TimeTravelManager = class {
|
|
|
4006
4081
|
try {
|
|
4007
4082
|
this.index = index;
|
|
4008
4083
|
applySnapshot(this.target, this.snapshots[index]);
|
|
4084
|
+
const undo = undoManagersRegistry.get(this.target);
|
|
4085
|
+
if (undo) {
|
|
4086
|
+
const N = this.snapshots.length;
|
|
4087
|
+
const M = undo.historyEntries.length;
|
|
4088
|
+
const undoIndex = this.index - 1 - (N - 1 - M);
|
|
4089
|
+
undo.currentIndex = Math.max(-1, Math.min(M - 1, undoIndex));
|
|
4090
|
+
}
|
|
4009
4091
|
} finally {
|
|
4010
4092
|
this.isApplying = false;
|
|
4011
4093
|
rootNode.$isApplyingHistory = wasApplying;
|
|
@@ -4023,6 +4105,7 @@ var TimeTravelManager = class {
|
|
|
4023
4105
|
this.record();
|
|
4024
4106
|
}
|
|
4025
4107
|
dispose() {
|
|
4108
|
+
timeTravelManagersRegistry.delete(this.target);
|
|
4026
4109
|
if (this.disposer) {
|
|
4027
4110
|
this.disposer();
|
|
4028
4111
|
this.disposer = null;
|
package/dist/index.mjs
CHANGED
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
tryResolve,
|
|
63
63
|
unfreeze,
|
|
64
64
|
walk
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-Q6QPBXHH.mjs";
|
|
66
66
|
|
|
67
67
|
// src/primitives.ts
|
|
68
68
|
function createSimpleType(name, validator, defaultValue) {
|
|
@@ -895,6 +895,9 @@ var ModelType = class _ModelType {
|
|
|
895
895
|
}
|
|
896
896
|
return descriptor.value;
|
|
897
897
|
}
|
|
898
|
+
if (propStr === "toggle") {
|
|
899
|
+
console.log("PROXY GET toggle:", propStr, "in allActions:", propStr in allActions, "keys:", Object.keys(allActions), "node alive:", node.$isAlive);
|
|
900
|
+
}
|
|
898
901
|
if (propStr in allActions) {
|
|
899
902
|
return allActions[propStr];
|
|
900
903
|
}
|
package/dist/react.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { ComponentType, FC, ReactNode } from 'react';
|
|
2
|
-
import { ag as getGlobalStore, aD as IUndoManagerOptions, aC as IUndoManager, aF as ITimeTravelManager } from './undo-
|
|
3
|
-
export { aI as hasStateTreeNode } from './undo-
|
|
2
|
+
import { ag as getGlobalStore, aD as IUndoManagerOptions, aC as IUndoManager, aF as ITimeTravelManager } from './undo-DL1pyOkT.mjs';
|
|
3
|
+
export { aI as hasStateTreeNode } from './undo-DL1pyOkT.mjs';
|
|
4
4
|
import 'jotai/vanilla/internals';
|
|
5
5
|
import 'jotai';
|
|
6
6
|
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { ComponentType, FC, ReactNode } from 'react';
|
|
2
|
-
import { ag as getGlobalStore, aD as IUndoManagerOptions, aC as IUndoManager, aF as ITimeTravelManager } from './undo-
|
|
3
|
-
export { aI as hasStateTreeNode } from './undo-
|
|
2
|
+
import { ag as getGlobalStore, aD as IUndoManagerOptions, aC as IUndoManager, aF as ITimeTravelManager } from './undo-DL1pyOkT.js';
|
|
3
|
+
export { aI as hasStateTreeNode } from './undo-DL1pyOkT.js';
|
|
4
4
|
import 'jotai/vanilla/internals';
|
|
5
5
|
import 'jotai';
|
|
6
6
|
|