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