@legendapp/state 1.3.5 → 1.4.0-next.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/CHANGELOG.md +10 -0
- package/index.d.ts +3 -3
- package/index.js +180 -127
- package/index.js.map +1 -1
- package/index.mjs +181 -126
- package/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/ObservableObject.d.ts +8 -0
- package/src/ObservablePrimitive.d.ts +1 -1
- package/src/computed.d.ts +1 -0
- package/src/globals.d.ts +5 -3
- package/src/helpers.d.ts +4 -3
- package/src/observable.d.ts +1 -8
- package/src/observableInterfaces.d.ts +6 -1
- package/src/observe.d.ts +1 -0
- package/trace.js +0 -2
- package/trace.js.map +1 -1
- package/trace.mjs +0 -2
- package/trace.mjs.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 1.4.0
|
|
2
|
+
|
|
3
|
+
- Feat: Returning an observable in a computed creates a two-way link to the target observable.
|
|
4
|
+
- Feat: `computed` is supported as a child of an observable
|
|
5
|
+
- Feat: Functions and computeds in the hierarchy of the constructing object in an observable are extracted into observable metadata so that setting the observable does not delete them.
|
|
6
|
+
|
|
7
|
+
## 1.3.6
|
|
8
|
+
|
|
9
|
+
- Fix: Setting a primitive observable to the same value was still notifying listeners
|
|
10
|
+
|
|
1
11
|
## 1.3.5
|
|
2
12
|
|
|
3
13
|
- Fix: array.find was returning `[]` instead of `undefined` when it found no matches
|
package/index.d.ts
CHANGED
|
@@ -9,9 +9,9 @@ export { when, whenReady } from './src/when';
|
|
|
9
9
|
export { configureLegendState } from './src/config';
|
|
10
10
|
export * from './src/observableInterfaces';
|
|
11
11
|
export { isEmpty, isArray, isBoolean, isFunction, isObject, isPrimitive, isPromise, isString, isSymbol, } from './src/is';
|
|
12
|
-
import { setAtPath
|
|
13
|
-
import { ensureNodeValue, get, peek } from './src/globals';
|
|
14
|
-
import { getProxy, set } from './src/
|
|
12
|
+
import { setAtPath } from './src/helpers';
|
|
13
|
+
import { ensureNodeValue, get, getNode, peek } from './src/globals';
|
|
14
|
+
import { getProxy, set } from './src/ObservableObject';
|
|
15
15
|
export declare const internal: {
|
|
16
16
|
ensureNodeValue: typeof ensureNodeValue;
|
|
17
17
|
get: typeof get;
|
package/index.js
CHANGED
|
@@ -10,7 +10,6 @@ function isString(obj) {
|
|
|
10
10
|
function isObject(obj) {
|
|
11
11
|
return !!obj && typeof obj === 'object' && !isArray(obj);
|
|
12
12
|
}
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
14
13
|
function isFunction(obj) {
|
|
15
14
|
return typeof obj === 'function';
|
|
16
15
|
}
|
|
@@ -92,14 +91,13 @@ function updateTracking(node, track) {
|
|
|
92
91
|
}
|
|
93
92
|
|
|
94
93
|
const symbolToPrimitive = Symbol.toPrimitive;
|
|
95
|
-
const symbolIsObservable = Symbol('isObservable');
|
|
96
|
-
const symbolIsEvent = Symbol('isEvent');
|
|
97
94
|
const symbolGetNode = Symbol('getNode');
|
|
98
95
|
const symbolDelete = /* @__PURE__ */ Symbol('delete');
|
|
99
96
|
const symbolOpaque = Symbol('opaque');
|
|
100
97
|
const optimized = Symbol('optimized');
|
|
101
98
|
const extraPrimitiveActivators = new Map();
|
|
102
99
|
const extraPrimitiveProps = new Map();
|
|
100
|
+
const __devExtractFunctionsAndComputedsNodes = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test' ? new Set() : undefined;
|
|
103
101
|
function checkActivate(node) {
|
|
104
102
|
const root = node.root;
|
|
105
103
|
const activate = root.activate;
|
|
@@ -108,6 +106,9 @@ function checkActivate(node) {
|
|
|
108
106
|
activate();
|
|
109
107
|
}
|
|
110
108
|
}
|
|
109
|
+
function getNode(obs) {
|
|
110
|
+
return obs && obs[symbolGetNode];
|
|
111
|
+
}
|
|
111
112
|
function get(node, track) {
|
|
112
113
|
// Track by default
|
|
113
114
|
updateTracking(node, track);
|
|
@@ -183,6 +184,36 @@ function findIDKey(obj, node) {
|
|
|
183
184
|
}
|
|
184
185
|
return idKey;
|
|
185
186
|
}
|
|
187
|
+
function extractFunction(node, value, key) {
|
|
188
|
+
if (!node.functions) {
|
|
189
|
+
node.functions = new Map();
|
|
190
|
+
}
|
|
191
|
+
node.functions.set(key, value[key]);
|
|
192
|
+
}
|
|
193
|
+
function extractFunctionsAndComputeds(obj, node) {
|
|
194
|
+
if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
195
|
+
if (__devExtractFunctionsAndComputedsNodes.has(obj)) {
|
|
196
|
+
console.error('[legend-state] Circular reference detected in object. You may want to use opaqueObject to stop traversing child nodes.', obj);
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
__devExtractFunctionsAndComputedsNodes.add(obj);
|
|
200
|
+
}
|
|
201
|
+
for (const k in obj) {
|
|
202
|
+
const v = obj[k];
|
|
203
|
+
if (typeof v === 'function') {
|
|
204
|
+
extractFunction(node, obj, k);
|
|
205
|
+
}
|
|
206
|
+
else if (typeof v == 'object' && v !== null && v !== undefined) {
|
|
207
|
+
const childNode = getNode(v);
|
|
208
|
+
if (childNode === null || childNode === void 0 ? void 0 : childNode.isComputed) {
|
|
209
|
+
extractFunction(node, obj, k);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
extractFunctionsAndComputeds(obj[k], getChildNode(node, k));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
186
217
|
|
|
187
218
|
let timeout;
|
|
188
219
|
let numInBatch = 0;
|
|
@@ -272,6 +303,11 @@ function computeChangesAtNode(changesInBatch, node, value, path, pathTypes, valu
|
|
|
272
303
|
function computeChangesRecursive(changesInBatch, node, value, path, pathTypes, valueAtPath, prevAtPath, immediate, level, whenOptimizedOnlyIf) {
|
|
273
304
|
// Do the compute at this node
|
|
274
305
|
computeChangesAtNode(changesInBatch, node, value, path, pathTypes, valueAtPath, prevAtPath, immediate, level, whenOptimizedOnlyIf);
|
|
306
|
+
if (node.linkedFromNodes) {
|
|
307
|
+
for (const linkedFromNode of node.linkedFromNodes) {
|
|
308
|
+
computeChangesAtNode(changesInBatch, linkedFromNode, value, path, pathTypes, valueAtPath, prevAtPath, immediate, level, whenOptimizedOnlyIf);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
275
311
|
// If not root notify up through parents
|
|
276
312
|
if (node.parent) {
|
|
277
313
|
const parent = node.parent;
|
|
@@ -395,17 +431,18 @@ function afterBatch(fn) {
|
|
|
395
431
|
}
|
|
396
432
|
|
|
397
433
|
function isObservable(obs) {
|
|
398
|
-
return obs && !!obs[
|
|
434
|
+
return obs && !!obs[symbolGetNode];
|
|
435
|
+
}
|
|
436
|
+
function isEvent(obs) {
|
|
437
|
+
var _a;
|
|
438
|
+
return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isEvent);
|
|
399
439
|
}
|
|
400
|
-
function computeSelector(selector, e) {
|
|
440
|
+
function computeSelector(selector, e, retainObservable) {
|
|
401
441
|
let c = selector;
|
|
402
442
|
if (isFunction(c)) {
|
|
403
443
|
c = e ? c(e) : c();
|
|
404
444
|
}
|
|
405
|
-
return isObservable(c) ? c.get() : c;
|
|
406
|
-
}
|
|
407
|
-
function getNode(obs) {
|
|
408
|
-
return obs[symbolGetNode];
|
|
445
|
+
return isObservable(c) && !retainObservable ? c.get() : c;
|
|
409
446
|
}
|
|
410
447
|
function getObservableIndex(obs) {
|
|
411
448
|
const node = getNode(obs);
|
|
@@ -640,7 +677,7 @@ function trackSelector(selector, update, observeEvent, observeOptions, createRes
|
|
|
640
677
|
else {
|
|
641
678
|
// Compute the selector inside a tracking context
|
|
642
679
|
beginTracking();
|
|
643
|
-
value = selector ? computeSelector(selector, observeEvent) : selector;
|
|
680
|
+
value = selector ? computeSelector(selector, observeEvent, observeOptions === null || observeOptions === void 0 ? void 0 : observeOptions.retainObservable) : selector;
|
|
644
681
|
tracker = tracking.current;
|
|
645
682
|
nodes = tracker.nodes;
|
|
646
683
|
endTracking();
|
|
@@ -665,70 +702,6 @@ function trackSelector(selector, update, observeEvent, observeOptions, createRes
|
|
|
665
702
|
return { value, dispose, resubscribe };
|
|
666
703
|
}
|
|
667
704
|
|
|
668
|
-
function ObservablePrimitiveClass(node) {
|
|
669
|
-
this._node = node;
|
|
670
|
-
this.set = this.set.bind(this);
|
|
671
|
-
this.toggle = this.toggle.bind(this);
|
|
672
|
-
}
|
|
673
|
-
// Getters
|
|
674
|
-
Object.defineProperty(ObservablePrimitiveClass.prototype, symbolGetNode, {
|
|
675
|
-
configurable: true,
|
|
676
|
-
get() {
|
|
677
|
-
return this._node;
|
|
678
|
-
},
|
|
679
|
-
});
|
|
680
|
-
Object.defineProperty(ObservablePrimitiveClass.prototype, symbolIsObservable, {
|
|
681
|
-
configurable: true,
|
|
682
|
-
value: true,
|
|
683
|
-
});
|
|
684
|
-
Object.defineProperty(ObservablePrimitiveClass.prototype, symbolIsEvent, {
|
|
685
|
-
configurable: true,
|
|
686
|
-
value: false,
|
|
687
|
-
});
|
|
688
|
-
ObservablePrimitiveClass.prototype.peek = function () {
|
|
689
|
-
checkActivate(this._node);
|
|
690
|
-
return this._node.root._;
|
|
691
|
-
};
|
|
692
|
-
ObservablePrimitiveClass.prototype.get = function () {
|
|
693
|
-
const node = this._node;
|
|
694
|
-
updateTracking(node);
|
|
695
|
-
return this.peek();
|
|
696
|
-
};
|
|
697
|
-
// Setters
|
|
698
|
-
ObservablePrimitiveClass.prototype.set = function (value) {
|
|
699
|
-
if (isFunction(value)) {
|
|
700
|
-
value = value(this._node.root._);
|
|
701
|
-
}
|
|
702
|
-
if (this._node.root.locked) {
|
|
703
|
-
throw new Error(process.env.NODE_ENV === 'development'
|
|
704
|
-
? '[legend-state] Cannot modify an observable while it is locked. Please make sure that you unlock the observable before making changes.'
|
|
705
|
-
: '[legend-state] Modified locked observable');
|
|
706
|
-
}
|
|
707
|
-
const root = this._node.root;
|
|
708
|
-
const prev = root._;
|
|
709
|
-
root._ = value;
|
|
710
|
-
notify(this._node, value, prev, 0);
|
|
711
|
-
return this;
|
|
712
|
-
};
|
|
713
|
-
ObservablePrimitiveClass.prototype.toggle = function () {
|
|
714
|
-
const value = this.peek();
|
|
715
|
-
if (value === undefined || isBoolean(value)) {
|
|
716
|
-
this.set(!value);
|
|
717
|
-
}
|
|
718
|
-
else if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
719
|
-
throw new Error('[legend-state] Cannot toggle a non-boolean value');
|
|
720
|
-
}
|
|
721
|
-
return !value;
|
|
722
|
-
};
|
|
723
|
-
ObservablePrimitiveClass.prototype.delete = function () {
|
|
724
|
-
this.set(undefined);
|
|
725
|
-
return this;
|
|
726
|
-
};
|
|
727
|
-
// Listener
|
|
728
|
-
ObservablePrimitiveClass.prototype.onChange = function (cb, options) {
|
|
729
|
-
return onChange(this._node, cb, options);
|
|
730
|
-
};
|
|
731
|
-
|
|
732
705
|
const ArrayModifiers = new Set([
|
|
733
706
|
'copyWithin',
|
|
734
707
|
'fill',
|
|
@@ -753,9 +726,7 @@ const ArrayLoopers = new Set([
|
|
|
753
726
|
'some',
|
|
754
727
|
]);
|
|
755
728
|
const ArrayLoopersReturn = new Set(['filter', 'find']);
|
|
756
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
757
729
|
const observableProperties = new Map();
|
|
758
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
759
730
|
const observableFns = new Map([
|
|
760
731
|
['get', get],
|
|
761
732
|
['set', set],
|
|
@@ -772,7 +743,6 @@ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
|
772
743
|
function collectionSetter(node, target, prop, ...args) {
|
|
773
744
|
var _a;
|
|
774
745
|
const prevValue = (isArray(target) && target.slice()) || target;
|
|
775
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
776
746
|
const ret = target[prop].apply(target, args);
|
|
777
747
|
if (node) {
|
|
778
748
|
const hasParent = isChildNodeValue(node);
|
|
@@ -966,22 +936,24 @@ function getProxy(node, p) {
|
|
|
966
936
|
return node.proxy || (node.proxy = new Proxy(node, proxyHandler));
|
|
967
937
|
}
|
|
968
938
|
const proxyHandler = {
|
|
969
|
-
get(node, p) {
|
|
939
|
+
get(node, p, receiver) {
|
|
940
|
+
var _a;
|
|
970
941
|
if (p === symbolToPrimitive) {
|
|
971
942
|
throw new Error(process.env.NODE_ENV === 'development'
|
|
972
943
|
? '[legend-state] observable should not be used as a primitive. You may have forgotten to use .get() or .peek() to get the value of the observable.'
|
|
973
944
|
: '[legend-state] observable is not a primitive.');
|
|
974
945
|
}
|
|
975
|
-
if (p === symbolIsObservable) {
|
|
976
|
-
// Return true if called by isObservable()
|
|
977
|
-
return true;
|
|
978
|
-
}
|
|
979
|
-
if (p === symbolIsEvent) {
|
|
980
|
-
return false;
|
|
981
|
-
}
|
|
982
946
|
if (p === symbolGetNode) {
|
|
983
947
|
return node;
|
|
984
948
|
}
|
|
949
|
+
if (node.isComputed) {
|
|
950
|
+
checkActivate(node);
|
|
951
|
+
}
|
|
952
|
+
// If this node is linked to another observable then forward to the target's handler.
|
|
953
|
+
// The exception is onChange because it needs to listen to this node for changes.
|
|
954
|
+
if (node.linkedToNode && p !== 'onChange') {
|
|
955
|
+
return proxyHandler.get(node.linkedToNode, p, receiver);
|
|
956
|
+
}
|
|
985
957
|
const value = peek(node);
|
|
986
958
|
if (value instanceof Map || value instanceof WeakMap || value instanceof Set || value instanceof WeakSet) {
|
|
987
959
|
const ret = handlerMapSet(node, p, value);
|
|
@@ -1080,6 +1052,10 @@ const proxyHandler = {
|
|
|
1080
1052
|
return vProp;
|
|
1081
1053
|
}
|
|
1082
1054
|
}
|
|
1055
|
+
const fnOrComputed = (_a = node.functions) === null || _a === void 0 ? void 0 : _a.get(p);
|
|
1056
|
+
if (fnOrComputed) {
|
|
1057
|
+
return fnOrComputed;
|
|
1058
|
+
}
|
|
1083
1059
|
// Return an observable proxy to the property
|
|
1084
1060
|
return getProxy(node, p);
|
|
1085
1061
|
},
|
|
@@ -1143,11 +1119,11 @@ const proxyHandler = {
|
|
|
1143
1119
|
},
|
|
1144
1120
|
};
|
|
1145
1121
|
function set(node, newValue) {
|
|
1146
|
-
if (
|
|
1147
|
-
return setKey(node,
|
|
1122
|
+
if (node.parent) {
|
|
1123
|
+
return setKey(node.parent, node.key, newValue);
|
|
1148
1124
|
}
|
|
1149
1125
|
else {
|
|
1150
|
-
return setKey(node
|
|
1126
|
+
return setKey(node, undefined, newValue);
|
|
1151
1127
|
}
|
|
1152
1128
|
}
|
|
1153
1129
|
function toggle(node) {
|
|
@@ -1189,12 +1165,12 @@ function setKey(node, key, newValue, level) {
|
|
|
1189
1165
|
newValue =
|
|
1190
1166
|
!node.isAssigning && isFunc
|
|
1191
1167
|
? newValue(prevValue)
|
|
1192
|
-
: isObject(newValue) && (newValue === null || newValue === void 0 ? void 0 : newValue[
|
|
1168
|
+
: isObject(newValue) && (newValue === null || newValue === void 0 ? void 0 : newValue[symbolGetNode])
|
|
1193
1169
|
? newValue.peek()
|
|
1194
1170
|
: newValue;
|
|
1195
1171
|
const isPrim = isPrimitive(newValue) || newValue instanceof Date;
|
|
1196
1172
|
try {
|
|
1197
|
-
node.isSetting
|
|
1173
|
+
node.isSetting = (node.isSetting || 0) + 1;
|
|
1198
1174
|
// Save the new value
|
|
1199
1175
|
if (isDelete) {
|
|
1200
1176
|
delete parentValue[key];
|
|
@@ -1209,7 +1185,9 @@ function setKey(node, key, newValue, level) {
|
|
|
1209
1185
|
if (node.root.locked && node.root.set) {
|
|
1210
1186
|
node.root.set(node.root._);
|
|
1211
1187
|
}
|
|
1212
|
-
|
|
1188
|
+
if (newValue !== prevValue) {
|
|
1189
|
+
updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRoot, level);
|
|
1190
|
+
}
|
|
1213
1191
|
return isFunc ? newValue : isRoot ? getProxy(node) : getProxy(node, key);
|
|
1214
1192
|
}
|
|
1215
1193
|
function assign(node, value) {
|
|
@@ -1237,33 +1215,6 @@ function deleteFn(node, key) {
|
|
|
1237
1215
|
}
|
|
1238
1216
|
setKey(node, key, symbolDelete, /*level*/ -1);
|
|
1239
1217
|
}
|
|
1240
|
-
function createObservable(value, makePrimitive) {
|
|
1241
|
-
const valueIsPromise = isPromise(value);
|
|
1242
|
-
const root = {
|
|
1243
|
-
_: valueIsPromise ? undefined : value,
|
|
1244
|
-
};
|
|
1245
|
-
const node = {
|
|
1246
|
-
root,
|
|
1247
|
-
};
|
|
1248
|
-
const obs = makePrimitive || isActualPrimitive(value)
|
|
1249
|
-
? new ObservablePrimitiveClass(node)
|
|
1250
|
-
: getProxy(node);
|
|
1251
|
-
if (valueIsPromise) {
|
|
1252
|
-
value.catch((error) => {
|
|
1253
|
-
obs.set({ error });
|
|
1254
|
-
});
|
|
1255
|
-
value.then((value) => {
|
|
1256
|
-
obs.set(value);
|
|
1257
|
-
});
|
|
1258
|
-
}
|
|
1259
|
-
return obs;
|
|
1260
|
-
}
|
|
1261
|
-
function observable(value) {
|
|
1262
|
-
return createObservable(value);
|
|
1263
|
-
}
|
|
1264
|
-
function observablePrimitive(value) {
|
|
1265
|
-
return createObservable(value, /*makePrimitive*/ true);
|
|
1266
|
-
}
|
|
1267
1218
|
function handlerMapSet(node, p, value) {
|
|
1268
1219
|
const vProp = value === null || value === void 0 ? void 0 : value[p];
|
|
1269
1220
|
if (isFunction(vProp)) {
|
|
@@ -1359,6 +1310,82 @@ function updateNodesAndNotify(node, newValue, prevValue, childNode, isPrim, isRo
|
|
|
1359
1310
|
endBatch();
|
|
1360
1311
|
}
|
|
1361
1312
|
|
|
1313
|
+
const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
|
|
1314
|
+
function ObservablePrimitiveClass(node) {
|
|
1315
|
+
this._node = node;
|
|
1316
|
+
// Bind to this
|
|
1317
|
+
for (let i = 0; i < fns.length; i++) {
|
|
1318
|
+
const key = fns[i];
|
|
1319
|
+
this[key] = this[key].bind(this);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
// Add observable functions to prototype
|
|
1323
|
+
function proto(key, fn) {
|
|
1324
|
+
ObservablePrimitiveClass.prototype[key] = function (...args) {
|
|
1325
|
+
return fn.call(this, this._node, ...args);
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
proto('peek', peek);
|
|
1329
|
+
proto('get', get);
|
|
1330
|
+
proto('set', set);
|
|
1331
|
+
proto('onChange', onChange);
|
|
1332
|
+
// Getters
|
|
1333
|
+
Object.defineProperty(ObservablePrimitiveClass.prototype, symbolGetNode, {
|
|
1334
|
+
configurable: true,
|
|
1335
|
+
get() {
|
|
1336
|
+
return this._node;
|
|
1337
|
+
},
|
|
1338
|
+
});
|
|
1339
|
+
ObservablePrimitiveClass.prototype.toggle = function () {
|
|
1340
|
+
const value = this.peek();
|
|
1341
|
+
if (value === undefined || isBoolean(value)) {
|
|
1342
|
+
this.set(!value);
|
|
1343
|
+
}
|
|
1344
|
+
else if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
1345
|
+
throw new Error('[legend-state] Cannot toggle a non-boolean value');
|
|
1346
|
+
}
|
|
1347
|
+
return !value;
|
|
1348
|
+
};
|
|
1349
|
+
ObservablePrimitiveClass.prototype.delete = function () {
|
|
1350
|
+
this.set(undefined);
|
|
1351
|
+
return this;
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
function createObservable(value, makePrimitive) {
|
|
1355
|
+
const valueIsPromise = isPromise(value);
|
|
1356
|
+
const root = {
|
|
1357
|
+
_: valueIsPromise ? undefined : value,
|
|
1358
|
+
};
|
|
1359
|
+
const node = {
|
|
1360
|
+
root,
|
|
1361
|
+
};
|
|
1362
|
+
const prim = makePrimitive || isActualPrimitive(value);
|
|
1363
|
+
const obs = prim
|
|
1364
|
+
? new ObservablePrimitiveClass(node)
|
|
1365
|
+
: getProxy(node);
|
|
1366
|
+
if (valueIsPromise) {
|
|
1367
|
+
value.catch((error) => {
|
|
1368
|
+
obs.set({ error });
|
|
1369
|
+
});
|
|
1370
|
+
value.then((value) => {
|
|
1371
|
+
obs.set(value);
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
else if (!prim) {
|
|
1375
|
+
if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
|
|
1376
|
+
__devExtractFunctionsAndComputedsNodes.clear();
|
|
1377
|
+
}
|
|
1378
|
+
extractFunctionsAndComputeds(value, node);
|
|
1379
|
+
}
|
|
1380
|
+
return obs;
|
|
1381
|
+
}
|
|
1382
|
+
function observable(value) {
|
|
1383
|
+
return createObservable(value);
|
|
1384
|
+
}
|
|
1385
|
+
function observablePrimitive(value) {
|
|
1386
|
+
return createObservable(value, /*makePrimitive*/ true);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1362
1389
|
function observe(selectorOrRun, reactionOrOptions, options) {
|
|
1363
1390
|
let reaction;
|
|
1364
1391
|
if (isFunction(reactionOrOptions)) {
|
|
@@ -1389,7 +1416,7 @@ function observe(selectorOrRun, reactionOrOptions, options) {
|
|
|
1389
1416
|
e.onCleanupReaction = undefined;
|
|
1390
1417
|
}
|
|
1391
1418
|
// Call the reaction if there is one and the value changed
|
|
1392
|
-
if (reaction && (e.num > 0 || !(selectorOrRun
|
|
1419
|
+
if (reaction && (e.num > 0 || !isEvent(selectorOrRun)) && e.previous !== e.value) {
|
|
1393
1420
|
reaction(e);
|
|
1394
1421
|
}
|
|
1395
1422
|
// Update the previous value
|
|
@@ -1414,16 +1441,40 @@ function computed(compute, set$1) {
|
|
|
1414
1441
|
// Create an observable for this computed variable
|
|
1415
1442
|
const obs = observable();
|
|
1416
1443
|
lockObservable(obs, true);
|
|
1417
|
-
// Lazily activate the observable when get is called
|
|
1418
1444
|
const node = getNode(obs);
|
|
1445
|
+
node.isComputed = true;
|
|
1419
1446
|
const setInner = function (val) {
|
|
1420
|
-
|
|
1447
|
+
const prevNode = node.linkedToNode;
|
|
1448
|
+
// If it was previously linked to a node remove self
|
|
1449
|
+
// from its linkedFromNodes
|
|
1450
|
+
if (prevNode) {
|
|
1451
|
+
node.linkedToNode.linkedFromNodes.delete(node);
|
|
1452
|
+
node.linkedToNode = undefined;
|
|
1453
|
+
}
|
|
1454
|
+
if (isObservable(val)) {
|
|
1455
|
+
// If the computed is a proxy to another observable
|
|
1456
|
+
// link it to the target observable
|
|
1457
|
+
const linkedNode = getNode(val);
|
|
1458
|
+
node.linkedToNode = linkedNode;
|
|
1459
|
+
if (!linkedNode.linkedFromNodes) {
|
|
1460
|
+
linkedNode.linkedFromNodes = new Set();
|
|
1461
|
+
}
|
|
1462
|
+
linkedNode.linkedFromNodes.add(node);
|
|
1463
|
+
// If the target observable is different then notify for the change
|
|
1464
|
+
if (prevNode) {
|
|
1465
|
+
const value = getNodeValue(linkedNode);
|
|
1466
|
+
const prevValue = getNodeValue(prevNode);
|
|
1467
|
+
notify(node, value, prevValue, 0);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
else if (val !== obs.peek()) {
|
|
1421
1471
|
// Update the computed value
|
|
1422
1472
|
lockObservable(obs, false);
|
|
1423
1473
|
set(node, val);
|
|
1424
1474
|
lockObservable(obs, true);
|
|
1425
1475
|
}
|
|
1426
1476
|
};
|
|
1477
|
+
// Lazily activate the observable when get is called
|
|
1427
1478
|
node.root.activate = () => {
|
|
1428
1479
|
observe(compute, ({ value }) => {
|
|
1429
1480
|
if (isPromise(value)) {
|
|
@@ -1432,7 +1483,7 @@ function computed(compute, set$1) {
|
|
|
1432
1483
|
else {
|
|
1433
1484
|
setInner(value);
|
|
1434
1485
|
}
|
|
1435
|
-
}, { immediate: true });
|
|
1486
|
+
}, { immediate: true, retainObservable: true });
|
|
1436
1487
|
};
|
|
1437
1488
|
if (set$1) {
|
|
1438
1489
|
node.root.set = (value) => {
|
|
@@ -1446,6 +1497,8 @@ function event() {
|
|
|
1446
1497
|
// event simply wraps around a number observable
|
|
1447
1498
|
// which increments its value to dispatch change events
|
|
1448
1499
|
const obs = observable(0);
|
|
1500
|
+
const node = getNode(obs);
|
|
1501
|
+
node.isEvent = true;
|
|
1449
1502
|
return {
|
|
1450
1503
|
fire: function () {
|
|
1451
1504
|
// Notify increments the value so that the observable changes
|
|
@@ -1454,10 +1507,12 @@ function event() {
|
|
|
1454
1507
|
on: function (cb) {
|
|
1455
1508
|
return obs.onChange(cb);
|
|
1456
1509
|
},
|
|
1457
|
-
get: ()
|
|
1510
|
+
get: function () {
|
|
1511
|
+
// Need to return undefined
|
|
1512
|
+
obs.get();
|
|
1513
|
+
},
|
|
1458
1514
|
// @ts-expect-error eslint doesn't like adding symbols to the object but this does work
|
|
1459
|
-
[
|
|
1460
|
-
[symbolIsEvent]: true,
|
|
1515
|
+
[symbolGetNode]: node,
|
|
1461
1516
|
};
|
|
1462
1517
|
}
|
|
1463
1518
|
|
|
@@ -1586,8 +1641,6 @@ exports.setAtPath = setAtPath;
|
|
|
1586
1641
|
exports.setInObservableAtPath = setInObservableAtPath;
|
|
1587
1642
|
exports.setupTracking = setupTracking;
|
|
1588
1643
|
exports.symbolDelete = symbolDelete;
|
|
1589
|
-
exports.symbolIsEvent = symbolIsEvent;
|
|
1590
|
-
exports.symbolIsObservable = symbolIsObservable;
|
|
1591
1644
|
exports.trackSelector = trackSelector;
|
|
1592
1645
|
exports.tracking = tracking;
|
|
1593
1646
|
exports.updateTracking = updateTracking;
|