-
Notifications
You must be signed in to change notification settings - Fork 6
/
signal.js
64 lines (60 loc) · 1.55 KB
/
signal.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// ulive copy, stable minimal implementation
let current, batched;
export let signal = (v, s, obs = new Set) => (
s = {
get value() {
current?.deps.push(obs.add(current));
return v
},
set value(val) {
if (val === v) return
v = val;
for (let sub of obs) batched ? batched.add(sub) : sub(); // notify effects
},
peek() { return v },
},
s.toJSON = s.then = s.toString = s.valueOf = () => s.value,
s
),
effect = (fn, teardown, fx, deps) => (
fx = (prev) => {
teardown?.call?.();
prev = current, current = fx;
try { teardown = fn(); } finally { current = prev; }
},
deps = fx.deps = [],
fx(),
(dep) => { teardown?.call?.(); while (dep = deps.pop()) dep.delete(fx); }
),
computed = (fn, s = signal(), c, e) => (
c = {
get value() {
e ||= effect(() => s.value = fn());
return s.value
},
peek: s.peek
},
c.toJSON = c.then = c.toString = c.valueOf = () => c.value,
c
),
batch = (fn) => {
let fxs = batched;
if (!fxs) batched = new Set;
try { fn(); }
finally {
if (!fxs) {
fxs = batched;
batched = null;
for (const fx of fxs) fx();
}
}
},
untracked = (fn, prev, v) => (prev = current, current = null, v = fn(), current = prev, v);
// signals adapter - allows switching signals implementation and not depend on core
export function use(s) {
signal = s.signal
effect = s.effect
computed = s.computed
batch = s.batch || (fn => fn())
untracked = s.untracked || batch
}