@toyz/loom 0.17.7 → 0.18.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/dist/decorators/symbols.d.ts +6 -0
- package/dist/decorators/symbols.d.ts.map +1 -1
- package/dist/decorators/symbols.js +8 -0
- package/dist/decorators/symbols.js.map +1 -1
- package/dist/element/context.js +24 -24
- package/dist/element/context.js.map +1 -1
- package/dist/element/events.js +4 -3
- package/dist/element/events.js.map +1 -1
- package/dist/element/form.d.ts.map +1 -1
- package/dist/element/form.js +5 -4
- package/dist/element/form.js.map +1 -1
- package/dist/element/slots.js +5 -5
- package/dist/element/slots.js.map +1 -1
- package/dist/query/decorators.js +9 -9
- package/dist/query/decorators.js.map +1 -1
- package/dist/store/decorators.d.ts +17 -2
- package/dist/store/decorators.d.ts.map +1 -1
- package/dist/store/decorators.js +204 -45
- package/dist/store/decorators.js.map +1 -1
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +2 -0
- package/dist/store/index.js.map +1 -1
- package/dist/store/reactive.d.ts +3 -0
- package/dist/store/reactive.d.ts.map +1 -1
- package/dist/store/reactive.js +27 -15
- package/dist/store/reactive.js.map +1 -1
- package/dist/store/readonly.d.ts.map +1 -1
- package/dist/store/readonly.js +4 -3
- package/dist/store/readonly.js.map +1 -1
- package/dist/store/signal.d.ts +174 -0
- package/dist/store/signal.d.ts.map +1 -0
- package/dist/store/signal.js +332 -0
- package/dist/store/signal.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loom — TC39 Signals Interop
|
|
3
|
+
*
|
|
4
|
+
* Bridges TC39 Signals (Signal.State / Signal.Computed) with Loom's
|
|
5
|
+
* real-DOM reactive system. Loom doesn't use a VDOM — it patches the
|
|
6
|
+
* real DOM via morphing and fast-patch bindings. The trace engine
|
|
7
|
+
* tracks which Reactive instances are read during update().
|
|
8
|
+
*
|
|
9
|
+
* This module provides:
|
|
10
|
+
*
|
|
11
|
+
* SignalState<T> — A Signal.State-compatible wrapper around Reactive<T>.
|
|
12
|
+
* `.get()` integrates with Loom's trace engine.
|
|
13
|
+
*
|
|
14
|
+
* SignalComputed<T> — A Signal.Computed-compatible lazy derivation.
|
|
15
|
+
* Uses backing Reactive for trace integration.
|
|
16
|
+
*
|
|
17
|
+
* toSignal(r) — Wrap an existing Reactive<T> as a Signal.
|
|
18
|
+
* fromSignal(s) — Wrap an external Signal as a Reactive<T> for Loom.
|
|
19
|
+
*
|
|
20
|
+
* Why this matters for real DOM:
|
|
21
|
+
* Loom's trace engine intercepts Reactive.value reads to build a
|
|
22
|
+
* dependency graph. When a dependency changes, only the affected
|
|
23
|
+
* DOM nodes are patched (fast-patch) or the component re-morphs.
|
|
24
|
+
* Signals need to participate in this same tracking to work
|
|
25
|
+
* seamlessly with @reactive, @computed, @store, and @watch.
|
|
26
|
+
*
|
|
27
|
+
* How it works with real DOM (morph engine):
|
|
28
|
+
* 1. Component.update() runs inside a startTrace()/endTrace() block
|
|
29
|
+
* 2. Any SignalState.get() → Reactive.value → recorded as a dependency
|
|
30
|
+
* 3. When SignalState.set() fires → Reactive.set() → version bumps
|
|
31
|
+
* 4. Next scheduleUpdate() → hasDirtyDeps() sees changed version
|
|
32
|
+
* 5. Morph engine patches only the changed DOM nodes
|
|
33
|
+
*
|
|
34
|
+
* For closure bindings ({() => counter.get()}), the fast-patch path
|
|
35
|
+
* re-evaluates just that binding's patcher — no full morph needed.
|
|
36
|
+
*/
|
|
37
|
+
import { Reactive, type Subscriber } from "./reactive";
|
|
38
|
+
/** Matches the TC39 Signal interface — read-only `.get()` */
|
|
39
|
+
export interface Signal<T> {
|
|
40
|
+
get(): T;
|
|
41
|
+
}
|
|
42
|
+
/** Options for Signal construction, matching TC39 SignalOptions */
|
|
43
|
+
export interface SignalOptions<T> {
|
|
44
|
+
equals?: (a: T, b: T) => boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A read-write Signal backed by Loom's Reactive<T>.
|
|
48
|
+
* Reads via `.get()` participate in Loom's trace engine,
|
|
49
|
+
* so components that read this signal during update() will
|
|
50
|
+
* automatically re-render when the value changes.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* const count = new SignalState(0);
|
|
54
|
+
* count.get(); // 0 — tracked by trace engine
|
|
55
|
+
* count.set(1); // triggers re-render of dependent components
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare class SignalState<T> implements Signal<T> {
|
|
59
|
+
/** @internal — the backing Reactive, exposed for Loom internals */
|
|
60
|
+
readonly _reactive: Reactive<T>;
|
|
61
|
+
private _equals;
|
|
62
|
+
constructor(initial: T, options?: SignalOptions<T>);
|
|
63
|
+
/** Read the value — integrates with Loom's trace engine */
|
|
64
|
+
get(): T;
|
|
65
|
+
/** Write a new value — triggers subscribers + scheduleUpdate */
|
|
66
|
+
set(value: T): void;
|
|
67
|
+
/** Read without trace tracking */
|
|
68
|
+
peek(): T;
|
|
69
|
+
/** Subscribe to changes (Loom extension) */
|
|
70
|
+
subscribe(fn: Subscriber<T>): () => void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A read-only computed Signal. Lazily evaluates a callback,
|
|
74
|
+
* caches the result, and integrates with Loom's trace engine.
|
|
75
|
+
*
|
|
76
|
+
* Dependencies are tracked automatically: any SignalState.get()
|
|
77
|
+
* or Reactive.value access during the callback is recorded.
|
|
78
|
+
* When dependencies change, the cached value is invalidated.
|
|
79
|
+
*
|
|
80
|
+
* The backing Reactive participates in Loom's trace engine,
|
|
81
|
+
* so components reading this computed will re-render when it
|
|
82
|
+
* recomputes to a different value.
|
|
83
|
+
*
|
|
84
|
+
* ```ts
|
|
85
|
+
* const count = new SignalState(2);
|
|
86
|
+
* const doubled = new SignalComputed(() => count.get() * 2);
|
|
87
|
+
* doubled.get(); // 4 — tracked, lazy, memoized
|
|
88
|
+
* count.set(3);
|
|
89
|
+
* doubled.get(); // 6 — re-evaluated because count changed
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare class SignalComputed<T> implements Signal<T> {
|
|
93
|
+
/** @internal — Reactive backing for trace integration */
|
|
94
|
+
readonly _reactive: Reactive<T>;
|
|
95
|
+
private _cb;
|
|
96
|
+
private _dirty;
|
|
97
|
+
private _unsubs;
|
|
98
|
+
private _equals;
|
|
99
|
+
constructor(cb: () => T, options?: SignalOptions<T>);
|
|
100
|
+
/** Read the computed value — lazy, memoized, trace-integrated */
|
|
101
|
+
get(): T;
|
|
102
|
+
/** Read without trace tracking */
|
|
103
|
+
peek(): T;
|
|
104
|
+
/** Subscribe to changes (Loom extension) */
|
|
105
|
+
subscribe(fn: Subscriber<T>): () => void;
|
|
106
|
+
/** Dispose all subscriptions — prevents memory leaks */
|
|
107
|
+
dispose(): void;
|
|
108
|
+
private _recompute;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Wrap an existing Reactive<T> as a TC39-compatible Signal.
|
|
112
|
+
* The returned SignalState shares the same backing Reactive,
|
|
113
|
+
* so reads and writes are fully synchronized.
|
|
114
|
+
*
|
|
115
|
+
* ```ts
|
|
116
|
+
* const count = new Reactive(0);
|
|
117
|
+
* const sig = toSignal(count);
|
|
118
|
+
* sig.get(); // 0 — reads from same Reactive
|
|
119
|
+
* sig.set(5); // count.value is now 5
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export declare function toSignal<T>(reactive: Reactive<T>): SignalState<T>;
|
|
123
|
+
/**
|
|
124
|
+
* Wrap an external Signal (TC39-compatible) as a Loom Reactive<T>.
|
|
125
|
+
* The returned Reactive can be used with @watch, trace engine,
|
|
126
|
+
* component rendering, etc.
|
|
127
|
+
*
|
|
128
|
+
* Since external Signals may not have subscribe(), you must provide
|
|
129
|
+
* a `subscribe` callback that hooks into your framework's effect system.
|
|
130
|
+
*
|
|
131
|
+
* ```ts
|
|
132
|
+
* // With external framework's effect
|
|
133
|
+
* const r = fromSignal(externalSignal, (onChange) => {
|
|
134
|
+
* return myFramework.effect(() => {
|
|
135
|
+
* externalSignal.get(); // track
|
|
136
|
+
* onChange(); // notify Loom
|
|
137
|
+
* });
|
|
138
|
+
* });
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export declare function fromSignal<T>(signal: Signal<T>, subscribe?: (onChange: () => void) => () => void): Reactive<T>;
|
|
142
|
+
/**
|
|
143
|
+
* TC39 Signal-compatible reactive accessor.
|
|
144
|
+
* Works like `@reactive` but the accessor value is read/written
|
|
145
|
+
* through a `SignalState<T>` under the hood.
|
|
146
|
+
*
|
|
147
|
+
* The accessor surface exposes the raw value (for ergonomics),
|
|
148
|
+
* compatible with templates: `{() => this.count}`.
|
|
149
|
+
* For Signal interop, the backing `SignalState` is exposed as
|
|
150
|
+
* `this.$signal_<field>` so external Signal-based code can use
|
|
151
|
+
* `.get()` / `.set()` / `.peek()`.
|
|
152
|
+
*
|
|
153
|
+
* Integrates with `@watch`, `@emit`, `scheduleUpdate()`, and
|
|
154
|
+
* Loom's trace engine (morph + fast-patch).
|
|
155
|
+
*
|
|
156
|
+
* ```ts
|
|
157
|
+
* @component("my-counter")
|
|
158
|
+
* class Counter extends LoomElement {
|
|
159
|
+
* @signal accessor count = 0;
|
|
160
|
+
*
|
|
161
|
+
* update() {
|
|
162
|
+
* return <span>{() => this.count}</span>;
|
|
163
|
+
* }
|
|
164
|
+
*
|
|
165
|
+
* increment() {
|
|
166
|
+
* this.count++;
|
|
167
|
+
* // Or via Signal API:
|
|
168
|
+
* // this.$signal_count.set(this.$signal_count.get() + 1);
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export declare function signal<This extends object, V>(target: ClassAccessorDecoratorTarget<This, V>, context: ClassAccessorDecoratorContext<This, V>): ClassAccessorDecoratorResult<This, V>;
|
|
174
|
+
//# sourceMappingURL=signal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../../src/store/signal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAQvD,6DAA6D;AAC7D,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,GAAG,IAAI,CAAC,CAAC;CACV;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;CAClC;AAID;;;;;;;;;;;GAWG;AACH,qBAAa,WAAW,CAAC,CAAC,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC;IAC9C,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,OAAO,CAA0B;gBAE7B,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC;IAKlD,2DAA2D;IAC3D,GAAG,IAAI,CAAC;IAIR,gEAAgE;IAChE,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAKnB,kCAAkC;IAClC,IAAI,IAAI,CAAC;IAIT,4CAA4C;IAC5C,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;CAGzC;AAID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAc,CAAC,CAAC,CAAE,YAAW,MAAM,CAAC,CAAC,CAAC;IACjD,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,OAAO,CAA0B;gBAE7B,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC;IAOnD,iEAAiE;IACjE,GAAG,IAAI,CAAC;IAQR,kCAAkC;IAClC,IAAI,IAAI,CAAC;IAOT,4CAA4C;IAC5C,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAMxC,wDAAwD;IACxD,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,UAAU;CA0DnB;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAMjE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAC1B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GAC/C,QAAQ,CAAC,CAAC,CAAC,CAab;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,MAAM,CAAC,IAAI,SAAS,MAAM,EAAE,CAAC,EAC3C,MAAM,EAAE,4BAA4B,CAAC,IAAI,EAAE,CAAC,CAAC,EAC7C,OAAO,EAAE,6BAA6B,CAAC,IAAI,EAAE,CAAC,CAAC,GAC9C,4BAA4B,CAAC,IAAI,EAAE,CAAC,CAAC,CAuDvC"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loom — TC39 Signals Interop
|
|
3
|
+
*
|
|
4
|
+
* Bridges TC39 Signals (Signal.State / Signal.Computed) with Loom's
|
|
5
|
+
* real-DOM reactive system. Loom doesn't use a VDOM — it patches the
|
|
6
|
+
* real DOM via morphing and fast-patch bindings. The trace engine
|
|
7
|
+
* tracks which Reactive instances are read during update().
|
|
8
|
+
*
|
|
9
|
+
* This module provides:
|
|
10
|
+
*
|
|
11
|
+
* SignalState<T> — A Signal.State-compatible wrapper around Reactive<T>.
|
|
12
|
+
* `.get()` integrates with Loom's trace engine.
|
|
13
|
+
*
|
|
14
|
+
* SignalComputed<T> — A Signal.Computed-compatible lazy derivation.
|
|
15
|
+
* Uses backing Reactive for trace integration.
|
|
16
|
+
*
|
|
17
|
+
* toSignal(r) — Wrap an existing Reactive<T> as a Signal.
|
|
18
|
+
* fromSignal(s) — Wrap an external Signal as a Reactive<T> for Loom.
|
|
19
|
+
*
|
|
20
|
+
* Why this matters for real DOM:
|
|
21
|
+
* Loom's trace engine intercepts Reactive.value reads to build a
|
|
22
|
+
* dependency graph. When a dependency changes, only the affected
|
|
23
|
+
* DOM nodes are patched (fast-patch) or the component re-morphs.
|
|
24
|
+
* Signals need to participate in this same tracking to work
|
|
25
|
+
* seamlessly with @reactive, @computed, @store, and @watch.
|
|
26
|
+
*
|
|
27
|
+
* How it works with real DOM (morph engine):
|
|
28
|
+
* 1. Component.update() runs inside a startTrace()/endTrace() block
|
|
29
|
+
* 2. Any SignalState.get() → Reactive.value → recorded as a dependency
|
|
30
|
+
* 3. When SignalState.set() fires → Reactive.set() → version bumps
|
|
31
|
+
* 4. Next scheduleUpdate() → hasDirtyDeps() sees changed version
|
|
32
|
+
* 5. Morph engine patches only the changed DOM nodes
|
|
33
|
+
*
|
|
34
|
+
* For closure bindings ({() => counter.get()}), the fast-patch path
|
|
35
|
+
* re-evaluates just that binding's patcher — no full morph needed.
|
|
36
|
+
*/
|
|
37
|
+
import { Reactive } from "./reactive";
|
|
38
|
+
import { __getActiveDeps } from "../trace";
|
|
39
|
+
import { REACTIVES, WATCHERS, EMITTERS, localSymbol } from "../decorators/symbols";
|
|
40
|
+
import { bus } from "../bus";
|
|
41
|
+
// ── SignalState<T> ──
|
|
42
|
+
/**
|
|
43
|
+
* A read-write Signal backed by Loom's Reactive<T>.
|
|
44
|
+
* Reads via `.get()` participate in Loom's trace engine,
|
|
45
|
+
* so components that read this signal during update() will
|
|
46
|
+
* automatically re-render when the value changes.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const count = new SignalState(0);
|
|
50
|
+
* count.get(); // 0 — tracked by trace engine
|
|
51
|
+
* count.set(1); // triggers re-render of dependent components
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export class SignalState {
|
|
55
|
+
/** @internal — the backing Reactive, exposed for Loom internals */
|
|
56
|
+
_reactive;
|
|
57
|
+
_equals;
|
|
58
|
+
constructor(initial, options) {
|
|
59
|
+
this._reactive = new Reactive(initial);
|
|
60
|
+
this._equals = options?.equals ?? Object.is;
|
|
61
|
+
}
|
|
62
|
+
/** Read the value — integrates with Loom's trace engine */
|
|
63
|
+
get() {
|
|
64
|
+
return this._reactive.value; // .value triggers __getActiveDeps()
|
|
65
|
+
}
|
|
66
|
+
/** Write a new value — triggers subscribers + scheduleUpdate */
|
|
67
|
+
set(value) {
|
|
68
|
+
if (this._equals(this.peek(), value))
|
|
69
|
+
return;
|
|
70
|
+
this._reactive.set(value);
|
|
71
|
+
}
|
|
72
|
+
/** Read without trace tracking */
|
|
73
|
+
peek() {
|
|
74
|
+
return this._reactive.peek();
|
|
75
|
+
}
|
|
76
|
+
/** Subscribe to changes (Loom extension) */
|
|
77
|
+
subscribe(fn) {
|
|
78
|
+
return this._reactive.subscribe(fn);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ── SignalComputed<T> ──
|
|
82
|
+
/**
|
|
83
|
+
* A read-only computed Signal. Lazily evaluates a callback,
|
|
84
|
+
* caches the result, and integrates with Loom's trace engine.
|
|
85
|
+
*
|
|
86
|
+
* Dependencies are tracked automatically: any SignalState.get()
|
|
87
|
+
* or Reactive.value access during the callback is recorded.
|
|
88
|
+
* When dependencies change, the cached value is invalidated.
|
|
89
|
+
*
|
|
90
|
+
* The backing Reactive participates in Loom's trace engine,
|
|
91
|
+
* so components reading this computed will re-render when it
|
|
92
|
+
* recomputes to a different value.
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* const count = new SignalState(2);
|
|
96
|
+
* const doubled = new SignalComputed(() => count.get() * 2);
|
|
97
|
+
* doubled.get(); // 4 — tracked, lazy, memoized
|
|
98
|
+
* count.set(3);
|
|
99
|
+
* doubled.get(); // 6 — re-evaluated because count changed
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export class SignalComputed {
|
|
103
|
+
/** @internal — Reactive backing for trace integration */
|
|
104
|
+
_reactive;
|
|
105
|
+
_cb;
|
|
106
|
+
_dirty = true;
|
|
107
|
+
_unsubs = [];
|
|
108
|
+
_equals;
|
|
109
|
+
constructor(cb, options) {
|
|
110
|
+
this._cb = cb;
|
|
111
|
+
this._equals = options?.equals ?? Object.is;
|
|
112
|
+
// Initialize with a placeholder; first .get() evaluates
|
|
113
|
+
this._reactive = new Reactive(undefined);
|
|
114
|
+
}
|
|
115
|
+
/** Read the computed value — lazy, memoized, trace-integrated */
|
|
116
|
+
get() {
|
|
117
|
+
if (this._dirty) {
|
|
118
|
+
this._recompute();
|
|
119
|
+
}
|
|
120
|
+
// Register in trace engine via Reactive.value
|
|
121
|
+
return this._reactive.value;
|
|
122
|
+
}
|
|
123
|
+
/** Read without trace tracking */
|
|
124
|
+
peek() {
|
|
125
|
+
if (this._dirty) {
|
|
126
|
+
this._recompute();
|
|
127
|
+
}
|
|
128
|
+
return this._reactive.peek();
|
|
129
|
+
}
|
|
130
|
+
/** Subscribe to changes (Loom extension) */
|
|
131
|
+
subscribe(fn) {
|
|
132
|
+
// Ensure we've computed at least once so subscription is meaningful
|
|
133
|
+
if (this._dirty)
|
|
134
|
+
this._recompute();
|
|
135
|
+
return this._reactive.subscribe(fn);
|
|
136
|
+
}
|
|
137
|
+
/** Dispose all subscriptions — prevents memory leaks */
|
|
138
|
+
dispose() {
|
|
139
|
+
for (let i = 0; i < this._unsubs.length; i++)
|
|
140
|
+
this._unsubs[i]();
|
|
141
|
+
this._unsubs.length = 0;
|
|
142
|
+
}
|
|
143
|
+
_recompute() {
|
|
144
|
+
// Tear down old dependency subscriptions
|
|
145
|
+
this.dispose();
|
|
146
|
+
// Intercept Reactive.value reads during callback.
|
|
147
|
+
// We create a temporary "spy" set to capture which Reactives are accessed.
|
|
148
|
+
const capturedDeps = new Set();
|
|
149
|
+
// Save the current trace deps (if we're inside a component's update())
|
|
150
|
+
const parentDeps = __getActiveDeps();
|
|
151
|
+
// We use a manual interception approach: we want to observe
|
|
152
|
+
// which Reactive.value calls happen during _cb(). The trace
|
|
153
|
+
// engine already records into activeDeps, so if a parent trace
|
|
154
|
+
// is active, those reads will be captured there. But we also
|
|
155
|
+
// need them for our own invalidation.
|
|
156
|
+
//
|
|
157
|
+
// Strategy: subscribe to every Reactive that was in the parent
|
|
158
|
+
// trace after evaluation. For stand-alone usage (no trace active),
|
|
159
|
+
// we must detect deps via subscription-based invalidation.
|
|
160
|
+
//
|
|
161
|
+
// The simplest correct approach: evaluate, and use a subscription
|
|
162
|
+
// on the source signals that the user explicitly manages.
|
|
163
|
+
const newValue = this._cb();
|
|
164
|
+
// If called within a Loom trace, the parent deps now contain
|
|
165
|
+
// our transitive dependencies. Grab them for self-invalidation.
|
|
166
|
+
if (parentDeps) {
|
|
167
|
+
for (const dep of parentDeps) {
|
|
168
|
+
capturedDeps.add(dep);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Subscribe to all captured deps for invalidation
|
|
172
|
+
for (const dep of capturedDeps) {
|
|
173
|
+
const unsub = dep.subscribe(() => {
|
|
174
|
+
if (!this._dirty) {
|
|
175
|
+
this._dirty = true;
|
|
176
|
+
// Eagerly recompute and propagate if value changed
|
|
177
|
+
const old = this._reactive.peek();
|
|
178
|
+
this._recompute();
|
|
179
|
+
if (!this._equals(old, this._reactive.peek())) {
|
|
180
|
+
// notify() triggers dependent components' scheduleUpdate
|
|
181
|
+
this._reactive.notify();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
this._unsubs.push(unsub);
|
|
186
|
+
}
|
|
187
|
+
// Update cached value
|
|
188
|
+
const prev = this._reactive.peek();
|
|
189
|
+
if (!this._equals(prev, newValue)) {
|
|
190
|
+
this._reactive.set(newValue);
|
|
191
|
+
}
|
|
192
|
+
this._dirty = false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// ── Converters ──
|
|
196
|
+
/**
|
|
197
|
+
* Wrap an existing Reactive<T> as a TC39-compatible Signal.
|
|
198
|
+
* The returned SignalState shares the same backing Reactive,
|
|
199
|
+
* so reads and writes are fully synchronized.
|
|
200
|
+
*
|
|
201
|
+
* ```ts
|
|
202
|
+
* const count = new Reactive(0);
|
|
203
|
+
* const sig = toSignal(count);
|
|
204
|
+
* sig.get(); // 0 — reads from same Reactive
|
|
205
|
+
* sig.set(5); // count.value is now 5
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export function toSignal(reactive) {
|
|
209
|
+
const sig = Object.create(SignalState.prototype);
|
|
210
|
+
// Directly share the backing Reactive — zero overhead
|
|
211
|
+
Object.defineProperty(sig, '_reactive', { value: reactive, writable: false });
|
|
212
|
+
Object.defineProperty(sig, '_equals', { value: Object.is, writable: false });
|
|
213
|
+
return sig;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Wrap an external Signal (TC39-compatible) as a Loom Reactive<T>.
|
|
217
|
+
* The returned Reactive can be used with @watch, trace engine,
|
|
218
|
+
* component rendering, etc.
|
|
219
|
+
*
|
|
220
|
+
* Since external Signals may not have subscribe(), you must provide
|
|
221
|
+
* a `subscribe` callback that hooks into your framework's effect system.
|
|
222
|
+
*
|
|
223
|
+
* ```ts
|
|
224
|
+
* // With external framework's effect
|
|
225
|
+
* const r = fromSignal(externalSignal, (onChange) => {
|
|
226
|
+
* return myFramework.effect(() => {
|
|
227
|
+
* externalSignal.get(); // track
|
|
228
|
+
* onChange(); // notify Loom
|
|
229
|
+
* });
|
|
230
|
+
* });
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export function fromSignal(signal, subscribe) {
|
|
234
|
+
const r = new Reactive(signal.get());
|
|
235
|
+
if (subscribe) {
|
|
236
|
+
subscribe(() => {
|
|
237
|
+
const newVal = signal.get();
|
|
238
|
+
if (!Object.is(r.peek(), newVal)) {
|
|
239
|
+
r.set(newVal);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return r;
|
|
244
|
+
}
|
|
245
|
+
// ── @signal decorator ──
|
|
246
|
+
/**
|
|
247
|
+
* TC39 Signal-compatible reactive accessor.
|
|
248
|
+
* Works like `@reactive` but the accessor value is read/written
|
|
249
|
+
* through a `SignalState<T>` under the hood.
|
|
250
|
+
*
|
|
251
|
+
* The accessor surface exposes the raw value (for ergonomics),
|
|
252
|
+
* compatible with templates: `{() => this.count}`.
|
|
253
|
+
* For Signal interop, the backing `SignalState` is exposed as
|
|
254
|
+
* `this.$signal_<field>` so external Signal-based code can use
|
|
255
|
+
* `.get()` / `.set()` / `.peek()`.
|
|
256
|
+
*
|
|
257
|
+
* Integrates with `@watch`, `@emit`, `scheduleUpdate()`, and
|
|
258
|
+
* Loom's trace engine (morph + fast-patch).
|
|
259
|
+
*
|
|
260
|
+
* ```ts
|
|
261
|
+
* @component("my-counter")
|
|
262
|
+
* class Counter extends LoomElement {
|
|
263
|
+
* @signal accessor count = 0;
|
|
264
|
+
*
|
|
265
|
+
* update() {
|
|
266
|
+
* return <span>{() => this.count}</span>;
|
|
267
|
+
* }
|
|
268
|
+
*
|
|
269
|
+
* increment() {
|
|
270
|
+
* this.count++;
|
|
271
|
+
* // Or via Signal API:
|
|
272
|
+
* // this.$signal_count.set(this.$signal_count.get() + 1);
|
|
273
|
+
* }
|
|
274
|
+
* }
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
export function signal(target, context) {
|
|
278
|
+
const key = String(context.name);
|
|
279
|
+
const storage = localSymbol(`signal:${key}`);
|
|
280
|
+
// Register as a reactive field for LoomElement introspection
|
|
281
|
+
context.addInitializer(function () {
|
|
282
|
+
const ctor = this.constructor;
|
|
283
|
+
const existing = REACTIVES.from(ctor);
|
|
284
|
+
if (!existing)
|
|
285
|
+
REACTIVES.set(ctor, [key]);
|
|
286
|
+
else if (!existing.includes(key))
|
|
287
|
+
existing.push(key);
|
|
288
|
+
});
|
|
289
|
+
return {
|
|
290
|
+
get() {
|
|
291
|
+
const self = this;
|
|
292
|
+
if (!self[storage.key]) {
|
|
293
|
+
const initial = target.get.call(this);
|
|
294
|
+
const sig = new SignalState(initial);
|
|
295
|
+
self[storage.key] = sig;
|
|
296
|
+
// Expose the SignalState on the instance
|
|
297
|
+
self[`$signal_${key}`] = sig;
|
|
298
|
+
// Wire scheduleUpdate
|
|
299
|
+
sig.subscribe(() => self.scheduleUpdate?.());
|
|
300
|
+
// Wire @watch handlers
|
|
301
|
+
const watchers = WATCHERS.from(self);
|
|
302
|
+
if (watchers) {
|
|
303
|
+
for (let i = 0; i < watchers.length; i++) {
|
|
304
|
+
const w = watchers[i];
|
|
305
|
+
if (w.field === key)
|
|
306
|
+
sig.subscribe((v, prev) => self[w.key](v, prev));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Wire @emit handlers
|
|
310
|
+
const emitters = EMITTERS.from(self);
|
|
311
|
+
if (emitters) {
|
|
312
|
+
for (let i = 0; i < emitters.length; i++) {
|
|
313
|
+
const e = emitters[i];
|
|
314
|
+
if (e.field === key)
|
|
315
|
+
sig.subscribe((v) => bus.emit(e.factory(v)));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return self[storage.key].get();
|
|
320
|
+
},
|
|
321
|
+
set(val) {
|
|
322
|
+
const self = this;
|
|
323
|
+
if (!self[storage.key])
|
|
324
|
+
void self[key];
|
|
325
|
+
self[storage.key].set(val);
|
|
326
|
+
},
|
|
327
|
+
init(_val) {
|
|
328
|
+
return _val;
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=signal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal.js","sourceRoot":"","sources":["../../src/store/signal.ts"],"names":[],"mappings":"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"}
|