balises 0.8.0 → 0.8.2
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 +18 -35
- package/dist/balises.esm.js +14 -8
- package/dist/balises.esm.js.map +1 -1
- package/dist/balises.iife.js +14 -8
- package/dist/balises.iife.js.map +1 -1
- package/dist/balises.iife.min.js +1 -1
- package/dist/balises.iife.min.js.map +1 -1
- package/dist/esm/each.d.ts +9 -38
- package/dist/esm/each.d.ts.map +1 -1
- package/dist/esm/each.js +228 -253
- package/dist/esm/each.js.map +1 -1
- package/dist/esm/signals/computed.d.ts.map +1 -1
- package/dist/esm/signals/computed.js +14 -6
- package/dist/esm/signals/computed.js.map +1 -1
- package/dist/esm/signals/context.d.ts +2 -0
- package/dist/esm/signals/context.d.ts.map +1 -1
- package/dist/esm/signals/context.js +1 -1
- package/dist/esm/signals/context.js.map +1 -1
- package/dist/esm/signals/signal.js +1 -1
- package/dist/esm/signals/signal.js.map +1 -1
- package/dist/esm/template.d.ts.map +1 -1
- package/dist/esm/template.js +11 -3
- package/dist/esm/template.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -268,19 +268,12 @@ When rendering lists that change frequently, use `each()` for keyed reconciliati
|
|
|
268
268
|
|
|
269
269
|
**Note:** The `each()` function is opt-in via the `balises/each` import to keep the base bundle small. Use `html.with(eachPlugin)` to enable keyed list support.
|
|
270
270
|
|
|
271
|
-
**Two forms:**
|
|
272
|
-
|
|
273
|
-
1. **Two-arg form** (object reference as key): Render receives raw item. DOM reused only when same object reference appears.
|
|
274
|
-
2. **Three-arg form** (explicit key function): Render receives `ReadonlySignal<T>`. DOM reused when keys match, even with new object references.
|
|
275
|
-
|
|
276
271
|
```ts
|
|
277
272
|
import { html as baseHtml, signal } from "balises";
|
|
278
273
|
import eachPlugin, { each } from "balises/each";
|
|
279
274
|
|
|
280
275
|
const html = baseHtml.with(eachPlugin);
|
|
281
276
|
|
|
282
|
-
// Three-arg form: explicit key, receives ReadonlySignal
|
|
283
|
-
// DOM is preserved when keys match (ideal for API data)
|
|
284
277
|
const users = signal([
|
|
285
278
|
{ id: 1, name: "Alice" },
|
|
286
279
|
{ id: 2, name: "Bob" },
|
|
@@ -302,25 +295,15 @@ users.value = [
|
|
|
302
295
|
{ id: 2, name: "Bobby" },
|
|
303
296
|
{ id: 3, name: "Carol" }, // New key - new DOM created
|
|
304
297
|
];
|
|
305
|
-
|
|
306
|
-
// Two-arg form: object reference as key, receives raw item
|
|
307
|
-
const items = signal([{ name: "Item 1" }, { name: "Item 2" }]);
|
|
308
|
-
|
|
309
|
-
html`
|
|
310
|
-
<ul>
|
|
311
|
-
${each(items, (item) => html`<li>${item.name}</li>`)}
|
|
312
|
-
</ul>
|
|
313
|
-
`.render();
|
|
314
298
|
```
|
|
315
299
|
|
|
316
|
-
|
|
300
|
+
Signature:
|
|
317
301
|
|
|
318
302
|
```ts
|
|
319
|
-
each(list, keyFn, renderFn); //
|
|
320
|
-
each(list, renderFn); // Two-arg: object reference as key, renderFn receives raw T
|
|
303
|
+
each(list, keyFn, renderFn); // keyFn extracts key, renderFn receives ReadonlySignal<T>
|
|
321
304
|
```
|
|
322
305
|
|
|
323
|
-
**Important:**
|
|
306
|
+
**Important:** Access item properties through `itemSignal.value` and wrap in `() => ...` for reactive updates.
|
|
324
307
|
|
|
325
308
|
## Reactivity API
|
|
326
309
|
|
|
@@ -717,23 +700,23 @@ Performance comparison of Balises against other popular reactive libraries. Benc
|
|
|
717
700
|
┌───────┬───────────────────┬───────┬───────────────┬──────────────────┐
|
|
718
701
|
│ Rank │ Library │ Score │ Avg Time (μs) │ vs Fastest │
|
|
719
702
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
720
|
-
│ #1 🏆 │ preact@1.12.1 │ 0.000 │
|
|
703
|
+
│ #1 🏆 │ preact@1.12.1 │ 0.000 │ 63.12 │ 1.00x (baseline) │
|
|
721
704
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
722
|
-
│ #2 │ balises@0.
|
|
705
|
+
│ #2 │ balises@0.8.1 │ 0.062 │ 96.24 │ 1.52x │
|
|
723
706
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
724
|
-
│ #3 │ vue@3.5.26 │ 0.
|
|
707
|
+
│ #3 │ vue@3.5.26 │ 0.103 │ 93.97 │ 1.49x │
|
|
725
708
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
726
|
-
│ #4 │ maverick@6.0.0 │ 0.
|
|
709
|
+
│ #4 │ maverick@6.0.0 │ 0.154 │ 125.73 │ 1.99x │
|
|
727
710
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
728
|
-
│ #5 │ usignal@0.10.0 │ 0.
|
|
711
|
+
│ #5 │ usignal@0.10.0 │ 0.186 │ 132.38 │ 2.10x │
|
|
729
712
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
730
|
-
│ #6 │ angular@19.2.17 │ 0.
|
|
713
|
+
│ #6 │ angular@19.2.17 │ 0.210 │ 157.89 │ 2.50x │
|
|
731
714
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
732
|
-
│ #7 │ solid@1.9.10 │ 0.
|
|
715
|
+
│ #7 │ solid@1.9.10 │ 0.342 │ 260.88 │ 4.13x │
|
|
733
716
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
734
|
-
│ #8 │ mobx@6.15.0 │ 0.
|
|
717
|
+
│ #8 │ mobx@6.15.0 │ 0.844 │ 892.34 │ 14.14x │
|
|
735
718
|
├───────┼───────────────────┼───────┼───────────────┼──────────────────┤
|
|
736
|
-
│ #9 │ hyperactiv@0.11.3 │ 1.000 │
|
|
719
|
+
│ #9 │ hyperactiv@0.11.3 │ 1.000 │ 1048.63 │ 16.61x │
|
|
737
720
|
└───────┴───────────────────┴───────┴───────────────┴──────────────────┘
|
|
738
721
|
```
|
|
739
722
|
|
|
@@ -743,15 +726,15 @@ Performance comparison of Balises against other popular reactive libraries. Benc
|
|
|
743
726
|
┌───────────────────┬───────────────┬─────────────┬────────────────┬────────────────────┬─────────────┬──────────────┬──────────┐
|
|
744
727
|
│ Library │ S1: 1: Layers │ S2: 2: Wide │ S3: 3: Diamond │ S4: 4: Conditional │ S5: 5: List │ S6: 6: Batch │ Avg Rank │
|
|
745
728
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
746
|
-
│ preact@1.12.1 │ #1 🏆 │ #
|
|
729
|
+
│ preact@1.12.1 │ #1 🏆 │ #1 🏆 │ #1 🏆 │ #1 🏆 │ #1 🏆 │ #1 🏆 │ 1.0 │
|
|
747
730
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
748
|
-
│ balises@0.
|
|
731
|
+
│ balises@0.8.1 │ #3 │ #2 │ #2 │ #2 │ #2 │ #2 │ 2.2 │
|
|
749
732
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
750
|
-
│ vue@3.5.26 │ #2 │ #3 │ #
|
|
733
|
+
│ vue@3.5.26 │ #2 │ #3 │ #5 │ #3 │ #3 │ #5 │ 3.5 │
|
|
751
734
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
752
|
-
│ maverick@6.0.0 │ #5 │ #5 │ #
|
|
735
|
+
│ maverick@6.0.0 │ #5 │ #5 │ #4 │ #4 │ #4 │ #4 │ 4.3 │
|
|
753
736
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
754
|
-
│ usignal@0.10.0 │ #4 │ #4 │ #
|
|
737
|
+
│ usignal@0.10.0 │ #4 │ #4 │ #3 │ #5 │ #8 │ #7 │ 5.2 │
|
|
755
738
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
756
739
|
│ angular@19.2.17 │ #6 │ #6 │ #6 │ #6 │ #5 │ #3 │ 5.3 │
|
|
757
740
|
├───────────────────┼───────────────┼─────────────┼────────────────┼────────────────────┼─────────────┼──────────────┼──────────┤
|
|
@@ -778,7 +761,7 @@ Performance comparison of Balises against other popular reactive libraries. Benc
|
|
|
778
761
|
- These are synthetic benchmarks measuring pure reactivity - real apps should consider the whole picture (ecosystem, docs, community, etc.)
|
|
779
762
|
- Lower rank = better performance
|
|
780
763
|
|
|
781
|
-
_Last updated: 2026-01-
|
|
764
|
+
_Last updated: 2026-01-11_
|
|
782
765
|
|
|
783
766
|
<!-- BENCHMARK_RESULTS_END -->
|
|
784
767
|
|
package/dist/balises.esm.js
CHANGED
|
@@ -200,7 +200,7 @@ var Signal = class {
|
|
|
200
200
|
*/
|
|
201
201
|
is(value) {
|
|
202
202
|
if (context) {
|
|
203
|
-
const slots = this.#isSlots
|
|
203
|
+
const slots = this.#isSlots ??= /* @__PURE__ */ new Map();
|
|
204
204
|
let slot = slots.get(value);
|
|
205
205
|
if (!slot) slots.set(value, slot = new IsSlot(slots, value));
|
|
206
206
|
context.trackSource(slot);
|
|
@@ -276,7 +276,7 @@ var Computed = class {
|
|
|
276
276
|
constructor(fn) {
|
|
277
277
|
this.#fn = fn;
|
|
278
278
|
this.#recompute();
|
|
279
|
-
registerDisposer(() => this.dispose());
|
|
279
|
+
if (disposalStack) registerDisposer(() => this.dispose());
|
|
280
280
|
}
|
|
281
281
|
get value() {
|
|
282
282
|
if (this.#dirty) this.#recompute();
|
|
@@ -370,8 +370,8 @@ var Computed = class {
|
|
|
370
370
|
c.#isSlots.get(old)?.notify();
|
|
371
371
|
c.#isSlots.get(c.#value)?.notify();
|
|
372
372
|
}
|
|
373
|
-
const subs = c.#subs
|
|
374
|
-
for (let j =
|
|
373
|
+
const subs = c.#subs;
|
|
374
|
+
for (let j = subs.length - 1; j >= 0; j--) subs[j]();
|
|
375
375
|
}
|
|
376
376
|
};
|
|
377
377
|
isBatching() ? enqueueBatchOne(notify) : notify();
|
|
@@ -392,8 +392,12 @@ var Computed = class {
|
|
|
392
392
|
const prevLen = this.#sources.length;
|
|
393
393
|
const prev = context;
|
|
394
394
|
setContext(this);
|
|
395
|
+
let threw = false;
|
|
395
396
|
try {
|
|
396
397
|
this.#value = this.#fn();
|
|
398
|
+
} catch (err) {
|
|
399
|
+
threw = true;
|
|
400
|
+
throw err;
|
|
397
401
|
} finally {
|
|
398
402
|
setContext(prev);
|
|
399
403
|
const newLen = this.#sourceIndex;
|
|
@@ -402,7 +406,7 @@ var Computed = class {
|
|
|
402
406
|
for (let i = newLen; i < prevLen; i++) sources[i]?.deleteTarget(this);
|
|
403
407
|
sources.length = newLen;
|
|
404
408
|
}
|
|
405
|
-
this.#dirty = false;
|
|
409
|
+
if (!threw) this.#dirty = false;
|
|
406
410
|
this.#computing = false;
|
|
407
411
|
}
|
|
408
412
|
}
|
|
@@ -869,7 +873,9 @@ var Template = class Template {
|
|
|
869
873
|
}
|
|
870
874
|
return {
|
|
871
875
|
fragment: frag,
|
|
872
|
-
dispose: () =>
|
|
876
|
+
dispose: () => {
|
|
877
|
+
for (const f of disposers) f();
|
|
878
|
+
}
|
|
873
879
|
};
|
|
874
880
|
}
|
|
875
881
|
/** Bind content slot - handles plugins, templates, arrays, and reactive values */
|
|
@@ -883,9 +889,9 @@ var Template = class Template {
|
|
|
883
889
|
}
|
|
884
890
|
let currentNodes = [], childDisposers = [];
|
|
885
891
|
const clear = () => {
|
|
886
|
-
|
|
892
|
+
for (const f of childDisposers) f();
|
|
887
893
|
childDisposers = [];
|
|
888
|
-
|
|
894
|
+
for (const n of currentNodes) n.remove();
|
|
889
895
|
currentNodes = [];
|
|
890
896
|
};
|
|
891
897
|
const update = (v) => {
|
package/dist/balises.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balises.esm.js","names":["context: Computed<unknown> | null","batchQueue: Set<Subscriber> | null","disposalStack: Array<Array<() => void>> | null","disposers: Array<() => void>","onTrack: {\n current: ((source: TrackableSource) => void) | null;\n}","#map","#key","#value","#targets","#isSlots","#subs","#signal","signal","#fn","#recompute","#dirty","#value","#subs","#sources","#isSlots","#sourceIndex","queue: Computed<unknown>[]","toNotify: [Computed<unknown>, unknown][]","#targets","#computing","cleanup: (() => void) | undefined","cleanup: (() => void) | undefined","result: Node[]","node: Node | null","#strings","#values","#plugins","#buildPrototype","#instantiate","bindings: Binding[]","stack: (Element | DocumentFragment)[]","disposers: (() => void)[]","#bindContent","prev: string | null | undefined","currentNodes: Node[]","childDisposers: (() => void)[]","html: HtmlTag"],"sources":["../src/signals/context.ts","../src/signals/signal.ts","../src/signals/computed.ts","../src/signals/effect.ts","../src/signals/store.ts","../src/signals/index.ts","../src/parser.ts","../src/template.ts"],"sourcesContent":["/**\n * Global state and batching for the reactive system.\n */\n\nimport type { Computed } from \"./computed.js\";\n\n/** Callback function for subscribers */\nexport type Subscriber = () => void;\n\n/**\n * Minimal interface for dependency tracking sources.\n * Implemented by Signal, Computed, and selector slots.\n */\nexport interface TrackableSource {\n targets: Computed<unknown>[];\n deleteTarget(target: Computed<unknown>): void;\n}\n\n/** The currently executing computed (for dependency tracking) */\nexport let context: Computed<unknown> | null = null;\n\n/** Set the current execution context */\nexport function setContext(c: Computed<unknown> | null): void {\n context = c;\n}\n\n/** Batching: defer subscriber notifications until batch completes */\nlet batchDepth = 0;\nlet batchQueue: Set<Subscriber> | null = null;\n\n/**\n * Batch multiple signal updates into a single notification pass.\n * Subscribers are only notified after the batch function completes.\n */\nexport function batch<T>(fn: () => T): T {\n batchDepth++;\n if (batchDepth === 1) batchQueue = new Set();\n try {\n return fn();\n } finally {\n if (--batchDepth === 0) {\n const q = batchQueue!;\n batchQueue = null;\n for (const sub of q) sub();\n }\n }\n}\n\n/** Check if currently batching */\nexport function isBatching(): boolean {\n return batchDepth > 0;\n}\n\n/** Add a subscriber to the batch queue */\nexport function enqueueBatchOne(sub: Subscriber): void {\n batchQueue!.add(sub);\n}\n\n/** Add multiple subscribers to the batch queue */\nexport function enqueueBatchAll(subs: Subscriber[]): void {\n for (let i = 0; i < subs.length; i++) batchQueue!.add(subs[i]!);\n}\n\n/** Scope disposal: collect all disposers in a scope */\nlet disposalStack: Array<Array<() => void>> | null = null;\n\n/**\n * Create a disposal scope that collects all subscriptions and computeds created within.\n * Returns the result of the function and a dispose function that cleans up all resources.\n *\n * @example\n * ```ts\n * const [result, dispose] = scope(() => {\n * const count = signal(0);\n * const doubled = computed(() => count.value * 2);\n * effect(() => console.log(doubled.value));\n * return { count, doubled };\n * });\n *\n * // Later: clean up all subscriptions and computeds\n * dispose();\n * ```\n */\nexport function scope<T>(fn: () => T): [result: T, dispose: () => void] {\n const disposers: Array<() => void> = [];\n\n // Push new disposal context\n if (!disposalStack) disposalStack = [];\n disposalStack.push(disposers);\n\n try {\n const result = fn();\n return [\n result,\n () => {\n for (let i = disposers.length - 1; i >= 0; i--) {\n disposers[i]!();\n }\n disposers.length = 0;\n },\n ];\n } finally {\n // Pop disposal context\n disposalStack.pop();\n if (!disposalStack.length) disposalStack = null;\n }\n}\n\n/**\n * Register a disposer in the current scope (if any).\n * This is called internally by computed/effect when they create cleanup functions.\n */\nexport function registerDisposer(dispose: () => void): void {\n disposalStack?.at(-1)?.push(dispose);\n}\n\n/**\n * Hook for tracking signal/computed accesses.\n * Set by async.ts when track() is active to capture dependencies.\n * Using an object wrapper so async.ts can mutate the current value.\n */\nexport const onTrack: {\n current: ((source: TrackableSource) => void) | null;\n} = { current: null };\n","/**\n * Signal - A reactive value container.\n */\n\nimport type { Computed } from \"./computed.js\";\nimport {\n batch,\n context,\n isBatching,\n enqueueBatchAll,\n onTrack,\n type Subscriber,\n type TrackableSource,\n} from \"./context.js\";\n\n/**\n * Remove an item from an array using swap-and-pop (O(1) removal).\n */\nexport function removeFromArray<T>(array: T[], item: T): void {\n const i = array.indexOf(item);\n if (i >= 0) {\n array[i] = array[array.length - 1]!;\n array.pop();\n }\n}\n\n/**\n * A tracking slot for .is() comparisons.\n * Self-removes from parent map when all targets are gone.\n * @internal\n */\nexport class IsSlot<T> implements TrackableSource {\n targets: Computed<unknown>[] = [];\n #map: Map<T, IsSlot<T>>;\n #key: T;\n\n constructor(map: Map<T, IsSlot<T>>, key: T) {\n this.#map = map;\n this.#key = key;\n }\n\n deleteTarget(target: Computed<unknown>): void {\n removeFromArray(this.targets, target);\n // Self-cleanup when empty\n if (!this.targets.length) {\n this.#map.delete(this.#key);\n }\n }\n\n /** Notify all targets that they may need to recompute */\n notify(): void {\n // Copy: markDirty can cause disposal which mutates the array\n const copy = this.targets.slice();\n for (let i = 0; i < copy.length; i++) copy[i]!.markDirty();\n }\n}\n\n/**\n * A reactive value container. When the value changes, all dependent\n * computeds are marked dirty and subscribers are notified.\n *\n * Uses Object.is() for equality checks to correctly handle NaN values.\n */\nexport class Signal<T> {\n #value: T;\n #subs: Subscriber[] = [];\n #targets: Computed<unknown>[] = [];\n #isSlots: Map<T, IsSlot<T>> | undefined;\n\n constructor(value: T) {\n this.#value = value;\n }\n\n get value(): T {\n if (context) context.trackSource(this);\n if (onTrack.current) onTrack.current(this);\n return this.#value;\n }\n\n set value(v: T) {\n if (Object.is(this.#value, v)) return;\n const prev = this.#value;\n this.#value = v;\n\n const targets = this.#targets;\n const isSlots = this.#isSlots;\n\n // Fast path: no .is() slots, just notify regular targets\n if (!isSlots) {\n for (let i = 0; i < targets.length; i++) {\n targets[i]!.markDirty();\n }\n } else {\n // When .is() slots exist, batch all notifications so markDirty()\n // defers recomputation. This allows the #dirty flag to remain true\n // across multiple markDirty() calls, preventing double recomputation\n // when a computed tracks both .value and .is() on the same signal.\n batch(() => {\n isSlots.get(prev)?.notify();\n isSlots.get(v)?.notify();\n for (let i = 0; i < targets.length; i++) {\n targets[i]!.markDirty();\n }\n });\n }\n\n // Notify subscribers\n if (this.#subs.length) {\n if (isBatching()) {\n enqueueBatchAll(this.#subs);\n } else {\n // Copy array to avoid issues if subscribers modify the array during iteration\n const subs = this.#subs.slice();\n for (let i = 0; i < subs.length; i++) subs[i]!();\n }\n }\n }\n\n subscribe(fn: Subscriber): () => void {\n this.#subs.push(fn);\n return () => removeFromArray(this.#subs, fn);\n }\n\n /**\n * Update the signal value using an updater function.\n *\n * @param fn - Function that receives current value and returns new value\n *\n * @example\n * const count = signal(0);\n * count.update(n => n + 1); // increment\n */\n update(fn: (current: T) => T): void {\n this.value = fn(this.#value);\n }\n\n /**\n * Read the signal value without tracking dependencies.\n * Useful in event handlers where you want the current value\n * but don't want to create a reactive dependency.\n *\n * @example\n * const count = signal(0);\n * // In an event handler - no dependency tracking\n * button.onclick = () => console.log(count.peek());\n */\n peek(): T {\n return this.#value;\n }\n\n /**\n * Check if the signal's value equals the given value.\n * Enables O(1) selection updates - only the old and new matching values\n * trigger recomputes, not all dependents.\n *\n * @example\n * ```ts\n * const selected = signal<number | null>(null);\n *\n * // In each row - only 2 rows recompute when selection changes\n * html`<tr class=${() => selected.is(row.id) ? 'danger' : ''}>...`\n * ```\n */\n is(value: T): boolean {\n if (context) {\n const slots = this.#isSlots ?? (this.#isSlots = new Map());\n let slot = slots.get(value);\n if (!slot) slots.set(value, (slot = new IsSlot(slots, value)));\n context.trackSource(slot);\n }\n return Object.is(this.#value, value);\n }\n\n /** @internal */\n get targets(): Computed<unknown>[] {\n return this.#targets;\n }\n\n /** @internal */\n deleteTarget(target: Computed<unknown>): void {\n removeFromArray(this.#targets, target);\n }\n}\n\n/** Create a new signal with the given initial value. */\nexport const signal = <T>(value: T) => new Signal(value);\n\n/**\n * A read-only view of a Signal.\n * Provides reactive access without allowing external mutation.\n * Used by `each()` to pass item signals to render functions.\n */\nexport class ReadonlySignal<T> {\n #signal: Signal<T>;\n\n /** @internal */\n constructor(signal: Signal<T>) {\n this.#signal = signal;\n }\n\n get value(): T {\n return this.#signal.value;\n }\n\n /**\n * Read the signal value without tracking dependencies.\n * Useful in event handlers where you want the current value\n * but don't want to create a reactive dependency.\n */\n peek(): T {\n return this.#signal.peek();\n }\n\n subscribe(fn: Subscriber): () => void {\n return this.#signal.subscribe(fn);\n }\n\n /**\n * Check if the signal's value equals the given value.\n * Enables O(1) selection updates.\n */\n is(value: T): boolean {\n return this.#signal.is(value);\n }\n}\n","/**\n * Computed - A derived reactive value.\n */\n\nimport { removeFromArray, IsSlot } from \"./signal.js\";\nimport {\n context,\n setContext,\n isBatching,\n enqueueBatchOne,\n registerDisposer,\n onTrack,\n type Subscriber,\n type TrackableSource,\n} from \"./context.js\";\n\n/**\n * A derived reactive value. Automatically tracks dependencies and\n * recomputes when any dependency changes.\n *\n * Uses Object.is() for equality checks to correctly handle NaN values.\n */\nexport class Computed<T> {\n #fn: (() => T) | undefined;\n #value: T | undefined;\n #dirty = true;\n #computing = false;\n #subs: Subscriber[] = [];\n #targets: Computed<unknown>[] = [];\n #sources: TrackableSource[] = [];\n #sourceIndex = 0;\n #isSlots: Map<T, IsSlot<T>> | undefined;\n\n constructor(fn: () => T) {\n this.#fn = fn;\n this.#recompute();\n\n // Auto-register disposal in current root scope\n registerDisposer(() => this.dispose());\n }\n\n get value(): T {\n if (this.#dirty) this.#recompute();\n if (context && context !== this) context.trackSource(this);\n if (onTrack.current) onTrack.current(this);\n return this.#value as T;\n }\n\n subscribe(fn: Subscriber): () => void {\n this.#subs.push(fn);\n return () => removeFromArray(this.#subs, fn);\n }\n\n dispose(): void {\n this.#fn = undefined;\n const sources = this.#sources;\n for (let i = 0; i < sources.length; i++) sources[i]?.deleteTarget(this);\n this.#sources = [];\n this.#subs.length = 0;\n this.#isSlots?.clear();\n }\n\n /**\n * Check if the computed's value equals the given value.\n * Enables O(1) selection updates - only the old and new matching values\n * trigger recomputes, not all dependents.\n *\n * @example\n * ```ts\n * const selected = computed(() => items.find(i => i.active)?.id ?? null);\n *\n * // In each row - only 2 rows recompute when selection changes\n * html`<tr class=${() => selected.is(row.id) ? 'danger' : ''}>...`\n * ```\n */\n is(value: T): boolean {\n if (this.#dirty) this.#recompute();\n if (context) {\n const slots = this.#isSlots ?? (this.#isSlots = new Map());\n let slot = slots.get(value);\n if (!slot) slots.set(value, (slot = new IsSlot(slots, value)));\n context.trackSource(slot);\n }\n return Object.is(this.#value, value);\n }\n\n /**\n * Called by sources when accessed during recompute.\n * @internal\n */\n trackSource(source: TrackableSource): void {\n // Skip tracking if disposed (can happen if dispose() is called during #fn execution)\n if (!this.#fn) return;\n\n const sources = this.#sources;\n const idx = this.#sourceIndex++;\n\n if (idx < sources.length) {\n if (sources[idx] === source) {\n // Same source at same position - nothing to do\n return;\n }\n // Different source - unlink old ones from this position\n for (let i = idx; i < sources.length; i++) {\n const s = sources[i];\n if (s) s.deleteTarget(this);\n }\n sources.length = idx;\n }\n // Add new source\n sources.push(source);\n source.targets.push(this);\n }\n\n /**\n * Mark this computed and all its dependents as dirty.\n * Uses a two-phase approach to avoid cascading issues:\n * 1. Mark all dependents as dirty (no subscriber calls)\n * 2. Notify subscribers after all dirty flags are set\n * @internal\n */\n markDirty(): void {\n if (this.#dirty) return;\n\n // Phase 1: Mark all dependents as dirty, collect subscribers\n const queue: Computed<unknown>[] = [this];\n const toNotify: [Computed<unknown>, unknown][] = [];\n\n for (let i = 0; i < queue.length; i++) {\n const c = queue[i]!;\n if (c.#dirty) continue;\n c.#dirty = true;\n\n // Propagate to all targets\n const targets = c.#targets;\n for (let j = 0; j < targets.length; j++) {\n const t = targets[j]!;\n if (!t.#dirty) queue.push(t);\n }\n\n // Collect computeds with subscribers or .is() slots for later notification\n if ((c.#subs.length || c.#isSlots?.size) && c.#fn) {\n toNotify.push([c, c.#value]);\n }\n }\n\n // Phase 2: Notify subscribers (after all dirty flags are set)\n for (let i = 0; i < toNotify.length; i++) {\n const [c, old] = toNotify[i]!;\n const notify = () => {\n if (!c.#fn) return;\n c.#recompute();\n if (!Object.is(c.#value, old)) {\n // Notify .is() slots for old and new values\n if (c.#isSlots) {\n c.#isSlots.get(old)?.notify();\n c.#isSlots.get(c.#value)?.notify();\n }\n const subs = c.#subs.slice();\n for (let j = 0; j < subs.length; j++) subs[j]!();\n }\n };\n void (isBatching() ? enqueueBatchOne(notify) : notify());\n }\n }\n\n /** @internal */\n get targets(): Computed<unknown>[] {\n return this.#targets;\n }\n\n /** @internal */\n deleteTarget(target: Computed<unknown>): void {\n removeFromArray(this.#targets, target);\n }\n\n #recompute(): void {\n if (this.#computing || !this.#fn) return;\n this.#computing = true;\n\n this.#sourceIndex = 0;\n const prevLen = this.#sources.length;\n\n const prev = context;\n setContext(this);\n try {\n this.#value = this.#fn();\n } finally {\n setContext(prev);\n\n // Unlink removed sources\n const newLen = this.#sourceIndex;\n if (newLen < prevLen) {\n const sources = this.#sources;\n for (let i = newLen; i < prevLen; i++) sources[i]?.deleteTarget(this);\n sources.length = newLen;\n }\n\n this.#dirty = false;\n this.#computing = false;\n }\n }\n}\n\n/** Create a new computed from the given function. */\nexport const computed = <T>(fn: () => T) => new Computed(fn);\n","/**\n * Effect - Run side effects reactively.\n */\n\nimport { computed } from \"./computed.js\";\nimport { context, setContext, registerDisposer } from \"./context.js\";\n\n/**\n * Create a reactive effect that automatically tracks dependencies\n * and re-runs when they change.\n *\n * The effect function can optionally return a cleanup function that will be\n * called before the effect re-runs and when the effect is disposed.\n *\n * @param fn - The effect function to run. May return a cleanup function.\n * @returns A dispose function to stop the effect\n *\n * @example\n * const count = signal(0);\n * const dispose = effect(() => {\n * console.log(\"Count is:\", count.value);\n * });\n *\n * count.value = 1; // logs: \"Count is: 1\"\n * dispose(); // stop the effect\n *\n * @example\n * // With cleanup function\n * const userId = signal(1);\n * const dispose = effect(() => {\n * const subscription = api.subscribe(userId.value);\n * return () => subscription.unsubscribe(); // cleanup\n * });\n *\n * userId.value = 2; // cleanup runs, then effect re-runs with new subscription\n * dispose(); // final cleanup runs\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n let cleanup: (() => void) | undefined;\n let disposed = false;\n\n const c = computed(() => {\n // Run cleanup outside of tracking context to avoid\n // reactive reads in cleanup creating new dependencies\n if (cleanup) {\n const prev = context;\n setContext(null);\n try {\n cleanup();\n } finally {\n setContext(prev);\n }\n }\n cleanup = fn() ?? undefined;\n return undefined;\n });\n // Subscribe to make it reactive (rerun on dependency changes)\n const unsub = c.subscribe(() => {});\n\n const dispose = () => {\n if (disposed) return;\n disposed = true;\n unsub();\n c.dispose();\n cleanup?.();\n };\n\n // Register full effect dispose (with cleanup) in current scope\n // This overrides the computed's auto-registration with a more complete cleanup\n registerDisposer(dispose);\n\n return dispose;\n}\n","/**\n * Store - Reactive wrapper for plain objects.\n */\n\nimport { Signal } from \"./signal.js\";\n\nconst STORE = Symbol();\n\n/**\n * Create a reactive store from a plain object.\n * Each property becomes a signal, and nested objects are recursively wrapped.\n */\nexport function store<T extends object>(obj: T): T {\n const signals = new Map<string | symbol, Signal<unknown>>();\n\n /** Recursively wrap nested objects and arrays */\n const wrap = (value: unknown): unknown => {\n if (typeof value !== \"object\" || value === null) return value;\n if (STORE in value) return value; // Already a store\n if ((value as object).constructor === Object) {\n return store(value as Record<string, unknown>);\n }\n if (Array.isArray(value)) {\n return value.map(wrap);\n }\n return value;\n };\n\n /** Get or create a signal for a property */\n const getSignal = (key: string | symbol, initialValue: unknown) => {\n let sig = signals.get(key);\n if (!sig) {\n sig = new Signal(wrap(initialValue));\n signals.set(key, sig);\n }\n return sig;\n };\n\n return new Proxy(obj, {\n get(target, key) {\n // Allow symbol access (for STORE check and other internal symbols)\n if (typeof key === \"symbol\") {\n return target[key as keyof T];\n }\n return getSignal(key, target[key as keyof T]).value;\n },\n\n set(target, key, value) {\n if (typeof key === \"symbol\") {\n target[key as keyof T] = value;\n return true;\n }\n const wrapped = wrap(value);\n getSignal(key, target[key as keyof T]).value = wrapped;\n target[key as keyof T] = wrapped as T[keyof T];\n return true;\n },\n\n has(target, key) {\n return key === STORE || key in target;\n },\n });\n}\n","/**\n * Reactive signals with automatic dependency tracking.\n *\n * Uses index-based tracking: computed functions are assumed to access\n * their dependencies in the same order on each run. This enables O(1)\n * dependency checks without complex linked-list structures.\n */\n\nexport { Signal, signal, ReadonlySignal } from \"./signal.js\";\nexport { Computed, computed } from \"./computed.js\";\nexport { effect } from \"./effect.js\";\nexport { store } from \"./store.js\";\nexport { batch, scope, type Subscriber } from \"./context.js\";\n\nimport { Signal, ReadonlySignal } from \"./signal.js\";\nimport { Computed } from \"./computed.js\";\n\n/** Common interface for reactive values (Signal or Computed). */\nexport interface Reactive<T> {\n readonly value: T;\n subscribe(fn: () => void): () => void;\n}\n\n/** Check if a value is a reactive signal or computed. @internal */\nexport const isSignal = (value: unknown): value is Reactive<unknown> =>\n value instanceof Signal ||\n value instanceof Computed ||\n value instanceof ReadonlySignal;\n","/**\n * Streaming HTML parser for template literals.\n * State machine: Text=0, TagOpen=1, TagName=2, InTag=3, AttrName=4, AttrEq=5, AttrVal=6, CloseTag=7, Comment=8\n */\n\n/** Pre-compiled attribute: static strings interleaved with slot indexes */\nexport type Attr = [name: string, statics: string[], indexes: number[]];\n\nexport interface ParseCallbacks {\n onText: (text: string) => void;\n onOpenTag: (tag: string, attrs: Attr[], selfClosing: boolean) => void;\n onClose: () => void;\n onSlot: (index: number) => void;\n}\n\nexport class HTMLParser {\n private s = 0; // state\n private tag = \"\";\n private attr = \"\";\n private statics: string[] = [];\n private indexes: number[] = [];\n private attrs: Attr[] = [];\n private text = \"\";\n private q = \"\";\n\n parseTemplate(strings: TemplateStringsArray, cb: ParseCallbacks) {\n for (let i = 0; i < strings.length; i++) {\n this.parse(strings[i]!, cb);\n if (i < strings.length - 1) this.slot(i, cb);\n }\n if (this.text) {\n cb.onText(this.text);\n this.text = \"\";\n }\n }\n\n private parse(str: string, cb: ParseCallbacks) {\n for (let i = 0; i < str.length; i++) {\n const ch = str[i]!,\n nx = str[i + 1],\n n2 = str[i + 2];\n\n if (this.s === 0) {\n // Text\n if (ch === \"<\") {\n if (this.text) {\n cb.onText(this.text);\n this.text = \"\";\n }\n this.s = 1;\n } else this.text += ch;\n } else if (this.s === 1) {\n // TagOpen\n if (ch === \"/\") this.s = 7;\n else if (ch === \"!\" && nx === \"-\" && n2 === \"-\") {\n i += 2;\n this.s = 8;\n } else if (ch === \"!\" || ch === \"?\") {\n while (i < str.length && str[i] !== \">\") i++;\n this.s = 0;\n } else if (this.isA(ch)) {\n this.tag = ch;\n this.s = 2;\n } else {\n this.text += \"<\" + ch;\n this.s = 0;\n }\n } else if (this.s === 2) {\n // TagName\n if (this.isT(ch)) this.tag += ch;\n else if (this.isW(ch)) {\n this.s = 3;\n } else if (ch === \">\") {\n this.emit(cb, false);\n } else if (ch === \"/\" && nx === \">\") {\n i++;\n this.emit(cb, true);\n }\n } else if (this.s === 3) {\n // InTag\n if (this.isW(ch)) continue;\n if (ch === \">\") this.emit(cb, false);\n else if (ch === \"/\" && nx === \">\") {\n i++;\n this.emit(cb, true);\n } else {\n this.attr = ch;\n this.statics = [\"\"];\n this.indexes = [];\n this.s = 4;\n }\n } else if (this.s === 4) {\n // AttrName\n if (this.isT(ch) || ch === \"_\") this.attr += ch;\n else if (ch === \"=\") this.s = 5;\n else if (this.isW(ch)) {\n this.emitAttr();\n this.s = 3;\n } else if (ch === \">\") {\n this.emitAttr();\n this.emit(cb, false);\n } else if (ch === \"/\" && nx === \">\") {\n this.emitAttr();\n i++;\n this.emit(cb, true);\n }\n } else if (this.s === 5) {\n // AttrEq\n if (ch === '\"' || ch === \"'\") {\n this.q = ch;\n this.s = 6;\n } else if (!this.isW(ch)) {\n this.q = \"\";\n this.statics[0] += ch;\n this.s = 6;\n }\n } else if (this.s === 6) {\n // AttrVal\n const end = this.q\n ? ch === this.q\n : this.isW(ch) || ch === \">\" || ch === \"/\";\n if (end) {\n this.emitAttr();\n this.q = \"\";\n this.s = 3;\n if (ch === \">\") this.emit(cb, false);\n else if (ch === \"/\" && nx === \">\") {\n i++;\n this.emit(cb, true);\n }\n } else {\n this.statics[this.statics.length - 1] += ch;\n }\n } else if (this.s === 7) {\n // CloseTag\n if (ch === \">\") {\n cb.onClose();\n this.s = 0;\n }\n } else if (this.s === 8) {\n // Comment\n if (ch === \"-\" && nx === \"-\" && n2 === \">\") {\n i += 2;\n this.s = 0;\n }\n }\n }\n }\n\n private slot(index: number, cb: ParseCallbacks) {\n if (this.s === 5 || this.s === 6) {\n this.indexes.push(index);\n this.statics.push(\"\");\n if (this.s === 5) this.s = 6;\n } else {\n if (this.text) {\n cb.onText(this.text);\n this.text = \"\";\n }\n cb.onSlot(index);\n }\n }\n\n private emit(cb: ParseCallbacks, self: boolean) {\n cb.onOpenTag(this.tag, this.attrs, self);\n this.tag = \"\";\n this.attrs = [];\n this.s = 0;\n }\n\n private emitAttr() {\n if (this.attr) this.attrs.push([this.attr, this.statics, this.indexes]);\n this.attr = \"\";\n this.statics = [];\n this.indexes = [];\n }\n private isA = (c: string) => (c >= \"a\" && c <= \"z\") || (c >= \"A\" && c <= \"Z\");\n private isT = (c: string) =>\n (c >= \"a\" && c <= \"z\") ||\n (c >= \"A\" && c <= \"Z\") ||\n (c >= \"0\" && c <= \"9\") ||\n c === \"-\" ||\n c === \":\";\n private isW = (c: string) => c <= \" \" && c !== \"\";\n}\n","/**\n * HTML template rendering with reactive bindings.\n *\n * Uses tagged template literals to create reactive DOM:\n * - Text interpolation: ${value} or ${signal}\n * - Attribute binding: class=\"${signal}\" (reactive)\n * - Event binding: @click=${handler}\n * - Property binding: .value=${signal} (sets DOM property, not attribute)\n * - Nested templates: ${html`<span>...</span>`}\n * - Arrays: ${items.map(i => html`<li>${i}</li>`)}\n *\n * Extend with plugins via html.with(...plugins) for additional interpolation types.\n *\n * Templates are cached by their static string parts - the DOM structure is built\n * once and cloned for subsequent renders, significantly improving performance.\n */\n\nimport { computed, isSignal, scope, type Reactive } from \"./signals/index.js\";\nimport { HTMLParser } from \"./parser.js\";\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\";\n\n/**\n * Plugin that handles custom interpolation types.\n * Return a bind function if this plugin handles the value, null otherwise.\n * First plugin to return non-null wins.\n */\nexport interface InterpolationPlugin {\n (\n value: unknown,\n ): ((marker: Comment, disposers: (() => void)[]) => void) | null;\n}\n\n/**\n * Html template tag function with plugin composition.\n */\nexport interface HtmlTag {\n (strings: TemplateStringsArray, ...values: unknown[]): Template;\n /** Create a new html tag with additional plugins */\n with(...plugins: InterpolationPlugin[]): HtmlTag;\n}\n\n/** Result of rendering a template */\nexport interface RenderResult {\n fragment: DocumentFragment;\n dispose: () => void;\n}\n\n/**\n * Binding descriptor stored in cache.\n * Uses tuple format for compact storage:\n * - [0, nodeIndex, slotIndex] - text content binding\n * - [1, nodeIndex, attrName, staticParts, slotIndices] - attribute binding\n * - [2, nodeIndex, propName, slotIndex] - property binding\n * - [3, nodeIndex, eventName, slotIndex] - event binding\n *\n * nodeIndex is the index in a TreeWalker traversal (elements + comments only).\n */\ntype Binding =\n | [0, number, number]\n | [1, number, string, string[], number[]]\n | [2, number, string, number]\n | [3, number, string, number];\n\n/** Cached template: prototype fragment and binding descriptors */\ntype Cached = [DocumentFragment, Binding[]];\n\n/** Template cache - keyed by static string parts identity */\nconst cache = new WeakMap<TemplateStringsArray, Cached>();\n\n/**\n * Wrap a function in a scoped computed.\n * Nested computeds/effects are automatically disposed on re-run.\n * Registers disposal of both the computed and nested reactives.\n */\nfunction wrapFn(fn: () => unknown, d: (() => void)[]) {\n let cleanup: (() => void) | undefined;\n const c = computed(() => {\n cleanup?.();\n const [r, dispose] = scope(fn);\n cleanup = dispose;\n return r;\n });\n d.push(() => (c.dispose(), cleanup?.()));\n return c;\n}\n\n/**\n * Bind a value to an update function.\n * Functions are wrapped in computed() for automatic reactivity.\n * Nested computeds/effects created inside functions are automatically\n * disposed when the function re-runs or the binding is disposed.\n */\nfunction bind(v: unknown, update: (v: unknown) => void, d: (() => void)[]) {\n if (typeof v === \"function\") v = wrapFn(v as () => unknown, d);\n if (isSignal(v)) {\n update(v.value);\n d.push(v.subscribe(() => update((v as Reactive<unknown>).value)));\n } else update(v);\n}\n\n/**\n * Collect nodes for all bindings using a single TreeWalker pass.\n * TreeWalker with filter 129 (SHOW_ELEMENT | SHOW_COMMENT) visits nodes\n * in the same order they were created, matching our nodeIndex counter.\n * Bindings are in document order but may share nodes (multiple attrs).\n */\nfunction collectBindingNodes(\n frag: DocumentFragment,\n bindings: Binding[],\n): Node[] {\n if (!bindings.length) return [];\n\n const result: Node[] = new Array(bindings.length);\n const walker = document.createTreeWalker(frag, 129); // SHOW_ELEMENT | SHOW_COMMENT\n let nodeIndex = -1;\n let node: Node | null = null;\n\n for (let i = 0; i < bindings.length; i++) {\n const targetIndex = bindings[i]![1];\n // Advance walker to the target node\n while (nodeIndex < targetIndex) {\n node = walker.nextNode();\n nodeIndex++;\n }\n result[i] = node!;\n }\n\n return result;\n}\n\n/** A parsed HTML template. Call render() to create live DOM. */\nexport class Template {\n #strings: TemplateStringsArray;\n #values: unknown[];\n #plugins: InterpolationPlugin[];\n\n constructor(\n strings: TemplateStringsArray,\n values: unknown[],\n plugins: InterpolationPlugin[] = [],\n ) {\n this.#strings = strings;\n this.#values = values;\n this.#plugins = plugins;\n }\n\n /**\n * Parse template and create live DOM.\n * Returns the fragment and a dispose function to clean up subscriptions.\n *\n * Templates are cached by their static string parts - subsequent renders\n * clone the cached DOM structure instead of rebuilding it.\n */\n render(): RenderResult {\n let cached = cache.get(this.#strings);\n if (!cached) cache.set(this.#strings, (cached = this.#buildPrototype()));\n return this.#instantiate(cached);\n }\n\n /** Build the prototype fragment and collect binding descriptors */\n #buildPrototype(): Cached {\n const frag = document.createDocumentFragment();\n const bindings: Binding[] = [];\n const stack: (Element | DocumentFragment)[] = [frag];\n // nodeIndex counts elements and comments (what TreeWalker visits)\n let nodeIndex = 0;\n\n new HTMLParser().parseTemplate(this.#strings, {\n onText: (t) => stack[stack.length - 1]!.append(t),\n\n onOpenTag: (tag, attrs, selfClose) => {\n const parent = stack[stack.length - 1]!;\n const svg =\n tag === \"svg\" ||\n tag === \"SVG\" ||\n (parent instanceof Element && parent.namespaceURI === SVG_NS);\n const el = svg\n ? document.createElementNS(SVG_NS, tag)\n : document.createElement(tag);\n\n const elIndex = nodeIndex++;\n for (const [name, statics, slots] of attrs) {\n if (!slots.length) el.setAttribute(name, statics[0] ?? \"\");\n else {\n const c = name[0];\n if (c === \"@\")\n bindings.push([3, elIndex, name.slice(1), slots[0]!]);\n else if (c === \".\")\n bindings.push([2, elIndex, name.slice(1), slots[0]!]);\n else bindings.push([1, elIndex, name, statics, slots]);\n }\n }\n\n parent.appendChild(el);\n if (!selfClose) stack.push(el);\n },\n\n onClose: () => {\n if (stack.length > 1) stack.pop();\n },\n\n onSlot: (i) => {\n const parent = stack[stack.length - 1]!;\n parent.appendChild(document.createComment(\"\"));\n bindings.push([0, nodeIndex++, i]);\n },\n });\n\n return [frag, bindings];\n }\n\n /** Clone the prototype and apply bindings with current values */\n #instantiate([proto, bindings]: Cached): RenderResult {\n const frag = proto.cloneNode(true) as DocumentFragment;\n const disposers: (() => void)[] = [];\n const values = this.#values;\n\n // Single TreeWalker pass to collect all binding nodes\n const nodes = collectBindingNodes(frag, bindings);\n\n for (let i = 0; i < bindings.length; i++) {\n const b = bindings[i]!;\n const node = nodes[i]!;\n\n if (b[0] === 0) {\n // Content binding - fast path for static values inline\n const value = values[b[2]];\n const t = typeof value;\n if (t === \"string\" || t === \"number\" || t === \"bigint\") {\n // Static primitive - insert text node directly, no disposer needed\n // (text nodes have no subscriptions and are removed with parent)\n const n = document.createTextNode(String(value));\n node.parentNode!.insertBefore(n, node);\n } else if (value == null || t === \"boolean\") {\n // null, undefined, boolean - render nothing, no disposer needed\n } else {\n // Functions, signals, objects, arrays, templates - full binding\n this.#bindContent(node as Comment, value, disposers);\n }\n } else if (b[0] === 1) {\n // Attribute binding\n const [, , name, statics, slots] = b;\n const resolved = slots.map((s) => {\n const v = values[s];\n return typeof v === \"function\"\n ? wrapFn(v as () => unknown, disposers)\n : v;\n });\n let prev: string | null | undefined;\n\n const update = () => {\n let result = statics[0]!,\n allNull = true;\n for (let j = 0; j < resolved.length; j++) {\n const val = isSignal(resolved[j])\n ? (resolved[j] as Reactive<unknown>).value\n : resolved[j];\n if (val != null && val !== false) allNull = false;\n result += (val === true ? \"\" : (val ?? \"\")) + statics[j + 1]!;\n }\n const next = slots.length === 1 && allNull ? null : result;\n if (next !== prev) {\n prev = next;\n if (next === null) (node as Element).removeAttribute(name);\n else (node as Element).setAttribute(name, next);\n }\n };\n update();\n for (const r of resolved)\n if (isSignal(r)) disposers.push(r.subscribe(update));\n } else if (b[0] === 2) {\n // Property binding\n const [, , name, slot] = b;\n bind(\n values[slot],\n (v) => ((node as unknown as Record<string, unknown>)[name] = v),\n disposers,\n );\n } else {\n // Event binding\n const [, , name, slot] = b;\n const handler = values[slot] as EventListener;\n node.addEventListener(name, handler);\n disposers.push(() => node.removeEventListener(name, handler));\n }\n }\n\n return { fragment: frag, dispose: () => disposers.forEach((f) => f()) };\n }\n\n /** Bind content slot - handles plugins, templates, arrays, and reactive values */\n #bindContent(marker: Comment, value: unknown, disposers: (() => void)[]) {\n // Try plugins first\n for (const plugin of this.#plugins) {\n const binder = plugin(value);\n if (binder) {\n binder(marker, disposers);\n return;\n }\n }\n\n // Full reactive path for functions, signals, objects, arrays, templates\n let currentNodes: Node[] = [],\n childDisposers: (() => void)[] = [];\n\n const clear = () => {\n childDisposers.forEach((f) => f());\n childDisposers = [];\n currentNodes.forEach((n) => (n as ChildNode).remove());\n currentNodes = [];\n };\n\n const update = (v: unknown) => {\n // Fast path: update existing text node for primitives\n if (\n v != null &&\n typeof v !== \"boolean\" &&\n typeof v !== \"object\" &&\n currentNodes.length === 1 &&\n !childDisposers.length &&\n currentNodes[0] instanceof Text\n ) {\n currentNodes[0].textContent = String(v);\n return;\n }\n clear();\n const parent = marker.parentNode!;\n // Optimize: avoid [v].flat() for non-arrays\n const items = Array.isArray(v) ? v.flat() : [v];\n for (const item of items) {\n if (item instanceof Template) {\n const { fragment, dispose } = item.render();\n childDisposers.push(dispose);\n currentNodes.push(...fragment.childNodes);\n parent.insertBefore(fragment, marker);\n } else if (item != null && typeof item !== \"boolean\") {\n const n = document.createTextNode(String(item));\n currentNodes.push(n);\n parent.insertBefore(n, marker);\n }\n }\n };\n\n bind(value, update, disposers);\n disposers.push(clear);\n }\n}\n\nfunction createHtml(plugins: InterpolationPlugin[]): HtmlTag {\n const tag = ((strings: TemplateStringsArray, ...values: unknown[]) =>\n new Template(strings, values, plugins)) as HtmlTag;\n tag.with = (...more: InterpolationPlugin[]) =>\n createHtml([...plugins, ...more]);\n return tag;\n}\n\nexport const html: HtmlTag = createHtml([]);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"balises.esm.js","names":["context: Computed<unknown> | null","batchQueue: Set<Subscriber> | null","disposalStack: Array<Array<() => void>> | null","disposers: Array<() => void>","onTrack: {\n current: ((source: TrackableSource) => void) | null;\n}","#map","#key","#value","#targets","#isSlots","#subs","#signal","signal","#fn","#recompute","#dirty","#value","#subs","#sources","#isSlots","#sourceIndex","queue: Computed<unknown>[]","toNotify: [Computed<unknown>, unknown][]","#targets","#computing","cleanup: (() => void) | undefined","cleanup: (() => void) | undefined","result: Node[]","node: Node | null","#strings","#values","#plugins","#buildPrototype","#instantiate","bindings: Binding[]","stack: (Element | DocumentFragment)[]","disposers: (() => void)[]","#bindContent","prev: string | null | undefined","currentNodes: Node[]","childDisposers: (() => void)[]","html: HtmlTag"],"sources":["../src/signals/context.ts","../src/signals/signal.ts","../src/signals/computed.ts","../src/signals/effect.ts","../src/signals/store.ts","../src/signals/index.ts","../src/parser.ts","../src/template.ts"],"sourcesContent":["/**\n * Global state and batching for the reactive system.\n */\n\nimport type { Computed } from \"./computed.js\";\n\n/** Callback function for subscribers */\nexport type Subscriber = () => void;\n\n/**\n * Minimal interface for dependency tracking sources.\n * Implemented by Signal, Computed, and selector slots.\n */\nexport interface TrackableSource {\n targets: Computed<unknown>[];\n deleteTarget(target: Computed<unknown>): void;\n}\n\n/** The currently executing computed (for dependency tracking) */\nexport let context: Computed<unknown> | null = null;\n\n/** Set the current execution context */\nexport function setContext(c: Computed<unknown> | null): void {\n context = c;\n}\n\n/** Batching: defer subscriber notifications until batch completes */\nlet batchDepth = 0;\nlet batchQueue: Set<Subscriber> | null = null;\n\n/**\n * Batch multiple signal updates into a single notification pass.\n * Subscribers are only notified after the batch function completes.\n */\nexport function batch<T>(fn: () => T): T {\n batchDepth++;\n if (batchDepth === 1) batchQueue = new Set();\n try {\n return fn();\n } finally {\n if (--batchDepth === 0) {\n const q = batchQueue!;\n batchQueue = null;\n for (const sub of q) sub();\n }\n }\n}\n\n/** Check if currently batching */\nexport function isBatching(): boolean {\n return batchDepth > 0;\n}\n\n/** Add a subscriber to the batch queue */\nexport function enqueueBatchOne(sub: Subscriber): void {\n batchQueue!.add(sub);\n}\n\n/** Add multiple subscribers to the batch queue */\nexport function enqueueBatchAll(subs: Subscriber[]): void {\n for (let i = 0; i < subs.length; i++) batchQueue!.add(subs[i]!);\n}\n\n/** Scope disposal: collect all disposers in a scope */\nexport let disposalStack: Array<Array<() => void>> | null = null;\n\n/**\n * Create a disposal scope that collects all subscriptions and computeds created within.\n * Returns the result of the function and a dispose function that cleans up all resources.\n *\n * @example\n * ```ts\n * const [result, dispose] = scope(() => {\n * const count = signal(0);\n * const doubled = computed(() => count.value * 2);\n * effect(() => console.log(doubled.value));\n * return { count, doubled };\n * });\n *\n * // Later: clean up all subscriptions and computeds\n * dispose();\n * ```\n */\nexport function scope<T>(fn: () => T): [result: T, dispose: () => void] {\n const disposers: Array<() => void> = [];\n\n // Push new disposal context\n if (!disposalStack) disposalStack = [];\n disposalStack.push(disposers);\n\n try {\n const result = fn();\n return [\n result,\n () => {\n for (let i = disposers.length - 1; i >= 0; i--) {\n disposers[i]!();\n }\n disposers.length = 0;\n },\n ];\n } finally {\n // Pop disposal context\n disposalStack.pop();\n if (!disposalStack.length) disposalStack = null;\n }\n}\n\n/**\n * Register a disposer in the current scope (if any).\n * This is called internally by computed/effect when they create cleanup functions.\n */\nexport function registerDisposer(dispose: () => void): void {\n disposalStack?.at(-1)?.push(dispose);\n}\n\n/**\n * Hook for tracking signal/computed accesses.\n * Set by async.ts when track() is active to capture dependencies.\n * Using an object wrapper so async.ts can mutate the current value.\n */\nexport const onTrack: {\n current: ((source: TrackableSource) => void) | null;\n} = { current: null };\n","/**\n * Signal - A reactive value container.\n */\n\nimport type { Computed } from \"./computed.js\";\nimport {\n batch,\n context,\n isBatching,\n enqueueBatchAll,\n onTrack,\n type Subscriber,\n type TrackableSource,\n} from \"./context.js\";\n\n/**\n * Remove an item from an array using swap-and-pop (O(1) removal).\n */\nexport function removeFromArray<T>(array: T[], item: T): void {\n const i = array.indexOf(item);\n if (i >= 0) {\n array[i] = array[array.length - 1]!;\n array.pop();\n }\n}\n\n/**\n * A tracking slot for .is() comparisons.\n * Self-removes from parent map when all targets are gone.\n * @internal\n */\nexport class IsSlot<T> implements TrackableSource {\n targets: Computed<unknown>[] = [];\n #map: Map<T, IsSlot<T>>;\n #key: T;\n\n constructor(map: Map<T, IsSlot<T>>, key: T) {\n this.#map = map;\n this.#key = key;\n }\n\n deleteTarget(target: Computed<unknown>): void {\n removeFromArray(this.targets, target);\n // Self-cleanup when empty\n if (!this.targets.length) {\n this.#map.delete(this.#key);\n }\n }\n\n /** Notify all targets that they may need to recompute */\n notify(): void {\n // Copy: markDirty can cause disposal which mutates the array\n const copy = this.targets.slice();\n for (let i = 0; i < copy.length; i++) copy[i]!.markDirty();\n }\n}\n\n/**\n * A reactive value container. When the value changes, all dependent\n * computeds are marked dirty and subscribers are notified.\n *\n * Uses Object.is() for equality checks to correctly handle NaN values.\n */\nexport class Signal<T> {\n #value: T;\n #subs: Subscriber[] = [];\n #targets: Computed<unknown>[] = [];\n #isSlots: Map<T, IsSlot<T>> | undefined;\n\n constructor(value: T) {\n this.#value = value;\n }\n\n get value(): T {\n if (context) context.trackSource(this);\n if (onTrack.current) onTrack.current(this);\n return this.#value;\n }\n\n set value(v: T) {\n if (Object.is(this.#value, v)) return;\n const prev = this.#value;\n this.#value = v;\n\n const targets = this.#targets;\n const isSlots = this.#isSlots;\n\n // Fast path: no .is() slots, just notify regular targets\n if (!isSlots) {\n for (let i = 0; i < targets.length; i++) {\n targets[i]!.markDirty();\n }\n } else {\n // When .is() slots exist, batch all notifications so markDirty()\n // defers recomputation. This allows the #dirty flag to remain true\n // across multiple markDirty() calls, preventing double recomputation\n // when a computed tracks both .value and .is() on the same signal.\n batch(() => {\n isSlots.get(prev)?.notify();\n isSlots.get(v)?.notify();\n for (let i = 0; i < targets.length; i++) {\n targets[i]!.markDirty();\n }\n });\n }\n\n // Notify subscribers\n if (this.#subs.length) {\n if (isBatching()) {\n enqueueBatchAll(this.#subs);\n } else {\n // Copy array to avoid issues if subscribers modify the array during iteration\n const subs = this.#subs.slice();\n for (let i = 0; i < subs.length; i++) subs[i]!();\n }\n }\n }\n\n subscribe(fn: Subscriber): () => void {\n this.#subs.push(fn);\n return () => removeFromArray(this.#subs, fn);\n }\n\n /**\n * Update the signal value using an updater function.\n *\n * @param fn - Function that receives current value and returns new value\n *\n * @example\n * const count = signal(0);\n * count.update(n => n + 1); // increment\n */\n update(fn: (current: T) => T): void {\n this.value = fn(this.#value);\n }\n\n /**\n * Read the signal value without tracking dependencies.\n * Useful in event handlers where you want the current value\n * but don't want to create a reactive dependency.\n *\n * @example\n * const count = signal(0);\n * // In an event handler - no dependency tracking\n * button.onclick = () => console.log(count.peek());\n */\n peek(): T {\n return this.#value;\n }\n\n /**\n * Check if the signal's value equals the given value.\n * Enables O(1) selection updates - only the old and new matching values\n * trigger recomputes, not all dependents.\n *\n * @example\n * ```ts\n * const selected = signal<number | null>(null);\n *\n * // In each row - only 2 rows recompute when selection changes\n * html`<tr class=${() => selected.is(row.id) ? 'danger' : ''}>...`\n * ```\n */\n is(value: T): boolean {\n if (context) {\n const slots = (this.#isSlots ??= new Map());\n let slot = slots.get(value);\n if (!slot) slots.set(value, (slot = new IsSlot(slots, value)));\n context.trackSource(slot);\n }\n return Object.is(this.#value, value);\n }\n\n /** @internal */\n get targets(): Computed<unknown>[] {\n return this.#targets;\n }\n\n /** @internal */\n deleteTarget(target: Computed<unknown>): void {\n removeFromArray(this.#targets, target);\n }\n}\n\n/** Create a new signal with the given initial value. */\nexport const signal = <T>(value: T) => new Signal(value);\n\n/**\n * A read-only view of a Signal.\n * Provides reactive access without allowing external mutation.\n * Used by `each()` to pass item signals to render functions.\n */\nexport class ReadonlySignal<T> {\n #signal: Signal<T>;\n\n /** @internal */\n constructor(signal: Signal<T>) {\n this.#signal = signal;\n }\n\n get value(): T {\n return this.#signal.value;\n }\n\n /**\n * Read the signal value without tracking dependencies.\n * Useful in event handlers where you want the current value\n * but don't want to create a reactive dependency.\n */\n peek(): T {\n return this.#signal.peek();\n }\n\n subscribe(fn: Subscriber): () => void {\n return this.#signal.subscribe(fn);\n }\n\n /**\n * Check if the signal's value equals the given value.\n * Enables O(1) selection updates.\n */\n is(value: T): boolean {\n return this.#signal.is(value);\n }\n}\n","/**\n * Computed - A derived reactive value.\n */\n\nimport { removeFromArray, IsSlot } from \"./signal.js\";\nimport {\n setContext,\n context,\n isBatching,\n enqueueBatchOne,\n disposalStack,\n registerDisposer,\n onTrack,\n type Subscriber,\n type TrackableSource,\n} from \"./context.js\";\n\n/**\n * A derived reactive value. Automatically tracks dependencies and\n * recomputes when any dependency changes.\n *\n * Uses Object.is() for equality checks to correctly handle NaN values.\n */\nexport class Computed<T> {\n #fn: (() => T) | undefined;\n #value: T | undefined;\n #dirty = true;\n #computing = false;\n #subs: Subscriber[] = [];\n #targets: Computed<unknown>[] = [];\n #sources: TrackableSource[] = [];\n #sourceIndex = 0;\n #isSlots: Map<T, IsSlot<T>> | undefined;\n\n constructor(fn: () => T) {\n this.#fn = fn;\n this.#recompute();\n\n // Auto-register disposal in current scope\n if (disposalStack) registerDisposer(() => this.dispose());\n }\n\n get value(): T {\n if (this.#dirty) this.#recompute();\n if (context && context !== this) context.trackSource(this);\n if (onTrack.current) onTrack.current(this);\n return this.#value as T;\n }\n\n subscribe(fn: Subscriber): () => void {\n this.#subs.push(fn);\n return () => removeFromArray(this.#subs, fn);\n }\n\n dispose(): void {\n this.#fn = undefined;\n const sources = this.#sources;\n for (let i = 0; i < sources.length; i++) sources[i]?.deleteTarget(this);\n this.#sources = [];\n this.#subs.length = 0;\n this.#isSlots?.clear();\n }\n\n /**\n * Check if the computed's value equals the given value.\n * Enables O(1) selection updates - only the old and new matching values\n * trigger recomputes, not all dependents.\n *\n * @example\n * ```ts\n * const selected = computed(() => items.find(i => i.active)?.id ?? null);\n *\n * // In each row - only 2 rows recompute when selection changes\n * html`<tr class=${() => selected.is(row.id) ? 'danger' : ''}>...`\n * ```\n */\n is(value: T): boolean {\n if (this.#dirty) this.#recompute();\n if (context) {\n const slots = this.#isSlots ?? (this.#isSlots = new Map());\n let slot = slots.get(value);\n if (!slot) slots.set(value, (slot = new IsSlot(slots, value)));\n context.trackSource(slot);\n }\n return Object.is(this.#value, value);\n }\n\n /**\n * Called by sources when accessed during recompute.\n * @internal\n */\n trackSource(source: TrackableSource): void {\n // Skip tracking if disposed (can happen if dispose() is called during #fn execution)\n if (!this.#fn) return;\n\n const sources = this.#sources;\n const idx = this.#sourceIndex++;\n\n if (idx < sources.length) {\n if (sources[idx] === source) {\n // Same source at same position - nothing to do\n return;\n }\n // Different source - unlink old ones from this position\n for (let i = idx; i < sources.length; i++) {\n const s = sources[i];\n if (s) s.deleteTarget(this);\n }\n sources.length = idx;\n }\n // Add new source\n sources.push(source);\n source.targets.push(this);\n }\n\n /**\n * Mark this computed and all its dependents as dirty.\n * Uses a two-phase approach to avoid cascading issues:\n * 1. Mark all dependents as dirty (no subscriber calls)\n * 2. Notify subscribers after all dirty flags are set\n * @internal\n */\n markDirty(): void {\n if (this.#dirty) return;\n\n // Phase 1: Mark all dependents as dirty, collect subscribers\n const queue: Computed<unknown>[] = [this];\n const toNotify: [Computed<unknown>, unknown][] = [];\n\n for (let i = 0; i < queue.length; i++) {\n const c = queue[i]!;\n if (c.#dirty) continue;\n c.#dirty = true;\n\n // Propagate to all targets\n const targets = c.#targets;\n for (let j = 0; j < targets.length; j++) {\n const t = targets[j]!;\n if (!t.#dirty) queue.push(t);\n }\n\n // Collect computeds with subscribers or .is() slots for later notification\n if ((c.#subs.length || c.#isSlots?.size) && c.#fn) {\n toNotify.push([c, c.#value]);\n }\n }\n\n // Phase 2: Notify subscribers (after all dirty flags are set)\n for (let i = 0; i < toNotify.length; i++) {\n const [c, old] = toNotify[i]!;\n const notify = () => {\n if (!c.#fn) return;\n c.#recompute();\n if (!Object.is(c.#value, old)) {\n // Notify .is() slots for old and new values\n if (c.#isSlots) {\n c.#isSlots.get(old)?.notify();\n c.#isSlots.get(c.#value)?.notify();\n }\n // Reverse iteration: safe for self-unsubscription with swap-and-pop removal\n const subs = c.#subs;\n for (let j = subs.length - 1; j >= 0; j--) subs[j]!();\n }\n };\n void (isBatching() ? enqueueBatchOne(notify) : notify());\n }\n }\n\n /** @internal */\n get targets(): Computed<unknown>[] {\n return this.#targets;\n }\n\n /** @internal */\n deleteTarget(target: Computed<unknown>): void {\n removeFromArray(this.#targets, target);\n }\n\n #recompute(): void {\n if (this.#computing || !this.#fn) return;\n this.#computing = true;\n\n this.#sourceIndex = 0;\n const prevLen = this.#sources.length;\n\n const prev = context;\n setContext(this);\n let threw = false;\n try {\n this.#value = this.#fn();\n } catch (err) {\n threw = true;\n throw err;\n } finally {\n setContext(prev);\n\n // Unlink removed sources\n const newLen = this.#sourceIndex;\n if (newLen < prevLen) {\n const sources = this.#sources;\n for (let i = newLen; i < prevLen; i++) sources[i]?.deleteTarget(this);\n sources.length = newLen;\n }\n\n if (!threw) this.#dirty = false;\n this.#computing = false;\n }\n }\n}\n\n/** Create a new computed from the given function. */\nexport const computed = <T>(fn: () => T) => new Computed(fn);\n","/**\n * Effect - Run side effects reactively.\n */\n\nimport { computed } from \"./computed.js\";\nimport { context, setContext, registerDisposer } from \"./context.js\";\n\n/**\n * Create a reactive effect that automatically tracks dependencies\n * and re-runs when they change.\n *\n * The effect function can optionally return a cleanup function that will be\n * called before the effect re-runs and when the effect is disposed.\n *\n * @param fn - The effect function to run. May return a cleanup function.\n * @returns A dispose function to stop the effect\n *\n * @example\n * const count = signal(0);\n * const dispose = effect(() => {\n * console.log(\"Count is:\", count.value);\n * });\n *\n * count.value = 1; // logs: \"Count is: 1\"\n * dispose(); // stop the effect\n *\n * @example\n * // With cleanup function\n * const userId = signal(1);\n * const dispose = effect(() => {\n * const subscription = api.subscribe(userId.value);\n * return () => subscription.unsubscribe(); // cleanup\n * });\n *\n * userId.value = 2; // cleanup runs, then effect re-runs with new subscription\n * dispose(); // final cleanup runs\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n let cleanup: (() => void) | undefined;\n let disposed = false;\n\n const c = computed(() => {\n // Run cleanup outside of tracking context to avoid\n // reactive reads in cleanup creating new dependencies\n if (cleanup) {\n const prev = context;\n setContext(null);\n try {\n cleanup();\n } finally {\n setContext(prev);\n }\n }\n cleanup = fn() ?? undefined;\n return undefined;\n });\n // Subscribe to make it reactive (rerun on dependency changes)\n const unsub = c.subscribe(() => {});\n\n const dispose = () => {\n if (disposed) return;\n disposed = true;\n unsub();\n c.dispose();\n cleanup?.();\n };\n\n // Register full effect dispose (with cleanup) in current scope\n // This overrides the computed's auto-registration with a more complete cleanup\n registerDisposer(dispose);\n\n return dispose;\n}\n","/**\n * Store - Reactive wrapper for plain objects.\n */\n\nimport { Signal } from \"./signal.js\";\n\nconst STORE = Symbol();\n\n/**\n * Create a reactive store from a plain object.\n * Each property becomes a signal, and nested objects are recursively wrapped.\n */\nexport function store<T extends object>(obj: T): T {\n const signals = new Map<string | symbol, Signal<unknown>>();\n\n /** Recursively wrap nested objects and arrays */\n const wrap = (value: unknown): unknown => {\n if (typeof value !== \"object\" || value === null) return value;\n if (STORE in value) return value; // Already a store\n if ((value as object).constructor === Object) {\n return store(value as Record<string, unknown>);\n }\n if (Array.isArray(value)) {\n return value.map(wrap);\n }\n return value;\n };\n\n /** Get or create a signal for a property */\n const getSignal = (key: string | symbol, initialValue: unknown) => {\n let sig = signals.get(key);\n if (!sig) {\n sig = new Signal(wrap(initialValue));\n signals.set(key, sig);\n }\n return sig;\n };\n\n return new Proxy(obj, {\n get(target, key) {\n // Allow symbol access (for STORE check and other internal symbols)\n if (typeof key === \"symbol\") {\n return target[key as keyof T];\n }\n return getSignal(key, target[key as keyof T]).value;\n },\n\n set(target, key, value) {\n if (typeof key === \"symbol\") {\n target[key as keyof T] = value;\n return true;\n }\n const wrapped = wrap(value);\n getSignal(key, target[key as keyof T]).value = wrapped;\n target[key as keyof T] = wrapped as T[keyof T];\n return true;\n },\n\n has(target, key) {\n return key === STORE || key in target;\n },\n });\n}\n","/**\n * Reactive signals with automatic dependency tracking.\n *\n * Uses index-based tracking: computed functions are assumed to access\n * their dependencies in the same order on each run. This enables O(1)\n * dependency checks without complex linked-list structures.\n */\n\nexport { Signal, signal, ReadonlySignal } from \"./signal.js\";\nexport { Computed, computed } from \"./computed.js\";\nexport { effect } from \"./effect.js\";\nexport { store } from \"./store.js\";\nexport { batch, scope, type Subscriber } from \"./context.js\";\n\nimport { Signal, ReadonlySignal } from \"./signal.js\";\nimport { Computed } from \"./computed.js\";\n\n/** Common interface for reactive values (Signal or Computed). */\nexport interface Reactive<T> {\n readonly value: T;\n subscribe(fn: () => void): () => void;\n}\n\n/** Check if a value is a reactive signal or computed. @internal */\nexport const isSignal = (value: unknown): value is Reactive<unknown> =>\n value instanceof Signal ||\n value instanceof Computed ||\n value instanceof ReadonlySignal;\n","/**\n * Streaming HTML parser for template literals.\n * State machine: Text=0, TagOpen=1, TagName=2, InTag=3, AttrName=4, AttrEq=5, AttrVal=6, CloseTag=7, Comment=8\n */\n\n/** Pre-compiled attribute: static strings interleaved with slot indexes */\nexport type Attr = [name: string, statics: string[], indexes: number[]];\n\nexport interface ParseCallbacks {\n onText: (text: string) => void;\n onOpenTag: (tag: string, attrs: Attr[], selfClosing: boolean) => void;\n onClose: () => void;\n onSlot: (index: number) => void;\n}\n\nexport class HTMLParser {\n private s = 0; // state\n private tag = \"\";\n private attr = \"\";\n private statics: string[] = [];\n private indexes: number[] = [];\n private attrs: Attr[] = [];\n private text = \"\";\n private q = \"\";\n\n parseTemplate(strings: TemplateStringsArray, cb: ParseCallbacks) {\n for (let i = 0; i < strings.length; i++) {\n this.parse(strings[i]!, cb);\n if (i < strings.length - 1) this.slot(i, cb);\n }\n if (this.text) {\n cb.onText(this.text);\n this.text = \"\";\n }\n }\n\n private parse(str: string, cb: ParseCallbacks) {\n for (let i = 0; i < str.length; i++) {\n const ch = str[i]!,\n nx = str[i + 1],\n n2 = str[i + 2];\n\n if (this.s === 0) {\n // Text\n if (ch === \"<\") {\n if (this.text) {\n cb.onText(this.text);\n this.text = \"\";\n }\n this.s = 1;\n } else this.text += ch;\n } else if (this.s === 1) {\n // TagOpen\n if (ch === \"/\") this.s = 7;\n else if (ch === \"!\" && nx === \"-\" && n2 === \"-\") {\n i += 2;\n this.s = 8;\n } else if (ch === \"!\" || ch === \"?\") {\n while (i < str.length && str[i] !== \">\") i++;\n this.s = 0;\n } else if (this.isA(ch)) {\n this.tag = ch;\n this.s = 2;\n } else {\n this.text += \"<\" + ch;\n this.s = 0;\n }\n } else if (this.s === 2) {\n // TagName\n if (this.isT(ch)) this.tag += ch;\n else if (this.isW(ch)) {\n this.s = 3;\n } else if (ch === \">\") {\n this.emit(cb, false);\n } else if (ch === \"/\" && nx === \">\") {\n i++;\n this.emit(cb, true);\n }\n } else if (this.s === 3) {\n // InTag\n if (this.isW(ch)) continue;\n if (ch === \">\") this.emit(cb, false);\n else if (ch === \"/\" && nx === \">\") {\n i++;\n this.emit(cb, true);\n } else {\n this.attr = ch;\n this.statics = [\"\"];\n this.indexes = [];\n this.s = 4;\n }\n } else if (this.s === 4) {\n // AttrName\n if (this.isT(ch) || ch === \"_\") this.attr += ch;\n else if (ch === \"=\") this.s = 5;\n else if (this.isW(ch)) {\n this.emitAttr();\n this.s = 3;\n } else if (ch === \">\") {\n this.emitAttr();\n this.emit(cb, false);\n } else if (ch === \"/\" && nx === \">\") {\n this.emitAttr();\n i++;\n this.emit(cb, true);\n }\n } else if (this.s === 5) {\n // AttrEq\n if (ch === '\"' || ch === \"'\") {\n this.q = ch;\n this.s = 6;\n } else if (!this.isW(ch)) {\n this.q = \"\";\n this.statics[0] += ch;\n this.s = 6;\n }\n } else if (this.s === 6) {\n // AttrVal\n const end = this.q\n ? ch === this.q\n : this.isW(ch) || ch === \">\" || ch === \"/\";\n if (end) {\n this.emitAttr();\n this.q = \"\";\n this.s = 3;\n if (ch === \">\") this.emit(cb, false);\n else if (ch === \"/\" && nx === \">\") {\n i++;\n this.emit(cb, true);\n }\n } else {\n this.statics[this.statics.length - 1] += ch;\n }\n } else if (this.s === 7) {\n // CloseTag\n if (ch === \">\") {\n cb.onClose();\n this.s = 0;\n }\n } else if (this.s === 8) {\n // Comment\n if (ch === \"-\" && nx === \"-\" && n2 === \">\") {\n i += 2;\n this.s = 0;\n }\n }\n }\n }\n\n private slot(index: number, cb: ParseCallbacks) {\n if (this.s === 5 || this.s === 6) {\n this.indexes.push(index);\n this.statics.push(\"\");\n if (this.s === 5) this.s = 6;\n } else {\n if (this.text) {\n cb.onText(this.text);\n this.text = \"\";\n }\n cb.onSlot(index);\n }\n }\n\n private emit(cb: ParseCallbacks, self: boolean) {\n cb.onOpenTag(this.tag, this.attrs, self);\n this.tag = \"\";\n this.attrs = [];\n this.s = 0;\n }\n\n private emitAttr() {\n if (this.attr) this.attrs.push([this.attr, this.statics, this.indexes]);\n this.attr = \"\";\n this.statics = [];\n this.indexes = [];\n }\n private isA = (c: string) => (c >= \"a\" && c <= \"z\") || (c >= \"A\" && c <= \"Z\");\n private isT = (c: string) =>\n (c >= \"a\" && c <= \"z\") ||\n (c >= \"A\" && c <= \"Z\") ||\n (c >= \"0\" && c <= \"9\") ||\n c === \"-\" ||\n c === \":\";\n private isW = (c: string) => c <= \" \" && c !== \"\";\n}\n","/**\n * HTML template rendering with reactive bindings.\n *\n * Uses tagged template literals to create reactive DOM:\n * - Text interpolation: ${value} or ${signal}\n * - Attribute binding: class=\"${signal}\" (reactive)\n * - Event binding: @click=${handler}\n * - Property binding: .value=${signal} (sets DOM property, not attribute)\n * - Nested templates: ${html`<span>...</span>`}\n * - Arrays: ${items.map(i => html`<li>${i}</li>`)}\n *\n * Extend with plugins via html.with(...plugins) for additional interpolation types.\n *\n * Templates are cached by their static string parts - the DOM structure is built\n * once and cloned for subsequent renders, significantly improving performance.\n */\n\nimport { computed, isSignal, scope, type Reactive } from \"./signals/index.js\";\nimport { HTMLParser } from \"./parser.js\";\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\";\n\n/**\n * Plugin that handles custom interpolation types.\n * Return a bind function if this plugin handles the value, null otherwise.\n * First plugin to return non-null wins.\n */\nexport interface InterpolationPlugin {\n (\n value: unknown,\n ): ((marker: Comment, disposers: (() => void)[]) => void) | null;\n}\n\n/**\n * Html template tag function with plugin composition.\n */\nexport interface HtmlTag {\n (strings: TemplateStringsArray, ...values: unknown[]): Template;\n /** Create a new html tag with additional plugins */\n with(...plugins: InterpolationPlugin[]): HtmlTag;\n}\n\n/** Result of rendering a template */\nexport interface RenderResult {\n fragment: DocumentFragment;\n dispose: () => void;\n}\n\n/**\n * Binding descriptor stored in cache.\n * Uses tuple format for compact storage:\n * - [0, nodeIndex, slotIndex] - text content binding\n * - [1, nodeIndex, attrName, staticParts, slotIndices] - attribute binding\n * - [2, nodeIndex, propName, slotIndex] - property binding\n * - [3, nodeIndex, eventName, slotIndex] - event binding\n *\n * nodeIndex is the index in a TreeWalker traversal (elements + comments only).\n */\ntype Binding =\n | [0, number, number]\n | [1, number, string, string[], number[]]\n | [2, number, string, number]\n | [3, number, string, number];\n\n/** Cached template: prototype fragment and binding descriptors */\ntype Cached = [DocumentFragment, Binding[]];\n\n/** Template cache - keyed by static string parts identity */\nconst cache = new WeakMap<TemplateStringsArray, Cached>();\n\n/**\n * Wrap a function in a scoped computed.\n * Nested computeds/effects are automatically disposed on re-run.\n * Registers disposal of both the computed and nested reactives.\n */\nfunction wrapFn(fn: () => unknown, d: (() => void)[]) {\n let cleanup: (() => void) | undefined;\n const c = computed(() => {\n cleanup?.();\n const [r, dispose] = scope(fn);\n cleanup = dispose;\n return r;\n });\n d.push(() => (c.dispose(), cleanup?.()));\n return c;\n}\n\n/**\n * Bind a value to an update function.\n * Functions are wrapped in computed() for automatic reactivity.\n * Nested computeds/effects created inside functions are automatically\n * disposed when the function re-runs or the binding is disposed.\n */\nfunction bind(v: unknown, update: (v: unknown) => void, d: (() => void)[]) {\n if (typeof v === \"function\") v = wrapFn(v as () => unknown, d);\n if (isSignal(v)) {\n update(v.value);\n d.push(v.subscribe(() => update((v as Reactive<unknown>).value)));\n } else update(v);\n}\n\n/**\n * Collect nodes for all bindings using a single TreeWalker pass.\n * TreeWalker with filter 129 (SHOW_ELEMENT | SHOW_COMMENT) visits nodes\n * in the same order they were created, matching our nodeIndex counter.\n * Bindings are in document order but may share nodes (multiple attrs).\n */\nfunction collectBindingNodes(\n frag: DocumentFragment,\n bindings: Binding[],\n): Node[] {\n if (!bindings.length) return [];\n\n const result: Node[] = new Array(bindings.length);\n const walker = document.createTreeWalker(frag, 129); // SHOW_ELEMENT | SHOW_COMMENT\n let nodeIndex = -1;\n let node: Node | null = null;\n\n for (let i = 0; i < bindings.length; i++) {\n const targetIndex = bindings[i]![1];\n // Advance walker to the target node\n while (nodeIndex < targetIndex) {\n node = walker.nextNode();\n nodeIndex++;\n }\n result[i] = node!;\n }\n\n return result;\n}\n\n/** A parsed HTML template. Call render() to create live DOM. */\nexport class Template {\n #strings: TemplateStringsArray;\n #values: unknown[];\n #plugins: InterpolationPlugin[];\n\n constructor(\n strings: TemplateStringsArray,\n values: unknown[],\n plugins: InterpolationPlugin[] = [],\n ) {\n this.#strings = strings;\n this.#values = values;\n this.#plugins = plugins;\n }\n\n /**\n * Parse template and create live DOM.\n * Returns the fragment and a dispose function to clean up subscriptions.\n *\n * Templates are cached by their static string parts - subsequent renders\n * clone the cached DOM structure instead of rebuilding it.\n */\n render(): RenderResult {\n let cached = cache.get(this.#strings);\n if (!cached) cache.set(this.#strings, (cached = this.#buildPrototype()));\n return this.#instantiate(cached);\n }\n\n /** Build the prototype fragment and collect binding descriptors */\n #buildPrototype(): Cached {\n const frag = document.createDocumentFragment();\n const bindings: Binding[] = [];\n const stack: (Element | DocumentFragment)[] = [frag];\n // nodeIndex counts elements and comments (what TreeWalker visits)\n let nodeIndex = 0;\n\n new HTMLParser().parseTemplate(this.#strings, {\n onText: (t) => stack[stack.length - 1]!.append(t),\n\n onOpenTag: (tag, attrs, selfClose) => {\n const parent = stack[stack.length - 1]!;\n const svg =\n tag === \"svg\" ||\n tag === \"SVG\" ||\n (parent instanceof Element && parent.namespaceURI === SVG_NS);\n const el = svg\n ? document.createElementNS(SVG_NS, tag)\n : document.createElement(tag);\n\n const elIndex = nodeIndex++;\n for (const [name, statics, slots] of attrs) {\n if (!slots.length) el.setAttribute(name, statics[0] ?? \"\");\n else {\n const c = name[0];\n if (c === \"@\")\n bindings.push([3, elIndex, name.slice(1), slots[0]!]);\n else if (c === \".\")\n bindings.push([2, elIndex, name.slice(1), slots[0]!]);\n else bindings.push([1, elIndex, name, statics, slots]);\n }\n }\n\n parent.appendChild(el);\n if (!selfClose) stack.push(el);\n },\n\n onClose: () => {\n if (stack.length > 1) stack.pop();\n },\n\n onSlot: (i) => {\n const parent = stack[stack.length - 1]!;\n parent.appendChild(document.createComment(\"\"));\n bindings.push([0, nodeIndex++, i]);\n },\n });\n\n return [frag, bindings];\n }\n\n /** Clone the prototype and apply bindings with current values */\n #instantiate([proto, bindings]: Cached): RenderResult {\n const frag = proto.cloneNode(true) as DocumentFragment;\n const disposers: (() => void)[] = [];\n const values = this.#values;\n\n // Single TreeWalker pass to collect all binding nodes\n const nodes = collectBindingNodes(frag, bindings);\n\n for (let i = 0; i < bindings.length; i++) {\n const b = bindings[i]!;\n const node = nodes[i]!;\n\n if (b[0] === 0) {\n // Content binding - fast path for static values inline\n const value = values[b[2]];\n const t = typeof value;\n if (t === \"string\" || t === \"number\" || t === \"bigint\") {\n // Static primitive - insert text node directly, no disposer needed\n // (text nodes have no subscriptions and are removed with parent)\n const n = document.createTextNode(String(value));\n node.parentNode!.insertBefore(n, node);\n } else if (value == null || t === \"boolean\") {\n // null, undefined, boolean - render nothing, no disposer needed\n } else {\n // Functions, signals, objects, arrays, templates - full binding\n this.#bindContent(node as Comment, value, disposers);\n }\n } else if (b[0] === 1) {\n // Attribute binding\n const [, , name, statics, slots] = b;\n const resolved = slots.map((s) => {\n const v = values[s];\n return typeof v === \"function\"\n ? wrapFn(v as () => unknown, disposers)\n : v;\n });\n let prev: string | null | undefined;\n\n const update = () => {\n let result = statics[0]!,\n allNull = true;\n for (let j = 0; j < resolved.length; j++) {\n const val = isSignal(resolved[j])\n ? (resolved[j] as Reactive<unknown>).value\n : resolved[j];\n if (val != null && val !== false) allNull = false;\n result += (val === true ? \"\" : (val ?? \"\")) + statics[j + 1]!;\n }\n const next = slots.length === 1 && allNull ? null : result;\n if (next !== prev) {\n prev = next;\n if (next === null) (node as Element).removeAttribute(name);\n else (node as Element).setAttribute(name, next);\n }\n };\n update();\n for (const r of resolved)\n if (isSignal(r)) disposers.push(r.subscribe(update));\n } else if (b[0] === 2) {\n // Property binding\n const [, , name, slot] = b;\n bind(\n values[slot],\n (v) => ((node as unknown as Record<string, unknown>)[name] = v),\n disposers,\n );\n } else {\n // Event binding\n const [, , name, slot] = b;\n const handler = values[slot] as EventListener;\n node.addEventListener(name, handler);\n disposers.push(() => node.removeEventListener(name, handler));\n }\n }\n\n return {\n fragment: frag,\n dispose: () => {\n for (const f of disposers) f();\n },\n };\n }\n\n /** Bind content slot - handles plugins, templates, arrays, and reactive values */\n #bindContent(marker: Comment, value: unknown, disposers: (() => void)[]) {\n // Try plugins first\n for (const plugin of this.#plugins) {\n const binder = plugin(value);\n if (binder) {\n binder(marker, disposers);\n return;\n }\n }\n\n // Full reactive path for functions, signals, objects, arrays, templates\n let currentNodes: Node[] = [],\n childDisposers: (() => void)[] = [];\n\n const clear = () => {\n for (const f of childDisposers) f();\n childDisposers = [];\n for (const n of currentNodes) (n as ChildNode).remove();\n currentNodes = [];\n };\n\n const update = (v: unknown) => {\n // Fast path: update existing text node for primitives\n if (\n v != null &&\n typeof v !== \"boolean\" &&\n typeof v !== \"object\" &&\n currentNodes.length === 1 &&\n !childDisposers.length &&\n currentNodes[0] instanceof Text\n ) {\n currentNodes[0].textContent = String(v);\n return;\n }\n clear();\n const parent = marker.parentNode!;\n // Optimize: avoid [v].flat() for non-arrays\n const items = Array.isArray(v) ? v.flat() : [v];\n for (const item of items) {\n if (item instanceof Template) {\n const { fragment, dispose } = item.render();\n childDisposers.push(dispose);\n currentNodes.push(...fragment.childNodes);\n parent.insertBefore(fragment, marker);\n } else if (item != null && typeof item !== \"boolean\") {\n const n = document.createTextNode(String(item));\n currentNodes.push(n);\n parent.insertBefore(n, marker);\n }\n }\n };\n\n bind(value, update, disposers);\n disposers.push(clear);\n }\n}\n\nfunction createHtml(plugins: InterpolationPlugin[]): HtmlTag {\n const tag = ((strings: TemplateStringsArray, ...values: unknown[]) =>\n new Template(strings, values, plugins)) as HtmlTag;\n tag.with = (...more: InterpolationPlugin[]) =>\n createHtml([...plugins, ...more]);\n return tag;\n}\n\nexport const html: HtmlTag = createHtml([]);\n"],"mappings":"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"}
|
package/dist/balises.iife.js
CHANGED
|
@@ -203,7 +203,7 @@ var Balises = (function(exports) {
|
|
|
203
203
|
*/
|
|
204
204
|
is(value) {
|
|
205
205
|
if (context) {
|
|
206
|
-
const slots = this.#isSlots
|
|
206
|
+
const slots = this.#isSlots ??= /* @__PURE__ */ new Map();
|
|
207
207
|
let slot = slots.get(value);
|
|
208
208
|
if (!slot) slots.set(value, slot = new IsSlot(slots, value));
|
|
209
209
|
context.trackSource(slot);
|
|
@@ -279,7 +279,7 @@ var Balises = (function(exports) {
|
|
|
279
279
|
constructor(fn) {
|
|
280
280
|
this.#fn = fn;
|
|
281
281
|
this.#recompute();
|
|
282
|
-
registerDisposer(() => this.dispose());
|
|
282
|
+
if (disposalStack) registerDisposer(() => this.dispose());
|
|
283
283
|
}
|
|
284
284
|
get value() {
|
|
285
285
|
if (this.#dirty) this.#recompute();
|
|
@@ -373,8 +373,8 @@ var Balises = (function(exports) {
|
|
|
373
373
|
c.#isSlots.get(old)?.notify();
|
|
374
374
|
c.#isSlots.get(c.#value)?.notify();
|
|
375
375
|
}
|
|
376
|
-
const subs = c.#subs
|
|
377
|
-
for (let j =
|
|
376
|
+
const subs = c.#subs;
|
|
377
|
+
for (let j = subs.length - 1; j >= 0; j--) subs[j]();
|
|
378
378
|
}
|
|
379
379
|
};
|
|
380
380
|
isBatching() ? enqueueBatchOne(notify) : notify();
|
|
@@ -395,8 +395,12 @@ var Balises = (function(exports) {
|
|
|
395
395
|
const prevLen = this.#sources.length;
|
|
396
396
|
const prev = context;
|
|
397
397
|
setContext(this);
|
|
398
|
+
let threw = false;
|
|
398
399
|
try {
|
|
399
400
|
this.#value = this.#fn();
|
|
401
|
+
} catch (err) {
|
|
402
|
+
threw = true;
|
|
403
|
+
throw err;
|
|
400
404
|
} finally {
|
|
401
405
|
setContext(prev);
|
|
402
406
|
const newLen = this.#sourceIndex;
|
|
@@ -405,7 +409,7 @@ var Balises = (function(exports) {
|
|
|
405
409
|
for (let i = newLen; i < prevLen; i++) sources[i]?.deleteTarget(this);
|
|
406
410
|
sources.length = newLen;
|
|
407
411
|
}
|
|
408
|
-
this.#dirty = false;
|
|
412
|
+
if (!threw) this.#dirty = false;
|
|
409
413
|
this.#computing = false;
|
|
410
414
|
}
|
|
411
415
|
}
|
|
@@ -872,7 +876,9 @@ var Balises = (function(exports) {
|
|
|
872
876
|
}
|
|
873
877
|
return {
|
|
874
878
|
fragment: frag,
|
|
875
|
-
dispose: () =>
|
|
879
|
+
dispose: () => {
|
|
880
|
+
for (const f of disposers) f();
|
|
881
|
+
}
|
|
876
882
|
};
|
|
877
883
|
}
|
|
878
884
|
/** Bind content slot - handles plugins, templates, arrays, and reactive values */
|
|
@@ -886,9 +892,9 @@ var Balises = (function(exports) {
|
|
|
886
892
|
}
|
|
887
893
|
let currentNodes = [], childDisposers = [];
|
|
888
894
|
const clear = () => {
|
|
889
|
-
|
|
895
|
+
for (const f of childDisposers) f();
|
|
890
896
|
childDisposers = [];
|
|
891
|
-
|
|
897
|
+
for (const n of currentNodes) n.remove();
|
|
892
898
|
currentNodes = [];
|
|
893
899
|
};
|
|
894
900
|
const update = (v) => {
|