@legendapp/state 2.1.0 → 2.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,5 @@
1
- ## 2.1.0
2
- - Feat: useLegendStatePauseProvider to pause/resume all updates under a context
1
+ ## 2.1.1
2
+ - Feat: usePauseProvider to pause/resume all updates under a context
3
3
 
4
4
  ## 2.0.3
5
5
  - Feat: support persistence with no get
package/index.d.ts CHANGED
@@ -12,21 +12,26 @@ export { trackSelector } from './src/trackSelector';
12
12
  export { when, whenReady } from './src/when';
13
13
  import { get, getProxy, peek, set } from './src/ObservableObject';
14
14
  import { ensureNodeValue, findIDKey, getNode, setNodeValue } from './src/globals';
15
- import { setAtPath } from './src/helpers';
15
+ import { getPathType, setAtPath, initializePathType, safeParse, safeStringify, clone } from './src/helpers';
16
16
  export declare const internal: {
17
+ clone: typeof clone;
17
18
  ensureNodeValue: typeof ensureNodeValue;
18
19
  findIDKey: typeof findIDKey;
19
20
  get: typeof get;
20
21
  getNode: typeof getNode;
22
+ getPathType: typeof getPathType;
21
23
  getProxy: typeof getProxy;
22
24
  globalState: {
23
25
  isLoadingLocal: boolean;
24
26
  isLoadingRemote: boolean;
25
27
  isMerging: boolean;
26
28
  };
29
+ initializePathType: typeof initializePathType;
27
30
  observableFns: Map<string, (node: import("./src/observableInterfaces").NodeValue, ...args: any[]) => any>;
28
31
  optimized: symbol;
29
32
  peek: typeof peek;
33
+ safeParse: typeof safeParse;
34
+ safeStringify: typeof safeStringify;
30
35
  set: typeof set;
31
36
  setAtPath: typeof setAtPath;
32
37
  setNodeValue: typeof setNodeValue;
package/index.js CHANGED
@@ -194,6 +194,228 @@ function extractFunction(node, key, fnOrComputed, computedChildNode) {
194
194
  }
195
195
  }
196
196
 
197
+ function isObservable(obs) {
198
+ return obs && !!obs[symbolGetNode];
199
+ }
200
+ function isEvent(obs) {
201
+ var _a;
202
+ return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isEvent);
203
+ }
204
+ function computeSelector(selector, e, retainObservable) {
205
+ let c = selector;
206
+ if (isFunction(c)) {
207
+ c = e ? c(e) : c();
208
+ }
209
+ return isObservable(c) && !retainObservable ? c.get() : c;
210
+ }
211
+ function getObservableIndex(obs) {
212
+ const node = getNode(obs);
213
+ const n = +node.key;
214
+ return n - n < 1 ? +n : -1;
215
+ }
216
+ function opaqueObject(value) {
217
+ if (value) {
218
+ value[symbolOpaque] = true;
219
+ }
220
+ return value;
221
+ }
222
+ function lockObservable(obs, value) {
223
+ var _a;
224
+ const root = (_a = getNode(obs)) === null || _a === void 0 ? void 0 : _a.root;
225
+ if (root) {
226
+ root.locked = value;
227
+ }
228
+ }
229
+ function setAtPath(obj, path, pathTypes, value, fullObj, restore) {
230
+ let o = obj;
231
+ let oFull = fullObj;
232
+ if (path.length > 0) {
233
+ for (let i = 0; i < path.length; i++) {
234
+ const p = path[i];
235
+ if (i === path.length - 1) {
236
+ // Don't set if the value is the same. This prevents creating a new key
237
+ // when setting undefined on an object without this key
238
+ if (o[p] !== value) {
239
+ o[p] = value;
240
+ }
241
+ }
242
+ else if (o[p] === symbolDelete) {
243
+ // If this was previously deleted, restore it
244
+ if (oFull) {
245
+ o[p] = oFull[p];
246
+ restore === null || restore === void 0 ? void 0 : restore(path.slice(0, i + 1), o[p]);
247
+ }
248
+ break;
249
+ }
250
+ else if (o[p] === undefined || o[p] === null) {
251
+ o[p] = initializePathType(pathTypes[i]);
252
+ }
253
+ o = o[p];
254
+ if (oFull) {
255
+ oFull = oFull[p];
256
+ }
257
+ }
258
+ }
259
+ else {
260
+ obj = value;
261
+ }
262
+ return obj;
263
+ }
264
+ function setInObservableAtPath(obs, path, pathTypes, value, mode) {
265
+ let o = obs;
266
+ let v = value;
267
+ for (let i = 0; i < path.length; i++) {
268
+ const p = path[i];
269
+ if (!o.peek()[p]) {
270
+ o[p].set(initializePathType(pathTypes[i]));
271
+ }
272
+ o = o[p];
273
+ v = v[p];
274
+ }
275
+ if (v === symbolDelete) {
276
+ o.delete();
277
+ }
278
+ // Assign if possible, or set otherwise
279
+ else if (mode === 'assign' && o.assign && isObject(o.peek())) {
280
+ o.assign(v);
281
+ }
282
+ else {
283
+ o.set(v);
284
+ }
285
+ }
286
+ function mergeIntoObservable(target, ...sources) {
287
+ beginBatch();
288
+ globalState.isMerging = true;
289
+ for (let i = 0; i < sources.length; i++) {
290
+ target = _mergeIntoObservable(target, sources[i]);
291
+ }
292
+ globalState.isMerging = false;
293
+ endBatch();
294
+ return target;
295
+ }
296
+ function _mergeIntoObservable(target, source) {
297
+ var _a;
298
+ const needsSet = isObservable(target);
299
+ const targetValue = needsSet ? target.peek() : target;
300
+ const isTargetArr = isArray(targetValue);
301
+ const isTargetObj = !isTargetArr && isObject(targetValue);
302
+ if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) ||
303
+ (isTargetArr && isArray(source) && targetValue.length > 0)) {
304
+ const keys = Object.keys(source);
305
+ for (let i = 0; i < keys.length; i++) {
306
+ const key = keys[i];
307
+ const sourceValue = source[key];
308
+ if (sourceValue === symbolDelete) {
309
+ needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete) ? target[key].delete() : delete target[key];
310
+ }
311
+ else {
312
+ const isObj = isObject(sourceValue);
313
+ const isArr = !isObj && isArray(sourceValue);
314
+ const targetChild = target[key];
315
+ if ((isObj || isArr) && targetChild && (needsSet || !isEmpty(targetChild))) {
316
+ if (!needsSet && (!targetChild || (isObj ? !isObject(targetChild) : !isArray(targetChild)))) {
317
+ target[key] = sourceValue;
318
+ }
319
+ else {
320
+ _mergeIntoObservable(targetChild, sourceValue);
321
+ }
322
+ }
323
+ else {
324
+ needsSet
325
+ ? targetChild.set(sourceValue)
326
+ : (target[key] = sourceValue);
327
+ }
328
+ }
329
+ }
330
+ }
331
+ else if (source !== undefined) {
332
+ needsSet ? target.set(source) : (target = source);
333
+ }
334
+ return target;
335
+ }
336
+ function constructObjectWithPath(path, pathTypes, value) {
337
+ let out;
338
+ if (path.length > 0) {
339
+ let o = (out = {});
340
+ for (let i = 0; i < path.length; i++) {
341
+ const p = path[i];
342
+ o[p] = i === path.length - 1 ? value : initializePathType(pathTypes[i]);
343
+ o = o[p];
344
+ }
345
+ }
346
+ else {
347
+ out = value;
348
+ }
349
+ return out;
350
+ }
351
+ function deconstructObjectWithPath(path, pathTypes, value) {
352
+ let o = value;
353
+ for (let i = 0; i < path.length; i++) {
354
+ const p = path[i];
355
+ o = o ? o[p] : initializePathType(pathTypes[i]);
356
+ }
357
+ return o;
358
+ }
359
+ function isObservableValueReady(value) {
360
+ return !!value && ((!isObject(value) && !isArray(value)) || !isEmpty(value));
361
+ }
362
+ function setSilently(obs, newValue) {
363
+ const node = getNode(obs);
364
+ return setNodeValue(node, newValue).newValue;
365
+ }
366
+ function getPathType(value) {
367
+ return isArray(value) ? 'array' : value instanceof Map ? 'map' : value instanceof Set ? 'set' : 'object';
368
+ }
369
+ function initializePathType(pathType) {
370
+ switch (pathType) {
371
+ case 'array':
372
+ return [];
373
+ case 'object':
374
+ return {};
375
+ case 'map':
376
+ return new Map();
377
+ case 'set':
378
+ return new Set();
379
+ }
380
+ }
381
+ function replacer(_, value) {
382
+ if (value instanceof Map) {
383
+ return {
384
+ __LSType: 'Map',
385
+ value: Array.from(value.entries()), // or with spread: value: [...value]
386
+ };
387
+ }
388
+ else if (value instanceof Set) {
389
+ return {
390
+ __LSType: 'Set',
391
+ value: Array.from(value), // or with spread: value: [...value]
392
+ };
393
+ }
394
+ else {
395
+ return value;
396
+ }
397
+ }
398
+ function reviver(_, value) {
399
+ if (typeof value === 'object' && value) {
400
+ if (value.__LSType === 'Map') {
401
+ return new Map(value.value);
402
+ }
403
+ else if (value.__LSType === 'Set') {
404
+ return new Set(value.value);
405
+ }
406
+ }
407
+ return value;
408
+ }
409
+ function safeStringify(value) {
410
+ return JSON.stringify(value, replacer);
411
+ }
412
+ function safeParse(value) {
413
+ return JSON.parse(value, reviver);
414
+ }
415
+ function clone(value) {
416
+ return safeParse(safeStringify(value));
417
+ }
418
+
197
419
  let timeout;
198
420
  let numInBatch = 0;
199
421
  let isRunningBatch = false;
@@ -219,22 +441,28 @@ function isArraySubset(mainArr, subsetArr) {
219
441
  }
220
442
  function createPreviousHandlerInner(value, changes) {
221
443
  // Clones the current state and inject the previous data at the changed path
222
- let clone = value ? JSON.parse(JSON.stringify(value)) : {};
444
+ let cloned = value ? clone(value) : {};
223
445
  for (let i = 0; i < changes.length; i++) {
224
446
  const { path, prevAtPath } = changes[i];
225
- let o = clone;
447
+ let o = cloned;
226
448
  if (path.length > 0) {
227
449
  let i;
228
450
  for (i = 0; i < path.length - 1; i++) {
229
451
  o = o[path[i]];
230
452
  }
231
- o[path[i]] = prevAtPath;
453
+ const key = path[i];
454
+ if (o instanceof Map) {
455
+ o.set(key, prevAtPath);
456
+ }
457
+ else {
458
+ o[key] = prevAtPath;
459
+ }
232
460
  }
233
461
  else {
234
- clone = prevAtPath;
462
+ cloned = prevAtPath;
235
463
  }
236
464
  }
237
- return clone;
465
+ return cloned;
238
466
  }
239
467
  function createPreviousHandler(value, changes) {
240
468
  // Create a function that generates the previous state
@@ -304,7 +532,7 @@ function computeChangesRecursive(changesInBatch, node, value, path, pathTypes, v
304
532
  const parent = node.parent;
305
533
  if (parent) {
306
534
  const parentValue = getNodeValue(parent);
307
- computeChangesRecursive(changesInBatch, parent, parentValue, [node.key].concat(path), [(isArray(value) ? 'array' : 'object')].concat(pathTypes), valueAtPath, prevAtPath, immediate, level + 1, whenOptimizedOnlyIf);
535
+ computeChangesRecursive(changesInBatch, parent, parentValue, [node.key].concat(path), [getPathType(value)].concat(pathTypes), valueAtPath, prevAtPath, immediate, level + 1, whenOptimizedOnlyIf);
308
536
  }
309
537
  }
310
538
  }
@@ -1121,6 +1349,9 @@ function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRo
1121
1349
  childNode = node;
1122
1350
  // Make sure we don't call too many listeners for ever property set
1123
1351
  beginBatch();
1352
+ if (isPrim === undefined) {
1353
+ isPrim = isPrimitive(newValue);
1354
+ }
1124
1355
  let hasADiff = isPrim;
1125
1356
  let whenOptimizedOnlyIf = false;
1126
1357
  // If new value is an object or array update notify down the tree
@@ -1195,176 +1426,6 @@ function peek(node) {
1195
1426
  return value;
1196
1427
  }
1197
1428
 
1198
- function isObservable(obs) {
1199
- return obs && !!obs[symbolGetNode];
1200
- }
1201
- function isEvent(obs) {
1202
- var _a;
1203
- return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isEvent);
1204
- }
1205
- function computeSelector(selector, e, retainObservable) {
1206
- let c = selector;
1207
- if (isFunction(c)) {
1208
- c = e ? c(e) : c();
1209
- }
1210
- return isObservable(c) && !retainObservable ? c.get() : c;
1211
- }
1212
- function getObservableIndex(obs) {
1213
- const node = getNode(obs);
1214
- const n = +node.key;
1215
- return n - n < 1 ? +n : -1;
1216
- }
1217
- function opaqueObject(value) {
1218
- if (value) {
1219
- value[symbolOpaque] = true;
1220
- }
1221
- return value;
1222
- }
1223
- function lockObservable(obs, value) {
1224
- var _a;
1225
- const root = (_a = getNode(obs)) === null || _a === void 0 ? void 0 : _a.root;
1226
- if (root) {
1227
- root.locked = value;
1228
- }
1229
- }
1230
- function setAtPath(obj, path, pathTypes, value, fullObj, restore) {
1231
- let o = obj;
1232
- let oFull = fullObj;
1233
- if (path.length > 0) {
1234
- for (let i = 0; i < path.length; i++) {
1235
- const p = path[i];
1236
- if (i === path.length - 1) {
1237
- // Don't set if the value is the same. This prevents creating a new key
1238
- // when setting undefined on an object without this key
1239
- if (o[p] !== value) {
1240
- o[p] = value;
1241
- }
1242
- }
1243
- else if (o[p] === symbolDelete) {
1244
- // If this was previously deleted, restore it
1245
- if (oFull) {
1246
- o[p] = oFull[p];
1247
- restore === null || restore === void 0 ? void 0 : restore(path.slice(0, i + 1), o[p]);
1248
- }
1249
- break;
1250
- }
1251
- else if (o[p] === undefined || o[p] === null) {
1252
- o[p] = pathTypes[i] === 'array' ? [] : {};
1253
- }
1254
- o = o[p];
1255
- if (oFull) {
1256
- oFull = oFull[p];
1257
- }
1258
- }
1259
- }
1260
- else {
1261
- obj = value;
1262
- }
1263
- return obj;
1264
- }
1265
- function setInObservableAtPath(obs, path, pathTypes, value, mode) {
1266
- let o = obs;
1267
- let v = value;
1268
- for (let i = 0; i < path.length; i++) {
1269
- const p = path[i];
1270
- if (!o.peek()[p] && pathTypes[i] === 'array') {
1271
- o[p].set([]);
1272
- }
1273
- o = o[p];
1274
- v = v[p];
1275
- }
1276
- if (v === symbolDelete) {
1277
- o.delete();
1278
- }
1279
- // Assign if possible, or set otherwise
1280
- else if (mode === 'assign' && o.assign && isObject(o.peek())) {
1281
- o.assign(v);
1282
- }
1283
- else {
1284
- o.set(v);
1285
- }
1286
- }
1287
- function mergeIntoObservable(target, ...sources) {
1288
- beginBatch();
1289
- globalState.isMerging = true;
1290
- for (let i = 0; i < sources.length; i++) {
1291
- target = _mergeIntoObservable(target, sources[i]);
1292
- }
1293
- globalState.isMerging = false;
1294
- endBatch();
1295
- return target;
1296
- }
1297
- function _mergeIntoObservable(target, source) {
1298
- var _a;
1299
- const needsSet = isObservable(target);
1300
- const targetValue = needsSet ? target.peek() : target;
1301
- const isTargetArr = isArray(targetValue);
1302
- const isTargetObj = !isTargetArr && isObject(targetValue);
1303
- if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) ||
1304
- (isTargetArr && isArray(source) && targetValue.length > 0)) {
1305
- const keys = Object.keys(source);
1306
- for (let i = 0; i < keys.length; i++) {
1307
- const key = keys[i];
1308
- const sourceValue = source[key];
1309
- if (sourceValue === symbolDelete) {
1310
- needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete) ? target[key].delete() : delete target[key];
1311
- }
1312
- else {
1313
- const isObj = isObject(sourceValue);
1314
- const isArr = !isObj && isArray(sourceValue);
1315
- const targetChild = target[key];
1316
- if ((isObj || isArr) && targetChild && (needsSet || !isEmpty(targetChild))) {
1317
- if (!needsSet && (!targetChild || (isObj ? !isObject(targetChild) : !isArray(targetChild)))) {
1318
- target[key] = sourceValue;
1319
- }
1320
- else {
1321
- _mergeIntoObservable(targetChild, sourceValue);
1322
- }
1323
- }
1324
- else {
1325
- needsSet
1326
- ? targetChild.set(sourceValue)
1327
- : (target[key] = sourceValue);
1328
- }
1329
- }
1330
- }
1331
- }
1332
- else if (source !== undefined) {
1333
- needsSet ? target.set(source) : (target = source);
1334
- }
1335
- return target;
1336
- }
1337
- function constructObjectWithPath(path, pathTypes, value) {
1338
- let out;
1339
- if (path.length > 0) {
1340
- let o = (out = {});
1341
- for (let i = 0; i < path.length; i++) {
1342
- const p = path[i];
1343
- o[p] = i === path.length - 1 ? value : pathTypes[i] === 'array' ? [] : {};
1344
- o = o[p];
1345
- }
1346
- }
1347
- else {
1348
- out = value;
1349
- }
1350
- return out;
1351
- }
1352
- function deconstructObjectWithPath(path, pathTypes, value) {
1353
- let o = value;
1354
- for (let i = 0; i < path.length; i++) {
1355
- const p = path[i];
1356
- o = o ? o[p] : pathTypes[i] === 'array' ? [] : {};
1357
- }
1358
- return o;
1359
- }
1360
- function isObservableValueReady(value) {
1361
- return !!value && ((!isObject(value) && !isArray(value)) || !isEmpty(value));
1362
- }
1363
- function setSilently(obs, newValue) {
1364
- const node = getNode(obs);
1365
- return setNodeValue(node, newValue).newValue;
1366
- }
1367
-
1368
1429
  const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
1369
1430
  function ObservablePrimitiveClass(node) {
1370
1431
  this._node = node;
@@ -1740,15 +1801,20 @@ function whenReady(predicate, effect) {
1740
1801
  }
1741
1802
 
1742
1803
  const internal = {
1804
+ clone,
1743
1805
  ensureNodeValue,
1744
1806
  findIDKey,
1745
1807
  get,
1746
1808
  getNode,
1809
+ getPathType,
1747
1810
  getProxy,
1748
1811
  globalState,
1812
+ initializePathType,
1749
1813
  observableFns,
1750
1814
  optimized,
1751
1815
  peek,
1816
+ safeParse,
1817
+ safeStringify,
1752
1818
  set,
1753
1819
  setAtPath,
1754
1820
  setNodeValue,