@rlabs-inc/signals 1.3.0 → 1.4.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/README.md +114 -0
- package/dist/core/constants.d.ts +6 -0
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/deep/proxy.d.ts.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +430 -56
- package/dist/index.mjs +430 -56
- package/dist/primitives/bind.d.ts.map +1 -1
- package/dist/primitives/effect.d.ts.map +1 -1
- package/dist/primitives/linked.d.ts +73 -0
- package/dist/primitives/linked.d.ts.map +1 -0
- package/dist/primitives/scope.d.ts +96 -0
- package/dist/primitives/scope.d.ts.map +1 -0
- package/dist/primitives/selector.d.ts +46 -0
- package/dist/primitives/selector.d.ts.map +1 -0
- package/dist/reactivity/scheduling.d.ts.map +1 -1
- package/dist/reactivity/tracking.d.ts +5 -0
- package/dist/reactivity/tracking.d.ts.map +1 -1
- package/dist/v2/bench-compare.d.ts +2 -0
- package/dist/v2/bench-compare.d.ts.map +1 -0
- package/dist/v2/bench.d.ts +5 -0
- package/dist/v2/bench.d.ts.map +1 -0
- package/dist/v2/bind.d.ts +94 -0
- package/dist/v2/bind.d.ts.map +1 -0
- package/dist/v2/collections.d.ts +133 -0
- package/dist/v2/collections.d.ts.map +1 -0
- package/dist/v2/compat-test.d.ts +2 -0
- package/dist/v2/compat-test.d.ts.map +1 -0
- package/dist/v2/debug-array.d.ts +2 -0
- package/dist/v2/debug-array.d.ts.map +1 -0
- package/dist/v2/debug-diamond.d.ts +2 -0
- package/dist/v2/debug-diamond.d.ts.map +1 -0
- package/dist/v2/index.d.ts +7 -0
- package/dist/v2/index.d.ts.map +1 -0
- package/dist/v2/primitives.d.ts +120 -0
- package/dist/v2/primitives.d.ts.map +1 -0
- package/dist/v2/proxy.d.ts +10 -0
- package/dist/v2/proxy.d.ts.map +1 -0
- package/dist/v2/registry.d.ts +35 -0
- package/dist/v2/registry.d.ts.map +1 -0
- package/dist/v2/stress.d.ts +7 -0
- package/dist/v2/stress.d.ts.map +1 -0
- package/dist/v2/test-suite.d.ts +2 -0
- package/dist/v2/test-suite.d.ts.map +1 -0
- package/dist/v2/test-v1.d.ts +2 -0
- package/dist/v2/test-v1.d.ts.map +1 -0
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -54,10 +54,13 @@ __export(exports_src, {
|
|
|
54
54
|
readVersion: () => readVersion,
|
|
55
55
|
proxy: () => proxy,
|
|
56
56
|
peek: () => peek,
|
|
57
|
+
onScopeDispose: () => onScopeDispose,
|
|
57
58
|
neverEquals: () => neverEquals,
|
|
58
59
|
mutableSource: () => mutableSource,
|
|
59
60
|
markReactions: () => markReactions,
|
|
61
|
+
linkedSignal: () => linkedSignal,
|
|
60
62
|
isReactive: () => isReactive,
|
|
63
|
+
isLinkedSignal: () => isLinkedSignal,
|
|
61
64
|
isDirty: () => isDirty,
|
|
62
65
|
isBinding: () => isBinding,
|
|
63
66
|
incrementWriteVersion: () => incrementWriteVersion,
|
|
@@ -65,15 +68,18 @@ __export(exports_src, {
|
|
|
65
68
|
incrementBatchDepth: () => incrementBatchDepth,
|
|
66
69
|
getWriteVersion: () => getWriteVersion,
|
|
67
70
|
getReadVersion: () => getReadVersion,
|
|
71
|
+
getCurrentScope: () => getCurrentScope,
|
|
68
72
|
getBatchDepth: () => getBatchDepth,
|
|
69
73
|
get: () => get,
|
|
70
74
|
flushSync: () => flushSync,
|
|
71
75
|
equals: () => equals,
|
|
76
|
+
effectScope: () => effectScope,
|
|
72
77
|
effect: () => effect,
|
|
73
78
|
disconnectDerived: () => disconnectDerived,
|
|
74
79
|
destroyEffect: () => destroyEffect,
|
|
75
80
|
derived: () => derived,
|
|
76
81
|
decrementBatchDepth: () => decrementBatchDepth,
|
|
82
|
+
createSelector: () => createSelector,
|
|
77
83
|
createEquals: () => createEquals,
|
|
78
84
|
createEffect: () => createEffect,
|
|
79
85
|
createDerived: () => createDerived,
|
|
@@ -97,6 +103,7 @@ __export(exports_src, {
|
|
|
97
103
|
REACTIVE_MARKER: () => REACTIVE_MARKER,
|
|
98
104
|
REACTION_IS_UPDATING: () => REACTION_IS_UPDATING,
|
|
99
105
|
MAYBE_DIRTY: () => MAYBE_DIRTY,
|
|
106
|
+
LINKED_SYMBOL: () => LINKED_SYMBOL,
|
|
100
107
|
INERT: () => INERT,
|
|
101
108
|
EFFECT_RAN: () => EFFECT_RAN,
|
|
102
109
|
EFFECT_PRESERVED: () => EFFECT_PRESERVED,
|
|
@@ -107,7 +114,8 @@ __export(exports_src, {
|
|
|
107
114
|
DERIVED: () => DERIVED,
|
|
108
115
|
CLEAN: () => CLEAN,
|
|
109
116
|
BRANCH_EFFECT: () => BRANCH_EFFECT,
|
|
110
|
-
BLOCK_EFFECT: () => BLOCK_EFFECT
|
|
117
|
+
BLOCK_EFFECT: () => BLOCK_EFFECT,
|
|
118
|
+
BINDING_SYMBOL: () => BINDING_SYMBOL
|
|
111
119
|
});
|
|
112
120
|
module.exports = __toCommonJS(exports_src);
|
|
113
121
|
|
|
@@ -176,6 +184,9 @@ var UNINITIALIZED = Symbol.for("rlabs.signals.uninitialized");
|
|
|
176
184
|
var STALE_REACTION = Symbol.for("rlabs.signals.stale_reaction");
|
|
177
185
|
var STATE_SYMBOL = Symbol.for("rlabs.signals.state");
|
|
178
186
|
var REACTIVE_MARKER = Symbol.for("rlabs.signals.reactive");
|
|
187
|
+
var BINDING_SYMBOL = Symbol.for("rlabs.signals.binding");
|
|
188
|
+
var LINKED_SYMBOL = Symbol.for("rlabs.signals.linked");
|
|
189
|
+
var SOURCE = 1 << 0;
|
|
179
190
|
var STATUS_MASK = ~(DIRTY | MAYBE_DIRTY | CLEAN);
|
|
180
191
|
|
|
181
192
|
// src/core/globals.ts
|
|
@@ -300,6 +311,9 @@ function setUpdateEffectImpl(impl) {
|
|
|
300
311
|
function flushEffects() {
|
|
301
312
|
const roots = clearQueuedRootEffects();
|
|
302
313
|
for (const root of roots) {
|
|
314
|
+
if ((root.f & INERT) !== 0) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
303
317
|
if (isDirty(root)) {
|
|
304
318
|
updateEffectImpl(root);
|
|
305
319
|
}
|
|
@@ -310,7 +324,7 @@ function processEffectTree(effect) {
|
|
|
310
324
|
let child = effect.first;
|
|
311
325
|
while (child !== null) {
|
|
312
326
|
const next = child.next;
|
|
313
|
-
if (isDirty(child)) {
|
|
327
|
+
if ((child.f & INERT) === 0 && isDirty(child)) {
|
|
314
328
|
updateEffectImpl(child);
|
|
315
329
|
}
|
|
316
330
|
if (child.first !== null) {
|
|
@@ -323,6 +337,9 @@ function flushPendingReactions() {
|
|
|
323
337
|
const reactions = [...pendingReactions];
|
|
324
338
|
clearPendingReactions();
|
|
325
339
|
for (const reaction of reactions) {
|
|
340
|
+
if ((reaction.f & INERT) !== 0) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
326
343
|
if (isDirty(reaction)) {
|
|
327
344
|
if ("parent" in reaction) {
|
|
328
345
|
updateEffectImpl(reaction);
|
|
@@ -354,6 +371,9 @@ function flushSync(fn) {
|
|
|
354
371
|
continue;
|
|
355
372
|
}
|
|
356
373
|
for (const root of roots) {
|
|
374
|
+
if ((root.f & INERT) !== 0) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
357
377
|
if (isDirty(root)) {
|
|
358
378
|
updateEffectImpl(root);
|
|
359
379
|
}
|
|
@@ -400,13 +420,63 @@ function get(signal) {
|
|
|
400
420
|
}
|
|
401
421
|
}
|
|
402
422
|
if ((signal.f & DERIVED) !== 0) {
|
|
403
|
-
|
|
404
|
-
if (isDirty(derived)) {
|
|
405
|
-
updateDerived(derived);
|
|
406
|
-
}
|
|
423
|
+
updateDerivedChain(signal);
|
|
407
424
|
}
|
|
408
425
|
return signal.v;
|
|
409
426
|
}
|
|
427
|
+
var updateCycleId = 0;
|
|
428
|
+
var processedInCycle = new WeakMap;
|
|
429
|
+
function updateDerivedChain(target) {
|
|
430
|
+
if ((target.f & (DIRTY | MAYBE_DIRTY)) === 0) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const cycleId = ++updateCycleId;
|
|
434
|
+
const chain = [target];
|
|
435
|
+
processedInCycle.set(target, cycleId);
|
|
436
|
+
let idx = 0;
|
|
437
|
+
while (idx < chain.length) {
|
|
438
|
+
const current = chain[idx];
|
|
439
|
+
idx++;
|
|
440
|
+
if ((current.f & (DIRTY | MAYBE_DIRTY)) === 0) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
const deps = current.deps;
|
|
444
|
+
if (deps !== null) {
|
|
445
|
+
for (let i = 0;i < deps.length; i++) {
|
|
446
|
+
const dep = deps[i];
|
|
447
|
+
if ((dep.f & DERIVED) !== 0 && (dep.f & (DIRTY | MAYBE_DIRTY)) !== 0 && processedInCycle.get(dep) !== cycleId) {
|
|
448
|
+
chain.push(dep);
|
|
449
|
+
processedInCycle.set(dep, cycleId);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
for (let i = chain.length - 1;i >= 0; i--) {
|
|
455
|
+
const current = chain[i];
|
|
456
|
+
if ((current.f & (DIRTY | MAYBE_DIRTY)) === 0) {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if ((current.f & DIRTY) !== 0) {
|
|
460
|
+
updateDerived(current);
|
|
461
|
+
} else {
|
|
462
|
+
const deps = current.deps;
|
|
463
|
+
let needsUpdate = false;
|
|
464
|
+
if (deps !== null) {
|
|
465
|
+
for (let j = 0;j < deps.length; j++) {
|
|
466
|
+
if (deps[j].wv > current.wv) {
|
|
467
|
+
needsUpdate = true;
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (needsUpdate) {
|
|
473
|
+
updateDerived(current);
|
|
474
|
+
} else {
|
|
475
|
+
setSignalStatus(current, CLEAN);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
410
480
|
function set(signal, value) {
|
|
411
481
|
if (activeReaction !== null && (activeReaction.f & DERIVED) !== 0) {
|
|
412
482
|
throw new Error("Cannot write to signals inside a derived. " + "Deriveds should be pure computations with no side effects.");
|
|
@@ -422,20 +492,24 @@ function set(signal, value) {
|
|
|
422
492
|
return value;
|
|
423
493
|
}
|
|
424
494
|
function markReactions(signal, status) {
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
495
|
+
const stack = [{ signal, status }];
|
|
496
|
+
while (stack.length > 0) {
|
|
497
|
+
const { signal: currentSignal, status: currentStatus } = stack.pop();
|
|
498
|
+
const reactions = currentSignal.reactions;
|
|
499
|
+
if (reactions === null)
|
|
500
|
+
continue;
|
|
501
|
+
for (let i = 0;i < reactions.length; i++) {
|
|
502
|
+
const reaction = reactions[i];
|
|
503
|
+
const flags = reaction.f;
|
|
504
|
+
const notDirty = (flags & DIRTY) === 0;
|
|
505
|
+
if (notDirty) {
|
|
506
|
+
setSignalStatus(reaction, currentStatus);
|
|
507
|
+
}
|
|
508
|
+
if ((flags & DERIVED) !== 0) {
|
|
509
|
+
stack.push({ signal: reaction, status: MAYBE_DIRTY });
|
|
510
|
+
} else if (notDirty) {
|
|
511
|
+
scheduleEffect(reaction);
|
|
512
|
+
}
|
|
439
513
|
}
|
|
440
514
|
}
|
|
441
515
|
}
|
|
@@ -446,22 +520,66 @@ function isDirty(reaction) {
|
|
|
446
520
|
if ((reaction.f & DIRTY) !== 0) {
|
|
447
521
|
return true;
|
|
448
522
|
}
|
|
449
|
-
if ((reaction.f & MAYBE_DIRTY)
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
523
|
+
if ((reaction.f & MAYBE_DIRTY) === 0) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
const toCheck = [reaction];
|
|
527
|
+
const toUpdate = [];
|
|
528
|
+
let idx = 0;
|
|
529
|
+
while (idx < toCheck.length) {
|
|
530
|
+
const current = toCheck[idx];
|
|
531
|
+
idx++;
|
|
532
|
+
if ((current.f & DIRTY) !== 0) {
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if ((current.f & MAYBE_DIRTY) === 0) {
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const deps2 = current.deps;
|
|
539
|
+
if (deps2 !== null) {
|
|
540
|
+
for (let i = 0;i < deps2.length; i++) {
|
|
541
|
+
const dep = deps2[i];
|
|
542
|
+
if ((dep.f & DERIVED) !== 0 && (dep.f & (DIRTY | MAYBE_DIRTY)) !== 0) {
|
|
543
|
+
toCheck.push(dep);
|
|
458
544
|
}
|
|
459
|
-
|
|
460
|
-
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
for (let i = toCheck.length - 1;i >= 0; i--) {
|
|
549
|
+
const current = toCheck[i];
|
|
550
|
+
if ((current.f & DERIVED) === 0) {
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
if ((current.f & DIRTY) !== 0) {
|
|
554
|
+
updateDerived(current);
|
|
555
|
+
} else if ((current.f & MAYBE_DIRTY) !== 0) {
|
|
556
|
+
const deps2 = current.deps;
|
|
557
|
+
let needsUpdate = false;
|
|
558
|
+
if (deps2 !== null) {
|
|
559
|
+
for (let j = 0;j < deps2.length; j++) {
|
|
560
|
+
if (deps2[j].wv > current.wv) {
|
|
561
|
+
needsUpdate = true;
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
461
564
|
}
|
|
462
565
|
}
|
|
566
|
+
if (needsUpdate) {
|
|
567
|
+
updateDerived(current);
|
|
568
|
+
} else {
|
|
569
|
+
setSignalStatus(current, CLEAN);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if ((reaction.f & DIRTY) !== 0) {
|
|
574
|
+
return true;
|
|
575
|
+
}
|
|
576
|
+
const deps = reaction.deps;
|
|
577
|
+
if (deps !== null) {
|
|
578
|
+
for (let i = 0;i < deps.length; i++) {
|
|
579
|
+
if (deps[i].wv > reaction.wv) {
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
463
582
|
}
|
|
464
|
-
setSignalStatus(reaction, CLEAN);
|
|
465
583
|
}
|
|
466
584
|
return false;
|
|
467
585
|
}
|
|
@@ -614,6 +732,7 @@ function stateRaw(initialValue) {
|
|
|
614
732
|
}
|
|
615
733
|
|
|
616
734
|
// src/deep/proxy.ts
|
|
735
|
+
var proxyCache = new WeakMap;
|
|
617
736
|
var proxyCleanup = new FinalizationRegistry((data) => {
|
|
618
737
|
data.version.reactions = null;
|
|
619
738
|
for (const src of data.sources.values()) {
|
|
@@ -625,6 +744,9 @@ function shouldProxy(value) {
|
|
|
625
744
|
if (value === null || typeof value !== "object") {
|
|
626
745
|
return false;
|
|
627
746
|
}
|
|
747
|
+
if (BINDING_SYMBOL in value) {
|
|
748
|
+
return false;
|
|
749
|
+
}
|
|
628
750
|
const proto = Object.getPrototypeOf(value);
|
|
629
751
|
return proto === Object.prototype || proto === Array.prototype || proto === null;
|
|
630
752
|
}
|
|
@@ -639,6 +761,10 @@ function proxy(value) {
|
|
|
639
761
|
if (!shouldProxy(value) || isProxy(value)) {
|
|
640
762
|
return value;
|
|
641
763
|
}
|
|
764
|
+
const cached = proxyCache.get(value);
|
|
765
|
+
if (cached) {
|
|
766
|
+
return cached;
|
|
767
|
+
}
|
|
642
768
|
const sources = new Map;
|
|
643
769
|
const version = source(0);
|
|
644
770
|
const isArray = Array.isArray(value);
|
|
@@ -690,7 +816,7 @@ function proxy(value) {
|
|
|
690
816
|
}
|
|
691
817
|
return currentValue;
|
|
692
818
|
},
|
|
693
|
-
set(target, prop, newValue
|
|
819
|
+
set(target, prop, newValue) {
|
|
694
820
|
const exists = prop in target;
|
|
695
821
|
let s = sources.get(prop);
|
|
696
822
|
if (s === undefined) {
|
|
@@ -700,29 +826,35 @@ function proxy(value) {
|
|
|
700
826
|
s = withParent(() => source(undefined));
|
|
701
827
|
sources.set(prop, s);
|
|
702
828
|
}
|
|
703
|
-
|
|
829
|
+
let proxied;
|
|
830
|
+
if (shouldProxy(newValue)) {
|
|
831
|
+
proxied = withParent(() => proxy(newValue));
|
|
832
|
+
} else {
|
|
833
|
+
proxied = newValue;
|
|
834
|
+
}
|
|
704
835
|
set(s, proxied);
|
|
705
|
-
|
|
706
|
-
if (isArray
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
836
|
+
target[prop] = newValue;
|
|
837
|
+
if (isArray) {
|
|
838
|
+
if (prop === "length") {
|
|
839
|
+
const oldLength = s.v;
|
|
840
|
+
const newLength = newValue;
|
|
841
|
+
for (let i = newLength;i < oldLength; i++) {
|
|
842
|
+
const indexKey = String(i);
|
|
843
|
+
const indexSource = sources.get(indexKey);
|
|
844
|
+
if (indexSource !== undefined) {
|
|
845
|
+
set(indexSource, UNINITIALIZED);
|
|
846
|
+
} else if (i in target) {
|
|
847
|
+
const deletedSource = withParent(() => source(UNINITIALIZED));
|
|
848
|
+
sources.set(indexKey, deletedSource);
|
|
849
|
+
}
|
|
717
850
|
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
set(lengthSource, index + 1);
|
|
851
|
+
} else if (typeof prop === "string") {
|
|
852
|
+
const index = Number(prop);
|
|
853
|
+
if (Number.isInteger(index) && index >= 0) {
|
|
854
|
+
const lengthSource = sources.get("length");
|
|
855
|
+
if (lengthSource !== undefined && index >= lengthSource.v) {
|
|
856
|
+
set(lengthSource, index + 1);
|
|
857
|
+
}
|
|
726
858
|
}
|
|
727
859
|
}
|
|
728
860
|
}
|
|
@@ -743,7 +875,7 @@ function proxy(value) {
|
|
|
743
875
|
}
|
|
744
876
|
set(version, get(version) + 1);
|
|
745
877
|
}
|
|
746
|
-
return
|
|
878
|
+
return delete target[prop];
|
|
747
879
|
},
|
|
748
880
|
has(target, prop) {
|
|
749
881
|
if (prop === STATE_SYMBOL) {
|
|
@@ -782,6 +914,7 @@ function proxy(value) {
|
|
|
782
914
|
}
|
|
783
915
|
});
|
|
784
916
|
proxyCleanup.register(proxyObj, { sources, version });
|
|
917
|
+
proxyCache.set(value, proxyObj);
|
|
785
918
|
return proxyObj;
|
|
786
919
|
}
|
|
787
920
|
function toRaw(value) {
|
|
@@ -871,6 +1004,123 @@ function disconnectDerived(derived2) {
|
|
|
871
1004
|
derived2.reactions = null;
|
|
872
1005
|
destroyDerivedEffects(derived2);
|
|
873
1006
|
}
|
|
1007
|
+
// src/primitives/scope.ts
|
|
1008
|
+
var activeScope = null;
|
|
1009
|
+
function getCurrentScope() {
|
|
1010
|
+
return activeScope;
|
|
1011
|
+
}
|
|
1012
|
+
function setActiveScope(scope) {
|
|
1013
|
+
const prev = activeScope;
|
|
1014
|
+
activeScope = scope;
|
|
1015
|
+
return prev;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
class EffectScopeImpl {
|
|
1019
|
+
_active = true;
|
|
1020
|
+
_paused = false;
|
|
1021
|
+
effects = [];
|
|
1022
|
+
cleanups = [];
|
|
1023
|
+
parent = null;
|
|
1024
|
+
scopes = null;
|
|
1025
|
+
constructor(detached = false) {
|
|
1026
|
+
this.parent = activeScope;
|
|
1027
|
+
if (!detached && this.parent) {
|
|
1028
|
+
if (this.parent.scopes === null) {
|
|
1029
|
+
this.parent.scopes = [];
|
|
1030
|
+
}
|
|
1031
|
+
this.parent.scopes.push(this);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
get active() {
|
|
1035
|
+
return this._active;
|
|
1036
|
+
}
|
|
1037
|
+
get paused() {
|
|
1038
|
+
return this._paused;
|
|
1039
|
+
}
|
|
1040
|
+
run(fn) {
|
|
1041
|
+
if (!this._active) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
const prevScope = setActiveScope(this);
|
|
1045
|
+
try {
|
|
1046
|
+
return fn();
|
|
1047
|
+
} finally {
|
|
1048
|
+
setActiveScope(prevScope);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
stop() {
|
|
1052
|
+
if (!this._active)
|
|
1053
|
+
return;
|
|
1054
|
+
for (const effect of [...this.effects]) {
|
|
1055
|
+
destroyEffect(effect);
|
|
1056
|
+
}
|
|
1057
|
+
this.effects.length = 0;
|
|
1058
|
+
for (const cleanup of this.cleanups) {
|
|
1059
|
+
try {
|
|
1060
|
+
cleanup();
|
|
1061
|
+
} catch {}
|
|
1062
|
+
}
|
|
1063
|
+
this.cleanups.length = 0;
|
|
1064
|
+
if (this.scopes) {
|
|
1065
|
+
for (const scope of this.scopes) {
|
|
1066
|
+
scope.stop();
|
|
1067
|
+
}
|
|
1068
|
+
this.scopes.length = 0;
|
|
1069
|
+
}
|
|
1070
|
+
if (this.parent?.scopes) {
|
|
1071
|
+
const idx = this.parent.scopes.indexOf(this);
|
|
1072
|
+
if (idx !== -1) {
|
|
1073
|
+
this.parent.scopes.splice(idx, 1);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
this._active = false;
|
|
1077
|
+
}
|
|
1078
|
+
pause() {
|
|
1079
|
+
if (!this._active || this._paused)
|
|
1080
|
+
return;
|
|
1081
|
+
this._paused = true;
|
|
1082
|
+
for (const effect of this.effects) {
|
|
1083
|
+
effect.f |= INERT;
|
|
1084
|
+
}
|
|
1085
|
+
if (this.scopes) {
|
|
1086
|
+
for (const scope of this.scopes) {
|
|
1087
|
+
scope.pause();
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
resume() {
|
|
1092
|
+
if (!this._active || !this._paused)
|
|
1093
|
+
return;
|
|
1094
|
+
this._paused = false;
|
|
1095
|
+
for (const effect of this.effects) {
|
|
1096
|
+
effect.f &= ~INERT;
|
|
1097
|
+
if ((effect.f & DIRTY) !== 0) {
|
|
1098
|
+
scheduleEffect(effect);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
if (this.scopes) {
|
|
1102
|
+
for (const scope of this.scopes) {
|
|
1103
|
+
scope.resume();
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
function effectScope(detached) {
|
|
1109
|
+
return new EffectScopeImpl(detached);
|
|
1110
|
+
}
|
|
1111
|
+
function onScopeDispose(fn) {
|
|
1112
|
+
if (activeScope) {
|
|
1113
|
+
activeScope.cleanups.push(fn);
|
|
1114
|
+
} else {
|
|
1115
|
+
console.warn("onScopeDispose() called outside of scope context");
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
function registerEffectWithScope(effect) {
|
|
1119
|
+
if (activeScope) {
|
|
1120
|
+
activeScope.effects.push(effect);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
874
1124
|
// src/primitives/effect.ts
|
|
875
1125
|
function createEffect(type, fn, sync, push = true) {
|
|
876
1126
|
const parent = activeEffect;
|
|
@@ -886,6 +1136,7 @@ function createEffect(type, fn, sync, push = true) {
|
|
|
886
1136
|
next: null,
|
|
887
1137
|
wv: 0
|
|
888
1138
|
};
|
|
1139
|
+
registerEffectWithScope(effect);
|
|
889
1140
|
if (sync) {
|
|
890
1141
|
updateEffect(effect);
|
|
891
1142
|
effect.f |= EFFECT_RAN;
|
|
@@ -998,7 +1249,6 @@ effect.tracking = function effectTracking() {
|
|
|
998
1249
|
var bindingCleanup = new FinalizationRegistry((internalSource) => {
|
|
999
1250
|
internalSource.reactions = null;
|
|
1000
1251
|
});
|
|
1001
|
-
var BINDING_SYMBOL = Symbol("binding");
|
|
1002
1252
|
function isBinding(value) {
|
|
1003
1253
|
return value !== null && typeof value === "object" && BINDING_SYMBOL in value;
|
|
1004
1254
|
}
|
|
@@ -1084,6 +1334,130 @@ function untrack(fn) {
|
|
|
1084
1334
|
}
|
|
1085
1335
|
}
|
|
1086
1336
|
var peek = untrack;
|
|
1337
|
+
|
|
1338
|
+
// src/primitives/linked.ts
|
|
1339
|
+
function linkedSignal(config) {
|
|
1340
|
+
let sourceFn;
|
|
1341
|
+
let computation;
|
|
1342
|
+
let equalsFn = Object.is;
|
|
1343
|
+
if (typeof config === "function") {
|
|
1344
|
+
const fn = config;
|
|
1345
|
+
sourceFn = fn;
|
|
1346
|
+
computation = (s) => s;
|
|
1347
|
+
} else {
|
|
1348
|
+
sourceFn = config.source;
|
|
1349
|
+
computation = config.computation;
|
|
1350
|
+
if (config.equal) {
|
|
1351
|
+
equalsFn = config.equal;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
let prevSource = undefined;
|
|
1355
|
+
let prevValue = undefined;
|
|
1356
|
+
let initialized = false;
|
|
1357
|
+
const valueSignal = signal(undefined, { equals: equalsFn });
|
|
1358
|
+
const sourceTracker = derived(() => {
|
|
1359
|
+
const newSource = sourceFn();
|
|
1360
|
+
return newSource;
|
|
1361
|
+
});
|
|
1362
|
+
let manualOverride = false;
|
|
1363
|
+
let lastKnownSource = undefined;
|
|
1364
|
+
const dispose = effect.pre(() => {
|
|
1365
|
+
const currentSource = sourceTracker.value;
|
|
1366
|
+
const sourceChanged = initialized && !Object.is(lastKnownSource, currentSource);
|
|
1367
|
+
if (!initialized || sourceChanged) {
|
|
1368
|
+
const previous = initialized ? { source: prevSource, value: prevValue } : undefined;
|
|
1369
|
+
const newValue = computation(currentSource, previous);
|
|
1370
|
+
prevSource = currentSource;
|
|
1371
|
+
prevValue = newValue;
|
|
1372
|
+
lastKnownSource = currentSource;
|
|
1373
|
+
initialized = true;
|
|
1374
|
+
manualOverride = false;
|
|
1375
|
+
untrack(() => {
|
|
1376
|
+
valueSignal.value = newValue;
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
const accessor = {
|
|
1381
|
+
[LINKED_SYMBOL]: true,
|
|
1382
|
+
get value() {
|
|
1383
|
+
sourceTracker.value;
|
|
1384
|
+
const currentSource = untrack(() => sourceTracker.value);
|
|
1385
|
+
if (initialized && !Object.is(lastKnownSource, currentSource)) {
|
|
1386
|
+
flushSync();
|
|
1387
|
+
}
|
|
1388
|
+
return valueSignal.value;
|
|
1389
|
+
},
|
|
1390
|
+
set value(newValue) {
|
|
1391
|
+
manualOverride = true;
|
|
1392
|
+
prevValue = newValue;
|
|
1393
|
+
valueSignal.value = newValue;
|
|
1394
|
+
},
|
|
1395
|
+
get peek() {
|
|
1396
|
+
return untrack(() => valueSignal.value);
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
return accessor;
|
|
1400
|
+
}
|
|
1401
|
+
function isLinkedSignal(value) {
|
|
1402
|
+
return value !== null && typeof value === "object" && LINKED_SYMBOL in value;
|
|
1403
|
+
}
|
|
1404
|
+
// src/primitives/selector.ts
|
|
1405
|
+
function createSelector(source2, fn = (k, v) => k === v) {
|
|
1406
|
+
const subscribers = new Map;
|
|
1407
|
+
const reactionKeys = new WeakMap;
|
|
1408
|
+
let prevValue;
|
|
1409
|
+
let initialized = false;
|
|
1410
|
+
effect.pre(() => {
|
|
1411
|
+
const value = source2();
|
|
1412
|
+
if (initialized && !Object.is(prevValue, value)) {
|
|
1413
|
+
for (const [key, reactions] of subscribers) {
|
|
1414
|
+
const wasSelected = fn(key, prevValue);
|
|
1415
|
+
const isSelected = fn(key, value);
|
|
1416
|
+
if (wasSelected !== isSelected) {
|
|
1417
|
+
const toRemove = [];
|
|
1418
|
+
for (const reaction of reactions) {
|
|
1419
|
+
if ((reaction.f & DESTROYED) !== 0) {
|
|
1420
|
+
toRemove.push(reaction);
|
|
1421
|
+
continue;
|
|
1422
|
+
}
|
|
1423
|
+
setSignalStatus(reaction, DIRTY);
|
|
1424
|
+
if ((reaction.f & EFFECT) !== 0 && (reaction.f & DERIVED) === 0) {
|
|
1425
|
+
scheduleEffect(reaction);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
for (const r of toRemove) {
|
|
1429
|
+
reactions.delete(r);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
prevValue = value;
|
|
1435
|
+
initialized = true;
|
|
1436
|
+
});
|
|
1437
|
+
return (key) => {
|
|
1438
|
+
const currentValue = prevValue;
|
|
1439
|
+
if (activeReaction !== null) {
|
|
1440
|
+
const reaction = activeReaction;
|
|
1441
|
+
if ((reaction.f & DESTROYED) === 0) {
|
|
1442
|
+
let keySubscribers = subscribers.get(key);
|
|
1443
|
+
if (!keySubscribers) {
|
|
1444
|
+
keySubscribers = new Set;
|
|
1445
|
+
subscribers.set(key, keySubscribers);
|
|
1446
|
+
}
|
|
1447
|
+
if (!keySubscribers.has(reaction)) {
|
|
1448
|
+
keySubscribers.add(reaction);
|
|
1449
|
+
let keys = reactionKeys.get(reaction);
|
|
1450
|
+
if (!keys) {
|
|
1451
|
+
keys = new Set;
|
|
1452
|
+
reactionKeys.set(reaction, keys);
|
|
1453
|
+
}
|
|
1454
|
+
keys.add(key);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
return fn(key, currentValue);
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1087
1461
|
// src/collections/map.ts
|
|
1088
1462
|
var mapCleanup = new FinalizationRegistry((data) => {
|
|
1089
1463
|
data.version.reactions = null;
|