@legendapp/state 2.0.0-next.2 → 2.0.0-next.4

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/index.mjs CHANGED
@@ -161,7 +161,7 @@ function setNodeValue(node, newValue) {
161
161
  if (parentNode.root.locked && parentNode.root.set) {
162
162
  parentNode.root.set(parentNode.root._);
163
163
  }
164
- return { prevValue, newValue };
164
+ return { prevValue, newValue, parentValue };
165
165
  }
166
166
  const arrNodeKeys = [];
167
167
  function getNodeValue(node) {
@@ -571,53 +571,50 @@ function setInObservableAtPath(obs, path, value, mode) {
571
571
  function mergeIntoObservable(target, ...sources) {
572
572
  beginBatch();
573
573
  globalState.isMerging = true;
574
- const value = _mergeIntoObservable(target, ...sources);
574
+ for (let i = 0; i < sources.length; i++) {
575
+ target = _mergeIntoObservable(target, sources[i]);
576
+ }
575
577
  globalState.isMerging = false;
576
578
  endBatch();
577
- return value;
579
+ return target;
578
580
  }
579
- function _mergeIntoObservable(target, ...sources) {
581
+ function _mergeIntoObservable(target, source) {
580
582
  var _a;
581
- if (!sources.length)
582
- return target;
583
- for (let u = 0; u < sources.length; u++) {
584
- const source = sources[u];
585
- const needsSet = isObservable(target);
586
- const targetValue = needsSet ? target.peek() : target;
587
- const isTargetArr = isArray(targetValue);
588
- const isTargetObj = !isTargetArr && isObject(targetValue);
589
- if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) ||
590
- (isTargetArr && isArray(source) && targetValue.length > 0)) {
591
- for (const key in source) {
592
- const sourceValue = source[key];
593
- if (sourceValue === symbolDelete) {
594
- needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete)
595
- ? target[key].delete()
596
- : delete target[key];
597
- }
598
- else {
599
- const isObj = isObject(sourceValue);
600
- const isArr = !isObj && isArray(sourceValue);
601
- const targetChild = target[key];
602
- if ((isObj || isArr) && targetChild && (needsSet || !isEmpty(targetChild))) {
603
- if (!needsSet && (!targetChild || (isObj ? !isObject(targetChild) : !isArray(targetChild)))) {
604
- target[key] = sourceValue;
605
- }
606
- else {
607
- _mergeIntoObservable(targetChild, sourceValue);
608
- }
583
+ const needsSet = isObservable(target);
584
+ const targetValue = needsSet ? target.peek() : target;
585
+ const isTargetArr = isArray(targetValue);
586
+ const isTargetObj = !isTargetArr && isObject(targetValue);
587
+ if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) ||
588
+ (isTargetArr && isArray(source) && targetValue.length > 0)) {
589
+ const keys = Object.keys(source);
590
+ for (let i = 0; i < keys.length; i++) {
591
+ const key = keys[i];
592
+ const sourceValue = source[key];
593
+ if (sourceValue === symbolDelete) {
594
+ needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete) ? target[key].delete() : delete target[key];
595
+ }
596
+ else {
597
+ const isObj = isObject(sourceValue);
598
+ const isArr = !isObj && isArray(sourceValue);
599
+ const targetChild = target[key];
600
+ if ((isObj || isArr) && targetChild && (needsSet || !isEmpty(targetChild))) {
601
+ if (!needsSet && (!targetChild || (isObj ? !isObject(targetChild) : !isArray(targetChild)))) {
602
+ target[key] = sourceValue;
609
603
  }
610
604
  else {
611
- needsSet
612
- ? targetChild.set(sourceValue)
613
- : (target[key] = sourceValue);
605
+ _mergeIntoObservable(targetChild, sourceValue);
614
606
  }
615
607
  }
608
+ else {
609
+ needsSet
610
+ ? targetChild.set(sourceValue)
611
+ : (target[key] = sourceValue);
612
+ }
616
613
  }
617
614
  }
618
- else if (source !== undefined) {
619
- needsSet ? target.set(source) : (target = source);
620
- }
615
+ }
616
+ else if (source !== undefined) {
617
+ needsSet ? target.set(source) : (target = source);
621
618
  }
622
619
  return target;
623
620
  }
@@ -680,11 +677,6 @@ function onChange(node, callback, options = {}) {
680
677
  noArgs,
681
678
  };
682
679
  listeners.add(listener);
683
- let parent = node.parent;
684
- while (parent && !parent.descendantHasListener) {
685
- parent.descendantHasListener = true;
686
- parent = parent.parent;
687
- }
688
680
  if (initial) {
689
681
  const value = getNodeValue(node);
690
682
  callback({
@@ -913,75 +905,74 @@ function updateNodes(parent, obj, prevValue) {
913
905
  hasADiff = hasADiff || (keys === null || keys === void 0 ? void 0 : keys.length) !== (keysPrev === null || keysPrev === void 0 ? void 0 : keysPrev.length);
914
906
  const isArrDiff = hasADiff;
915
907
  let didMove = false;
916
- if (parent.descendantHasListener || !hasADiff) {
917
- for (let i = 0; i < length; i++) {
918
- const key = keys[i];
919
- const value = isMap ? obj.get(key) : obj[key];
920
- const prev = isMap ? prevValue === null || prevValue === void 0 ? void 0 : prevValue.get(key) : prevValue === null || prevValue === void 0 ? void 0 : prevValue[key];
921
- let isDiff = value !== prev;
922
- if (isDiff) {
923
- const id = idField && value
924
- ? isIdFieldFunction
925
- ? idField(value)
926
- : value[idField]
927
- : undefined;
928
- let child = getChildNode(parent, key);
929
- // Detect moves within an array. Need to move the original proxy to the new position to keep
930
- // the proxy stable, so that listeners to this node will be unaffected by the array shift.
931
- if (isArr && id !== undefined) {
932
- // Find the previous position of this element in the array
933
- const prevChild = id !== undefined ? prevChildrenById === null || prevChildrenById === void 0 ? void 0 : prevChildrenById.get(id) : undefined;
934
- if (!prevChild) {
935
- // This id was not in the array before so it does not need to notify children
936
- isDiff = false;
937
- hasADiff = true;
938
- }
939
- else if (prevChild !== undefined && prevChild.key !== key) {
940
- const valuePrevChild = prevValue[prevChild.key];
941
- // If array length changed then move the original node to the current position.
942
- // That should be faster than notifying every single element that
943
- // it's in a new position.
944
- if (isArrDiff) {
945
- child = prevChild;
946
- parent.children.delete(child.key);
947
- child.key = key;
948
- moved.push([key, child]);
949
- }
950
- didMove = true;
951
- // And check for diff against the previous value in the previous position
952
- isDiff = valuePrevChild !== value;
953
- }
908
+ for (let i = 0; i < length; i++) {
909
+ const key = keys[i];
910
+ const value = isMap ? obj.get(key) : obj[key];
911
+ const prev = isMap ? prevValue === null || prevValue === void 0 ? void 0 : prevValue.get(key) : prevValue === null || prevValue === void 0 ? void 0 : prevValue[key];
912
+ let isDiff = value !== prev;
913
+ if (isDiff) {
914
+ extractFunctionOrComputed(parent, obj, key, value);
915
+ const id = idField && value
916
+ ? isIdFieldFunction
917
+ ? idField(value)
918
+ : value[idField]
919
+ : undefined;
920
+ let child = getChildNode(parent, key);
921
+ // Detect moves within an array. Need to move the original proxy to the new position to keep
922
+ // the proxy stable, so that listeners to this node will be unaffected by the array shift.
923
+ if (isArr && id !== undefined) {
924
+ // Find the previous position of this element in the array
925
+ const prevChild = id !== undefined ? prevChildrenById === null || prevChildrenById === void 0 ? void 0 : prevChildrenById.get(id) : undefined;
926
+ if (!prevChild) {
927
+ // This id was not in the array before so it does not need to notify children
928
+ isDiff = false;
929
+ hasADiff = true;
954
930
  }
955
- if (isDiff) {
956
- // Array has a new / modified element
957
- // If object iterate through its children
958
- if (isPrimitive(value)) {
959
- hasADiff = true;
960
- }
961
- else {
962
- // Always need to updateNodes so we notify through all children
963
- const updatedNodes = (!hasADiff || !!child.descendantHasListener) && updateNodes(child, value, prev);
964
- hasADiff = hasADiff || updatedNodes;
931
+ else if (prevChild !== undefined && prevChild.key !== key) {
932
+ const valuePrevChild = prevValue[prevChild.key];
933
+ // If array length changed then move the original node to the current position.
934
+ // That should be faster than notifying every single element that
935
+ // it's in a new position.
936
+ if (isArrDiff) {
937
+ child = prevChild;
938
+ parent.children.delete(child.key);
939
+ child.key = key;
940
+ moved.push([key, child]);
965
941
  }
942
+ didMove = true;
943
+ // And check for diff against the previous value in the previous position
944
+ isDiff = valuePrevChild !== value;
966
945
  }
967
- if (isDiff || !isArrDiff) {
968
- // Notify for this child if this element is different and it has listeners
969
- // Or if the position changed in an array whose length did not change
970
- // But do not notify child if the parent is an array with changing length -
971
- // the array's listener will cover it
972
- if (child.listeners || child.listenersImmediate) {
973
- notify(child, value, prev, 0, !isArrDiff);
974
- }
946
+ }
947
+ if (isDiff) {
948
+ // Array has a new / modified element
949
+ // If object iterate through its children
950
+ if (isPrimitive(value)) {
951
+ hasADiff = true;
952
+ }
953
+ else {
954
+ // Always need to updateNodes so we notify through all children
955
+ const updatedNodes = updateNodes(child, value, prev);
956
+ hasADiff = hasADiff || updatedNodes;
975
957
  }
976
958
  }
977
- }
978
- if (moved) {
979
- for (let i = 0; i < moved.length; i++) {
980
- const [key, child] = moved[i];
981
- parent.children.set(key, child);
959
+ if (isDiff || !isArrDiff) {
960
+ // Notify for this child if this element is different and it has listeners
961
+ // Or if the position changed in an array whose length did not change
962
+ // But do not notify child if the parent is an array with changing length -
963
+ // the array's listener will cover it
964
+ if (child.listeners || child.listenersImmediate) {
965
+ notify(child, value, prev, 0, !isArrDiff);
966
+ }
982
967
  }
983
968
  }
984
969
  }
970
+ if (moved) {
971
+ for (let i = 0; i < moved.length; i++) {
972
+ const [key, child] = moved[i];
973
+ parent.children.set(key, child);
974
+ }
975
+ }
985
976
  // The full array does not need to re-render if the length is the same
986
977
  // So don't notify shallow listeners
987
978
  retValue = hasADiff || didMove;
@@ -1194,10 +1185,7 @@ const proxyHandler = {
1194
1185
  },
1195
1186
  };
1196
1187
  function set(node, newValue) {
1197
- if (isPromise(newValue)) {
1198
- newValue.then((v) => set(node, v)).catch((error) => set(node, { error }));
1199
- }
1200
- else if (node.parent) {
1188
+ if (node.parent) {
1201
1189
  return setKey(node.parent, node.key, newValue);
1202
1190
  }
1203
1191
  else {
@@ -1237,12 +1225,13 @@ function setKey(node, key, newValue, level) {
1237
1225
  // Get the child node for updating and notifying
1238
1226
  const childNode = isRoot ? node : getChildNode(node, key);
1239
1227
  // Set the raw value on the parent object
1240
- const { newValue: savedValue, prevValue } = setNodeValue(childNode, newValue);
1241
- const isFunc = isFunction(newValue);
1228
+ const { newValue: savedValue, prevValue, parentValue } = setNodeValue(childNode, newValue);
1229
+ const isFunc = isFunction(savedValue);
1242
1230
  const isPrim = isPrimitive(savedValue) || savedValue instanceof Date;
1243
1231
  if (savedValue !== prevValue) {
1244
1232
  updateNodesAndNotify(node, savedValue, prevValue, childNode, isPrim, isRoot, level);
1245
1233
  }
1234
+ extractFunctionOrComputed(node, parentValue, key, newValue);
1246
1235
  return isFunc ? savedValue : isRoot ? getProxy(node) : getProxy(node, key);
1247
1236
  }
1248
1237
  function assign(node, value) {
@@ -1368,13 +1357,48 @@ function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRo
1368
1357
  }
1369
1358
  function extractPromise(node, value) {
1370
1359
  value.status = 'pending';
1371
- value.catch((error) => {
1372
- set(node, { error, status: 'rejected' });
1373
- });
1374
- value.then((value) => {
1360
+ value
1361
+ .then((value) => {
1375
1362
  set(node, value);
1363
+ })
1364
+ .catch((error) => {
1365
+ set(node, { error, status: 'rejected' });
1376
1366
  });
1377
1367
  }
1368
+ const __devExtractFunctionsAndComputedsNodes = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test' ? new Set() : undefined;
1369
+ function extractFunctionOrComputed(node, obj, k, v) {
1370
+ if (isPromise(v)) {
1371
+ extractPromise(getChildNode(node, k), v);
1372
+ }
1373
+ else if (typeof v === 'function') {
1374
+ extractFunction(node, k, v);
1375
+ }
1376
+ else if (typeof v == 'object' && v !== null && v !== undefined) {
1377
+ const childNode = getNode(v);
1378
+ if (childNode === null || childNode === void 0 ? void 0 : childNode.isComputed) {
1379
+ extractFunction(node, k, v, childNode);
1380
+ delete obj[k];
1381
+ }
1382
+ else {
1383
+ return true;
1384
+ }
1385
+ }
1386
+ }
1387
+ function extractFunctionsAndComputeds(node, obj) {
1388
+ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
1389
+ if (__devExtractFunctionsAndComputedsNodes.has(obj)) {
1390
+ console.error('[legend-state] Circular reference detected in object. You may want to use opaqueObject to stop traversing child nodes.', obj);
1391
+ return false;
1392
+ }
1393
+ __devExtractFunctionsAndComputedsNodes.add(obj);
1394
+ }
1395
+ for (const k in obj) {
1396
+ const v = obj[k];
1397
+ if (v && extractFunctionOrComputed(node, obj, k, v) && !v[symbolOpaque]) {
1398
+ extractFunctionsAndComputeds(getChildNode(node, k), v);
1399
+ }
1400
+ }
1401
+ }
1378
1402
 
1379
1403
  const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
1380
1404
  function ObservablePrimitiveClass(node) {
@@ -1417,35 +1441,6 @@ ObservablePrimitiveClass.prototype.delete = function () {
1417
1441
  return this;
1418
1442
  };
1419
1443
 
1420
- const __devExtractFunctionsAndComputedsNodes = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test' ? new Set() : undefined;
1421
- function extractFunctionsAndComputeds(node, obj) {
1422
- if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
1423
- if (__devExtractFunctionsAndComputedsNodes.has(obj)) {
1424
- console.error('[legend-state] Circular reference detected in object. You may want to use opaqueObject to stop traversing child nodes.', obj);
1425
- return false;
1426
- }
1427
- __devExtractFunctionsAndComputedsNodes.add(obj);
1428
- }
1429
- for (const k in obj) {
1430
- const v = obj[k];
1431
- if (isPromise(v)) {
1432
- extractPromise(getChildNode(node, k), v);
1433
- }
1434
- else if (typeof v === 'function') {
1435
- extractFunction(node, k, v);
1436
- }
1437
- else if (typeof v == 'object' && v !== null && v !== undefined) {
1438
- const childNode = getNode(v);
1439
- if (childNode === null || childNode === void 0 ? void 0 : childNode.isComputed) {
1440
- extractFunction(node, k, v, childNode);
1441
- delete obj[k];
1442
- }
1443
- else if (!v[symbolOpaque]) {
1444
- extractFunctionsAndComputeds(getChildNode(node, k), obj[k]);
1445
- }
1446
- }
1447
- }
1448
- }
1449
1444
  function createObservable(value, makePrimitive) {
1450
1445
  const valueIsPromise = isPromise(value);
1451
1446
  const root = {