@legendapp/state 2.1.0-next.1 → 2.1.0

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
@@ -60,17 +60,9 @@ const extraPrimitiveActivators = new Map();
60
60
  const extraPrimitiveProps = new Map();
61
61
  const globalState = {
62
62
  isLoadingLocal: false,
63
+ isLoadingRemote: false,
63
64
  isMerging: false,
64
- isLoadingRemote$: undefined,
65
- onChangeRemote: undefined,
66
65
  };
67
- function isObservable(obs) {
68
- return !!obs && !!obs[symbolGetNode];
69
- }
70
- function isComputed(obs) {
71
- var _a;
72
- return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isComputed);
73
- }
74
66
  function checkActivate(node) {
75
67
  var _a;
76
68
  const root = node.root;
@@ -97,13 +89,12 @@ function setNodeValue(node, newValue) {
97
89
  const prevValue = parentValue[key];
98
90
  const isFunc = isFunction(newValue);
99
91
  // Compute newValue if newValue is a function or an observable
100
- newValue = !parentNode.isAssigning && isFunc ? newValue(prevValue) : newValue;
101
- // If setting an observable, set a link to the observable instead
102
- if (isObservable(newValue) && !isComputed(newValue)) {
103
- const val = newValue;
104
- node.lazy = () => val;
105
- newValue = undefined;
106
- }
92
+ newValue =
93
+ !parentNode.isAssigning && isFunc
94
+ ? newValue(prevValue)
95
+ : isObject(newValue) && (newValue === null || newValue === void 0 ? void 0 : newValue[symbolGetNode])
96
+ ? newValue.peek()
97
+ : newValue;
107
98
  try {
108
99
  parentNode.isSetting = (parentNode.isSetting || 0) + 1;
109
100
  // Save the new value
@@ -137,13 +128,7 @@ function getNodeValue(node) {
137
128
  }
138
129
  return child;
139
130
  }
140
- const cloneFunction = (originalFunction) => {
141
- const length = originalFunction.length;
142
- return length > 1
143
- ? (arg1, arg2) => originalFunction(arg1, arg2)
144
- : (...args) => originalFunction(...args);
145
- };
146
- function getChildNode(node, key, asFunction) {
131
+ function getChildNode(node, key) {
147
132
  var _a;
148
133
  // Get the child by key
149
134
  let child = (_a = node.children) === null || _a === void 0 ? void 0 : _a.get(key);
@@ -155,12 +140,6 @@ function getChildNode(node, key, asFunction) {
155
140
  key,
156
141
  lazy: true,
157
142
  };
158
- if (asFunction) {
159
- child = Object.assign(cloneFunction(asFunction), child);
160
- }
161
- else if (node.proxyFn2) {
162
- child = Object.assign(node.proxyFn2.bind(node, key), child);
163
- }
164
143
  if (!node.children) {
165
144
  node.children = new Map();
166
145
  }
@@ -182,7 +161,6 @@ function ensureNodeValue(node) {
182
161
  return value;
183
162
  }
184
163
  function findIDKey(obj, node) {
185
- var _a, _b;
186
164
  let idKey = isObject(obj)
187
165
  ? 'id' in obj
188
166
  ? 'id'
@@ -195,8 +173,7 @@ function findIDKey(obj, node) {
195
173
  : undefined
196
174
  : undefined;
197
175
  if (!idKey && node.parent) {
198
- const k = node.key + '_keyExtractor';
199
- const keyExtractor = (_b = (_a = node.functions) === null || _a === void 0 ? void 0 : _a.get(k)) !== null && _b !== void 0 ? _b : getNodeValue(node.parent)[node.key + '_keyExtractor'];
176
+ const keyExtractor = getNodeValue(node.parent)[node.key + '_keyExtractor'];
200
177
  if (keyExtractor && isFunction(keyExtractor)) {
201
178
  idKey = keyExtractor;
202
179
  }
@@ -452,19 +429,15 @@ function endBatch(force) {
452
429
  }
453
430
  }
454
431
 
455
- function createObservable(value, makePrimitive, extractPromise, createObject, createPrimitive) {
432
+ function createObservable(value, makePrimitive, createObject, createPrimitive) {
456
433
  const valueIsPromise = isPromise(value);
457
- const valueIsFunction = isFunction(value);
458
434
  const root = {
459
435
  _: value,
460
436
  };
461
- let node = {
437
+ const node = {
462
438
  root,
463
439
  lazy: true,
464
440
  };
465
- if (valueIsFunction) {
466
- node = Object.assign(cloneFunction(value), node);
467
- }
468
441
  const prim = makePrimitive || isActualPrimitive(value);
469
442
  const obs = prim
470
443
  ? new createPrimitive(node)
@@ -475,176 +448,6 @@ function createObservable(value, makePrimitive, extractPromise, createObject, cr
475
448
  return obs;
476
449
  }
477
450
 
478
- function isEvent(obs) {
479
- var _a;
480
- return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isEvent);
481
- }
482
- function computeSelector(selector, e, retainObservable) {
483
- let c = selector;
484
- if (isFunction(c)) {
485
- c = e ? c(e) : c();
486
- }
487
- return isObservable(c) && !retainObservable ? c.get() : c;
488
- }
489
- function getObservableIndex(obs) {
490
- const node = getNode(obs);
491
- const n = +node.key;
492
- return n - n < 1 ? +n : -1;
493
- }
494
- function opaqueObject(value) {
495
- if (value) {
496
- value[symbolOpaque] = true;
497
- }
498
- return value;
499
- }
500
- function lockObservable(obs, value) {
501
- var _a;
502
- const root = (_a = getNode(obs)) === null || _a === void 0 ? void 0 : _a.root;
503
- if (root) {
504
- root.locked = value;
505
- }
506
- }
507
- function setAtPath(obj, path, pathTypes, value, fullObj, restore) {
508
- let o = obj;
509
- let oFull = fullObj;
510
- if (path.length > 0) {
511
- for (let i = 0; i < path.length; i++) {
512
- const p = path[i];
513
- if (i === path.length - 1) {
514
- // Don't set if the value is the same. This prevents creating a new key
515
- // when setting undefined on an object without this key
516
- if (o[p] !== value) {
517
- o[p] = value;
518
- }
519
- }
520
- else if (o[p] === symbolDelete) {
521
- // If this was previously deleted, restore it
522
- if (oFull) {
523
- o[p] = oFull[p];
524
- restore === null || restore === void 0 ? void 0 : restore(path.slice(0, i + 1), o[p]);
525
- }
526
- break;
527
- }
528
- else if (o[p] === undefined || o[p] === null) {
529
- o[p] = pathTypes[i] === 'array' ? [] : {};
530
- }
531
- o = o[p];
532
- if (oFull) {
533
- oFull = oFull[p];
534
- }
535
- }
536
- }
537
- else {
538
- obj = value;
539
- }
540
- return obj;
541
- }
542
- function setInObservableAtPath(obs, path, pathTypes, value, mode) {
543
- let o = obs;
544
- let v = value;
545
- for (let i = 0; i < path.length; i++) {
546
- const p = path[i];
547
- if (!o.peek()[p] && pathTypes[i] === 'array') {
548
- o[p].set([]);
549
- }
550
- o = o[p];
551
- v = v[p];
552
- }
553
- if (v === symbolDelete) {
554
- o.delete();
555
- }
556
- // Assign if possible, or set otherwise
557
- else if (mode === 'assign' && o.assign && isObject(o.peek())) {
558
- o.assign(v);
559
- }
560
- else {
561
- o.set(v);
562
- }
563
- }
564
- function mergeIntoObservable(target, ...sources) {
565
- beginBatch();
566
- globalState.isMerging = true;
567
- for (let i = 0; i < sources.length; i++) {
568
- target = _mergeIntoObservable(target, sources[i]);
569
- }
570
- globalState.isMerging = false;
571
- endBatch();
572
- return target;
573
- }
574
- function _mergeIntoObservable(target, source) {
575
- var _a;
576
- if (isObservable(source)) {
577
- source = source.peek();
578
- }
579
- const needsSet = isObservable(target);
580
- const targetValue = needsSet ? target.peek() : target;
581
- const isTargetArr = isArray(targetValue);
582
- const isTargetObj = !isTargetArr && isObject(targetValue);
583
- if ((isTargetObj && isObject(source) && !isEmpty(targetValue)) ||
584
- (isTargetArr && isArray(source) && targetValue.length > 0)) {
585
- const keys = Object.keys(source);
586
- for (let i = 0; i < keys.length; i++) {
587
- const key = keys[i];
588
- const sourceValue = source[key];
589
- if (sourceValue === symbolDelete) {
590
- needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete) ? target[key].delete() : delete target[key];
591
- }
592
- else {
593
- const isObj = isObject(sourceValue);
594
- const isArr = !isObj && isArray(sourceValue);
595
- const targetChild = target[key];
596
- if ((isObj || isArr) && targetChild && (needsSet || !isEmpty(targetChild))) {
597
- if (!needsSet && (!targetChild || (isObj ? !isObject(targetChild) : !isArray(targetChild)))) {
598
- target[key] = sourceValue;
599
- }
600
- else {
601
- _mergeIntoObservable(targetChild, sourceValue);
602
- }
603
- }
604
- else {
605
- needsSet
606
- ? targetChild.set(sourceValue)
607
- : (target[key] = sourceValue);
608
- }
609
- }
610
- }
611
- }
612
- else if (source !== undefined) {
613
- needsSet ? target.set(source) : (target = source);
614
- }
615
- return target;
616
- }
617
- function constructObjectWithPath(path, pathTypes, value) {
618
- let out;
619
- if (path.length > 0) {
620
- let o = (out = {});
621
- for (let i = 0; i < path.length; i++) {
622
- const p = path[i];
623
- o[p] = i === path.length - 1 ? value : pathTypes[i] === 'array' ? [] : {};
624
- o = o[p];
625
- }
626
- }
627
- else {
628
- out = value;
629
- }
630
- return out;
631
- }
632
- function deconstructObjectWithPath(path, pathTypes, value) {
633
- let o = value;
634
- for (let i = 0; i < path.length; i++) {
635
- const p = path[i];
636
- o = o ? o[p] : pathTypes[i] === 'array' ? [] : {};
637
- }
638
- return o;
639
- }
640
- function isObservableValueReady(value) {
641
- return !!value && ((!isObject(value) && !isArray(value)) || !isEmpty(value));
642
- }
643
- function setSilently(obs, newValue) {
644
- const node = getNode(obs);
645
- return setNodeValue(node, newValue).newValue;
646
- }
647
-
648
451
  function onChange(node, callback, options = {}) {
649
452
  const { initial, immediate, noArgs } = options;
650
453
  const { trackingType } = options;
@@ -683,23 +486,6 @@ function onChange(node, callback, options = {}) {
683
486
  return () => listeners.delete(listener);
684
487
  }
685
488
 
686
- function setupTracking(nodes, update, noArgs, immediate) {
687
- let listeners = [];
688
- // Listen to tracked nodes
689
- nodes === null || nodes === void 0 ? void 0 : nodes.forEach((tracked) => {
690
- const { node, track } = tracked;
691
- listeners.push(onChange(node, update, { trackingType: track, immediate, noArgs }));
692
- });
693
- return () => {
694
- if (listeners) {
695
- for (let i = 0; i < listeners.length; i++) {
696
- listeners[i]();
697
- }
698
- listeners = undefined;
699
- }
700
- };
701
- }
702
-
703
489
  let trackCount = 0;
704
490
  const trackingQueue = [];
705
491
  const tracking = {
@@ -739,148 +525,56 @@ function updateTracking(node, track) {
739
525
  }
740
526
  }
741
527
 
742
- function trackSelector(selector, update, observeEvent, observeOptions, createResubscribe) {
528
+ const ArrayModifiers = new Set([
529
+ 'copyWithin',
530
+ 'fill',
531
+ 'from',
532
+ 'pop',
533
+ 'push',
534
+ 'reverse',
535
+ 'shift',
536
+ 'sort',
537
+ 'splice',
538
+ 'unshift',
539
+ ]);
540
+ const ArrayLoopers = new Set([
541
+ 'every',
542
+ 'filter',
543
+ 'find',
544
+ 'findIndex',
545
+ 'forEach',
546
+ 'includes',
547
+ 'join',
548
+ 'map',
549
+ 'some',
550
+ ]);
551
+ const ArrayLoopersReturn = new Set(['filter', 'find']);
552
+ const observableProperties = new Map();
553
+ const observableFns = new Map([
554
+ ['get', get],
555
+ ['set', set],
556
+ ['peek', peek],
557
+ ['onChange', onChange],
558
+ ['assign', assign],
559
+ ['delete', deleteFn],
560
+ ['toggle', toggle],
561
+ ]);
562
+ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
563
+ // eslint-disable-next-line no-var
564
+ var __devUpdateNodes = new Set();
565
+ }
566
+ function collectionSetter(node, target, prop, ...args) {
743
567
  var _a;
744
- let nodes;
745
- let value;
746
- let dispose;
747
- let tracker;
748
- let resubscribe;
749
- let updateFn = update;
750
- if (isObservable(selector)) {
751
- value = selector.peek();
752
- dispose = selector.onChange(update);
753
- resubscribe = createResubscribe ? selector.onChange(update) : undefined;
754
- }
755
- else {
756
- // Compute the selector inside a tracking context
757
- beginTracking();
758
- value = selector ? computeSelector(selector, observeEvent, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.fromComputed) : selector;
759
- tracker = tracking.current;
760
- nodes = tracker.nodes;
761
- endTracking();
762
- if ((process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') && tracker && nodes) {
763
- (_a = tracker.traceListeners) === null || _a === void 0 ? void 0 : _a.call(tracker, nodes);
764
- if (tracker.traceUpdates) {
765
- updateFn = tracker.traceUpdates(update);
766
- }
767
- // Clear tracing so it doesn't leak to other components
768
- tracker.traceListeners = undefined;
769
- tracker.traceUpdates = undefined;
770
- }
771
- }
772
- if (!(observeEvent === null || observeEvent === void 0 ? void 0 : observeEvent.cancel)) {
773
- // Do tracing if it was requested
774
- // useSyncExternalStore doesn't subscribe until after the component mount.
775
- // We want to subscribe immediately so we don't miss any updates
776
- dispose = setupTracking(nodes, updateFn, false, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.immediate);
777
- resubscribe = createResubscribe ? () => setupTracking(nodes, updateFn) : undefined;
778
- }
779
- return { value, dispose, resubscribe };
780
- }
781
-
782
- function observe(selectorOrRun, reactionOrOptions, options) {
783
- let reaction;
784
- if (isFunction(reactionOrOptions)) {
785
- reaction = reactionOrOptions;
786
- }
787
- else {
788
- options = reactionOrOptions;
789
- }
790
- let dispose;
791
- const e = { num: 0 };
792
- // Wrap it in a function so it doesn't pass all the arguments to run()
793
- const update = function () {
794
- if (e.onCleanup) {
795
- e.onCleanup();
796
- e.onCleanup = undefined;
797
- }
798
- // Run in a batch so changes don't happen until we're done tracking here
799
- beginBatch();
800
- // Run the function/selector
801
- delete e.value;
802
- // Dispose listeners from previous run
803
- dispose === null || dispose === void 0 ? void 0 : dispose();
804
- const { dispose: _dispose, value } = trackSelector(selectorOrRun, update, e, options);
805
- dispose = _dispose;
806
- e.value = value;
807
- if (e.onCleanupReaction) {
808
- e.onCleanupReaction();
809
- e.onCleanupReaction = undefined;
810
- }
811
- endBatch();
812
- // Call the reaction if there is one and the value changed
813
- if (reaction &&
814
- ((options === null || options === void 0 ? void 0 : options.fromComputed) || ((e.num > 0 || !isEvent(selectorOrRun)) && e.previous !== e.value))) {
815
- reaction(e);
816
- }
817
- // Update the previous value
818
- e.previous = e.value;
819
- // Increment the counter
820
- e.num++;
821
- };
822
- update();
823
- // Return function calling dispose because dispose may be changed in update()
824
- return () => {
825
- var _a, _b;
826
- (_a = e.onCleanup) === null || _a === void 0 ? void 0 : _a.call(e);
827
- e.onCleanup = undefined;
828
- (_b = e.onCleanupReaction) === null || _b === void 0 ? void 0 : _b.call(e);
829
- e.onCleanupReaction = undefined;
830
- dispose === null || dispose === void 0 ? void 0 : dispose();
831
- };
832
- }
833
-
834
- const ArrayModifiers = new Set([
835
- 'copyWithin',
836
- 'fill',
837
- 'from',
838
- 'pop',
839
- 'push',
840
- 'reverse',
841
- 'shift',
842
- 'sort',
843
- 'splice',
844
- 'unshift',
845
- ]);
846
- const ArrayLoopers = new Set([
847
- 'every',
848
- 'filter',
849
- 'find',
850
- 'findIndex',
851
- 'forEach',
852
- 'includes',
853
- 'join',
854
- 'map',
855
- 'some',
856
- ]);
857
- const ArrayLoopersReturn = new Set(['filter', 'find']);
858
- const observableProperties = new Map();
859
- const observableFns = new Map([
860
- ['get', get],
861
- ['set', set],
862
- ['peek', peek],
863
- ['onChange', onChange],
864
- ['assign', assign],
865
- ['delete', deleteFn],
866
- ['toggle', toggle],
867
- ]);
868
- if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
869
- // eslint-disable-next-line no-var
870
- var __devUpdateNodes = new Set();
871
- }
872
- function collectionSetter(node, target, prop, ...args) {
873
- var _a;
874
- const prevValue = (isArray(target) && target.slice()) || target;
875
- const ret = target[prop].apply(target, args);
876
- if (node) {
877
- const hasParent = isChildNodeValue(node);
878
- const key = hasParent ? node.key : '_';
879
- const parentValue = hasParent ? getNodeValue(node.parent) : node.root;
880
- // Set the object to the previous value first
881
- parentValue[key] = prevValue;
882
- // Then set with the new value so it notifies with the correct prevValue
883
- setKey((_a = node.parent) !== null && _a !== void 0 ? _a : node, key, target);
568
+ const prevValue = (isArray(target) && target.slice()) || target;
569
+ const ret = target[prop].apply(target, args);
570
+ if (node) {
571
+ const hasParent = isChildNodeValue(node);
572
+ const key = hasParent ? node.key : '_';
573
+ const parentValue = hasParent ? getNodeValue(node.parent) : node.root;
574
+ // Set the object to the previous value first
575
+ parentValue[key] = prevValue;
576
+ // Then set with the new value so it notifies with the correct prevValue
577
+ setKey((_a = node.parent) !== null && _a !== void 0 ? _a : node, key, target);
884
578
  }
885
579
  // Return the original value
886
580
  return ret;
@@ -1069,10 +763,10 @@ function updateNodes(parent, obj, prevValue) {
1069
763
  }
1070
764
  return retValue !== null && retValue !== void 0 ? retValue : false;
1071
765
  }
1072
- function getProxy(node, p, asFunction) {
766
+ function getProxy(node, p) {
1073
767
  // Get the child node if p prop
1074
768
  if (p !== undefined)
1075
- node = getChildNode(node, p, asFunction);
769
+ node = getChildNode(node, p);
1076
770
  // Create a proxy if not already cached and return it
1077
771
  return (node.proxy || (node.proxy = new Proxy(node, proxyHandler)));
1078
772
  }
@@ -1150,15 +844,6 @@ const proxyHandler = {
1150
844
  if (isObject(value) && value[symbolOpaque]) {
1151
845
  return vProp;
1152
846
  }
1153
- const fnOrComputed = (_a = node.functions) === null || _a === void 0 ? void 0 : _a.get(p);
1154
- if (fnOrComputed) {
1155
- if (isObservable(fnOrComputed)) {
1156
- return fnOrComputed;
1157
- }
1158
- else {
1159
- return getProxy(node, p, fnOrComputed);
1160
- }
1161
- }
1162
847
  // Handle function calls
1163
848
  if (isFunction(vProp)) {
1164
849
  if (isArray(value)) {
@@ -1205,9 +890,15 @@ const proxyHandler = {
1205
890
  // Update that this primitive node was accessed for observers
1206
891
  if (isArray(value) && p === 'length') {
1207
892
  updateTracking(node, true);
893
+ // } else if (!isPrimitive(value)) {
894
+ // updateTracking(getChildNode(node, p));
1208
895
  return vProp;
1209
896
  }
1210
897
  }
898
+ const fnOrComputed = (_a = node.functions) === null || _a === void 0 ? void 0 : _a.get(p);
899
+ if (fnOrComputed) {
900
+ return fnOrComputed;
901
+ }
1211
902
  // TODOV3: Remove "state"
1212
903
  if (vProp === undefined && (p === 'state' || p === '_state') && node.state) {
1213
904
  return node.state;
@@ -1274,10 +965,6 @@ const proxyHandler = {
1274
965
  const value = getNodeValue(node);
1275
966
  return Reflect.has(value, prop);
1276
967
  },
1277
- apply(target, thisArg, argArray) {
1278
- // If it's a function call it as a function
1279
- return Reflect.apply(target, thisArg, argArray);
1280
- },
1281
968
  };
1282
969
  function set(node, newValue) {
1283
970
  if (node.parent) {
@@ -1318,7 +1005,7 @@ function setKey(node, key, newValue, level) {
1318
1005
  }
1319
1006
  const isRoot = !node.parent && key === '_';
1320
1007
  // Get the child node for updating and notifying
1321
- const childNode = isRoot ? node : getChildNode(node, key, isFunction(newValue) ? newValue : undefined);
1008
+ const childNode = isRoot ? node : getChildNode(node, key);
1322
1009
  // Set the raw value on the parent object
1323
1010
  const { newValue: savedValue, prevValue, parentValue } = setNodeValue(childNode, newValue);
1324
1011
  const isFunc = isFunction(savedValue);
@@ -1457,7 +1144,7 @@ function extractPromise(node, value) {
1457
1144
  if (!node.state) {
1458
1145
  node.state = createObservable({
1459
1146
  isLoaded: false,
1460
- }, false, extractPromise, getProxy);
1147
+ }, false, getProxy);
1461
1148
  }
1462
1149
  value
1463
1150
  .then((value) => {
@@ -1474,7 +1161,6 @@ function extractFunctionOrComputed(node, obj, k, v) {
1474
1161
  }
1475
1162
  else if (typeof v === 'function') {
1476
1163
  extractFunction(node, k, v);
1477
- delete obj[k];
1478
1164
  }
1479
1165
  else if (typeof v == 'object' && v !== null && v !== undefined) {
1480
1166
  const childNode = getNode(v);
@@ -1497,137 +1183,202 @@ function peek(node) {
1497
1183
  const value = getNodeValue(node);
1498
1184
  // If node is not yet lazily computed go do that
1499
1185
  if (node.lazy) {
1500
- if (isFunction(node) || isFunction(node.lazy)) {
1501
- activateNodeFunction(node);
1502
- }
1503
- else {
1504
- for (const key in value) {
1505
- if (hasOwnProperty.call(value, key)) {
1506
- extractFunctionOrComputed(node, value, key, value[key]);
1507
- }
1186
+ delete node.lazy;
1187
+ for (const key in value) {
1188
+ if (hasOwnProperty.call(value, key)) {
1189
+ extractFunctionOrComputed(node, value, key, value[key]);
1508
1190
  }
1509
1191
  }
1510
- delete node.lazy;
1511
1192
  }
1512
1193
  // Check if computed needs to activate
1513
1194
  checkActivate(node);
1514
1195
  return value;
1515
1196
  }
1516
- function activateNodeFunction(node) {
1517
- let dispose;
1518
- let subscribed = false;
1519
- let isSetting = false;
1520
- // The onSet function handles the observable being set
1521
- // and forwards the set elsewhere
1522
- const onSet = (setter) => {
1523
- const doSet = (params) => {
1524
- // Don't call the set if this is the first value coming in
1525
- if (params.changes.length > 1 || !isFunction(params.changes[0].prevAtPath)) {
1526
- isSetting = true;
1527
- try {
1528
- params.isRemote = globalState.isLoadingRemote$.peek();
1529
- setter(params);
1530
- }
1531
- finally {
1532
- isSetting = false;
1197
+
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;
1533
1241
  }
1534
1242
  }
1535
- };
1536
- dispose === null || dispose === void 0 ? void 0 : dispose();
1537
- dispose = onChange(node, doSet, { immediate: true });
1538
- };
1539
- // The subscribe function runs a function that listens to
1540
- // a data source and sends updates into the observable
1541
- const subscribe = (fn) => {
1542
- if (!subscribed) {
1543
- subscribed = true;
1544
- fn({
1545
- update: ({ value }) => {
1546
- globalState.onChangeRemote(() => {
1547
- set(node, value);
1548
- });
1549
- },
1550
- });
1551
- }
1552
- };
1553
- // The proxy function simply marks the node as a proxy with this function
1554
- // so that child nodes will be created with this function, and then simply
1555
- // activated as a function
1556
- const proxy = (fn) => {
1557
- node.proxyFn2 = fn;
1558
- };
1559
- if (!node.state) {
1560
- node.state = createObservable({
1561
- isLoaded: false,
1562
- }, false, extractPromise, getProxy);
1563
- }
1564
- const { isLoaded } = node.state;
1565
- let prevTarget$;
1566
- let curTarget$;
1567
- let wasPromise;
1568
- const activator = (isFunction(node) ? node : node.lazy);
1569
- observe(() => {
1570
- // Run the function at this node
1571
- let value = activator({ onSet, subscribe, proxy });
1572
- // If target is an observable, get() it to make sure we listen to its changes
1573
- // and set up an onSet to write changes back to it
1574
- if (isObservable(value)) {
1575
- prevTarget$ = curTarget$;
1576
- curTarget$ = value;
1577
- onSet(({ value: newValue, getPrevious }) => {
1578
- // Don't set the target observable if the target has changed since the last run
1579
- if (!prevTarget$ || curTarget$ === prevTarget$) {
1580
- // Set the node value back to what it was before before setting it.
1581
- // This is a workaround for linked objects because it might not notify
1582
- // if setting a property of an object
1583
- // TODO: Is there a way to not do this? Or at least only do it in a
1584
- // small subset of cases?
1585
- setNodeValue(getNode(curTarget$), getPrevious());
1586
- // Set the value on the curTarget
1587
- curTarget$.set(newValue);
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]);
1588
1248
  }
1589
- });
1590
- // Get the value from the observable because we still want the raw value
1591
- // for the effect.
1592
- value = value.get();
1593
- }
1594
- if (isPromise(value)) {
1595
- wasPromise = true;
1596
- extractPromise(node, value);
1597
- value = undefined;
1598
- }
1599
- return value;
1600
- }, ({ value }) => {
1601
- if (!isSetting) {
1602
- const doSet = () => {
1603
- set(node, value);
1604
- isLoaded.set(true);
1605
- };
1606
- if (wasPromise) {
1607
- wasPromise = false;
1608
- globalState.onChangeRemote(doSet);
1249
+ break;
1609
1250
  }
1610
- else {
1611
- doSet();
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];
1612
1257
  }
1613
1258
  }
1614
- }, { immediate: true, fromComputed: true });
1259
+ }
1260
+ else {
1261
+ obj = value;
1262
+ }
1263
+ return obj;
1615
1264
  }
1616
-
1617
- const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
1618
- function ObservablePrimitiveClass(node) {
1619
- this._node = node;
1620
- // Bind to this
1621
- for (let i = 0; i < fns.length; i++) {
1622
- const key = fns[i];
1623
- this[key] = this[key].bind(this);
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);
1624
1285
  }
1625
1286
  }
1626
- // Add observable functions to prototype
1627
- function proto(key, fn) {
1628
- ObservablePrimitiveClass.prototype[key] = function (...args) {
1629
- return fn.call(this, this._node, ...args);
1630
- };
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
+ const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
1369
+ function ObservablePrimitiveClass(node) {
1370
+ this._node = node;
1371
+ // Bind to this
1372
+ for (let i = 0; i < fns.length; i++) {
1373
+ const key = fns[i];
1374
+ this[key] = this[key].bind(this);
1375
+ }
1376
+ }
1377
+ // Add observable functions to prototype
1378
+ function proto(key, fn) {
1379
+ ObservablePrimitiveClass.prototype[key] = function (...args) {
1380
+ return fn.call(this, this._node, ...args);
1381
+ };
1631
1382
  }
1632
1383
  proto('peek', peek);
1633
1384
  proto('get', get);
@@ -1655,76 +1406,122 @@ ObservablePrimitiveClass.prototype.delete = function () {
1655
1406
  return this;
1656
1407
  };
1657
1408
 
1658
- function _when(predicate, effect, checkReady) {
1659
- // If predicate is a regular Promise skip all the observable stuff
1660
- if (isPromise(predicate)) {
1661
- return effect ? predicate.then(effect) : predicate;
1662
- }
1663
- let value;
1664
- // Create a wrapping fn that calls the effect if predicate returns true
1665
- function run(e) {
1666
- const ret = computeSelector(predicate);
1667
- if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) {
1668
- value = ret;
1669
- // Set cancel so that observe does not track anymore
1670
- e.cancel = true;
1409
+ function observable(value) {
1410
+ return createObservable(value, false, getProxy, ObservablePrimitiveClass);
1411
+ }
1412
+ function observablePrimitive(value) {
1413
+ return createObservable(value, true, getProxy, ObservablePrimitiveClass);
1414
+ }
1415
+
1416
+ function setupTracking(nodes, update, noArgs, immediate) {
1417
+ let listeners = [];
1418
+ // Listen to tracked nodes
1419
+ nodes === null || nodes === void 0 ? void 0 : nodes.forEach((tracked) => {
1420
+ const { node, track } = tracked;
1421
+ listeners.push(onChange(node, update, { trackingType: track, immediate, noArgs }));
1422
+ });
1423
+ return () => {
1424
+ if (listeners) {
1425
+ for (let i = 0; i < listeners.length; i++) {
1426
+ listeners[i]();
1427
+ }
1428
+ listeners = undefined;
1671
1429
  }
1672
- return value;
1673
- }
1674
- function doEffect() {
1675
- // If value is truthy then run the effect
1676
- effect === null || effect === void 0 ? void 0 : effect(value);
1677
- }
1678
- // Run in an observe
1679
- observe(run, doEffect);
1680
- // If first run resulted in a truthy value just return it.
1681
- // It will have set e.cancel so no need to dispose
1682
- if (isPromise(value)) {
1683
- return effect ? value.then(effect) : value;
1684
- }
1685
- else if (value !== undefined) {
1686
- return Promise.resolve(value);
1430
+ };
1431
+ }
1432
+
1433
+ function trackSelector(selector, update, observeEvent, observeOptions, createResubscribe) {
1434
+ var _a;
1435
+ let nodes;
1436
+ let value;
1437
+ let dispose;
1438
+ let tracker;
1439
+ let resubscribe;
1440
+ let updateFn = update;
1441
+ if (isObservable(selector)) {
1442
+ value = selector.peek();
1443
+ dispose = selector.onChange(update);
1444
+ resubscribe = createResubscribe ? selector.onChange(update) : undefined;
1687
1445
  }
1688
1446
  else {
1689
- // Wrap it in a promise
1690
- const promise = new Promise((resolve) => {
1691
- if (effect) {
1692
- const originalEffect = effect;
1693
- effect = (value) => {
1694
- const effectValue = originalEffect(value);
1695
- resolve(effectValue);
1696
- };
1697
- }
1698
- else {
1699
- effect = resolve;
1447
+ // Compute the selector inside a tracking context
1448
+ beginTracking();
1449
+ value = selector ? computeSelector(selector, observeEvent, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.fromComputed) : selector;
1450
+ tracker = tracking.current;
1451
+ nodes = tracker.nodes;
1452
+ endTracking();
1453
+ if ((process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') && tracker && nodes) {
1454
+ (_a = tracker.traceListeners) === null || _a === void 0 ? void 0 : _a.call(tracker, nodes);
1455
+ if (tracker.traceUpdates) {
1456
+ updateFn = tracker.traceUpdates(update);
1700
1457
  }
1701
- });
1702
- return promise;
1458
+ // Clear tracing so it doesn't leak to other components
1459
+ tracker.traceListeners = undefined;
1460
+ tracker.traceUpdates = undefined;
1461
+ }
1703
1462
  }
1704
- }
1705
- function when(predicate, effect) {
1706
- return _when(predicate, effect, false);
1707
- }
1708
- function whenReady(predicate, effect) {
1709
- return _when(predicate, effect, true);
1463
+ if (!(observeEvent === null || observeEvent === void 0 ? void 0 : observeEvent.cancel)) {
1464
+ // Do tracing if it was requested
1465
+ // useSyncExternalStore doesn't subscribe until after the component mount.
1466
+ // We want to subscribe immediately so we don't miss any updates
1467
+ dispose = setupTracking(nodes, updateFn, false, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.immediate);
1468
+ resubscribe = createResubscribe ? () => setupTracking(nodes, updateFn) : undefined;
1469
+ }
1470
+ return { value, dispose, resubscribe };
1710
1471
  }
1711
1472
 
1712
- function observable(value) {
1713
- return createObservable(value, false, extractPromise, getProxy, ObservablePrimitiveClass);
1473
+ function observe(selectorOrRun, reactionOrOptions, options) {
1474
+ let reaction;
1475
+ if (isFunction(reactionOrOptions)) {
1476
+ reaction = reactionOrOptions;
1477
+ }
1478
+ else {
1479
+ options = reactionOrOptions;
1480
+ }
1481
+ let dispose;
1482
+ const e = { num: 0 };
1483
+ // Wrap it in a function so it doesn't pass all the arguments to run()
1484
+ const update = function () {
1485
+ if (e.onCleanup) {
1486
+ e.onCleanup();
1487
+ e.onCleanup = undefined;
1488
+ }
1489
+ // Run in a batch so changes don't happen until we're done tracking here
1490
+ beginBatch();
1491
+ // Run the function/selector
1492
+ delete e.value;
1493
+ // Dispose listeners from previous run
1494
+ dispose === null || dispose === void 0 ? void 0 : dispose();
1495
+ const { dispose: _dispose, value } = trackSelector(selectorOrRun, update, e, options);
1496
+ dispose = _dispose;
1497
+ e.value = value;
1498
+ if (e.onCleanupReaction) {
1499
+ e.onCleanupReaction();
1500
+ e.onCleanupReaction = undefined;
1501
+ }
1502
+ endBatch();
1503
+ // Call the reaction if there is one and the value changed
1504
+ if (reaction &&
1505
+ (e.num > 0 || !isEvent(selectorOrRun)) &&
1506
+ (e.previous !== e.value || (options === null || options === void 0 ? void 0 : options.fromComputed))) {
1507
+ reaction(e);
1508
+ }
1509
+ // Update the previous value
1510
+ e.previous = e.value;
1511
+ // Increment the counter
1512
+ e.num++;
1513
+ };
1514
+ update();
1515
+ // Return function calling dispose because dispose may be changed in update()
1516
+ return () => {
1517
+ var _a, _b;
1518
+ (_a = e.onCleanup) === null || _a === void 0 ? void 0 : _a.call(e);
1519
+ e.onCleanup = undefined;
1520
+ (_b = e.onCleanupReaction) === null || _b === void 0 ? void 0 : _b.call(e);
1521
+ e.onCleanupReaction = undefined;
1522
+ dispose === null || dispose === void 0 ? void 0 : dispose();
1523
+ };
1714
1524
  }
1715
- function observablePrimitive(value) {
1716
- return createObservable(value, true, extractPromise, getProxy, ObservablePrimitiveClass);
1717
- }
1718
- globalState.isLoadingRemote$ = observable(false);
1719
- globalState.onChangeRemote = function onChangeRemote(cb) {
1720
- when(() => !globalState.isLoadingRemote$.get(), () => {
1721
- // Remote changes should only update local state
1722
- globalState.isLoadingRemote$.set(true);
1723
- batch(cb, () => {
1724
- globalState.isLoadingRemote$.set(false);
1725
- });
1726
- });
1727
- };
1728
1525
 
1729
1526
  function computed(compute, set$1) {
1730
1527
  // Create an observable for this computed variable
@@ -1888,6 +1685,60 @@ function proxy(get, set) {
1888
1685
  return obs;
1889
1686
  }
1890
1687
 
1688
+ function _when(predicate, effect, checkReady) {
1689
+ // If predicate is a regular Promise skip all the observable stuff
1690
+ if (isPromise(predicate)) {
1691
+ return effect ? predicate.then(effect) : predicate;
1692
+ }
1693
+ let value;
1694
+ // Create a wrapping fn that calls the effect if predicate returns true
1695
+ function run(e) {
1696
+ const ret = computeSelector(predicate);
1697
+ if (!isPromise(ret) && (checkReady ? isObservableValueReady(ret) : ret)) {
1698
+ value = ret;
1699
+ // Set cancel so that observe does not track anymore
1700
+ e.cancel = true;
1701
+ }
1702
+ return value;
1703
+ }
1704
+ function doEffect() {
1705
+ // If value is truthy then run the effect
1706
+ effect === null || effect === void 0 ? void 0 : effect(value);
1707
+ }
1708
+ // Run in an observe
1709
+ observe(run, doEffect);
1710
+ // If first run resulted in a truthy value just return it.
1711
+ // It will have set e.cancel so no need to dispose
1712
+ if (isPromise(value)) {
1713
+ return effect ? value.then(effect) : value;
1714
+ }
1715
+ else if (value !== undefined) {
1716
+ return Promise.resolve(value);
1717
+ }
1718
+ else {
1719
+ // Wrap it in a promise
1720
+ const promise = new Promise((resolve) => {
1721
+ if (effect) {
1722
+ const originalEffect = effect;
1723
+ effect = (value) => {
1724
+ const effectValue = originalEffect(value);
1725
+ resolve(effectValue);
1726
+ };
1727
+ }
1728
+ else {
1729
+ effect = resolve;
1730
+ }
1731
+ });
1732
+ return promise;
1733
+ }
1734
+ }
1735
+ function when(predicate, effect) {
1736
+ return _when(predicate, effect, false);
1737
+ }
1738
+ function whenReady(predicate, effect) {
1739
+ return _when(predicate, effect, true);
1740
+ }
1741
+
1891
1742
  const internal = {
1892
1743
  ensureNodeValue,
1893
1744
  findIDKey,