@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.
@@ -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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toyz/loom",
3
- "version": "0.17.7",
3
+ "version": "0.18.0",
4
4
  "type": "module",
5
5
  "description": "Decorator-driven web component framework with reactive state, DOM morphing, DI, and JSX",
6
6
  "license": "MIT",