sigula 2.0.0 → 2.0.1

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 CHANGED
@@ -4,16 +4,28 @@
4
4
 
5
5
  A minimal, signal-based web framework with fine-grained reactivity. No virtual DOM — just direct, minimal updates to the real DOM.
6
6
 
7
+ ```ts
8
+ import {html, on, patch, render, sig, text} from 'sigula';
9
+
10
+ const count = sig(0);
11
+
12
+ render(
13
+ html`<p>${count}</p>
14
+ <button ${patch(on('click', () => count.trans((v) => v + 1)))}>+1</button>`,
15
+ document.querySelector('#app')!,
16
+ );
17
+ ```
18
+
7
19
  ## ✨ Features
8
20
 
9
- - Fine-grained signal reactivity — when state changes, only the DOM nodes that actually depend on it are updated, not the whole component tree
10
- - Declarative signal sources + precise bindings — describe data sources declaratively with signals, then bind them precisely to the DOM or any effect
11
- - No virtual DOM — no diffing, no VNodes. Direct real DOM operations with minimal runtime overhead
12
- - Minimal HTML templates — based on native string templates. No custom compiler, no DSL — just JavaScript strings
13
- - Batched, coalesced updates — writes are queued in a microtask, so a signal touched many times before the flush runs its bindings once, with the final value
14
- - Ultra small — ~4.0KB minified + gzipped
15
- - TypeScript friendly — full type inference for signals and template bindings
16
- - Simple but performant — tiny API surface, low mental overhead, no compromise on performance
21
+ - **Fine-grained signal reactivity** — when a signal changes, only the DOM nodes that actually depend on it are updated, not the whole component tree.
22
+ - **Declarative sources + precise bindings** — describe state with signals, then bind them precisely to a text node, an attribute, or an effect.
23
+ - **No virtual DOM** — no VNodes, no diffing, no reconciliation pass. Direct real DOM operations.
24
+ - **Native string templates** — `html` is a tagged template over plain JavaScript strings. No custom compiler, no JSX transform, no `.vue` files.
25
+ - **Batched, coalesced updates** — writes are queued in a microtask; a signal touched many times before the flush runs each dependent binding once, against the final value.
26
+ - **Ultra small** — ~4.5KB minified + gzipped, with an API surface you can read in one sitting.
27
+ - **TypeScript first** — full type inference for signals, template bindings, and patch commands.
28
+ - **Zero tooling** — ESM-only, `sideEffects: false`, no build step required to author components.
17
29
 
18
30
  ## Installation
19
31
 
@@ -23,225 +35,397 @@ pnpm add sigula
23
35
  yarn add sigula
24
36
  ```
25
37
 
38
+ Sigula is ESM-only and ships type declarations. Importing the module is side-effect free; the DOM is only touched when you actually render.
39
+
26
40
  ## Quick Start
27
41
 
42
+ ### 1. Render something
43
+
28
44
  ```ts
29
- import {compute, html, on, patch, render, sig, text, type View} from 'sigula';
45
+ import {html, render} from 'sigula';
46
+
47
+ const app = document.querySelector('#app')!;
30
48
 
31
- const Equation = (): View => {
32
- const x = sig(0);
33
- const y = sig(1);
49
+ render(html`<h1>Hello, world!</h1>`, app);
50
+ ```
34
51
 
35
- const s = {x, y};
36
- const sum = compute(s, (v) => v.x + v.y);
37
- const product = compute(s, (v) => v.x * v.y);
38
- const diff = compute(s, (v) => v.x - v.y);
39
- const quotient = compute(s, (v) => v.x / v.y);
52
+ `html` returns a `View` — a real `DocumentFragment` plus the metadata Sigula needs to update it later. `render(view, node)` appends it and returns a disposer.
40
53
 
41
- const xSquare = compute(x, (v) => v * v);
42
- const ySquare = compute(y, (v) => v * v);
54
+ ### 2. Make it reactive
43
55
 
44
- const sumDiffProduct = compute({sum, diff}, (v) => v.sum * v.diff);
45
- const squareDiff = compute({xSquare, ySquare}, (v) => v.xSquare - v.ySquare);
56
+ ```ts
57
+ import {html, render, sig} from 'sigula';
46
58
 
47
- return html`<div>
48
- <h1>Equation</h1>
49
- <div>
50
- <p>x: ${text(x)} -
51
- <button ${patch(on('click', () => x.trans((v) => v + 1)))}>+1</button>
52
- <button ${patch(on('click', () => x.trans((v) => v - 1)))}>-1</button>
53
- </p>
54
- <p>y: ${text(y)} -
55
- <button ${patch(on('click', () => y.trans((v) => v + 1)))}>+1</button>
56
- <button ${patch(on('click', () => y.trans((v) => v - 1)))}>-1</button>
57
- </p>
58
- <p>sum: x + y = ${text(x)} + ${text(y)} = ${text(sum)}</p>
59
- <p>difference: x - y = ${text(x)} - ${text(y)} = ${text(diff)}</p>
60
- <p>product: x * y = ${text(x)} * ${text(y)} = ${text(product)}</p>
61
- <p>quotient: x / y = ${text(x)} / ${text(y)} = ${text(quotient)}</p>
62
- <p>
63
- (x + y)(x - y)
64
- = (${text(x)} + ${text(y)})(${text(x)} - ${text(y)})
65
- = ${text(sum)}*${text(diff)} = ${text(sumDiffProduct)}
66
- <br />
67
- = x^2 - y^2 = ${text(xSquare)} - ${text(ySquare)} = ${text(squareDiff)}
68
- </p>
69
- </div>
70
- </div>`;
71
- };
59
+ const name = sig('Alice');
72
60
 
73
- const appNode = document.querySelector('#app');
74
- if (!appNode) throw new Error('#app not found');
75
- render(Equation(), appNode);
61
+ render(html`<h1>Hello, ${name}!</h1>`, app);
62
+
63
+ // Only the text node inside <h1> is updated.
64
+ name.update('Bob'); // → "Hello, Bob!"
76
65
  ```
77
66
 
78
- ## 🧠 Core Concepts
67
+ A `Sig` interpolated in a **content position** is upgraded to a `text()` view automatically, so `${name}` and `${text(name)}` are equivalent.
79
68
 
80
- ### Fine-grained updates to the real DOM
69
+ ### 3. Handle events and patch attributes
81
70
 
82
- Traditional frameworks like React re-run component functions, generate a virtual DOM, diff it, and finally apply changes to the real DOM. Sigula works completely differently:
71
+ Dynamic values in an **attribute position** must be wrapped in `patch(...)`:
83
72
 
84
73
  ```ts
85
- import {html, text} from 'sigula';
74
+ import {compute, html, on, patch, render, sig, style, text} from 'sigula';
86
75
 
87
- const name = sig('Alice');
88
-
89
- const App = html`<h1>Hello, ${text(name)}!</h1>`;
76
+ const count = sig(0);
77
+ const color = compute(count, (v) => (v >= 0 ? 'green' : 'red'));
90
78
 
91
- // When name changes, only the text node inside <h1> is updated
92
- name.update('Bob'); // → the text changes from "Hello, Alice!" to "Hello, Bob!"
79
+ render(
80
+ html`<p ${patch(style('color', color))}>${text(count)}</p>
81
+ <button ${patch(on('click', () => count.trans((v) => v + 1)))}>+1</button>
82
+ <button ${patch(on('click', () => count.trans((v) => v - 1)))}>-1</button>`,
83
+ app,
84
+ );
93
85
  ```
94
86
 
95
- Only the exact text node that depends on `name` is updated. Everything else stays untouched.
87
+ ### 4. Split into components
88
+
89
+ There is no component class, no lifecycle, no registration. **A component is just a function that returns a `View`.** It runs once, wires up bindings, and is never called again.
90
+
91
+ ```ts
92
+ import {html, on, patch, render, sig, type View} from 'sigula';
93
+
94
+ const Counter = (initial: number): View => {
95
+ const count = sig(initial);
96
+ return html`<div>
97
+ <span>${count}</span>
98
+ <button ${patch(on('click', () => count.trans((v) => v + 1)))}>+1</button>
99
+ </div>`;
100
+ };
101
+
102
+ render(html`<main>${Counter(0)} ${Counter(100)}</main>`, app);
103
+ ```
96
104
 
97
- ### Declarative signal sources + precise bindings
105
+ Because the function body runs exactly once, `sig(initial)` *is* the local state — no hooks, no `this`, no re-run semantics to reason about.
98
106
 
99
- Signals are the single source of truth. Every view and side effect is derived from them:
107
+ ### 5. Render lists conditionally
100
108
 
101
109
  ```ts
102
- import {
103
- compute,
104
- html,
105
- on,
106
- patch,
107
- render,
108
- repeat,
109
- type Sig,
110
- sig,
111
- style,
112
- text,
113
- type View,
114
- val,
115
- view,
116
- } from 'sigula';
117
-
118
- interface Todo {
119
- id: number;
120
- text: string;
121
- done: Sig<boolean>;
122
- }
110
+ import {compute, html, on, patch, render, repeat, sig, text, val, view} from 'sigula';
123
111
 
124
- const Todos = (): View => {
112
+ interface Todo { id: number; text: string; done: boolean }
113
+
114
+ const Todos = () => {
125
115
  const input = sig('');
126
116
  const todos = sig<Todo[]>([]);
127
- const filter = sig<'all' | 'active' | 'done'>('all');
128
-
129
- // Derived Signals
130
- const visibleTodos = compute({todos, filter}, (v) => {
131
- switch (v.filter) {
132
- case 'active':
133
- return v.todos.filter((t) => !t.done.get());
134
- case 'done':
135
- return v.todos.filter((t) => t.done.get());
136
- default:
137
- return v.todos;
138
- }
139
- });
140
-
141
- const isEmpty = compute(visibleTodos, (v) => v.length <= 0);
142
-
143
- const addTodo = (e: Event) => {
117
+ const filter = sig<'all' | 'active'>('all');
118
+
119
+ const visible = compute({todos, filter}, (v) =>
120
+ v.filter === 'active' ? v.todos.filter((t) => !t.done) : v.todos,
121
+ );
122
+ const isEmpty = compute(visible, (v) => v.length === 0);
123
+
124
+ const add = (e: Event) => {
144
125
  e.preventDefault();
145
126
  if (!input.get().trim()) return;
146
-
147
- todos.trans((items) => [
148
- ...items,
149
- {id: Date.now(), text: input.get().trim(), done: sig(false)},
150
- ]);
127
+ todos.trans((items) => [...items, {id: Date.now(), text: input.get().trim(), done: false}]);
151
128
  input.update('');
152
129
  };
153
130
 
154
- const remove = (id: number) => {
155
- todos.trans((items) => items.filter((item) => item.id !== id));
156
- };
157
-
158
- const itemView = (item: Todo) => html`<li>
159
- <span
160
- ${patch(
161
- on('click', () => item.done.trans((v) => !v)),
162
- style(
163
- 'textDecoration',
164
- compute(item.done, (v): string => (v ? 'line-through' : 'none')),
165
- ),
166
- )}
167
- >${text(item.text)}</span>
168
- <button ${patch(on('click', () => remove(item.id)))}>x</button>
169
- </li>`;
170
-
171
- // Bind precisely to the DOM
172
- return html`<div style="margin: 2rem auto; max-width: 400px">
173
- <h1>Todos</h1>
174
- <form ${patch(on('submit', addTodo))}>
175
- <input ${patch(
176
- val(input),
177
- on('change', (e) => {
178
- if (e.target) input.update((e.target as HTMLInputElement).value);
179
- }),
180
- )} />
131
+ return html`<form ${patch(on('submit', add))}>
132
+ <input ${patch(val(input), on('change', (e) => input.update((e.target as HTMLInputElement).value)))} />
181
133
  <button>Add</button>
182
134
  </form>
183
- <div>
184
- filter:
185
- <button ${patch(on('click', () => filter.update('all')))}>all</button>
186
- <button ${patch(on('click', () => filter.update('active')))}>active</button>
187
- <button ${patch(on('click', () => filter.update('done')))}>done</button>
188
- </div>
189
- ${view(isEmpty, (v) =>
190
- v
191
- ? text('empty')
192
- : html`<ul>${repeat(visibleTodos, {
193
- key: (item) => item.id.toString(),
194
- view: (item) => itemView(item),
135
+ ${view(isEmpty, (empty) =>
136
+ empty
137
+ ? text('Nothing here yet')
138
+ : html`<ul>${repeat(visible, {
139
+ key: (t) => t.id.toString(),
140
+ view: (t) => html`<li>${text(t.text)}</li>`,
195
141
  })}</ul>`,
196
- )}
197
- </div>`;
142
+ )}`;
198
143
  };
199
144
 
200
- const appNode = document.querySelector('#app');
201
- if (!appNode) throw new Error('#app not found');
202
- render(Todos(), appNode);
145
+ const dispose = render(Todos(), app);
146
+ dispose(); // detaches every binding and removes the nodes
147
+ ```
148
+
149
+ Runnable versions live in [`examples/`](./examples) (`equation`, `filtertodos`).
150
+
151
+ ## 🧠 Core Concepts
152
+
153
+ ### The whole architecture in one picture
154
+
155
+ ```
156
+ ┌──────────────── Core Concepts ────────────────┐
157
+ │ │
158
+ Sig ──┤ holds a value + a list of Binds │ state
159
+ │ │
160
+ Bind ─┤ { sig, context, cmd } │ the edge
161
+ │ │
162
+ Cmd ──┤ (value, context) => void │ the work
163
+ │ │
164
+ View ─┤ { node, boundary(), cleanBinds() } │ DOM region
165
+ Patch ┤ deferred commands for one element │
166
+ │ │
167
+ Queue ┤ one global microtask, coalesced per Bind │ scheduling
168
+ └───────────────────────────────────────────────┘
203
169
  ```
204
170
 
205
- Signals can bind to the DOM, to effects, or to other computed signals — one reactive model across the entire application.
171
+ Everything else in the library is a convenience layer over these five pieces. Read the rest as: *how do I create a `Bind`, and what `Cmd` should it run?*
206
172
 
207
- ### No virtual DOM
173
+ ### Signals: `sig`
208
174
 
209
- Sigula does not create VNodes and does not diff trees. During the initial mount, the template establishes direct subscriptions between signals and DOM nodes. Every subsequent signal change goes straight to the corresponding DOM node.
175
+ A `Sig<T>` is a value container that owns a list of **bindings**. It never touches the DOM itself.
176
+
177
+ ```ts
178
+ const count = sig(0);
179
+
180
+ count.get(); // 0 — read the current value
181
+ count.update(1); // set; dependents notified only if not deeply equal
182
+ count.update(1); // no-op: deeply equal, nothing is scheduled
183
+ count.forceUpdate(1); // set and always notify (even when equal)
184
+ count.trans((v) => v + 1);// apply a function to the current value
185
+ count.notify(); // re-run dependents without changing the value
186
+ ```
210
187
 
211
- This means:
212
- - No VNode creation or destruction overhead
213
- - No diffing traversal cost
214
- - Memory usage scales linearly with DOM nodes, not with component tree depth
188
+ | Method | Purpose |
189
+ | --- | --- |
190
+ | `get()` | Read the current value. |
191
+ | `update(v)` | Write, skipping the notification when `eq(v, current)`. |
192
+ | `forceUpdate(v)` | Write and always notify. Use after a structurally-equal-but-new value. |
193
+ | `trans(fn)` | `update(fn(current))` — the idiomatic way to derive the next state. |
194
+ | `notify()` | Re-run dependents against the current value. Use after mutating a held object/array **in place**. |
195
+ | `addBind` / `removeBind` / `getBinds` | Low-level binding management; prefer `createBind` or the template APIs. |
215
196
 
216
- ### Minimal HTML templates
197
+ **Equality is deep by default.** `update` compares with `eq`, a structural comparator covering primitives, arrays, `Date`, `RegExp`, `Map`, `Set` and plain objects, and delegating to `a.equals(b)` when the value implements `Equatable`. Replacing `{a: 1}` with another `{a: 1}` is therefore a no-op. Values with different prototypes are never equal. `sig(v, {eq})` accepts a custom comparator.
217
198
 
218
- Templates are plain JavaScript native string templates. No custom compiler, no `.vue` files, no JSX transform:
199
+ **In-place mutation needs `notify()`.** Sigula does not proxy your objects. If you mutate a held array or object instead of replacing it, the value identity never changes and `update` cannot see it:
219
200
 
220
201
  ```ts
221
- const App: View = html`
222
- <div class="card">
223
- <h2>${text(title)}</h2>
224
- <p>${text(description)}</p>
225
- <button ${patch(on('click', handleClick))}>Click me</button>
226
- </div>
227
- `;
202
+ const items = sig<string[]>([]);
203
+ items.get().push('a'); // value object mutated, no write detected
204
+ items.notify(); // ← tell dependents to re-run
228
205
  ```
229
206
 
230
- `html` is a tagged template function that returns a mountable template (`View`) object. You can use any editor's syntax highlighting, formatting, and ESLint rules — no extra tooling required. Templates are cached per call site, so rendering the same template twice only parses it once.
207
+ ### Bindings: the unit of reactivity
208
+
209
+ A binding is a three-field record — that is the entire reactive primitive:
210
+
211
+ ```ts
212
+ interface Bind<T, C> {
213
+ sig: Sig<T>; // what it observes
214
+ context: C; // where the result goes (a text node, an element, …)
215
+ cmd: (val: T, ctx: C) => void; // what to do with the new value
216
+ removed: boolean;
217
+ queued?: boolean;
218
+ }
219
+ ```
220
+
221
+ So "fine-grained" is literal: `text(name)` creates a bind whose `context` is one `Text` node and whose `cmd` is `node.textContent = String(val)`. Nothing else in the tree is involved.
222
+
223
+ ```ts
224
+ const name = sig('Alice');
225
+ const v = text(name); // Bind{ sig: name, context: {node: <Text>}, cmd: textCmd }
226
+
227
+ name.update('Bob'); // → textCmd('Bob', {node}) → that one node changes
228
+ ```
229
+
230
+ Because a `Cmd` is just a function, the same model covers DOM writes, derived values, and arbitrary side effects — there is no separate `effect()`/`watch()` API to learn.
231
+
232
+ ### Derived signals: `compute`
233
+
234
+ `compute` returns a `DerivedSig<T>`, which is a `Sig` you cannot write to. Two overloads:
235
+
236
+ ```ts
237
+ const x = sig(1);
238
+ const doubled = compute(x, (v) => v * 2); // from one signal
239
+
240
+ const sum = compute({x, y}, (v) => v.x + v.y); // from a record of signals
241
+ ```
231
242
 
232
- ### Ultra small
243
+ With the record form, `fn` receives the matching record of *values* (`ValRecord<S>`), fully typed. Derived signals compose: a `DerivedSig` is a valid source for another `compute`, and a valid interpolation target in a template.
233
244
 
234
- minified + gzipped: ~4.0KB
245
+ Derived signals are **lazy about upstream**. A `DerivedSig` detaches from its sources when it loses its last consumer (which happens whenever a `view()` subtree is hidden), and re-links and recomputes once when a consumer comes back. You get the memory savings without manual disposal.
235
246
 
236
- ## 📖 Reference
247
+ ### Templates: `html`
248
+
249
+ ```ts
250
+ const html = (strs: TemplateStringsArray, ...rawItems: HtmlItem[]): View;
251
+ ```
252
+
253
+ `html` is a tagged template over **native HTML strings** — no compiler, no DSL, no JSX pragma. Interpolations fall into two positions, and the distinction is the one rule to memorize:
254
+
255
+ | Position | What goes there | Example |
256
+ | --- | --- | --- |
257
+ | **Content** (child slot) | a `View`, `text`, `raw`, a `Sig`, or any primitive | `` html`<h1>${name}</h1>` `` |
258
+ | **Attribute** (inside a tag) | a `Patch` from `patch(...)` | `` html`<input ${patch(val(name))} />` `` |
259
+
260
+ Anything interpolated in a content position that is not already a `View` or `Patch` is coerced with `text()`, i.e. escaped and rendered as `String(value)`:
261
+
262
+ ```ts
263
+ const sigItem = sig('signal item');
264
+ const strItem = 'string data';
265
+ const numItem = 2026;
266
+ const htmlItem = html`<span>Html Span Element</span>`;
267
+
268
+ render(
269
+ html`<p>${sigItem} / ${strItem} / ${numItem}</p>
270
+ <div>${htmlItem}</div>
271
+ <div>${raw('<strong>Trusted</strong> HTML')}</div>`,
272
+ app,
273
+ );
274
+
275
+ sigItem.update('string with <strong>markup</strong>'); // stays escaped — renders as text
276
+ ```
277
+
278
+ `raw(source)` parses its value through a detached `<template>` and mounts the resulting nodes with no wrapper element. **It does not escape** — only ever pass trusted HTML.
279
+
280
+ #### How parsing works (and why it is fast)
281
+
282
+ Every call site gets a random marker, `@sig_<rand>`. Interpolations are rendered into the template string as:
283
+
284
+ - an **attribute marker** `@sig_x` for a `Patch`,
285
+ - a **comment marker** `<!--@sig_x-->` for a `View`.
286
+
287
+ ```html
288
+ <div @sig_2734618> <!--@sig_2734618--> <!--@sig_2734618--> </div>
289
+ ```
290
+
291
+ Therefore parsing needs no regular expressions: Sigula walks the parsed fragment with a single `TreeWalker`, collects each marker node in order, and commits the matching item (`commitPatch` for elements, `commitView` for comments). The uniform format is also what makes the API extensible — `id`, `on`, `attr`, `style` are all just patch items, and you can write your own.
292
+
293
+ Two consequences worth knowing:
294
+
295
+ 1. **One `Patch` per element.** The marker is an attribute, so a second `patch()` on the same element cannot be located. Combine everything into a single `patch(...)` call — that is what its variadic form is for.
296
+ 2. **Templates are cached per call site** (a `WeakMap` on the `TemplateStringsArray`), and the cache key includes the *mix* of patch/view slots (a bitmask for up to 31 slots, a string beyond that). Repeated renders skip parsing entirely; a call site that changes its interpolation mix simply gets a fresh template.
297
+
298
+ The returned `View` is `{node, children, boundary(), cleanBinds()}` — see [Boundaries](#boundaries-and-teardown).
299
+
300
+ ### Patching an element: `patch`
301
+
302
+ `patch` declares bindings to apply to **one** element. It accepts either a props object, or a list of command items, or both:
303
+
304
+ ```ts
305
+ // Props form — desugared into commands
306
+ html`<input ${patch({id: 'name', val: name, placeholder: 'Your name'})} />`
307
+
308
+ // Command form
309
+ html`<input ${patch(val(name), attr('placeholder', placeholder))} />`
310
+ ```
311
+
312
+ The props object handles `id`, `val`, `class`, `style`, `styleProp`, `on`; any other key becomes an attribute. A key whose value is `undefined` is skipped.
313
+
314
+ | Command | What it does |
315
+ | --- | --- |
316
+ | `id(source)` | Sets `element.id`. |
317
+ | `val(source)` | Sets the `value` **property** (form controls). |
318
+ | `attr(key, source)` | `setAttribute(key, …)` — for boolean/ARIA/data attributes. |
319
+ | `style(key, source)` | Sets a typed inline style property. |
320
+ | `styleProp(key, source)` | `style.setProperty` — for `--custom-properties`. |
321
+ | `toggleClass(token, source)` | Toggles one class from the truthiness of the value. |
322
+ | `toggleClasses(tokens, source)` | Toggles several classes from one value. |
323
+ | `on(type, listener, options?)` | `addEventListener`. |
324
+ | `act(source, fn)` | Escape hatch: run arbitrary code with `(element, value)`. |
325
+
326
+ Every command takes a plain value (applied once at mount) **or** a `Sig` (applied at mount and re-applied on change):
327
+
328
+ ```ts
329
+ const disabled = sig(false);
330
+ const label = 'Submit';
331
+
332
+ html`<button ${patch(attr('disabled', disabled), attr('aria-label', label))}>Go</button>`
333
+ // ↑ reactive ↑ static
334
+ ```
335
+
336
+ Note that `on` registers the listener **once at mount**; the listener itself is not a reactive source. Drive updates by writing to a signal inside it.
337
+
338
+ ### Control flow
339
+
340
+ Sigula has exactly four control-flow helpers, all returning a `View`:
341
+
342
+ | Helper | Use it for |
343
+ | --- | --- |
344
+ | `view(sig, viewFn)` | Swap one view for another when `sig` changes (conditional rendering). |
345
+ | `repeat(sig, {key, view, eq?})` | Keyed list rendering with minimal DOM reuse/moves. |
346
+ | `list(items, viewFn)` | A **static** array rendered once — no keying, no reconciliation. |
347
+ | `frag(...views)` | Compose several views as flat siblings with no wrapper element. |
348
+
349
+ ```ts
350
+ // conditional
351
+ ${view(isEmpty, (empty) => (empty ? text('empty') : listView))}
352
+
353
+ // keyed list
354
+ ${repeat(todos, {
355
+ key: (t) => t.id.toString(),
356
+ view: (t) => html`<li>${text(t.text)}</li>`,
357
+ eq: (a, b) => a.id === b.id && a.text === b.text, // optional, defaults to eq
358
+ })}
359
+ ```
360
+
361
+ `repeat` matches items by `key` with a two-pointer walk, reusing, moving, creating, or removing as few nodes as possible, and uses `moveBefore` when available to preserve element state across moves. When nothing changed — same keys, same order, equal items — it bails out before touching the DOM at all. Use `list` instead when the array never changes shape.
362
+
363
+ ### Boundaries and teardown
364
+
365
+ A `View` occupies a contiguous **range of sibling nodes**, described by `boundary(): {start, end}`. This is how Sigula swaps or removes multi-node regions without a wrapper element or a virtual tree.
366
+
367
+ Teardown is explicit and recursive:
368
+
369
+ ```ts
370
+ const dispose = render(App(), app);
371
+ dispose(); // removeBoundary(view.boundary()) + view.cleanBinds()
372
+ ```
373
+
374
+ `cleanBinds()` detaches the view's own bind and, recursively, all child binds. When a `Sig` loses its last bind it calls `cleanup()`, so a subtree that is removed stops receiving updates immediately — no manual effect cleanup, no leak by default.
375
+
376
+ ### The update queue
377
+
378
+ Writes never run synchronously. Every write pushes the signal's binds onto one global queue and schedules a single `queueMicrotask`.
379
+
380
+ ```ts
381
+ sig0.update(a); // ┐
382
+ sig1.update(b); // ├── one microtask
383
+ sig2.update(c); // ┘
384
+
385
+ sig.update(1); sig.update(2); sig.update(3); // each dependent binding runs ONCE, against 3
386
+ ```
387
+
388
+ - **Batched** across signals — many writes, one flush.
389
+ - **Coalesced per binding** — a `queued` flag keeps a bind from entering the queue twice; since `cmd` reads `sig.get()` at call time, it always sees the newest value.
390
+ - **Error-isolated** — a throwing bind is logged (`console.error('[Queue] task failed:', …)`) and the rest of the queue still runs.
391
+
392
+ ### What Sigula deliberately does not have
393
+
394
+ | Not included | Why |
395
+ | --- | --- |
396
+ | Virtual DOM / diffing | Updates are bound at mount time; there is nothing to diff. |
397
+ | A component instance or lifecycle | A component is a function that returns a `View`, and it runs once. |
398
+ | A compiler / build step | Templates are native tagged-template strings. |
399
+ | A router, store, or SSR runtime | Out of scope. Sigula is the rendering and reactivity layer; bring your own. |
400
+ | Proxy-based deep reactivity | Values are compared, not wrapped. Mutate in place and call `notify()`. |
401
+ | Automatic dependency tracking | Bindings are explicit (`sig` → `cmd` → target), which is what keeps the runtime at ~4.5KB. |
402
+
403
+ ## 📖 API Cheat Sheet
404
+
405
+ Full signatures and documentation: [Reference.md](./Reference.md).
406
+
407
+ | Export | Kind | Returns |
408
+ | --- | --- | --- |
409
+ | `sig(v, opts?)` | state | `Sig<T>` |
410
+ | `compute(sig, fn)` / `compute(record, fn)` | derived | `DerivedSig<T>` |
411
+ | `html\`…\`` | template | `View` |
412
+ | `text(source)` | template | `View` (escaped text node) |
413
+ | `raw(source)` | template | `View` (**unescaped** HTML) |
414
+ | `patch(props \| …items)` | binding | `Patch` |
415
+ | `id`, `val`, `attr`, `style`, `styleProp`, `toggleClass`, `toggleClasses`, `on`, `act` | patch commands | `ToPatchItem<T>` |
416
+ | `view(sig, viewFn)` | control flow | `View` |
417
+ | `repeat(sig, {key, view, eq?})` | control flow | `View` |
418
+ | `list(items, viewFn)` | control flow | `View` (static) |
419
+ | `frag(...views)` | composition | `View` |
420
+ | `render(view \| () => view, node)` | mounting | disposer `() => void` |
421
+ | `createBind`, `removeBind`, `eq`, `toBoundary`, `walkBoundary` | low-level | — |
422
+ | `Sig`, `DerivedSig`, `View`, `Patch`, `Reactive<T>`, `Eq<T>`, `Equatable` | types | — |
237
423
 
238
424
  The full API reference is generated from the TSDoc comments in the source: see [Reference.md](./Reference.md).
239
425
 
240
426
  ## Errors
241
427
 
242
- Runtime errors carry a short code in `message` instead of a sentence, so the
243
- string tables stay out of the bundle. Codes with arguments are colon-separated.
244
- Look yours up here:
428
+ Runtime errors carry a short code in `message` instead of a sentence, so the string tables stay out of the bundle. Codes with arguments are colon-separated.
245
429
 
246
430
  | Code | Thrown by | Meaning |
247
431
  | --- | --- | --- |
@@ -256,16 +440,20 @@ Look yours up here:
256
440
  | `E9` | `repeat` | There is no node after the fence to move before. |
257
441
  | `E10` | `html` | The template is empty (an empty tagged template). |
258
442
  | `E11:<expected>:<got>` | `html` | Interpolation count does not match the template's slots. |
259
- | `E12` | `html` | Unmatched interpolation; a `Patch` must be in an attribute position and a `View`/text value in a content position. |
443
+ | `E12` | `html` | Unmatched interpolation: a `Patch` must sit in an attribute position, a `View`/text value in a content position. |
444
+
445
+ ## How it compares
260
446
 
261
- ## Reactivity model
447
+ | | Sigula | Lit | Solid | React |
448
+ | --- | --- | --- | --- | --- |
449
+ | Update model | Signal → bind → DOM node | Property → `render()` → part commit | Signal → compiled DOM | Component re-render → VDOM diff |
450
+ | Compiler required | No | No | Yes (JSX/babel) | Yes (JSX) |
451
+ | Component re-runs | Never | On property change | Never | On every state change |
452
+ | Approx. size | ~4.5KB min+gzip | ~5KB | ~7KB | — (much larger runtime) |
453
+ | Templating | Native tagged templates | Tagged templates | JSX | JSX |
454
+ | Standard Web Components | No (any DOM node) | Yes | No | No |
262
455
 
263
- - **Batched.** When a signal changes, its bindings are queued, not run synchronously.
264
- - **Coalesced per binding.** A binding that is written to multiple times before the microtask flush runs once, reading the signal's final value. `sig.update(1); sig.update(2); sig.update(3)` runs each dependent binding a single time against `3`.
265
- - **`update` vs `forceUpdate`.** `update` skips work when the new value is deeply equal to the current one; `forceUpdate` always notifies. Use `forceUpdate` when a value is structurally equal but you still need a re-render (for example, mutating an object in place).
266
- - **`notify` for in-place mutation.** `sig.notify()` re-runs dependents against the current value without setting a new one. Use it after mutating a held object or array in place; `update`/`forceUpdate` set a value. On a `DerivedSig`, `notify` schedules its consumers but does not itself recompute the derived value.
267
- - **Error isolation.** A throwing binding does not stop the rest of the queue; the error is logged as `console.error('[Queue] task failed:', error, bind)`.
268
- - **Deep equality by default.** `update`, `compute`, and `repeat` compare with `eq`, so replacing `{a: 1}` with another `{a: 1}` is a no-op.
456
+ *Size figures are each project's own published claim, measured with different tooling and feature sets — treat them as an order of magnitude, not a benchmark.*
269
457
 
270
458
  ## License
271
459
 
package/dist/sigula.d.ts CHANGED
@@ -192,6 +192,7 @@ export declare class DerivedSig<T> extends Sig<T> {
192
192
  * Creates a writable signal holding `v`.
193
193
  *
194
194
  * @param v - the initial value.
195
+ * @param opts - optional settings; `eq` overrides the comparator used by `update`.
195
196
  * @returns a new `Sig` for `v`.
196
197
  * @example
197
198
  * ```ts
@@ -201,7 +202,9 @@ export declare class DerivedSig<T> extends Sig<T> {
201
202
  * ```
202
203
  * @group Reactivity
203
204
  */
204
- export declare const sig: <T>(v: T) => Sig<T>;
205
+ export declare const sig: <T>(v: T, opts?: {
206
+ eq?: Eq<T>;
207
+ }) => Sig<T>;
205
208
  /**
206
209
  * Detaches a binding and marks it removed so queued runs are skipped.
207
210
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sigula.d.ts","names":[],"sources":["../src/core/boundary.ts","../src/core/cmd.ts","../src/core/eq.ts","../src/core/sig.bind.ts","../src/core/compute.ts","../src/core/err.ts","../src/core/patch.core.ts","../src/core/utils.ts","../src/core/view.core.ts","../src/frag.ts","../src/html.ts","../src/list.ts","../src/patch.ts","../src/raw.ts","../src/render.ts","../src/repeat.ts","../src/text.ts","../src/view.ts"],"mappings":"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"}
1
+ {"version":3,"file":"sigula.d.ts","names":[],"sources":["../src/core/boundary.ts","../src/core/cmd.ts","../src/core/eq.ts","../src/core/sig.bind.ts","../src/core/compute.ts","../src/core/err.ts","../src/core/patch.core.ts","../src/core/utils.ts","../src/core/view.core.ts","../src/frag.ts","../src/html.ts","../src/list.ts","../src/patch.ts","../src/raw.ts","../src/render.ts","../src/repeat.ts","../src/text.ts","../src/view.ts"],"mappings":"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"}
package/dist/sigula.js CHANGED
@@ -1,2 +1,2 @@
1
- function e(e){throw Error(e)}const t=(e,t)=>{let n=e.start;for(;n;){let r=n.nextSibling;if(t(n),n===e.end)break;n=r}},n=e=>{let n=e.start.parentNode;n&&t(e,e=>n.removeChild(e))},r=t=>{let n=t.nodeType===Node.DOCUMENT_FRAGMENT_NODE?{start:t.firstChild,end:t.lastChild}:{start:t,end:t};return(!n.start||!n.end)&&e(`E2`),n},i=(t,n)=>{let i=r(n),a=t.start.parentNode;if(a||e(`E3`),t.start===t.end)a.replaceChild(n,t.start);else{let e=t.start.nextSibling;for(a.replaceChild(n,t.start);e;){let n=e.nextSibling;if(a.removeChild(e),e===t.end)break;e=n}}return i},a=e=>typeof e==`object`&&!!e&&`equals`in e&&typeof e.equals==`function`,o=(e,t)=>{if(e===t)return!0;if(typeof e!=typeof t||e===null||t===null||typeof e!=`object`)return!1;if(a(e))return e.equals(t);if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(!o(e[n],t[n]))return!1;return!0}if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(e instanceof RegExp&&t instanceof RegExp)return e.toString()===t.toString();if(e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(let[n,r]of e)if(!t.has(n)||!o(r,t.get(n)))return!1;return!0}if(e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;let n=Array.from(e),r=Array.from(t);return o(n,r)}if(Object.getPrototypeOf(e)!==Object.getPrototypeOf(t))return!1;let n=e,r=t,i=Object.keys(n),s=Object.keys(r);if(i.length!==s.length)return!1;for(let e=0;e<i.length;e++){let t=i[e];if(!Object.hasOwn(r,t)||!o(n[t],r[t]))return!1}return!0},s=new class{_binds=[];head=0;running=!1;scheduled=!1;addAll(e){for(let t of e)t.queued||(t.queued=!0,this._binds.push(t));return this._binds.length>this.head&&this.kick(),this}kick(){this.running||this.scheduled||(this.scheduled=!0,queueMicrotask(()=>{this.running=!0,this.scheduled=!1,this.flush()}))}flush(){this.running=!0;try{for(;this.head<this._binds.length;){let e=this._binds[this.head++];try{let{removed:t,sig:n,context:r,cmd:i}=e;t||i(n.get(),r)}catch(t){console.error(`[Queue] task failed:`,t,e)}finally{e.queued=!1}}}finally{this.running=!1,this.head<this._binds.length?(this._binds=this._binds.slice(this.head),this.head=0,this.kick()):(this._binds.length=0,this.head=0)}}};var c=class e{_val;_binds=[];_eq;constructor(e,t){this._val=e,this._eq=t?.eq??o}equals(t){return t instanceof e&&this._eq(this.get(),t.get())}get(){return this._val}notify(){s.addAll(this._binds)}forceUpdate(e){this._val=e,this.notify()}update(e){this._eq(e,this._val)||this.forceUpdate(e)}trans(e){this.update(e(this._val))}addBind(e){this._binds.push(e)}removeBind(e){let t=this._binds.indexOf(e);t>=0&&this._binds.splice(t,1),this._binds.length===0&&this.cleanup()}getBinds(){return this._binds}cleanup(){}},l=class extends c{_fromBinds=[];_linked=!0;addFromBind(e){this._fromBinds.push(e)}addBind(e){if(super.addBind(e),this._linked)return;this._linked=!0;for(let e=0;e<this._fromBinds.length;e++){let t=this._fromBinds[e];this._fromBinds[e]=f(t.sig,t.context,t.cmd)}let t=this._fromBinds[0];t&&t.cmd(t.sig.get(),t.context)}cleanup(){if(this._linked){this._linked=!1;for(let e of this._fromBinds)d(e)}}};const u=e=>new c(e),d=e=>{e.removed=!0,e.sig.removeBind(e)},f=(e,t,n)=>{let r={sig:e,context:t,cmd:n,removed:!1,queued:!1};return e.addBind(r),r},p=(e,t)=>{t.target.update(t.fn(e))},m=(e,t)=>{let n={};for(let[e,r]of t.entries)n[e]=r.get();t.target.update(t.fn(n))},h=(e,t)=>{let n=new l(t(e.get())),r={target:n,fn:t};return n.addFromBind(f(e,r,p)),n},g=(e,t)=>{let n=[],r={};for(let[t,i]of Object.entries(e))t&&i&&(n.push([t,i]),r[t]=i.get());let i=new l(t(r)),a={target:i,fn:t,entries:n};for(let e of n)i.addFromBind(f(e[1],a,m));return i};function _(e,t){return e instanceof c?h(e,t):g(e,t)}const v=(e,t)=>{let n=e[t];if(n===void 0)throw RangeError(`E1:${t}`);return n},y=(e,t)=>i(e,t.node),b=(...e)=>{if(e.length===0){let e=document.createTextNode(``);return{type:`view`,node:e,boundary:()=>({start:e,end:e}),cleanBinds:()=>{}}}let t=document.createDocumentFragment();return e.forEach(e=>{t.appendChild(e.node)}),{type:`view`,node:t,boundary:()=>{let t=v(e,0),n=v(e,e.length-1);return{start:t.boundary().start,end:n.boundary().end}},cleanBinds:()=>{e.forEach(e=>{e.cleanBinds()})}}},x=(e,t)=>{t.node.textContent=String(e)},S=e=>{let t=document.createTextNode(e instanceof c?String(e.get()):String(e)),n={node:t},i=e instanceof c?f(e,n,x):void 0,a=r(t);return{type:`view`,node:t,bind:i,boundary:()=>a,cleanBinds:()=>{i&&d(i)}}},C=`@sig_${Math.random().toFixed(9).slice(2)}`,w=/* @__PURE__ */ new WeakMap;let T;const ee=()=>(T??=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT),T),te=e=>e.type===`patch`?C:`<!--${C}-->`,ne=e=>{if(e.length>31){let t=``;for(let n of e)t+=n.type===`patch`?`p`:`v`;return t}let t=0;for(let n=0;n<e.length;n++)e[n]?.type===`patch`&&(t|=1<<n);return t},re=e=>e.hasAttribute(C),ie=e=>e.removeAttribute(C),ae=e=>e.data.trim()===C,oe=e=>typeof e==`object`&&!!e&&e.type===`patch`,E=e=>typeof e==`object`&&!!e&&e.type===`view`,se=e=>oe(e)||E(e)?e:S(e),ce=(e,t)=>{t.replaceWith(e.node)},D=(e,t)=>{let n=[];e.toPatchItems.forEach(e=>{let r=e(t);r.source instanceof c?(r.cmd(r.source.get(),r.context),n.push(f(r.source,r.context,r.cmd))):r.cmd(r.source,r.context)}),e.cleanBinds=()=>{n.forEach(d)}},O=(e,t,n,r,i)=>{let a=ee();a.currentNode=e;let o=a.nextNode(),s=0,c=0;for(;o!==null&&c<t.length;)r(o,s,c)&&(n.push({item:v(t,c),node:o}),i&&i.push(s),c++,o.nodeType===Node.ELEMENT_NODE&&ie(o)),o=a.nextNode(),s++;a.currentNode=document},k=(t,...n)=>{t.length<=1&&!t?.[0]&&e(`E10`);let i=t.length-1;n.length!==i&&e(`E11:${i}:${n.length}`);let a=n.map(se),o,s=[],c=ne(a),l=w.get(t);if(l?.shape===c)o=document.importNode(l.el.content,!0),a&&a.length>0&&O(o,a,s,(e,t,n)=>t===l.indexes[n]);else{let e=document.createElement(`template`);e.innerHTML=A(t,...a);let n={el:e,indexes:[],shape:c};o=document.importNode(e.content,!0),a&&a.length>0&&O(o,a,s,e=>e.nodeType===Node.ELEMENT_NODE?re(e):e.nodeType===Node.COMMENT_NODE&&ae(e),n.indexes),w.set(t,n)}s.length!==a.length&&e(`E12`),s.forEach(({item:e,node:t})=>{e.type===`patch`?D(e,t):ce(e,t)});let u=s.map(e=>e.item),d=r(o);return{type:`view`,node:o,children:u,boundary:()=>{let e=t.length-1;if(!t[0]){let e=u[0];e?.type===`view`&&(d.start=e.boundary().start)}if(!t[e]){let t=u[e-1];t?.type===`view`&&(d.end=t.boundary().end)}return d},cleanBinds:()=>{u.forEach(e=>{e.cleanBinds()})}}},A=(e,...t)=>{let n=e[0]??``;for(let r=0;r<t.length;r++)n+=te(v(t,r))+(e[r+1]??``);return n},j=(e,t)=>{if(e.length===0){let e=document.createComment(`empty-list`);return{type:`view`,node:e,boundary:()=>({start:e,end:e}),cleanBinds:()=>{}}}let n=document.createDocumentFragment(),r=[];return e.forEach((e,i)=>{let a=t(e,i);r.push(a),n.appendChild(a.node)}),{type:`view`,node:n,boundary:()=>{let e=v(r,0),t=v(r,r.length-1);return{start:e.boundary().start,end:t.boundary().end}},cleanBinds:()=>{r.forEach(e=>{e.cleanBinds()})}}},le=()=>{};function ue(e,...t){return{type:`patch`,toPatchItems:typeof e==`function`?[e,...t]:e?[..._e(e),...t]:t,cleanBinds:le}}const M=(e,t,n)=>r=>({source:e,context:t?{node:r,extra:t}:{node:r},cmd:n}),N=t=>{let n=t.extra?.[0];return n||e(`E4`),n},de=(e,t)=>{t.node.id=String(e)},P=e=>M(e,void 0,de),F=(e,t)=>{t.node.value=String(e)},I=e=>M(e,void 0,F),L=(e,t)=>{t.node.setAttribute(N(t),String(e))},R=(e,t)=>M(t,[e],L),z=(e,t)=>{t.node.style[N(t)]=String(e)},B=(e,t)=>M(t,[e],z),V=(e,t)=>{t.node.style.setProperty(N(t),String(e))},H=(e,t)=>M(t,[e],V),U=(e,t)=>{t.node.classList.toggle(N(t),!!e)},W=(e,t)=>M(t,[e],U),fe=(e,t)=>{t.extra?.forEach(n=>{t.node.classList.toggle(n,!!e)})},pe=(e,t)=>M(t,[...e],fe),me=(t,n)=>{let r=n.extra?.[0];r||e(`E5`),r(n.node,t)},he=(e,t)=>M(e,[t],me),ge=(t,n)=>{let r=n.extra?.[0],i=n.extra?.[1];r||e(`E6`),n.node.addEventListener(r,t,i)},G=(e,t,n)=>M(t,[e,n],ge),_e=e=>{let t=[];for(let[n,r]of Object.entries(e))if(r!==void 0)switch(n){case`id`:t.push(P(r));break;case`val`:t.push(I(r));break;case`class`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(W(e,n));break;case`style`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(B(e,n));break;case`styleProp`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(H(e,n));break;case`on`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(G(e,n));break;default:t.push(R(n,r))}return t},K=e=>{let t=document.createElement(`template`);t.innerHTML=e;let n=t.content;return n.firstChild||n.appendChild(document.createTextNode(``)),n},ve=(e,t)=>{t.boundary=i(t.boundary,K(e))},ye=e=>{let t=K(e instanceof c?e.get():e),n={boundary:r(t)},i=e instanceof c?f(e,n,ve):void 0;return{type:`view`,node:t,bind:i,boundary:()=>n.boundary,cleanBinds:()=>{i&&d(i)}}},be=(e,t)=>{let r=typeof e==`function`?e():e;return t.appendChild(r.node),()=>{n(r.boundary()),r.cleanBinds()}},q=e=>{n(e.view.boundary()),e.view.cleanBinds(),e.cleaned=!0},xe=(t,n)=>{if(!Array.isArray(t)||t.length===0){let e=document.createDocumentFragment();e.appendChild(document.createComment(`empty-list`)),n.boundary=i(n.boundary,e),n.tracks.forEach(q),n.tracks=[];return}let r=[];if(!Array.isArray(n.tracks)||n.tracks.length===0){let e=$(t,n.prop,r);n.boundary=i(n.boundary,e),n.tracks=r;return}let a=n.boundary.start,s=n.boundary.end,c=a.parentNode;c||e(`E7`);let l=n.prop.eq??o,u=t.map(e=>n.prop.key(e)),d=n.tracks;if(d.length===t.length&&d.every((e,n)=>{let r=t[n];return e.key===u[n]&&l(e.item,r)}))return;let f=document.createComment(`repeat-start-fence`),p=document.createComment(`repeat-end-fence`);c.insertBefore(f,a),c.insertBefore(p,s.nextSibling);let m={parent:c,startFence:f,endFence:p},h=d.map(e=>e.key),g,_,y=0,b=n.tracks.length-1,x=0,S=t.length-1;for(;y<=b&&x<=S;)if(n.tracks[y]?.checked)y++;else if(n.tracks[b]?.checked)b--;else if(n.tracks[y]?.key===u[x])r[x]=Q(v(n.tracks,y),v(t,x),n.prop,l),y++,x++;else if(n.tracks[b]?.key===u[S])r[S]=Q(v(n.tracks,b),v(t,S),n.prop,l),b--,S--;else if(n.tracks[y]?.key===u[S])r[S]=Q(v(n.tracks,y),v(t,S),n.prop,l),X(m,v(r,S),Se(m,r[S+1])),y++,S--;else if(n.tracks[b]?.key===u[x])r[x]=Q(v(n.tracks,b),v(t,x),n.prop,l),X(m,v(r,x),Y(m,r[x-1])),b--,x++;else if((g===void 0||_===void 0)&&(g=J(u,x,S),_=J(h,y,b)),!g.has(h[y]))q(v(n.tracks,y)),y++;else if(!g.has(h[b]))q(v(n.tracks,b)),b--;else{let e=_.get(u[x]),i=e===void 0?null:n.tracks[e];i?(r[x]=Q(i,v(t,x),n.prop,l),X(m,v(r,x),Y(m,r[x-1])),i.checked=!0):r[x]=Z(m,v(t,x),n.prop,Y(m,r[x-1])),x++}for(;x<=S;)r[x]=Z(m,v(t,x),n.prop,Y(m,r[x-1])),x++;for(;y<=b;)!n.tracks[y]?.cleaned&&!n.tracks[y]?.checked&&q(v(n.tracks,y)),y++;(!m.startFence.nextSibling||!m.endFence.previousSibling)&&e(`E8`),n.boundary={start:m.startFence.nextSibling,end:m.endFence.previousSibling},m.parent.removeChild(m.startFence),m.parent.removeChild(m.endFence),n.tracks=r},J=(e,t,n)=>{let r=/* @__PURE__ */ new Map;for(let i=t;i<=n;i++)r.set(e[i],i);return r},Se=(e,t)=>t?t.view.boundary().start:e.endFence,Y=(t,n)=>{let r=n?n.view.boundary().end:t.startFence;return r.nextSibling||e(`E9`),r.nextSibling},Ce=(e,t,n)=>{e.moveBefore?e.moveBefore(t,n):e.insertBefore(t,n)},X=(e,n,r)=>{let i=e.parent;t(n.view.boundary(),e=>Ce(i,e,r))},Z=(e,t,n,r)=>{let i=n.view(t);return e.parent.insertBefore(i.node,r),{key:n.key(t),item:t,view:i}},Q=(e,t,n,r)=>{if(r(e.item,t))return{...e,checked:!1,cleaned:!1};let i=e.view.boundary(),a=n.view(t);return y(i,a),q(e),{key:n.key(t),item:t,view:a}},$=(e,t,n)=>{let r=document.createDocumentFragment();return e.forEach(e=>{let i=t.view(e),a=t.key(e);n.push({key:a,item:e,view:i}),r.appendChild(i.node)}),r.childNodes.length===0&&r.appendChild(document.createComment(`empty-list`)),r},we=(e,t)=>{let n=[],i=$(e.get(),t,n),a={prop:t,tracks:n,boundary:r(i)},o=f(e,a,xe);return{type:`view`,node:i,bind:o,boundary:()=>a.boundary,cleanBinds:()=>{d(o),a.tracks.forEach(e=>{e.view.cleanBinds()})}}},Te=(e,t)=>{let n=t.inner.boundary(),r=t.viewFn(e);y(n,r),t.inner.cleanBinds(),t.inner=r},Ee=(e,t)=>{let n=t(e.get()),r={inner:n,viewFn:t},i=f(e,r,Te);return{type:`view`,node:n.node,bind:i,boundary:()=>r.inner.boundary(),cleanBinds:()=>{d(i),r.inner.cleanBinds()}}};export{l as DerivedSig,c as Sig,he as act,v as at,R as attr,_ as compute,f as createBind,o as eq,e as err,b as frag,k as html,P as id,j as list,G as on,ue as patch,ye as raw,d as removeBind,n as removeBoundary,be as render,we as repeat,i as replaceWithNode,y as replaceWithView,u as sig,B as style,H as styleProp,S as text,r as toBoundary,W as toggleClass,pe as toggleClasses,I as val,Ee as view,t as walkBoundary};
1
+ function e(e){throw Error(e)}const t=(e,t)=>{let n=e.start;for(;n;){let r=n.nextSibling;if(t(n),n===e.end)break;n=r}},n=e=>{let n=e.start.parentNode;n&&t(e,e=>n.removeChild(e))},r=t=>{let n=t.nodeType===Node.DOCUMENT_FRAGMENT_NODE?{start:t.firstChild,end:t.lastChild}:{start:t,end:t};return(!n.start||!n.end)&&e(`E2`),n},i=(t,n)=>{let i=r(n),a=t.start.parentNode;if(a||e(`E3`),t.start===t.end)a.replaceChild(n,t.start);else{let e=t.start.nextSibling;for(a.replaceChild(n,t.start);e;){let n=e.nextSibling;if(a.removeChild(e),e===t.end)break;e=n}}return i},a=e=>typeof e==`object`&&!!e&&`equals`in e&&typeof e.equals==`function`,o=(e,t)=>{if(e===t)return!0;if(typeof e!=typeof t||e===null||t===null||typeof e!=`object`)return!1;if(a(e))return e.equals(t);if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(!o(e[n],t[n]))return!1;return!0}if(e instanceof Date&&t instanceof Date)return e.getTime()===t.getTime();if(e instanceof RegExp&&t instanceof RegExp)return e.toString()===t.toString();if(e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(let[n,r]of e)if(!t.has(n)||!o(r,t.get(n)))return!1;return!0}if(e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;let n=Array.from(e),r=Array.from(t);return o(n,r)}if(Object.getPrototypeOf(e)!==Object.getPrototypeOf(t))return!1;let n=e,r=t,i=Object.keys(n),s=Object.keys(r);if(i.length!==s.length)return!1;for(let e=0;e<i.length;e++){let t=i[e];if(!Object.hasOwn(r,t)||!o(n[t],r[t]))return!1}return!0},s=new class{_binds=[];head=0;running=!1;scheduled=!1;addAll(e){for(let t of e)t.queued||(t.queued=!0,this._binds.push(t));return this._binds.length>this.head&&this.kick(),this}kick(){this.running||this.scheduled||(this.scheduled=!0,queueMicrotask(()=>{this.running=!0,this.scheduled=!1,this.flush()}))}flush(){this.running=!0;try{for(;this.head<this._binds.length;){let e=this._binds[this.head++];try{let{removed:t,sig:n,context:r,cmd:i}=e;t||i(n.get(),r)}catch(t){console.error(`[Queue] task failed:`,t,e)}finally{e.queued=!1}}}finally{this.running=!1,this.head<this._binds.length?(this._binds=this._binds.slice(this.head),this.head=0,this.kick()):(this._binds.length=0,this.head=0)}}};var c=class e{_val;_binds=[];_eq;constructor(e,t){this._val=e,this._eq=t?.eq??o}equals(t){return t instanceof e&&this._eq(this.get(),t.get())}get(){return this._val}notify(){s.addAll(this._binds)}forceUpdate(e){this._val=e,this.notify()}update(e){this._eq(e,this._val)||this.forceUpdate(e)}trans(e){this.update(e(this._val))}addBind(e){this._binds.push(e)}removeBind(e){let t=this._binds.indexOf(e);t>=0&&this._binds.splice(t,1),this._binds.length===0&&this.cleanup()}getBinds(){return this._binds}cleanup(){}},l=class extends c{_fromBinds=[];_linked=!0;addFromBind(e){this._fromBinds.push(e)}addBind(e){if(super.addBind(e),this._linked)return;this._linked=!0;for(let e=0;e<this._fromBinds.length;e++){let t=this._fromBinds[e];this._fromBinds[e]=f(t.sig,t.context,t.cmd)}let t=this._fromBinds[0];t&&t.cmd(t.sig.get(),t.context)}cleanup(){if(this._linked){this._linked=!1;for(let e of this._fromBinds)d(e)}}};const u=(e,t)=>new c(e,t),d=e=>{e.removed=!0,e.sig.removeBind(e)},f=(e,t,n)=>{let r={sig:e,context:t,cmd:n,removed:!1,queued:!1};return e.addBind(r),r},p=(e,t)=>{t.target.update(t.fn(e))},m=(e,t)=>{let n={};for(let[e,r]of t.entries)n[e]=r.get();t.target.update(t.fn(n))},h=(e,t)=>{let n=new l(t(e.get())),r={target:n,fn:t};return n.addFromBind(f(e,r,p)),n},g=(e,t)=>{let n=[],r={};for(let[t,i]of Object.entries(e))t&&i&&(n.push([t,i]),r[t]=i.get());let i=new l(t(r)),a={target:i,fn:t,entries:n};for(let e of n)i.addFromBind(f(e[1],a,m));return i};function _(e,t){return e instanceof c?h(e,t):g(e,t)}const v=(e,t)=>{let n=e[t];if(n===void 0)throw RangeError(`E1:${t}`);return n},y=(e,t)=>i(e,t.node),b=(...e)=>{if(e.length===0){let e=document.createTextNode(``);return{type:`view`,node:e,boundary:()=>({start:e,end:e}),cleanBinds:()=>{}}}let t=document.createDocumentFragment();return e.forEach(e=>{t.appendChild(e.node)}),{type:`view`,node:t,boundary:()=>{let t=v(e,0),n=v(e,e.length-1);return{start:t.boundary().start,end:n.boundary().end}},cleanBinds:()=>{e.forEach(e=>{e.cleanBinds()})}}},x=(e,t)=>{t.node.textContent=String(e)},S=e=>{let t=document.createTextNode(e instanceof c?String(e.get()):String(e)),n={node:t},i=e instanceof c?f(e,n,x):void 0,a=r(t);return{type:`view`,node:t,bind:i,boundary:()=>a,cleanBinds:()=>{i&&d(i)}}},C=`@sig_${Math.random().toFixed(9).slice(2)}`,w=/* @__PURE__ */ new WeakMap;let T;const ee=()=>(T??=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT),T),te=e=>e.type===`patch`?C:`<!--${C}-->`,ne=e=>{if(e.length>31){let t=``;for(let n of e)t+=n.type===`patch`?`p`:`v`;return t}let t=0;for(let n=0;n<e.length;n++)e[n]?.type===`patch`&&(t|=1<<n);return t},re=e=>e.hasAttribute(C),ie=e=>e.removeAttribute(C),ae=e=>e.data.trim()===C,oe=e=>typeof e==`object`&&!!e&&e.type===`patch`,E=e=>typeof e==`object`&&!!e&&e.type===`view`,se=e=>oe(e)||E(e)?e:S(e),ce=(e,t)=>{t.replaceWith(e.node)},D=(e,t)=>{let n=[];e.toPatchItems.forEach(e=>{let r=e(t);r.source instanceof c?(r.cmd(r.source.get(),r.context),n.push(f(r.source,r.context,r.cmd))):r.cmd(r.source,r.context)}),e.cleanBinds=()=>{n.forEach(d)}},O=(e,t,n,r,i)=>{let a=ee();a.currentNode=e;let o=a.nextNode(),s=0,c=0;for(;o!==null&&c<t.length;)r(o,s,c)&&(n.push({item:v(t,c),node:o}),i&&i.push(s),c++,o.nodeType===Node.ELEMENT_NODE&&ie(o)),o=a.nextNode(),s++;a.currentNode=document},k=(t,...n)=>{t.length<=1&&!t?.[0]&&e(`E10`);let i=t.length-1;n.length!==i&&e(`E11:${i}:${n.length}`);let a=n.map(se),o,s=[],c=ne(a),l=w.get(t);if(l?.shape===c)o=document.importNode(l.el.content,!0),a&&a.length>0&&O(o,a,s,(e,t,n)=>t===l.indexes[n]);else{let e=document.createElement(`template`);e.innerHTML=A(t,...a);let n={el:e,indexes:[],shape:c};o=document.importNode(e.content,!0),a&&a.length>0&&O(o,a,s,e=>e.nodeType===Node.ELEMENT_NODE?re(e):e.nodeType===Node.COMMENT_NODE&&ae(e),n.indexes),w.set(t,n)}s.length!==a.length&&e(`E12`),s.forEach(({item:e,node:t})=>{e.type===`patch`?D(e,t):ce(e,t)});let u=s.map(e=>e.item),d=r(o);return{type:`view`,node:o,children:u,boundary:()=>{let e=t.length-1;if(!t[0]){let e=u[0];e?.type===`view`&&(d.start=e.boundary().start)}if(!t[e]){let t=u[e-1];t?.type===`view`&&(d.end=t.boundary().end)}return d},cleanBinds:()=>{u.forEach(e=>{e.cleanBinds()})}}},A=(e,...t)=>{let n=e[0]??``;for(let r=0;r<t.length;r++)n+=te(v(t,r))+(e[r+1]??``);return n},j=(e,t)=>{if(e.length===0){let e=document.createComment(`empty-list`);return{type:`view`,node:e,boundary:()=>({start:e,end:e}),cleanBinds:()=>{}}}let n=document.createDocumentFragment(),r=[];return e.forEach((e,i)=>{let a=t(e,i);r.push(a),n.appendChild(a.node)}),{type:`view`,node:n,boundary:()=>{let e=v(r,0),t=v(r,r.length-1);return{start:e.boundary().start,end:t.boundary().end}},cleanBinds:()=>{r.forEach(e=>{e.cleanBinds()})}}},le=()=>{};function ue(e,...t){return{type:`patch`,toPatchItems:typeof e==`function`?[e,...t]:e?[..._e(e),...t]:t,cleanBinds:le}}const M=(e,t,n)=>r=>({source:e,context:t?{node:r,extra:t}:{node:r},cmd:n}),N=t=>{let n=t.extra?.[0];return n||e(`E4`),n},de=(e,t)=>{t.node.id=String(e)},P=e=>M(e,void 0,de),F=(e,t)=>{t.node.value=String(e)},I=e=>M(e,void 0,F),L=(e,t)=>{t.node.setAttribute(N(t),String(e))},R=(e,t)=>M(t,[e],L),z=(e,t)=>{t.node.style[N(t)]=String(e)},B=(e,t)=>M(t,[e],z),V=(e,t)=>{t.node.style.setProperty(N(t),String(e))},H=(e,t)=>M(t,[e],V),U=(e,t)=>{t.node.classList.toggle(N(t),!!e)},W=(e,t)=>M(t,[e],U),fe=(e,t)=>{t.extra?.forEach(n=>{t.node.classList.toggle(n,!!e)})},pe=(e,t)=>M(t,[...e],fe),me=(t,n)=>{let r=n.extra?.[0];r||e(`E5`),r(n.node,t)},he=(e,t)=>M(e,[t],me),ge=(t,n)=>{let r=n.extra?.[0],i=n.extra?.[1];r||e(`E6`),n.node.addEventListener(r,t,i)},G=(e,t,n)=>M(t,[e,n],ge),_e=e=>{let t=[];for(let[n,r]of Object.entries(e))if(r!==void 0)switch(n){case`id`:t.push(P(r));break;case`val`:t.push(I(r));break;case`class`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(W(e,n));break;case`style`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(B(e,n));break;case`styleProp`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(H(e,n));break;case`on`:for(let[e,n]of Object.entries(r))n!==void 0&&t.push(G(e,n));break;default:t.push(R(n,r))}return t},K=e=>{let t=document.createElement(`template`);t.innerHTML=e;let n=t.content;return n.firstChild||n.appendChild(document.createTextNode(``)),n},ve=(e,t)=>{t.boundary=i(t.boundary,K(e))},ye=e=>{let t=K(e instanceof c?e.get():e),n={boundary:r(t)},i=e instanceof c?f(e,n,ve):void 0;return{type:`view`,node:t,bind:i,boundary:()=>n.boundary,cleanBinds:()=>{i&&d(i)}}},be=(e,t)=>{let r=typeof e==`function`?e():e;return t.appendChild(r.node),()=>{n(r.boundary()),r.cleanBinds()}},q=e=>{n(e.view.boundary()),e.view.cleanBinds(),e.cleaned=!0},xe=(t,n)=>{if(!Array.isArray(t)||t.length===0){let e=document.createDocumentFragment();e.appendChild(document.createComment(`empty-list`)),n.boundary=i(n.boundary,e),n.tracks.forEach(q),n.tracks=[];return}let r=[];if(!Array.isArray(n.tracks)||n.tracks.length===0){let e=$(t,n.prop,r);n.boundary=i(n.boundary,e),n.tracks=r;return}let a=n.boundary.start,s=n.boundary.end,c=a.parentNode;c||e(`E7`);let l=n.prop.eq??o,u=t.map(e=>n.prop.key(e)),d=n.tracks;if(d.length===t.length&&d.every((e,n)=>{let r=t[n];return e.key===u[n]&&l(e.item,r)}))return;let f=document.createComment(`repeat-start-fence`),p=document.createComment(`repeat-end-fence`);c.insertBefore(f,a),c.insertBefore(p,s.nextSibling);let m={parent:c,startFence:f,endFence:p},h=d.map(e=>e.key),g,_,y=0,b=n.tracks.length-1,x=0,S=t.length-1;for(;y<=b&&x<=S;)if(n.tracks[y]?.checked)y++;else if(n.tracks[b]?.checked)b--;else if(n.tracks[y]?.key===u[x])r[x]=Q(v(n.tracks,y),v(t,x),n.prop,l),y++,x++;else if(n.tracks[b]?.key===u[S])r[S]=Q(v(n.tracks,b),v(t,S),n.prop,l),b--,S--;else if(n.tracks[y]?.key===u[S])r[S]=Q(v(n.tracks,y),v(t,S),n.prop,l),X(m,v(r,S),Se(m,r[S+1])),y++,S--;else if(n.tracks[b]?.key===u[x])r[x]=Q(v(n.tracks,b),v(t,x),n.prop,l),X(m,v(r,x),Y(m,r[x-1])),b--,x++;else if((g===void 0||_===void 0)&&(g=J(u,x,S),_=J(h,y,b)),!g.has(h[y]))q(v(n.tracks,y)),y++;else if(!g.has(h[b]))q(v(n.tracks,b)),b--;else{let e=_.get(u[x]),i=e===void 0?null:n.tracks[e];i?(r[x]=Q(i,v(t,x),n.prop,l),X(m,v(r,x),Y(m,r[x-1])),i.checked=!0):r[x]=Z(m,v(t,x),n.prop,Y(m,r[x-1])),x++}for(;x<=S;)r[x]=Z(m,v(t,x),n.prop,Y(m,r[x-1])),x++;for(;y<=b;)!n.tracks[y]?.cleaned&&!n.tracks[y]?.checked&&q(v(n.tracks,y)),y++;(!m.startFence.nextSibling||!m.endFence.previousSibling)&&e(`E8`),n.boundary={start:m.startFence.nextSibling,end:m.endFence.previousSibling},m.parent.removeChild(m.startFence),m.parent.removeChild(m.endFence),n.tracks=r},J=(e,t,n)=>{let r=/* @__PURE__ */ new Map;for(let i=t;i<=n;i++)r.set(e[i],i);return r},Se=(e,t)=>t?t.view.boundary().start:e.endFence,Y=(t,n)=>{let r=n?n.view.boundary().end:t.startFence;return r.nextSibling||e(`E9`),r.nextSibling},Ce=(e,t,n)=>{e.moveBefore?e.moveBefore(t,n):e.insertBefore(t,n)},X=(e,n,r)=>{let i=e.parent;t(n.view.boundary(),e=>Ce(i,e,r))},Z=(e,t,n,r)=>{let i=n.view(t);return e.parent.insertBefore(i.node,r),{key:n.key(t),item:t,view:i}},Q=(e,t,n,r)=>{if(r(e.item,t))return{...e,checked:!1,cleaned:!1};let i=e.view.boundary(),a=n.view(t);return y(i,a),q(e),{key:n.key(t),item:t,view:a}},$=(e,t,n)=>{let r=document.createDocumentFragment();return e.forEach(e=>{let i=t.view(e),a=t.key(e);n.push({key:a,item:e,view:i}),r.appendChild(i.node)}),r.childNodes.length===0&&r.appendChild(document.createComment(`empty-list`)),r},we=(e,t)=>{let n=[],i=$(e.get(),t,n),a={prop:t,tracks:n,boundary:r(i)},o=f(e,a,xe);return{type:`view`,node:i,bind:o,boundary:()=>a.boundary,cleanBinds:()=>{d(o),a.tracks.forEach(e=>{e.view.cleanBinds()})}}},Te=(e,t)=>{let n=t.inner.boundary(),r=t.viewFn(e);y(n,r),t.inner.cleanBinds(),t.inner=r},Ee=(e,t)=>{let n=t(e.get()),r={inner:n,viewFn:t},i=f(e,r,Te);return{type:`view`,node:n.node,bind:i,boundary:()=>r.inner.boundary(),cleanBinds:()=>{d(i),r.inner.cleanBinds()}}};export{l as DerivedSig,c as Sig,he as act,v as at,R as attr,_ as compute,f as createBind,o as eq,e as err,b as frag,k as html,P as id,j as list,G as on,ue as patch,ye as raw,d as removeBind,n as removeBoundary,be as render,we as repeat,i as replaceWithNode,y as replaceWithView,u as sig,B as style,H as styleProp,S as text,r as toBoundary,W as toggleClass,pe as toggleClasses,I as val,Ee as view,t as walkBoundary};
2
2
  //# sourceMappingURL=sigula.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sigula.js","names":["err","code","walkBoundary","b","next","fn","removeBoundary","parent","node","toBoundary","replaceWithNode","newBoundary","old","n","isEquatable","value","eq","a","i","key","val","arrA","arrB","ao","bo","aKeys","bKeys","QUEUE","bind","binds","removed","cmd","sig","context","Sig","opts","v","index","DerivedSig","f","createBind","first","removeBind","computeCmd","ctx","s","computeRecordCmd","vals","k","_compute","target","source","_computeRecord","entries","entry","compute","at","arr","replaceWithView","view","frag","views","empty","last","textCmd","text","boundary","MARK","tplCache","walker","_walker","_toMark","item","_shape","items","shape","bits","_hasMark","el","_rmMark","_isViewMark","isPatch","isView","_toItem","commitView","commitPatch","patch","toPatchItem","_scan","w","nodeIndex","itemIndex","hit","wraps","indexes","html","rawItems","strs","slots","exist","template","_text","tpl","children","endChild","child","parts","list","viewFn","_noop","rest","_propsToItems","_toPatchItem","extra","elem","_key","idCmd","id","valCmd","attrCmd","attr","styleCmd","style","stylePropCmd","styleProp","toggleClassCmd","toggleClass","token","toggleClassesCmd","toggleClasses","tokens","actCmd","act","onCmd","type","options","listener","on","props","name","_parse","content","rawCmd","raw","render","viewArg","_cleanTrack","track","repeatCmd","newFrag","newTracks","_init","start","end","compare","newKeys","tracks","startFence","endFence","container","oldKeys","newKeyToIndexMap","oldKeyToIndexMap","oldHead","oldTail","newHead","newTail","_setTrack","_moveTrack","_beforeFence","_afterFence","_generateMap","oldIndex","oldTrack","_insertNewTrack","map","_mvNodeBefore","fence","prop","oldBoundary","repeat","t","viewCmd","newInner","inner"],"sources":["../src/core/err.ts","../src/core/boundary.ts","../src/core/eq.ts","../src/core/sig.bind.ts","../src/core/compute.ts","../src/core/utils.ts","../src/core/view.core.ts","../src/frag.ts","../src/text.ts","../src/html.ts","../src/list.ts","../src/patch.ts","../src/raw.ts","../src/render.ts","../src/repeat.ts","../src/view.ts"],"sourcesContent":["/**\n * Throws an `Error` whose message is the short `code` (for example `E2` or\n * `E11:1:2`). The full text for each code lives in the README error table, so\n * string tables stay out of the bundle.\n *\n * @param code - the coded error message.\n * @group Low-level API\n */\n// Thrown errors carry a short code instead of a message. The full text for\n// every code lives in the README so the runtime bundle stays small; use the\n// table there to translate `E1`, `E7`, ... back into a sentence.\nexport function err(code: string): never {\n throw new Error(code);\n}\n","import {err} from './err';\n\n/**\n * An inclusive range of sibling nodes (`start` through `end`).\n *\n * @group Low-level API\n */\nexport interface Boundary {\n /** The first node in the range. */\n start: Node;\n /** The last node in the range. */\n end: Node;\n}\n\n/**\n * Visits every node from `b.start` through `b.end`.\n *\n * @param b - the boundary to walk.\n * @param fn - called with each node.\n * @group Low-level API\n */\n// Visits every node from start through end. Callers capture nextSibling before\n// mutating, so the walk survives removals and moves.\nexport const walkBoundary = (b: Boundary, fn: (node: Node) => void) => {\n let n: Node | null = b.start;\n while (n) {\n const next: Node | null = n.nextSibling;\n fn(n);\n if (n === b.end) break;\n n = next;\n }\n};\n\n/**\n * Removes every node in the boundary. No-op if the boundary has no parent.\n *\n * @param b - the boundary to remove.\n * @group Low-level API\n */\nexport const removeBoundary = (b: Boundary) => {\n const parent = b.start.parentNode;\n if (!parent) return;\n walkBoundary(b, (node) => parent.removeChild(node));\n};\n\n/**\n * Wraps a node in a {@link Boundary}. A `DocumentFragment` spans its first and\n * last child; any other node covers itself. Throws `E2` on an empty fragment.\n *\n * @param node - the node to wrap.\n * @returns the node's boundary.\n * @group Low-level API\n */\nexport const toBoundary = (node: Node): Boundary => {\n const b =\n node.nodeType === Node.DOCUMENT_FRAGMENT_NODE\n ? {start: node.firstChild, end: node.lastChild}\n : {start: node, end: node};\n if (!b.start || !b.end) err('E2');\n return b as Boundary;\n};\n\n/**\n * Replaces an entire boundary with `node` and returns the new boundary. Throws\n * `E3` if the old boundary has no parent.\n *\n * @param old - the boundary to replace.\n * @param node - the replacement node.\n * @returns the boundary of the inserted node.\n * @group Low-level API\n */\nexport const replaceWithNode = (old: Boundary, node: Node): Boundary => {\n const newBoundary = toBoundary(node);\n const parent = old.start.parentNode;\n if (!parent) err('E3');\n\n if (old.start === old.end) {\n parent.replaceChild(node, old.start);\n } else {\n let n = old.start.nextSibling;\n parent.replaceChild(node, old.start);\n while (n) {\n const next = n.nextSibling;\n parent.removeChild(n);\n if (n === old.end) break;\n n = next;\n }\n }\n\n return newBoundary;\n};\n","/**\n * Implement this on a value type to give `eq` custom equality semantics.\n *\n * @group Reactivity\n */\nexport interface Equatable {\n /** Returns whether `this` and `other` are equal. */\n equals(other: unknown): boolean;\n}\n\n/**\n * A value equality function.\n *\n * @typeParam T - the value type.\n * @group Reactivity\n */\nexport type Eq<T> = (a: T, b: T) => boolean;\n\nconst isEquatable = (value: unknown): value is Equatable =>\n typeof value === 'object' &&\n value !== null &&\n 'equals' in value &&\n typeof value.equals === 'function';\n\n/**\n * Convenience alias for an arbitrary string-keyed object.\n *\n * @group Reactivity\n */\nexport type UnknownRecord = Record<string, unknown>;\n\n/**\n * Deep structural equality. Compares primitives, arrays, `Date`, `RegExp`,\n * `Map`, `Set`, and plain objects, and defers to `a.equals(b)` when `a`\n * implements `Equatable`. This is the default comparator for `Sig.update` and\n * `repeat`. Values with different prototypes are never equal.\n *\n * @typeParam T - the value type.\n * @param a - the first value.\n * @param b - the second value.\n * @returns `true` when `a` and `b` are deeply equal.\n * @group Reactivity\n */\nexport const eq = <T>(a: T, b: T): boolean => {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n\n if (a === null || b === null || typeof a !== 'object') return false;\n\n if (isEquatable(a)) return a.equals(b);\n\n // may let Array always return false\n // if (Array.isArray(a) || Array.isArray(b)) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!eq(a[i], b[i])) return false;\n }\n return true;\n }\n\n // Date\n if (a instanceof Date && b instanceof Date)\n return a.getTime() === b.getTime();\n\n // RegExp\n if (a instanceof RegExp && b instanceof RegExp) {\n return a.toString() === b.toString();\n }\n\n // Map\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n for (const [key, val] of a) {\n if (!b.has(key) || !eq(val, b.get(key))) return false;\n }\n return true;\n }\n\n // Set\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n const arrA = Array.from(a);\n const arrB = Array.from(b);\n return eq(arrA, arrB);\n }\n\n // Object & Record\n // Reject different prototypes before falling back to a key comparison.\n // Object.keys is [] for Date, Map, Set, RegExp, Error and [], so without\n // this guard isEqual([], {}) and isEqual(new Date(0), {}) both report\n // equal and Sig.update silently swallows a shape-changing write.\n // Must stay BELOW the isEquatable check above: hoisting it stops a user\n // Equatable from ever being consulted.\n if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false;\n\n // both are objects sharing one prototype from here on, and the length check\n // plus Object.hasOwn below prove the two key sets are identical, so ao[key]\n // is always an own property\n const ao = a as UnknownRecord;\n const bo = b as UnknownRecord;\n\n const aKeys = Object.keys(ao);\n const bKeys = Object.keys(bo);\n if (aKeys.length !== bKeys.length) return false;\n\n for (let i = 0; i < aKeys.length; i++) {\n const key = aKeys[i] as string;\n if (!Object.hasOwn(bo, key)) return false;\n if (!eq(ao[key], bo[key])) return false;\n }\n\n return true;\n};\n","import type {Cmd, CmdContext} from './cmd';\nimport {type Eq, type Equatable, eq} from './eq';\n\n/**\n * A registered binding: the signal, its command context, and the command that\n * runs when the signal changes.\n *\n * @typeParam T - the signal's value type.\n * @typeParam C - the command context type.\n * @group Reactivity\n */\nexport interface Bind<T, C extends CmdContext> {\n /** The signal this binding observes. */\n sig: Sig<T>;\n /** The context passed to `cmd` on each run. */\n context: C;\n /** The command run with the current value and context. */\n cmd: Cmd<T, C>;\n /** Set when the binding is detached; a removed binding is skipped. */\n removed: boolean;\n /** Queue flag; true while the binding is queued for the next flush. */\n queued?: boolean;\n}\n\n/**\n * A {@link Bind} with erased value and context types.\n *\n * @group Reactivity\n */\n// biome-ignore lint/suspicious/noExplicitAny: any bind\nexport type AnyBind = Bind<any, any>;\n\nclass Queue {\n private _binds: AnyBind[] = [];\n private head = 0;\n private running = false;\n private scheduled = false;\n\n addAll(binds: readonly AnyBind[]): this {\n for (const bind of binds) {\n if (bind.queued) continue;\n bind.queued = true;\n this._binds.push(bind);\n }\n if (this._binds.length > this.head) this.kick();\n return this;\n }\n\n private kick(): void {\n if (this.running || this.scheduled) return;\n this.scheduled = true;\n queueMicrotask(() => {\n this.running = true;\n this.scheduled = false;\n this.flush();\n });\n }\n\n private flush(): void {\n this.running = true;\n try {\n while (this.head < this._binds.length) {\n const bind = this._binds[this.head++] as AnyBind;\n try {\n const {removed, sig, context, cmd} = bind;\n if (!removed) cmd(sig.get(), context);\n } catch (err) {\n console.error('[Queue] task failed:', err, bind);\n } finally {\n // re-arm after running: cmd reads sig.get() at call time, so a bind\n // that runs after a write already sees the newest value and must\n // not re-run, while one that ran before it has to be queued again\n bind.queued = false;\n }\n }\n } finally {\n this.running = false;\n if (this.head < this._binds.length) {\n // almost impossible in js/ts\n this._binds = this._binds.slice(this.head);\n this.head = 0;\n this.kick();\n } else {\n this._binds.length = 0;\n this.head = 0;\n }\n }\n }\n}\n\nconst QUEUE = new Queue();\n\n/**\n * The core reactive value. A `Sig` holds a value and a set of bindings that run\n * when it changes; writes are queued and coalesced in a microtask.\n *\n * @typeParam T - the value type.\n * @group Reactivity\n */\nexport class Sig<T> implements Equatable {\n private _val: T;\n private _binds: AnyBind[] = [];\n private _eq: Eq<T>;\n\n constructor(val: T, opts?: {eq?: Eq<T>}) {\n this._val = val;\n this._eq = opts?.eq ?? eq;\n }\n\n /** `Equatable` implementation; two `Sig`s are equal when their values are deeply equal. */\n equals(b: unknown) {\n if (b instanceof Sig) return this._eq(this.get(), b.get());\n return false;\n }\n\n /** Reads the current value. */\n get(): T {\n return this._val;\n }\n\n /** Enqueues dependents without changing the value; use after in-place mutation. */\n notify() {\n QUEUE.addAll(this._binds);\n }\n\n /** Sets the value and always notifies dependents, even when deeply equal. */\n forceUpdate(v: T) {\n this._val = v;\n this.notify();\n }\n\n /** Sets the value and notifies dependents only when `eq(v, current)` is false. */\n update(v: T) {\n if (this._eq(v, this._val)) return;\n this.forceUpdate(v);\n }\n\n /** Applies `fn` to the current value via `update`, so an equal result is skipped. */\n trans(fn: (v: T) => T) {\n this.update(fn(this._val));\n }\n\n /** Registers a binding. Prefer `createBind` or the `patch`/`text`/`view` APIs. */\n addBind<C extends CmdContext>(bind: Bind<T, C>) {\n this._binds.push(bind);\n }\n\n /** Unregisters a binding; runs `cleanup()` when the last one goes away. */\n removeBind<C extends CmdContext>(bind: Bind<T, C>) {\n const index = this._binds.indexOf(bind);\n if (index >= 0) this._binds.splice(index, 1);\n if (this._binds.length === 0) {\n this.cleanup();\n }\n }\n\n /** Returns the current bindings. */\n getBinds(): Bind<T, CmdContext>[] {\n return this._binds;\n }\n\n /** Overridable hook called when a signal loses all bindings. No-op on `Sig`. */\n // empty: DerivedSig overrides this to detach from its sources when its last\n // observer goes away\n cleanup() {}\n}\n\n/**\n * A `Sig` produced by {@link compute}. Extends `Sig` and additionally tracks the\n * source bindings that feed it: it detaches from its sources when it loses its\n * last consumer, and re-links and recomputes once when a consumer is added\n * again.\n *\n * @typeParam T - the derived value type.\n * @group Reactivity\n */\nexport class DerivedSig<T> extends Sig<T> {\n private _fromBinds: AnyBind[] = [];\n private _linked = true;\n\n /** Registers a source binding. */\n addFromBind<S, C extends CmdContext>(bind: Bind<S, C>) {\n this._fromBinds.push(bind);\n }\n\n /** Registers a consumer; re-links to sources and recomputes once if detached. */\n // A derived signal's upstream links are torn down when its last observer\n // goes away, which happens any time a view() subtree is hidden. The links\n // cannot be revived in place because removeBind marks them removed, so we\n // rebuild fresh binds from each recipe and recompute once: sources usually\n // moved while we were detached.\n //\n // super.addBind must stay first: the recompute below updates this signal\n // straight away, so the returning observer has to be registered before it\n // or it misses the value and only catches up on some later update.\n override addBind<C extends CmdContext>(bind: Bind<T, C>) {\n super.addBind(bind);\n if (this._linked) return;\n this._linked = true;\n for (let i = 0; i < this._fromBinds.length; i++) {\n const f = this._fromBinds[i] as AnyBind;\n this._fromBinds[i] = createBind(f.sig, f.context, f.cmd);\n }\n // every from-bind shares one context whose cmd reads all sources, so one\n // invocation recomputes the whole derived value\n const first = this._fromBinds[0];\n if (first) first.cmd(first.sig.get(), first.context);\n }\n\n /** Removes every source binding when the derived signal has no consumers. */\n override cleanup() {\n if (!this._linked) return;\n this._linked = false;\n for (const b of this._fromBinds) removeBind(b);\n }\n}\n\n/**\n * Creates a writable signal holding `v`.\n *\n * @param v - the initial value.\n * @returns a new `Sig` for `v`.\n * @example\n * ```ts\n * const count = sig(0);\n * count.get(); // 0\n * count.update(1); // schedules dependents\n * ```\n * @group Reactivity\n */\nexport const sig = <T>(v: T) => new Sig(v);\n\n/**\n * Detaches a binding and marks it removed so queued runs are skipped.\n *\n * @typeParam T - the signal's value type.\n * @typeParam C - the command context type.\n * @param bind - the binding to remove.\n * @group Reactivity\n */\nexport const removeBind = <T, C extends CmdContext>(bind: Bind<T, C>) => {\n bind.removed = true;\n bind.sig.removeBind(bind);\n};\n\n/**\n * Wires `cmd(sig.get(), context)` to run whenever `sig` changes.\n *\n * @typeParam T - the signal's value type.\n * @typeParam C - the command context type.\n * @param sig - the signal to observe.\n * @param context - the context passed to `cmd`.\n * @param cmd - the command run on change.\n * @returns the registered binding.\n * @group Reactivity\n */\nexport const createBind = <T, C extends CmdContext>(\n sig: Sig<T>,\n context: C,\n cmd: Cmd<T, C>,\n): Bind<T, C> => {\n const bind: Bind<T, C> = {sig, context, cmd, removed: false, queued: false};\n sig.addBind(bind);\n return bind;\n};\n\n/**\n * A value that may be plain, a `Sig`, or `undefined`.\n *\n * @typeParam T - the underlying value type.\n * @group Reactivity\n */\nexport type Reactive<T> = T | Sig<T> | undefined;\n","import type {CmdContext} from './cmd';\nimport {createBind, DerivedSig, Sig} from './sig.bind';\n\n/**\n * A record whose values are signals, used by the record overload of\n * {@link compute}.\n *\n * @group Reactivity\n */\nexport interface SigRecord {\n /** Each key maps to a signal of any value type. */\n // biome-ignore lint/suspicious/noExplicitAny: any sig val\n [key: string]: Sig<any>;\n}\n\n/**\n * Maps a {@link SigRecord} to a record of the signals' values.\n *\n * @typeParam K - the signal record type.\n * @group Reactivity\n */\nexport type ValRecord<K extends SigRecord> = {\n [P in keyof K]: K[P] extends Sig<infer U> ? U : never;\n};\n\n// biome-ignore lint/suspicious/noExplicitAny: heterogeneous source sigs\ntype ComputeEntry = [string, Sig<any>];\n\ninterface ComputeContext<S, T> extends CmdContext {\n target: Sig<T>;\n fn: (s: S) => T;\n}\n\ninterface ComputeRecordContext<S extends SigRecord, T> extends CmdContext {\n target: Sig<T>;\n fn: (v: ValRecord<S>) => T;\n entries: ComputeEntry[];\n}\n\nconst computeCmd = <S, T>(s: S, ctx: ComputeContext<S, T>) => {\n ctx.target.update(ctx.fn(s));\n};\n\nconst computeRecordCmd = <S extends SigRecord, T>(\n _s: unknown,\n ctx: ComputeRecordContext<S, T>,\n) => {\n const vals: Record<string, unknown> = {};\n for (const [k, s] of ctx.entries) vals[k] = s.get();\n ctx.target.update(ctx.fn(vals as ValRecord<S>));\n};\n\nconst _compute = <S, T>(source: Sig<S>, fn: (v: S) => T): DerivedSig<T> => {\n const target = new DerivedSig(fn(source.get()));\n const ctx: ComputeContext<S, T> = {target, fn};\n target.addFromBind(createBind(source, ctx, computeCmd));\n return target;\n};\n\nconst _computeRecord = <S extends SigRecord, T>(\n source: S,\n fn: (v: ValRecord<S>) => T,\n): DerivedSig<T> => {\n const entries: ComputeEntry[] = [];\n const vals: Record<string, unknown> = {};\n for (const [k, s] of Object.entries(source)) {\n if (!k || !s) continue;\n entries.push([k, s]);\n vals[k] = s.get();\n }\n\n const target = new DerivedSig(fn(vals as ValRecord<S>));\n const ctx: ComputeRecordContext<S, T> = {target, fn, entries};\n\n for (const entry of entries) {\n target.addFromBind(createBind(entry[1], ctx, computeRecordCmd));\n }\n\n return target;\n};\n\n/**\n * Derives a signal from one source signal. The result recomputes whenever\n * `source` changes.\n *\n * @typeParam S - the source value type.\n * @typeParam T - the derived value type.\n * @param source - the source signal.\n * @param fn - maps the source value to the derived value.\n * @returns a `DerivedSig` for the mapped value.\n * @example\n * ```ts\n * const x = sig(1);\n * const doubled = compute(x, (v) => v * 2);\n * ```\n * @group Reactivity\n */\nexport function compute<S, T>(source: Sig<S>, fn: (v: S) => T): DerivedSig<T>;\n/**\n * Derives a signal from a record of signals; `fn` receives the matching record\n * of values. The result recomputes whenever any source changes.\n *\n * @typeParam S - the signal record type.\n * @typeParam T - the derived value type.\n * @param source - a record of signals.\n * @param fn - maps the record of values to the derived value.\n * @returns a `DerivedSig` for the mapped value.\n * @example\n * ```ts\n * const sum = compute({x, y}, (v) => v.x + v.y);\n * ```\n * @group Reactivity\n */\nexport function compute<S extends SigRecord, T>(\n source: S,\n fn: (v: ValRecord<S>) => T,\n): DerivedSig<T>;\n// biome-ignore lint/suspicious/noExplicitAny: any source\nexport function compute(source: any, fn: (v: any) => any): DerivedSig<any> {\n return source instanceof Sig\n ? _compute(source, fn)\n : _computeRecord(source, fn);\n}\n","/**\n * Reads `arr[index]`, throwing `E1:<index>` when it is out of range.\n *\n * @typeParam T - the element type.\n * @param arr - the array to read from.\n * @param index - the index to read.\n * @returns the element at `index`.\n * @group Low-level API\n */\nexport const at = <T>(arr: T[], index: number): T => {\n const v = arr[index];\n if (v === undefined) throw new RangeError(`E1:${index}`);\n return v;\n};\n","import {type Boundary, replaceWithNode} from './boundary';\nimport type {CmdContext} from './cmd';\nimport type {Patch} from './patch.core';\nimport type {Bind} from './sig.bind';\n\n/**\n * An item that can occupy a slot in a view's children: a view or a patch.\n *\n * @group Templates\n */\nexport type ChildView = AnyView | Patch;\n\n/**\n * The unit returned by `html`, `text`, `raw`, `view`, `repeat`, `list`, and\n * `frag`.\n *\n * @typeParam T - the bound value type.\n * @typeParam C - the bind context type.\n * @group Templates\n */\n// biome-ignore lint/suspicious/noExplicitAny: View with any context\nexport interface View<T = unknown, C extends CmdContext = any> {\n /** Discriminant identifying a view. */\n type: 'view';\n /** The DOM node or `DocumentFragment` the view occupies. */\n node: Node;\n /** The view's own binding, when it is reactive. */\n bind?: Bind<T, C> | undefined;\n /** Detaches the view's bindings and, recursively, those of its children. */\n cleanBinds: () => void;\n /** Returns the nodes the view currently occupies. */\n boundary: () => Boundary;\n\n /** The interpolated children of a template view. */\n children?: ChildView[] | undefined;\n}\n\n/**\n * A {@link View} with erased value and context types.\n *\n * @group Templates\n */\n// biome-ignore lint/suspicious/noExplicitAny: any view\nexport type AnyView = View<any, any>;\n\n/**\n * Context for the `view` command: the current inner view and the view factory.\n *\n * @typeParam T - the value type.\n * @group Templates\n */\nexport interface ViewContext<T> extends CmdContext {\n /** The currently mounted inner view. */\n inner: AnyView;\n /** Builds the next inner view from a new value. */\n viewFn: (val: T) => AnyView;\n}\n\n/**\n * Replaces an existing boundary with a view's node and returns the new boundary.\n *\n * @param old - the boundary to replace.\n * @param view - the view to mount.\n * @returns the boundary of the mounted view.\n * @group Templates\n */\nexport const replaceWithView = (old: Boundary, view: View): Boundary =>\n replaceWithNode(old, view.node);\n","import {type AnyView, at, type View} from './core';\n\n/**\n * Composes several views into one content-position view. The views' nodes are\n * inserted as flat siblings, in order, with no wrapper element; nested\n * fragments flatten. Reactivity comes from the child views. `frag()` with no\n * arguments renders nothing.\n *\n * @param views - the views to compose.\n * @returns a `View` rendering the views as siblings.\n * @example\n * ```ts\n * html`<div>${frag(text('a'), html`<b>${text('b')}</b>`)}</div>`;\n * ```\n * @group Control flow\n */\nexport const frag = (...views: AnyView[]): View => {\n if (views.length === 0) {\n const empty = document.createTextNode('');\n return {\n type: 'view',\n node: empty,\n boundary: () => ({start: empty, end: empty}),\n cleanBinds: () => {},\n };\n }\n\n const node = document.createDocumentFragment();\n views.forEach((view) => {\n node.appendChild(view.node);\n });\n\n return {\n type: 'view',\n node,\n // Derive the boundary from the child views on demand: an edge view() can\n // swap its root node, and a boundary captured at construction would point\n // at the detached old node, leaking on teardown.\n boundary: () => {\n const first = at(views, 0);\n const last = at(views, views.length - 1);\n return {start: first.boundary().start, end: last.boundary().end};\n },\n cleanBinds: () => {\n views.forEach((view) => {\n view.cleanBinds();\n });\n },\n };\n};\n","import {\n createBind,\n type PatchContext,\n removeBind,\n Sig,\n toBoundary,\n type View,\n} from './core';\n\nconst textCmd = <T>(val: T, ctx: PatchContext) => {\n ctx.node.textContent = String(val);\n};\n\n/**\n * Creates a text-node view. With a `Sig`, the text updates whenever the signal\n * changes; a plain value is static.\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @returns a text `View`.\n * @example\n * ```ts\n * html`<span>${text(count)}</span>`;\n * ```\n * @group Templates\n */\nexport const text = <T>(source: T | Sig<T>): View<T, PatchContext> => {\n const text = document.createTextNode(\n source instanceof Sig ? String(source.get()) : String(source),\n );\n const ctx: PatchContext = {node: text};\n const bind =\n source instanceof Sig ? createBind(source, ctx, textCmd) : undefined;\n const boundary = toBoundary(text);\n return {\n type: 'view',\n node: text,\n bind,\n boundary: () => boundary,\n cleanBinds: () => {\n if (bind) removeBind(bind);\n },\n };\n};\n","import {\n type AnyView,\n at,\n type Bind,\n type CmdContext,\n createBind,\n err,\n type Patch,\n type PatchContext,\n removeBind,\n Sig,\n toBoundary,\n type View,\n} from './core';\nimport {text} from './text';\n\nconst MARK = `@sig_${Math.random().toFixed(9).slice(2)}`;\n\ninterface Tpl {\n el: HTMLTemplateElement;\n indexes: number[];\n // a bitmask for up to 31 slots, the string form beyond that\n shape: number | string;\n}\n\ninterface Wrap<T, C extends CmdContext> {\n item: Patch | View<T, C>;\n node: Node;\n}\n\nconst tplCache = new WeakMap<TemplateStringsArray, Tpl>();\n\nlet walker: TreeWalker | undefined;\n\n// Created on first use rather than at module scope so that importing sigula\n// stays side-effect free and works where there is no document (SSR, tests).\nconst _walker = (): TreeWalker => {\n walker ??= document.createTreeWalker(\n document,\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n );\n return walker;\n};\n\nconst _toMark = (item: Patch | View): string =>\n item.type === 'patch' ? MARK : `<!--${MARK}-->`;\n\n// The markup of a call site depends on the kind of every interpolation: a patch\n// gets an attribute marker, a view gets a comment marker. Reusing a cached\n// template across a different mix would hand the wrong node type to\n// commitPatch/commitView, so the mix is part of the cache identity.\n// A bitmask is far cheaper to build and compare than a string, and 31 slots\n// keeps it a non-negative int32 — 1 << 31 flips the sign. Beyond that fall\n// back to the string form so wide templates keep working unchanged.\nconst MAX_MASKED_SLOTS = 31;\n\nconst _shape = (items: readonly (Patch | AnyView)[]): number | string => {\n if (items.length > MAX_MASKED_SLOTS) {\n let shape = '';\n for (const item of items) shape += item.type === 'patch' ? 'p' : 'v';\n return shape;\n }\n let bits = 0;\n for (let i = 0; i < items.length; i++) {\n if (items[i]?.type === 'patch') bits |= 1 << i;\n }\n return bits;\n};\n\nconst _hasMark = (el: Element) => el.hasAttribute(MARK);\nconst _rmMark = (el: Element) => el.removeAttribute(MARK);\nconst _isViewMark = (item: Comment) => item.data.trim() === MARK;\n\nconst isPatch = (item: unknown): item is Patch =>\n typeof item === 'object' &&\n item !== null &&\n (item as {type?: string}).type === 'patch';\n\nconst isView = (item: unknown): item is AnyView =>\n typeof item === 'object' &&\n item !== null &&\n (item as {type?: string}).type === 'view';\n\nconst _toItem = (item: unknown): Patch | AnyView =>\n isPatch(item) || isView(item) ? item : text(item);\n\nconst commitView = <T, C extends CmdContext>(view: View<T, C>, node: Node) => {\n (node as Comment).replaceWith(view.node);\n};\n\nconst commitPatch = (patch: Patch, node: Node) => {\n const binds: Bind<unknown, PatchContext>[] = [];\n patch.toPatchItems.forEach((toPatchItem) => {\n const item = toPatchItem(node as Element);\n if (item.source instanceof Sig) {\n item.cmd(item.source.get(), item.context);\n binds.push(createBind(item.source, item.context, item.cmd));\n } else {\n item.cmd(item.source, item.context);\n }\n });\n\n patch.cleanBinds = () => {\n binds.forEach(removeBind);\n };\n};\n\n// Both template passes walk the same tree hunting for the next interpolation\n// slot and then do exactly the same thing with it; only the way a slot is\n// recognised differs, so that part is the only argument.\nconst _scan = (\n frag: DocumentFragment,\n items: (Patch | AnyView)[],\n wraps: Wrap<unknown, CmdContext>[],\n hit: (node: Node, nodeIndex: number, itemIndex: number) => boolean,\n indexes?: number[],\n) => {\n const w = _walker();\n w.currentNode = frag;\n let node = w.nextNode();\n let nodeIndex = 0;\n let itemIndex = 0;\n while (node !== null && itemIndex < items.length) {\n if (hit(node, nodeIndex, itemIndex)) {\n wraps.push({item: at(items, itemIndex), node});\n if (indexes) indexes.push(nodeIndex);\n itemIndex++;\n if (node.nodeType === Node.ELEMENT_NODE) _rmMark(node as Element);\n }\n node = w.nextNode();\n nodeIndex++;\n }\n // https://github.com/lit/lit/blob/c42ee1e96b8fd61f7256f61d715daef572e76e52/packages/lit-html/src/lit-html.ts#L1260\n // We need to set the currentNode away from the cloned tree so that we\n // don't hold onto the tree even if it is detached and should be freed.\n w.currentNode = document;\n};\n\ntype TextValue = string | number | boolean | bigint | null | undefined;\n// biome-ignore lint/suspicious/noExplicitAny: any val sig\ntype HtmlItem = Patch | AnyView | TextValue | Sig<any>;\n\n/**\n * Tagged template that parses native HTML and returns a {@link View}. Three\n * kinds of interpolation are supported:\n *\n * - a `View` fills a content position;\n * - a `Patch` (from `patch(...)`) fills an attribute position;\n * - a plain value or a `Sig` fills a content position as text — a `Sig` binds\n * reactively and any other value becomes `String(value)`.\n *\n * Templates are cached per call site, so repeated renders skip parsing. Throws\n * `E10` for an empty template, `E11:<expected>:<got>` for an interpolation-count\n * mismatch, and `E12` for an unmatched interpolation (a `patch` in content\n * position, or a text value in an attribute position).\n *\n * @param strs - the static template strings.\n * @param rawItems - the interpolated views, patches, or text values.\n * @returns the parsed `View`.\n * @example\n * ```ts\n * html`<p>Hello, ${name}!</p>`;\n * html`<button ${patch(on('click', handler))}>Go</button>`;\n * ```\n * @group Templates\n */\nexport const html = (\n strs: TemplateStringsArray,\n ...rawItems: HtmlItem[]\n): View => {\n if (strs.length <= 1 && !strs?.[0]) err('E10');\n const slots = strs.length - 1;\n if (rawItems.length !== slots) err(`E11:${slots}:${rawItems.length}`);\n\n const items = rawItems.map(_toItem);\n\n let frag: DocumentFragment;\n const wraps: Wrap<unknown, CmdContext>[] = [];\n\n const shape = _shape(items);\n const exist = tplCache.get(strs);\n if (exist?.shape === shape) {\n frag = document.importNode(exist.el.content, true);\n if (items && items.length > 0) {\n _scan(\n frag,\n items,\n wraps,\n (_node, nodeIndex, itemIndex) => nodeIndex === exist.indexes[itemIndex],\n );\n }\n } else {\n const template = document.createElement('template');\n template.innerHTML = _text(strs, ...items);\n const tpl: Tpl = {el: template, indexes: [], shape};\n frag = document.importNode(template.content, true);\n\n if (items && items.length > 0) {\n _scan(\n frag,\n items,\n wraps,\n (node) =>\n node.nodeType === Node.ELEMENT_NODE\n ? _hasMark(node as Element)\n : node.nodeType === Node.COMMENT_NODE &&\n _isViewMark(node as Comment),\n tpl.indexes,\n );\n }\n\n tplCache.set(strs, tpl);\n }\n\n if (wraps.length !== items.length) err('E12');\n\n wraps.forEach(({item, node}) => {\n if (item.type === 'patch') commitPatch(item, node);\n else commitView(item, node);\n });\n const children = wraps.map((w) => w.item);\n const boundary = toBoundary(frag);\n\n return {\n type: 'view',\n node: frag,\n children,\n boundary: () => {\n // A view swapping its own contents changes the node at the edge, so when\n // the template begins or ends with an interpolation track that edge.\n const last = strs.length - 1;\n if (!strs[0]) {\n const first = children[0];\n if (first?.type === 'view') boundary.start = first.boundary().start;\n }\n if (!strs[last]) {\n const endChild = children[last - 1];\n if (endChild?.type === 'view') boundary.end = endChild.boundary().end;\n }\n return boundary;\n },\n cleanBinds: () => {\n children.forEach((child) => {\n child.cleanBinds();\n });\n },\n };\n};\n\nconst _text = (strs: TemplateStringsArray, ...parts: (Patch | AnyView)[]) => {\n let text = strs[0] ?? '';\n for (let i = 0; i < parts.length; i++) {\n text += _toMark(at(parts, i)) + (strs[i + 1] ?? '');\n }\n return text;\n};\n","import {type AnyView, at, type View} from './core';\n\n/**\n * Renders a fixed array in order. `viewFn` is called once per item with the item\n * and its 0-based index, and each returned `AnyView` is appended in sequence.\n * There is no keying or reconciliation and no reactive source; any reactivity\n * comes from the views `viewFn` returns. An empty array renders\n * `<!--empty-list-->`.\n *\n * @typeParam T - the item type.\n * @param items - the items to render.\n * @param viewFn - builds the view for an item and its index.\n * @returns a `View` rendering the items.\n * @example\n * ```ts\n * html`<ul>${list(items, (item, i) => html`<li>${i}: ${text(item)}</li>`)}</ul>`;\n * ```\n * @group Control flow\n */\nexport const list = <T>(\n items: readonly T[],\n viewFn: (item: T, index: number) => AnyView,\n): View => {\n if (items.length === 0) {\n const empty = document.createComment('empty-list');\n return {\n type: 'view',\n node: empty,\n boundary: () => ({start: empty, end: empty}),\n cleanBinds: () => {},\n };\n }\n\n const frag = document.createDocumentFragment();\n const views: AnyView[] = [];\n\n items.forEach((item, index) => {\n const view = viewFn(item, index);\n views.push(view);\n frag.appendChild(view.node);\n });\n\n return {\n type: 'view',\n node: frag,\n // Derive the boundary from the child views on demand: an edge view() can\n // swap its root node, and a boundary captured at construction would point\n // at the detached old node, leaking on teardown.\n boundary: () => {\n const first = at(views, 0);\n const last = at(views, views.length - 1);\n return {start: first.boundary().start, end: last.boundary().end};\n },\n cleanBinds: () => {\n views.forEach((view) => {\n view.cleanBinds();\n });\n },\n };\n};\n","import {\n type Cmd,\n err,\n type Patch,\n type PatchContext,\n type Reactive,\n type Sig,\n type ToAnyPatchItem,\n type ToPatchItem,\n} from './core';\n\n/**\n * Object form for {@link patch}, desugared into commands in key order:\n * `id`, `val`, `class` (per entry, via `toggleClass`), `style` (per entry,\n * via `style`), `styleProp` (per entry), `on` (per entry), and any other key\n * via `attr`. A key whose value is `undefined` is skipped.\n *\n * @group DOM bindings\n */\nexport interface PatchProps {\n /** Sets the element's `id`. */\n id?: Reactive<string>;\n /** Sets the element's `value` property. */\n val?: Reactive<string>;\n /** Toggles each class from the truthiness of its value. */\n class?: Record<string, Reactive<boolean>>;\n /** Sets inline style properties by typed name. */\n style?: Partial<Record<WritableStyleKey, Reactive<string>>>;\n /** Sets style properties via `setProperty` (custom properties, untyped names). */\n styleProp?: Record<string, Reactive<string>>;\n /** Registers DOM event listeners. */\n on?: {\n [K in keyof HTMLElementEventMap]?: (ev: HTMLElementEventMap[K]) => void;\n };\n /** Any other key is set as an attribute via `attr`. */\n [attr: string]: unknown;\n}\n\nconst _noop = (): void => {};\n\n/**\n * Declares one or more bindings to apply to the same element; must be\n * interpolated in an attribute position. Each command receives a plain value\n * (applied once) or a `Sig` (applied on mount and re-applied on change).\n *\n * The first argument may be a {@link PatchProps} object, desugared into the\n * commands below in key order, optionally followed by command items.\n *\n * @param props - a props object.\n * @param items - command items applied after the props.\n * @returns a `Patch` for `html` to commit.\n * @example\n * ```ts\n * html`<input ${patch({val: name, placeholder: 'name'})} />`;\n * ```\n * @group DOM bindings\n */\nexport function patch(props: PatchProps, ...items: ToAnyPatchItem[]): Patch;\n/**\n * Declares one or more command bindings to apply to the same element.\n *\n * @param toPatchItems - the command items to apply.\n * @returns a `Patch` for `html` to commit.\n * @example\n * ```ts\n * html`<input ${patch(val(name), attr('name', placeholder))} />`;\n * ```\n * @group DOM bindings\n */\nexport function patch(...toPatchItems: ToAnyPatchItem[]): Patch;\nexport function patch(\n first?: PatchProps | ToAnyPatchItem,\n ...rest: ToAnyPatchItem[]\n): Patch {\n const toPatchItems =\n typeof first === 'function'\n ? [first, ...rest]\n : first\n ? [..._propsToItems(first), ...rest]\n : rest;\n return {type: 'patch', toPatchItems, cleanBinds: _noop};\n}\n\n// Every patch item is the same shape -- bind `source` to `elem` plus whatever\n// arguments the command needs -- so the whole body lives here once.\nconst _toPatchItem =\n <T>(\n source: T | Sig<T>,\n extra: unknown[] | undefined,\n cmd: Cmd<T, PatchContext>,\n ): ToPatchItem<T> =>\n (elem) => ({\n source,\n context: extra ? {node: elem, extra} : {node: elem},\n cmd,\n });\n\n// most commands take their attribute/style/class name as the first extra\nconst _key = (ctx: PatchContext): string => {\n const key = ctx.extra?.[0];\n if (!key) err('E4');\n return key as string;\n};\n\nconst idCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as Element).id = String(val);\n};\n\n/**\n * Sets the element's `id`.\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const id = <T>(source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, undefined, idCmd);\n\nconst valCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as unknown as {value: string}).value = String(val);\n};\n\n/**\n * Sets the element's `value` property (form controls).\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const val = <T>(source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, undefined, valCmd);\n\nconst attrCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as Element).setAttribute(_key(ctx), String(val));\n};\n\n/**\n * Sets attribute `key`. Use this for boolean/ARIA/data attributes.\n *\n * @typeParam T - the value type.\n * @param key - the attribute name.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const attr = <T>(key: string, source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, [key], attrCmd);\n\n/**\n * The union of `CSSStyleDeclaration` keys whose values are strings.\n *\n * @group DOM bindings\n */\nexport type WritableStyleKey = {\n [K in keyof CSSStyleDeclaration]: CSSStyleDeclaration[K] extends string\n ? K\n : never;\n}[keyof CSSStyleDeclaration];\n\nconst styleCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as HTMLElement).style[_key(ctx) as WritableStyleKey] = String(val);\n};\n\n/**\n * Sets an inline style property by typed name.\n *\n * @typeParam T - the value type.\n * @param key - the typed style property name.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @example\n * ```ts\n * html`<span ${patch(style('color', color))}>text</span>`;\n * ```\n * @group DOM bindings\n */\nexport const style = <T>(\n key: WritableStyleKey,\n source: T | Sig<T>,\n): ToPatchItem<T> => _toPatchItem(source, [key], styleCmd);\n\nconst stylePropCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as HTMLElement).style.setProperty(_key(ctx), String(val));\n};\n\n/**\n * Sets a style property via `CSSStyleDeclaration.setProperty`; use this for\n * custom properties (`--my-var`) or untyped names.\n *\n * @typeParam T - the value type.\n * @param key - the style property name.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @example\n * ```ts\n * html`<div ${patch(styleProp('--size', size))}></div>`;\n * ```\n * @group DOM bindings\n */\nexport const styleProp = <T>(key: string, source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, [key], stylePropCmd);\n\nconst toggleClassCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as Element).classList.toggle(_key(ctx), Boolean(val));\n};\n\n/**\n * Toggles a single class from the truthiness of the value.\n *\n * @typeParam T - the value type.\n * @param token - the class token.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const toggleClass = <T>(\n token: string,\n source: T | Sig<T>,\n): ToPatchItem<T> => _toPatchItem(source, [token], toggleClassCmd);\n\nconst toggleClassesCmd = <T>(val: T, ctx: PatchContext) => {\n ctx.extra?.forEach((token) => {\n (ctx.node as Element).classList.toggle(token as string, Boolean(val));\n });\n};\n\n/**\n * Toggles several classes from one value.\n *\n * @typeParam T - the value type.\n * @param tokens - the class tokens.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const toggleClasses = <T>(\n tokens: readonly string[],\n source: T | Sig<T>,\n): ToPatchItem<T> => _toPatchItem(source, [...tokens], toggleClassesCmd);\n\n/**\n * A custom patch callback run on mount and on change.\n *\n * @typeParam T - the value type.\n * @group DOM bindings\n */\nexport type ActFn<T> = (elem: Element, val?: T) => void;\n\nconst actCmd = <T>(val: T, ctx: PatchContext) => {\n const fn = ctx.extra?.[0] as ActFn<T> | undefined;\n if (!fn) err('E5');\n fn(ctx.node as Element, val);\n};\n\n/**\n * Runs arbitrary code with the bound node and value, on mount and again on\n * change. The escape hatch for anything the built-in commands do not cover.\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @param fn - called with the node and current value.\n * @returns a deferred patch item.\n * @example\n * ```ts\n * html`<canvas ${patch(act(frame, (node, v) => draw(node, v)))}></canvas>`;\n * ```\n * @group DOM bindings\n */\nexport const act = <T>(source: T | Sig<T>, fn: ActFn<T>): ToPatchItem<T> =>\n _toPatchItem(source, [fn], actCmd);\n\ntype _Listener<K extends keyof HTMLElementEventMap> = (\n this: HTMLElement,\n ev: HTMLElementEventMap[K],\n) => unknown;\n\nconst onCmd = (listener: unknown, ctx: PatchContext) => {\n const type = ctx.extra?.[0] as string | undefined;\n const options = ctx.extra?.[1] as\n | boolean\n | AddEventListenerOptions\n | undefined;\n if (!type) err('E6');\n ctx.node.addEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n );\n};\n\n/**\n * Adds a DOM event listener. The listener is registered once at mount and is\n * not a reactive source; combine it with `sig` writes to drive updates.\n *\n * @typeParam K - the event type.\n * @param type - the event name.\n * @param listener - the event listener.\n * @param options - standard `addEventListener` options.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const on = <K extends keyof HTMLElementEventMap>(\n type: K,\n listener: _Listener<K>,\n options?: boolean | AddEventListenerOptions,\n): ToPatchItem<_Listener<K>> => _toPatchItem(listener, [type, options], onCmd);\n\nconst _propsToItems = (props: PatchProps): ToAnyPatchItem[] => {\n const items: ToAnyPatchItem[] = [];\n for (const [key, value] of Object.entries(props)) {\n if (value === undefined) continue;\n switch (key) {\n case 'id':\n items.push(id(value as NonNullable<Reactive<string>>));\n break;\n case 'val':\n items.push(val(value as NonNullable<Reactive<string>>));\n break;\n case 'class':\n for (const [token, v] of Object.entries(\n value as Record<string, Reactive<boolean>>,\n )) {\n if (v !== undefined) items.push(toggleClass(token, v));\n }\n break;\n case 'style':\n for (const [name, v] of Object.entries(\n value as Partial<Record<WritableStyleKey, Reactive<string>>>,\n )) {\n if (v !== undefined) items.push(style(name as WritableStyleKey, v));\n }\n break;\n case 'styleProp':\n for (const [name, v] of Object.entries(\n value as Record<string, Reactive<string>>,\n )) {\n if (v !== undefined) items.push(styleProp(name, v));\n }\n break;\n case 'on':\n for (const [type, listener] of Object.entries(\n value as Record<string, _Listener<keyof HTMLElementEventMap>>,\n )) {\n if (listener !== undefined) {\n items.push(on(type as keyof HTMLElementEventMap, listener));\n }\n }\n break;\n default:\n items.push(attr(key, value));\n }\n }\n return items;\n};\n","import {\n type AnyView,\n type Boundary,\n type CmdContext,\n createBind,\n removeBind,\n replaceWithNode,\n Sig,\n toBoundary,\n} from './core';\n\ninterface RawContext extends CmdContext {\n boundary: Boundary;\n}\n\n// Parse trusted HTML through a detached <template>. Assigning innerHTML does\n// not run scripts, but the parsed nodes are later connected to the document, so\n// inline handlers and other vectors still apply and callers must sanitize\n// untrusted input. An empty string parses to no nodes; append an empty text\n// node so the fragment (and thus the boundary) always has a parent and anchor.\nconst _parse = (source: string): DocumentFragment => {\n const template = document.createElement('template');\n template.innerHTML = source;\n const content = template.content;\n if (!content.firstChild) content.appendChild(document.createTextNode(''));\n return content;\n};\n\nconst rawCmd = (val: string, ctx: RawContext) => {\n ctx.boundary = replaceWithNode(ctx.boundary, _parse(val));\n};\n\n/**\n * Parses its value as HTML and mounts the resulting nodes with no wrapper\n * element. Unlike `text`, the value is **not** escaped, so only pass trusted\n * HTML; inline handlers and other vectors still apply once the nodes connect.\n * A `Sig` re-parses and replaces the content on change; an empty string renders\n * nothing.\n *\n * @param source - an HTML string or a `Sig` of one.\n * @returns a content-position `View`.\n * @example\n * ```ts\n * html`<article>${raw(post.bodyHtml)}</article>`;\n * ```\n * @group Templates\n */\nexport const raw = (source: string | Sig<string>): AnyView => {\n const node = _parse(source instanceof Sig ? source.get() : source);\n const ctx: RawContext = {boundary: toBoundary(node)};\n const bind =\n source instanceof Sig ? createBind(source, ctx, rawCmd) : undefined;\n\n return {\n type: 'view',\n node,\n bind,\n boundary: () => ctx.boundary,\n cleanBinds: () => {\n if (bind) removeBind(bind);\n },\n };\n};\n","import {type AnyView, removeBoundary} from './core';\n\n/**\n * Mounts a view into `node` by appending its `node`. Accepts a `View` directly\n * or a factory function that returns one. Returns a disposer that detaches every\n * bind in the tree and removes the nodes from `node`; calling it twice is a\n * no-op.\n *\n * @param viewArg - the view, or a function returning one.\n * @param node - the node to mount into.\n * @returns a disposer that unmounts the view.\n * @example\n * ```ts\n * const dispose = render(App(), document.querySelector('#app')!);\n * dispose();\n * ```\n * @group Rendering\n */\nexport const render = (\n viewArg: AnyView | (() => AnyView),\n node: Node,\n): (() => void) => {\n const view = typeof viewArg === 'function' ? viewArg() : viewArg;\n node.appendChild(view.node);\n\n return () => {\n removeBoundary(view.boundary());\n view.cleanBinds();\n };\n};\n","import {\n type AnyView,\n at,\n type Boundary,\n type CmdContext,\n createBind,\n eq,\n err,\n removeBind,\n removeBoundary,\n replaceWithNode,\n replaceWithView,\n type Sig,\n toBoundary,\n type View,\n walkBoundary,\n} from './core';\n\n/**\n * Options for {@link repeat}.\n *\n * @typeParam T - the item type.\n * @group Control flow\n */\nexport type RepeatProp<T> = {\n /** Returns the unique, stable key for an item. */\n key: (item: T) => string;\n /** Builds the view for an item. */\n view: (item: T) => AnyView;\n /**\n * Item comparator.\n *\n * @defaultValue `eq`\n */\n eq?: (a: T, b: T) => boolean;\n};\n\ninterface Container {\n parent: ParentNode;\n startFence: Node;\n endFence: Node;\n}\n\ninterface Track<T> {\n key: string;\n item: T;\n view: AnyView;\n checked?: boolean;\n cleaned?: boolean;\n}\n\n/**\n * Context for the `repeat` command.\n *\n * @typeParam T - the item type.\n * @group Control flow\n */\nexport interface RepeatContext<T> extends CmdContext {\n /** The repeat options. */\n prop: RepeatProp<T>;\n /** The current node boundary. */\n boundary: Boundary;\n /** The tracked items and their views. */\n tracks: Track<T>[];\n}\n\nconst _cleanTrack = <T>(track: Track<T>) => {\n removeBoundary(track.view.boundary());\n track.view.cleanBinds();\n track.cleaned = true;\n};\n\nconst repeatCmd = <T>(items: T[], ctx: RepeatContext<T>) => {\n if (!Array.isArray(items) || items.length === 0) {\n const newFrag = document.createDocumentFragment();\n newFrag.appendChild(document.createComment('empty-list'));\n const newBoundary = replaceWithNode(ctx.boundary, newFrag);\n ctx.boundary = newBoundary;\n ctx.tracks.forEach(_cleanTrack);\n ctx.tracks = [];\n return;\n }\n const newTracks: Track<T>[] = [];\n if (!Array.isArray(ctx.tracks) || ctx.tracks.length === 0) {\n const newFrag = _init(items, ctx.prop, newTracks);\n const newBoundary = replaceWithNode(ctx.boundary, newFrag);\n ctx.boundary = newBoundary;\n ctx.tracks = newTracks;\n return;\n }\n\n const start = ctx.boundary.start;\n const end = ctx.boundary.end;\n const parent = start.parentNode;\n if (!parent) err('E7');\n\n const compare = ctx.prop.eq ?? eq;\n const newKeys = items.map((item) => ctx.prop.key(item));\n const tracks = ctx.tracks;\n\n // Nothing changed: same keys, same order, equal items. Bail out before\n // touching the DOM so a redundant re-render costs zero DOM mutations\n // instead of a fence insert/remove pair.\n if (tracks.length === items.length) {\n const unchanged = tracks.every((track, i) => {\n const item = items[i] as T;\n return track.key === newKeys[i] && compare(track.item, item);\n });\n if (unchanged) return;\n }\n\n const startFence = document.createComment('repeat-start-fence');\n const endFence = document.createComment('repeat-end-fence');\n\n parent.insertBefore(startFence, start);\n parent.insertBefore(endFence, end.nextSibling);\n\n const container: Container = {\n parent,\n startFence,\n endFence,\n };\n\n const oldKeys = tracks.map((track) => track.key);\n\n let newKeyToIndexMap: Map<unknown, number> | undefined;\n let oldKeyToIndexMap: Map<unknown, number> | undefined;\n\n let oldHead = 0;\n let oldTail = ctx.tracks.length - 1;\n let newHead = 0;\n let newTail = items.length - 1;\n\n while (oldHead <= oldTail && newHead <= newTail) {\n if (ctx.tracks[oldHead]?.checked) {\n oldHead++;\n } else if (ctx.tracks[oldTail]?.checked) {\n oldTail--;\n } else if (ctx.tracks[oldHead]?.key === newKeys[newHead]) {\n // old head matches new head; update in place\n newTracks[newHead] = _setTrack(\n at(ctx.tracks, oldHead),\n at(items, newHead),\n ctx.prop,\n compare,\n );\n oldHead++;\n newHead++;\n } else if (ctx.tracks[oldTail]?.key === newKeys[newTail]) {\n // old tail matches new tail; update in place\n newTracks[newTail] = _setTrack(\n at(ctx.tracks, oldTail),\n at(items, newTail),\n ctx.prop,\n compare,\n );\n oldTail--;\n newTail--;\n } else if (ctx.tracks[oldHead]?.key === newKeys[newTail]) {\n // old head matches new tail; update and move to new tail\n newTracks[newTail] = _setTrack(\n at(ctx.tracks, oldHead),\n at(items, newTail),\n ctx.prop,\n compare,\n );\n _moveTrack(\n container,\n at(newTracks, newTail),\n _beforeFence(container, newTracks[newTail + 1]),\n );\n oldHead++;\n newTail--;\n } else if (ctx.tracks[oldTail]?.key === newKeys[newHead]) {\n // old tail matches new head; update and move to new head\n newTracks[newHead] = _setTrack(\n at(ctx.tracks, oldTail),\n at(items, newHead),\n ctx.prop,\n compare,\n );\n _moveTrack(\n container,\n at(newTracks, newHead),\n _afterFence(container, newTracks[newHead - 1]),\n );\n oldTail--;\n newHead++;\n } else {\n if (newKeyToIndexMap === undefined || oldKeyToIndexMap === undefined) {\n newKeyToIndexMap = _generateMap(newKeys, newHead, newTail);\n oldKeyToIndexMap = _generateMap(oldKeys, oldHead, oldTail);\n }\n if (!newKeyToIndexMap.has(oldKeys[oldHead])) {\n _cleanTrack(at(ctx.tracks, oldHead));\n oldHead++;\n } else if (!newKeyToIndexMap.has(oldKeys[oldTail])) {\n _cleanTrack(at(ctx.tracks, oldTail));\n oldTail--;\n } else {\n const oldIndex = oldKeyToIndexMap.get(newKeys[newHead]);\n const oldTrack = oldIndex !== undefined ? ctx.tracks[oldIndex] : null;\n if (oldTrack) {\n newTracks[newHead] = _setTrack(\n oldTrack,\n at(items, newHead),\n ctx.prop,\n compare,\n );\n _moveTrack(\n container,\n at(newTracks, newHead),\n _afterFence(container, newTracks[newHead - 1]),\n );\n oldTrack.checked = true;\n } else {\n newTracks[newHead] = _insertNewTrack(\n container,\n at(items, newHead),\n ctx.prop,\n _afterFence(container, newTracks[newHead - 1]),\n );\n }\n newHead++;\n }\n }\n }\n\n while (newHead <= newTail) {\n newTracks[newHead] = _insertNewTrack(\n container,\n at(items, newHead),\n ctx.prop,\n _afterFence(container, newTracks[newHead - 1]),\n );\n newHead++;\n }\n\n while (oldHead <= oldTail) {\n if (!ctx.tracks[oldHead]?.cleaned && !ctx.tracks[oldHead]?.checked)\n _cleanTrack(at(ctx.tracks, oldHead));\n oldHead++;\n }\n\n if (!container.startFence.nextSibling || !container.endFence.previousSibling)\n err('E8');\n\n ctx.boundary = {\n start: container.startFence.nextSibling,\n end: container.endFence.previousSibling,\n };\n container.parent.removeChild(container.startFence);\n container.parent.removeChild(container.endFence);\n ctx.tracks = newTracks;\n};\n\nconst _generateMap = (list: unknown[], start: number, end: number) => {\n const map = new Map<unknown, number>();\n for (let i = start; i <= end; i++) {\n map.set(list[i], i);\n }\n return map;\n};\n\nconst _beforeFence = <T>(container: Container, track?: Track<T>): Node =>\n track ? track.view.boundary().start : container.endFence;\nconst _afterFence = <T>(container: Container, track?: Track<T>): Node => {\n const node = track ? track.view.boundary().end : container.startFence;\n if (!node.nextSibling) err('E9');\n return node.nextSibling;\n};\n\nconst _mvNodeBefore = (parent: ParentNode, node: Node, child: Node | null) => {\n if (parent.moveBefore) parent.moveBefore(node, child);\n else parent.insertBefore(node, child);\n};\n\nconst _moveTrack = <T>(container: Container, track: Track<T>, fence: Node) => {\n const parent = container.parent;\n walkBoundary(track.view.boundary(), (node) =>\n _mvNodeBefore(parent, node, fence),\n );\n};\n\nconst _insertNewTrack = <T>(\n container: Container,\n item: T,\n prop: RepeatProp<T>,\n fence: Node,\n): Track<T> => {\n const view = prop.view(item);\n container.parent.insertBefore(view.node, fence);\n return {\n key: prop.key(item),\n item,\n view,\n };\n};\n\nconst _setTrack = <T>(\n old: Track<T>,\n item: T,\n prop: RepeatProp<T>,\n compare: (a: T, b: T) => boolean,\n): Track<T> => {\n if (compare(old.item, item)) {\n return {\n ...old,\n checked: false,\n cleaned: false,\n };\n }\n\n const oldBoundary = old.view.boundary();\n const view = prop.view(item);\n replaceWithView(oldBoundary, view);\n _cleanTrack(old);\n\n const newTrack: Track<T> = {\n key: prop.key(item),\n item,\n view,\n };\n\n return newTrack;\n};\n\nconst _init = <T>(\n items: T[],\n prop: RepeatProp<T>,\n tracks: Track<T>[],\n): DocumentFragment => {\n const frag = document.createDocumentFragment();\n items.forEach((item) => {\n const view = prop.view(item);\n const key = prop.key(item);\n\n tracks.push({\n key,\n item,\n view,\n });\n frag.appendChild(view.node);\n });\n\n if (frag.childNodes.length === 0) {\n frag.appendChild(document.createComment('empty-list'));\n }\n return frag;\n};\n\n/**\n * Keyed list rendering. On each change `repeat` matches items by `key`, then\n * reuses, moves, creates, or removes as few DOM nodes as possible. The item\n * comparator defaults to `eq`; when an item is deeply equal to the track it\n * already occupies, the track is reused without rebuilding its view. An empty\n * array renders `<!--empty-list-->`.\n *\n * @typeParam T - the item type.\n * @param sig - the signal holding the items.\n * @param prop - the key/view/eq options.\n * @returns a `View` rendering the list.\n * @example\n * ```ts\n * html`<ul>${repeat(todos, {\n * key: (item) => item.id.toString(),\n * view: (item) => html`<li>${text(item.label)}</li>`,\n * })}</ul>`;\n * ```\n * @group Control flow\n */\nexport const repeat = <T>(\n sig: Sig<T[]>,\n prop: RepeatProp<T>,\n): View<T[], RepeatContext<T>> => {\n const tracks: Track<T>[] = [];\n const frag = _init(sig.get(), prop, tracks);\n\n const ctx: RepeatContext<T> = {prop, tracks, boundary: toBoundary(frag)};\n const bind = createBind(sig, ctx, repeatCmd);\n\n return {\n type: 'view',\n node: frag,\n bind,\n boundary: () => ctx.boundary,\n cleanBinds: () => {\n removeBind(bind);\n ctx.tracks.forEach((t) => {\n t.view.cleanBinds();\n });\n },\n };\n};\n","import {\n type AnyView,\n createBind,\n removeBind,\n replaceWithView,\n type Sig,\n type View,\n type ViewContext,\n} from './core';\n\nconst viewCmd = <T>(val: T, ctx: ViewContext<T>) => {\n const oldBoundary = ctx.inner.boundary();\n const newInner = ctx.viewFn(val);\n replaceWithView(oldBoundary, newInner);\n ctx.inner.cleanBinds();\n ctx.inner = newInner;\n};\n\n/**\n * Conditionally renders one view or another. Whenever `sig` changes, `viewFn`\n * runs with the new value, the previous view is torn down, and a new one is\n * mounted in its place.\n *\n * @typeParam T - the value type.\n * @param sig - the signal to switch on.\n * @param viewFn - builds the view for a value.\n * @returns a `View` that swaps its contents.\n * @example\n * ```ts\n * html`<div>${view(isEmpty, (v) => (v ? text('empty') : listView))}</div>`;\n * ```\n * @group Control flow\n */\nexport const view = <T>(\n sig: Sig<T>,\n viewFn: (val: T) => AnyView,\n): View<T, ViewContext<T>> => {\n const inner = viewFn(sig.get());\n\n const ctx: ViewContext<T> = {\n inner,\n viewFn,\n };\n\n const bind = createBind(sig, ctx, viewCmd);\n\n return {\n type: 'view',\n node: inner.node,\n bind,\n boundary: () => ctx.inner.boundary(),\n cleanBinds: () => {\n removeBind(bind);\n ctx.inner.cleanBinds();\n },\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"sigula.js","names":["err","code","walkBoundary","b","next","fn","removeBoundary","parent","node","toBoundary","replaceWithNode","newBoundary","old","n","isEquatable","value","eq","a","i","key","val","arrA","arrB","ao","bo","aKeys","bKeys","QUEUE","bind","binds","removed","cmd","sig","context","Sig","opts","v","index","DerivedSig","f","createBind","first","removeBind","computeCmd","ctx","s","computeRecordCmd","vals","k","_compute","target","source","_computeRecord","entries","entry","compute","at","arr","replaceWithView","view","frag","views","empty","last","textCmd","text","boundary","MARK","tplCache","walker","_walker","_toMark","item","_shape","items","shape","bits","_hasMark","el","_rmMark","_isViewMark","isPatch","isView","_toItem","commitView","commitPatch","patch","toPatchItem","_scan","w","nodeIndex","itemIndex","hit","wraps","indexes","html","rawItems","strs","slots","exist","template","_text","tpl","children","endChild","child","parts","list","viewFn","_noop","rest","_propsToItems","_toPatchItem","extra","elem","_key","idCmd","id","valCmd","attrCmd","attr","styleCmd","style","stylePropCmd","styleProp","toggleClassCmd","toggleClass","token","toggleClassesCmd","toggleClasses","tokens","actCmd","act","onCmd","type","options","listener","on","props","name","_parse","content","rawCmd","raw","render","viewArg","_cleanTrack","track","repeatCmd","newFrag","newTracks","_init","start","end","compare","newKeys","tracks","startFence","endFence","container","oldKeys","newKeyToIndexMap","oldKeyToIndexMap","oldHead","oldTail","newHead","newTail","_setTrack","_moveTrack","_beforeFence","_afterFence","_generateMap","oldIndex","oldTrack","_insertNewTrack","map","_mvNodeBefore","fence","prop","oldBoundary","repeat","t","viewCmd","newInner","inner"],"sources":["../src/core/err.ts","../src/core/boundary.ts","../src/core/eq.ts","../src/core/sig.bind.ts","../src/core/compute.ts","../src/core/utils.ts","../src/core/view.core.ts","../src/frag.ts","../src/text.ts","../src/html.ts","../src/list.ts","../src/patch.ts","../src/raw.ts","../src/render.ts","../src/repeat.ts","../src/view.ts"],"sourcesContent":["/**\n * Throws an `Error` whose message is the short `code` (for example `E2` or\n * `E11:1:2`). The full text for each code lives in the README error table, so\n * string tables stay out of the bundle.\n *\n * @param code - the coded error message.\n * @group Low-level API\n */\n// Thrown errors carry a short code instead of a message. The full text for\n// every code lives in the README so the runtime bundle stays small; use the\n// table there to translate `E1`, `E7`, ... back into a sentence.\nexport function err(code: string): never {\n throw new Error(code);\n}\n","import {err} from './err';\n\n/**\n * An inclusive range of sibling nodes (`start` through `end`).\n *\n * @group Low-level API\n */\nexport interface Boundary {\n /** The first node in the range. */\n start: Node;\n /** The last node in the range. */\n end: Node;\n}\n\n/**\n * Visits every node from `b.start` through `b.end`.\n *\n * @param b - the boundary to walk.\n * @param fn - called with each node.\n * @group Low-level API\n */\n// Visits every node from start through end. Callers capture nextSibling before\n// mutating, so the walk survives removals and moves.\nexport const walkBoundary = (b: Boundary, fn: (node: Node) => void) => {\n let n: Node | null = b.start;\n while (n) {\n const next: Node | null = n.nextSibling;\n fn(n);\n if (n === b.end) break;\n n = next;\n }\n};\n\n/**\n * Removes every node in the boundary. No-op if the boundary has no parent.\n *\n * @param b - the boundary to remove.\n * @group Low-level API\n */\nexport const removeBoundary = (b: Boundary) => {\n const parent = b.start.parentNode;\n if (!parent) return;\n walkBoundary(b, (node) => parent.removeChild(node));\n};\n\n/**\n * Wraps a node in a {@link Boundary}. A `DocumentFragment` spans its first and\n * last child; any other node covers itself. Throws `E2` on an empty fragment.\n *\n * @param node - the node to wrap.\n * @returns the node's boundary.\n * @group Low-level API\n */\nexport const toBoundary = (node: Node): Boundary => {\n const b =\n node.nodeType === Node.DOCUMENT_FRAGMENT_NODE\n ? {start: node.firstChild, end: node.lastChild}\n : {start: node, end: node};\n if (!b.start || !b.end) err('E2');\n return b as Boundary;\n};\n\n/**\n * Replaces an entire boundary with `node` and returns the new boundary. Throws\n * `E3` if the old boundary has no parent.\n *\n * @param old - the boundary to replace.\n * @param node - the replacement node.\n * @returns the boundary of the inserted node.\n * @group Low-level API\n */\nexport const replaceWithNode = (old: Boundary, node: Node): Boundary => {\n const newBoundary = toBoundary(node);\n const parent = old.start.parentNode;\n if (!parent) err('E3');\n\n if (old.start === old.end) {\n parent.replaceChild(node, old.start);\n } else {\n let n = old.start.nextSibling;\n parent.replaceChild(node, old.start);\n while (n) {\n const next = n.nextSibling;\n parent.removeChild(n);\n if (n === old.end) break;\n n = next;\n }\n }\n\n return newBoundary;\n};\n","/**\n * Implement this on a value type to give `eq` custom equality semantics.\n *\n * @group Reactivity\n */\nexport interface Equatable {\n /** Returns whether `this` and `other` are equal. */\n equals(other: unknown): boolean;\n}\n\n/**\n * A value equality function.\n *\n * @typeParam T - the value type.\n * @group Reactivity\n */\nexport type Eq<T> = (a: T, b: T) => boolean;\n\nconst isEquatable = (value: unknown): value is Equatable =>\n typeof value === 'object' &&\n value !== null &&\n 'equals' in value &&\n typeof value.equals === 'function';\n\n/**\n * Convenience alias for an arbitrary string-keyed object.\n *\n * @group Reactivity\n */\nexport type UnknownRecord = Record<string, unknown>;\n\n/**\n * Deep structural equality. Compares primitives, arrays, `Date`, `RegExp`,\n * `Map`, `Set`, and plain objects, and defers to `a.equals(b)` when `a`\n * implements `Equatable`. This is the default comparator for `Sig.update` and\n * `repeat`. Values with different prototypes are never equal.\n *\n * @typeParam T - the value type.\n * @param a - the first value.\n * @param b - the second value.\n * @returns `true` when `a` and `b` are deeply equal.\n * @group Reactivity\n */\nexport const eq = <T>(a: T, b: T): boolean => {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n\n if (a === null || b === null || typeof a !== 'object') return false;\n\n if (isEquatable(a)) return a.equals(b);\n\n // may let Array always return false\n // if (Array.isArray(a) || Array.isArray(b)) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!eq(a[i], b[i])) return false;\n }\n return true;\n }\n\n // Date\n if (a instanceof Date && b instanceof Date)\n return a.getTime() === b.getTime();\n\n // RegExp\n if (a instanceof RegExp && b instanceof RegExp) {\n return a.toString() === b.toString();\n }\n\n // Map\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n for (const [key, val] of a) {\n if (!b.has(key) || !eq(val, b.get(key))) return false;\n }\n return true;\n }\n\n // Set\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n const arrA = Array.from(a);\n const arrB = Array.from(b);\n return eq(arrA, arrB);\n }\n\n // Object & Record\n // Reject different prototypes before falling back to a key comparison.\n // Object.keys is [] for Date, Map, Set, RegExp, Error and [], so without\n // this guard isEqual([], {}) and isEqual(new Date(0), {}) both report\n // equal and Sig.update silently swallows a shape-changing write.\n // Must stay BELOW the isEquatable check above: hoisting it stops a user\n // Equatable from ever being consulted.\n if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false;\n\n // both are objects sharing one prototype from here on, and the length check\n // plus Object.hasOwn below prove the two key sets are identical, so ao[key]\n // is always an own property\n const ao = a as UnknownRecord;\n const bo = b as UnknownRecord;\n\n const aKeys = Object.keys(ao);\n const bKeys = Object.keys(bo);\n if (aKeys.length !== bKeys.length) return false;\n\n for (let i = 0; i < aKeys.length; i++) {\n const key = aKeys[i] as string;\n if (!Object.hasOwn(bo, key)) return false;\n if (!eq(ao[key], bo[key])) return false;\n }\n\n return true;\n};\n","import type {Cmd, CmdContext} from './cmd';\nimport {type Eq, type Equatable, eq} from './eq';\n\n/**\n * A registered binding: the signal, its command context, and the command that\n * runs when the signal changes.\n *\n * @typeParam T - the signal's value type.\n * @typeParam C - the command context type.\n * @group Reactivity\n */\nexport interface Bind<T, C extends CmdContext> {\n /** The signal this binding observes. */\n sig: Sig<T>;\n /** The context passed to `cmd` on each run. */\n context: C;\n /** The command run with the current value and context. */\n cmd: Cmd<T, C>;\n /** Set when the binding is detached; a removed binding is skipped. */\n removed: boolean;\n /** Queue flag; true while the binding is queued for the next flush. */\n queued?: boolean;\n}\n\n/**\n * A {@link Bind} with erased value and context types.\n *\n * @group Reactivity\n */\n// biome-ignore lint/suspicious/noExplicitAny: any bind\nexport type AnyBind = Bind<any, any>;\n\nclass Queue {\n private _binds: AnyBind[] = [];\n private head = 0;\n private running = false;\n private scheduled = false;\n\n addAll(binds: readonly AnyBind[]): this {\n for (const bind of binds) {\n if (bind.queued) continue;\n bind.queued = true;\n this._binds.push(bind);\n }\n if (this._binds.length > this.head) this.kick();\n return this;\n }\n\n private kick(): void {\n if (this.running || this.scheduled) return;\n this.scheduled = true;\n queueMicrotask(() => {\n this.running = true;\n this.scheduled = false;\n this.flush();\n });\n }\n\n private flush(): void {\n this.running = true;\n try {\n while (this.head < this._binds.length) {\n const bind = this._binds[this.head++] as AnyBind;\n try {\n const {removed, sig, context, cmd} = bind;\n if (!removed) cmd(sig.get(), context);\n } catch (err) {\n console.error('[Queue] task failed:', err, bind);\n } finally {\n // re-arm after running: cmd reads sig.get() at call time, so a bind\n // that runs after a write already sees the newest value and must\n // not re-run, while one that ran before it has to be queued again\n bind.queued = false;\n }\n }\n } finally {\n this.running = false;\n if (this.head < this._binds.length) {\n // almost impossible in js/ts\n this._binds = this._binds.slice(this.head);\n this.head = 0;\n this.kick();\n } else {\n this._binds.length = 0;\n this.head = 0;\n }\n }\n }\n}\n\nconst QUEUE = new Queue();\n\n/**\n * The core reactive value. A `Sig` holds a value and a set of bindings that run\n * when it changes; writes are queued and coalesced in a microtask.\n *\n * @typeParam T - the value type.\n * @group Reactivity\n */\nexport class Sig<T> implements Equatable {\n private _val: T;\n private _binds: AnyBind[] = [];\n private _eq: Eq<T>;\n\n constructor(val: T, opts?: {eq?: Eq<T>}) {\n this._val = val;\n this._eq = opts?.eq ?? eq;\n }\n\n /** `Equatable` implementation; two `Sig`s are equal when their values are deeply equal. */\n equals(b: unknown) {\n if (b instanceof Sig) return this._eq(this.get(), b.get());\n return false;\n }\n\n /** Reads the current value. */\n get(): T {\n return this._val;\n }\n\n /** Enqueues dependents without changing the value; use after in-place mutation. */\n notify() {\n QUEUE.addAll(this._binds);\n }\n\n /** Sets the value and always notifies dependents, even when deeply equal. */\n forceUpdate(v: T) {\n this._val = v;\n this.notify();\n }\n\n /** Sets the value and notifies dependents only when `eq(v, current)` is false. */\n update(v: T) {\n if (this._eq(v, this._val)) return;\n this.forceUpdate(v);\n }\n\n /** Applies `fn` to the current value via `update`, so an equal result is skipped. */\n trans(fn: (v: T) => T) {\n this.update(fn(this._val));\n }\n\n /** Registers a binding. Prefer `createBind` or the `patch`/`text`/`view` APIs. */\n addBind<C extends CmdContext>(bind: Bind<T, C>) {\n this._binds.push(bind);\n }\n\n /** Unregisters a binding; runs `cleanup()` when the last one goes away. */\n removeBind<C extends CmdContext>(bind: Bind<T, C>) {\n const index = this._binds.indexOf(bind);\n if (index >= 0) this._binds.splice(index, 1);\n if (this._binds.length === 0) {\n this.cleanup();\n }\n }\n\n /** Returns the current bindings. */\n getBinds(): Bind<T, CmdContext>[] {\n return this._binds;\n }\n\n /** Overridable hook called when a signal loses all bindings. No-op on `Sig`. */\n // empty: DerivedSig overrides this to detach from its sources when its last\n // observer goes away\n cleanup() {}\n}\n\n/**\n * A `Sig` produced by {@link compute}. Extends `Sig` and additionally tracks the\n * source bindings that feed it: it detaches from its sources when it loses its\n * last consumer, and re-links and recomputes once when a consumer is added\n * again.\n *\n * @typeParam T - the derived value type.\n * @group Reactivity\n */\nexport class DerivedSig<T> extends Sig<T> {\n private _fromBinds: AnyBind[] = [];\n private _linked = true;\n\n /** Registers a source binding. */\n addFromBind<S, C extends CmdContext>(bind: Bind<S, C>) {\n this._fromBinds.push(bind);\n }\n\n /** Registers a consumer; re-links to sources and recomputes once if detached. */\n // A derived signal's upstream links are torn down when its last observer\n // goes away, which happens any time a view() subtree is hidden. The links\n // cannot be revived in place because removeBind marks them removed, so we\n // rebuild fresh binds from each recipe and recompute once: sources usually\n // moved while we were detached.\n //\n // super.addBind must stay first: the recompute below updates this signal\n // straight away, so the returning observer has to be registered before it\n // or it misses the value and only catches up on some later update.\n override addBind<C extends CmdContext>(bind: Bind<T, C>) {\n super.addBind(bind);\n if (this._linked) return;\n this._linked = true;\n for (let i = 0; i < this._fromBinds.length; i++) {\n const f = this._fromBinds[i] as AnyBind;\n this._fromBinds[i] = createBind(f.sig, f.context, f.cmd);\n }\n // every from-bind shares one context whose cmd reads all sources, so one\n // invocation recomputes the whole derived value\n const first = this._fromBinds[0];\n if (first) first.cmd(first.sig.get(), first.context);\n }\n\n /** Removes every source binding when the derived signal has no consumers. */\n override cleanup() {\n if (!this._linked) return;\n this._linked = false;\n for (const b of this._fromBinds) removeBind(b);\n }\n}\n\n/**\n * Creates a writable signal holding `v`.\n *\n * @param v - the initial value.\n * @param opts - optional settings; `eq` overrides the comparator used by `update`.\n * @returns a new `Sig` for `v`.\n * @example\n * ```ts\n * const count = sig(0);\n * count.get(); // 0\n * count.update(1); // schedules dependents\n * ```\n * @group Reactivity\n */\nexport const sig = <T>(v: T, opts?: {eq?: Eq<T>}) => new Sig(v, opts);\n\n/**\n * Detaches a binding and marks it removed so queued runs are skipped.\n *\n * @typeParam T - the signal's value type.\n * @typeParam C - the command context type.\n * @param bind - the binding to remove.\n * @group Reactivity\n */\nexport const removeBind = <T, C extends CmdContext>(bind: Bind<T, C>) => {\n bind.removed = true;\n bind.sig.removeBind(bind);\n};\n\n/**\n * Wires `cmd(sig.get(), context)` to run whenever `sig` changes.\n *\n * @typeParam T - the signal's value type.\n * @typeParam C - the command context type.\n * @param sig - the signal to observe.\n * @param context - the context passed to `cmd`.\n * @param cmd - the command run on change.\n * @returns the registered binding.\n * @group Reactivity\n */\nexport const createBind = <T, C extends CmdContext>(\n sig: Sig<T>,\n context: C,\n cmd: Cmd<T, C>,\n): Bind<T, C> => {\n const bind: Bind<T, C> = {sig, context, cmd, removed: false, queued: false};\n sig.addBind(bind);\n return bind;\n};\n\n/**\n * A value that may be plain, a `Sig`, or `undefined`.\n *\n * @typeParam T - the underlying value type.\n * @group Reactivity\n */\nexport type Reactive<T> = T | Sig<T> | undefined;\n","import type {CmdContext} from './cmd';\nimport {createBind, DerivedSig, Sig} from './sig.bind';\n\n/**\n * A record whose values are signals, used by the record overload of\n * {@link compute}.\n *\n * @group Reactivity\n */\nexport interface SigRecord {\n /** Each key maps to a signal of any value type. */\n // biome-ignore lint/suspicious/noExplicitAny: any sig val\n [key: string]: Sig<any>;\n}\n\n/**\n * Maps a {@link SigRecord} to a record of the signals' values.\n *\n * @typeParam K - the signal record type.\n * @group Reactivity\n */\nexport type ValRecord<K extends SigRecord> = {\n [P in keyof K]: K[P] extends Sig<infer U> ? U : never;\n};\n\n// biome-ignore lint/suspicious/noExplicitAny: heterogeneous source sigs\ntype ComputeEntry = [string, Sig<any>];\n\ninterface ComputeContext<S, T> extends CmdContext {\n target: Sig<T>;\n fn: (s: S) => T;\n}\n\ninterface ComputeRecordContext<S extends SigRecord, T> extends CmdContext {\n target: Sig<T>;\n fn: (v: ValRecord<S>) => T;\n entries: ComputeEntry[];\n}\n\nconst computeCmd = <S, T>(s: S, ctx: ComputeContext<S, T>) => {\n ctx.target.update(ctx.fn(s));\n};\n\nconst computeRecordCmd = <S extends SigRecord, T>(\n _s: unknown,\n ctx: ComputeRecordContext<S, T>,\n) => {\n const vals: Record<string, unknown> = {};\n for (const [k, s] of ctx.entries) vals[k] = s.get();\n ctx.target.update(ctx.fn(vals as ValRecord<S>));\n};\n\nconst _compute = <S, T>(source: Sig<S>, fn: (v: S) => T): DerivedSig<T> => {\n const target = new DerivedSig(fn(source.get()));\n const ctx: ComputeContext<S, T> = {target, fn};\n target.addFromBind(createBind(source, ctx, computeCmd));\n return target;\n};\n\nconst _computeRecord = <S extends SigRecord, T>(\n source: S,\n fn: (v: ValRecord<S>) => T,\n): DerivedSig<T> => {\n const entries: ComputeEntry[] = [];\n const vals: Record<string, unknown> = {};\n for (const [k, s] of Object.entries(source)) {\n if (!k || !s) continue;\n entries.push([k, s]);\n vals[k] = s.get();\n }\n\n const target = new DerivedSig(fn(vals as ValRecord<S>));\n const ctx: ComputeRecordContext<S, T> = {target, fn, entries};\n\n for (const entry of entries) {\n target.addFromBind(createBind(entry[1], ctx, computeRecordCmd));\n }\n\n return target;\n};\n\n/**\n * Derives a signal from one source signal. The result recomputes whenever\n * `source` changes.\n *\n * @typeParam S - the source value type.\n * @typeParam T - the derived value type.\n * @param source - the source signal.\n * @param fn - maps the source value to the derived value.\n * @returns a `DerivedSig` for the mapped value.\n * @example\n * ```ts\n * const x = sig(1);\n * const doubled = compute(x, (v) => v * 2);\n * ```\n * @group Reactivity\n */\nexport function compute<S, T>(source: Sig<S>, fn: (v: S) => T): DerivedSig<T>;\n/**\n * Derives a signal from a record of signals; `fn` receives the matching record\n * of values. The result recomputes whenever any source changes.\n *\n * @typeParam S - the signal record type.\n * @typeParam T - the derived value type.\n * @param source - a record of signals.\n * @param fn - maps the record of values to the derived value.\n * @returns a `DerivedSig` for the mapped value.\n * @example\n * ```ts\n * const sum = compute({x, y}, (v) => v.x + v.y);\n * ```\n * @group Reactivity\n */\nexport function compute<S extends SigRecord, T>(\n source: S,\n fn: (v: ValRecord<S>) => T,\n): DerivedSig<T>;\n// biome-ignore lint/suspicious/noExplicitAny: any source\nexport function compute(source: any, fn: (v: any) => any): DerivedSig<any> {\n return source instanceof Sig\n ? _compute(source, fn)\n : _computeRecord(source, fn);\n}\n","/**\n * Reads `arr[index]`, throwing `E1:<index>` when it is out of range.\n *\n * @typeParam T - the element type.\n * @param arr - the array to read from.\n * @param index - the index to read.\n * @returns the element at `index`.\n * @group Low-level API\n */\nexport const at = <T>(arr: T[], index: number): T => {\n const v = arr[index];\n if (v === undefined) throw new RangeError(`E1:${index}`);\n return v;\n};\n","import {type Boundary, replaceWithNode} from './boundary';\nimport type {CmdContext} from './cmd';\nimport type {Patch} from './patch.core';\nimport type {Bind} from './sig.bind';\n\n/**\n * An item that can occupy a slot in a view's children: a view or a patch.\n *\n * @group Templates\n */\nexport type ChildView = AnyView | Patch;\n\n/**\n * The unit returned by `html`, `text`, `raw`, `view`, `repeat`, `list`, and\n * `frag`.\n *\n * @typeParam T - the bound value type.\n * @typeParam C - the bind context type.\n * @group Templates\n */\n// biome-ignore lint/suspicious/noExplicitAny: View with any context\nexport interface View<T = unknown, C extends CmdContext = any> {\n /** Discriminant identifying a view. */\n type: 'view';\n /** The DOM node or `DocumentFragment` the view occupies. */\n node: Node;\n /** The view's own binding, when it is reactive. */\n bind?: Bind<T, C> | undefined;\n /** Detaches the view's bindings and, recursively, those of its children. */\n cleanBinds: () => void;\n /** Returns the nodes the view currently occupies. */\n boundary: () => Boundary;\n\n /** The interpolated children of a template view. */\n children?: ChildView[] | undefined;\n}\n\n/**\n * A {@link View} with erased value and context types.\n *\n * @group Templates\n */\n// biome-ignore lint/suspicious/noExplicitAny: any view\nexport type AnyView = View<any, any>;\n\n/**\n * Context for the `view` command: the current inner view and the view factory.\n *\n * @typeParam T - the value type.\n * @group Templates\n */\nexport interface ViewContext<T> extends CmdContext {\n /** The currently mounted inner view. */\n inner: AnyView;\n /** Builds the next inner view from a new value. */\n viewFn: (val: T) => AnyView;\n}\n\n/**\n * Replaces an existing boundary with a view's node and returns the new boundary.\n *\n * @param old - the boundary to replace.\n * @param view - the view to mount.\n * @returns the boundary of the mounted view.\n * @group Templates\n */\nexport const replaceWithView = (old: Boundary, view: View): Boundary =>\n replaceWithNode(old, view.node);\n","import {type AnyView, at, type View} from './core';\n\n/**\n * Composes several views into one content-position view. The views' nodes are\n * inserted as flat siblings, in order, with no wrapper element; nested\n * fragments flatten. Reactivity comes from the child views. `frag()` with no\n * arguments renders nothing.\n *\n * @param views - the views to compose.\n * @returns a `View` rendering the views as siblings.\n * @example\n * ```ts\n * html`<div>${frag(text('a'), html`<b>${text('b')}</b>`)}</div>`;\n * ```\n * @group Control flow\n */\nexport const frag = (...views: AnyView[]): View => {\n if (views.length === 0) {\n const empty = document.createTextNode('');\n return {\n type: 'view',\n node: empty,\n boundary: () => ({start: empty, end: empty}),\n cleanBinds: () => {},\n };\n }\n\n const node = document.createDocumentFragment();\n views.forEach((view) => {\n node.appendChild(view.node);\n });\n\n return {\n type: 'view',\n node,\n // Derive the boundary from the child views on demand: an edge view() can\n // swap its root node, and a boundary captured at construction would point\n // at the detached old node, leaking on teardown.\n boundary: () => {\n const first = at(views, 0);\n const last = at(views, views.length - 1);\n return {start: first.boundary().start, end: last.boundary().end};\n },\n cleanBinds: () => {\n views.forEach((view) => {\n view.cleanBinds();\n });\n },\n };\n};\n","import {\n createBind,\n type PatchContext,\n removeBind,\n Sig,\n toBoundary,\n type View,\n} from './core';\n\nconst textCmd = <T>(val: T, ctx: PatchContext) => {\n ctx.node.textContent = String(val);\n};\n\n/**\n * Creates a text-node view. With a `Sig`, the text updates whenever the signal\n * changes; a plain value is static.\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @returns a text `View`.\n * @example\n * ```ts\n * html`<span>${text(count)}</span>`;\n * ```\n * @group Templates\n */\nexport const text = <T>(source: T | Sig<T>): View<T, PatchContext> => {\n const text = document.createTextNode(\n source instanceof Sig ? String(source.get()) : String(source),\n );\n const ctx: PatchContext = {node: text};\n const bind =\n source instanceof Sig ? createBind(source, ctx, textCmd) : undefined;\n const boundary = toBoundary(text);\n return {\n type: 'view',\n node: text,\n bind,\n boundary: () => boundary,\n cleanBinds: () => {\n if (bind) removeBind(bind);\n },\n };\n};\n","import {\n type AnyView,\n at,\n type Bind,\n type CmdContext,\n createBind,\n err,\n type Patch,\n type PatchContext,\n removeBind,\n Sig,\n toBoundary,\n type View,\n} from './core';\nimport {text} from './text';\n\nconst MARK = `@sig_${Math.random().toFixed(9).slice(2)}`;\n\ninterface Tpl {\n el: HTMLTemplateElement;\n indexes: number[];\n // a bitmask for up to 31 slots, the string form beyond that\n shape: number | string;\n}\n\ninterface Wrap<T, C extends CmdContext> {\n item: Patch | View<T, C>;\n node: Node;\n}\n\nconst tplCache = new WeakMap<TemplateStringsArray, Tpl>();\n\nlet walker: TreeWalker | undefined;\n\n// Created on first use rather than at module scope so that importing sigula\n// stays side-effect free and works where there is no document (SSR, tests).\nconst _walker = (): TreeWalker => {\n walker ??= document.createTreeWalker(\n document,\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n );\n return walker;\n};\n\nconst _toMark = (item: Patch | View): string =>\n item.type === 'patch' ? MARK : `<!--${MARK}-->`;\n\n// The markup of a call site depends on the kind of every interpolation: a patch\n// gets an attribute marker, a view gets a comment marker. Reusing a cached\n// template across a different mix would hand the wrong node type to\n// commitPatch/commitView, so the mix is part of the cache identity.\n// A bitmask is far cheaper to build and compare than a string, and 31 slots\n// keeps it a non-negative int32 — 1 << 31 flips the sign. Beyond that fall\n// back to the string form so wide templates keep working unchanged.\nconst MAX_MASKED_SLOTS = 31;\n\nconst _shape = (items: readonly (Patch | AnyView)[]): number | string => {\n if (items.length > MAX_MASKED_SLOTS) {\n let shape = '';\n for (const item of items) shape += item.type === 'patch' ? 'p' : 'v';\n return shape;\n }\n let bits = 0;\n for (let i = 0; i < items.length; i++) {\n if (items[i]?.type === 'patch') bits |= 1 << i;\n }\n return bits;\n};\n\nconst _hasMark = (el: Element) => el.hasAttribute(MARK);\nconst _rmMark = (el: Element) => el.removeAttribute(MARK);\nconst _isViewMark = (item: Comment) => item.data.trim() === MARK;\n\nconst isPatch = (item: unknown): item is Patch =>\n typeof item === 'object' &&\n item !== null &&\n (item as {type?: string}).type === 'patch';\n\nconst isView = (item: unknown): item is AnyView =>\n typeof item === 'object' &&\n item !== null &&\n (item as {type?: string}).type === 'view';\n\nconst _toItem = (item: unknown): Patch | AnyView =>\n isPatch(item) || isView(item) ? item : text(item);\n\nconst commitView = <T, C extends CmdContext>(view: View<T, C>, node: Node) => {\n (node as Comment).replaceWith(view.node);\n};\n\nconst commitPatch = (patch: Patch, node: Node) => {\n const binds: Bind<unknown, PatchContext>[] = [];\n patch.toPatchItems.forEach((toPatchItem) => {\n const item = toPatchItem(node as Element);\n if (item.source instanceof Sig) {\n item.cmd(item.source.get(), item.context);\n binds.push(createBind(item.source, item.context, item.cmd));\n } else {\n item.cmd(item.source, item.context);\n }\n });\n\n patch.cleanBinds = () => {\n binds.forEach(removeBind);\n };\n};\n\n// Both template passes walk the same tree hunting for the next interpolation\n// slot and then do exactly the same thing with it; only the way a slot is\n// recognised differs, so that part is the only argument.\nconst _scan = (\n frag: DocumentFragment,\n items: (Patch | AnyView)[],\n wraps: Wrap<unknown, CmdContext>[],\n hit: (node: Node, nodeIndex: number, itemIndex: number) => boolean,\n indexes?: number[],\n) => {\n const w = _walker();\n w.currentNode = frag;\n let node = w.nextNode();\n let nodeIndex = 0;\n let itemIndex = 0;\n while (node !== null && itemIndex < items.length) {\n if (hit(node, nodeIndex, itemIndex)) {\n wraps.push({item: at(items, itemIndex), node});\n if (indexes) indexes.push(nodeIndex);\n itemIndex++;\n if (node.nodeType === Node.ELEMENT_NODE) _rmMark(node as Element);\n }\n node = w.nextNode();\n nodeIndex++;\n }\n // https://github.com/lit/lit/blob/c42ee1e96b8fd61f7256f61d715daef572e76e52/packages/lit-html/src/lit-html.ts#L1260\n // We need to set the currentNode away from the cloned tree so that we\n // don't hold onto the tree even if it is detached and should be freed.\n w.currentNode = document;\n};\n\ntype TextValue = string | number | boolean | bigint | null | undefined;\n// biome-ignore lint/suspicious/noExplicitAny: any val sig\ntype HtmlItem = Patch | AnyView | TextValue | Sig<any>;\n\n/**\n * Tagged template that parses native HTML and returns a {@link View}. Three\n * kinds of interpolation are supported:\n *\n * - a `View` fills a content position;\n * - a `Patch` (from `patch(...)`) fills an attribute position;\n * - a plain value or a `Sig` fills a content position as text — a `Sig` binds\n * reactively and any other value becomes `String(value)`.\n *\n * Templates are cached per call site, so repeated renders skip parsing. Throws\n * `E10` for an empty template, `E11:<expected>:<got>` for an interpolation-count\n * mismatch, and `E12` for an unmatched interpolation (a `patch` in content\n * position, or a text value in an attribute position).\n *\n * @param strs - the static template strings.\n * @param rawItems - the interpolated views, patches, or text values.\n * @returns the parsed `View`.\n * @example\n * ```ts\n * html`<p>Hello, ${name}!</p>`;\n * html`<button ${patch(on('click', handler))}>Go</button>`;\n * ```\n * @group Templates\n */\nexport const html = (\n strs: TemplateStringsArray,\n ...rawItems: HtmlItem[]\n): View => {\n if (strs.length <= 1 && !strs?.[0]) err('E10');\n const slots = strs.length - 1;\n if (rawItems.length !== slots) err(`E11:${slots}:${rawItems.length}`);\n\n const items = rawItems.map(_toItem);\n\n let frag: DocumentFragment;\n const wraps: Wrap<unknown, CmdContext>[] = [];\n\n const shape = _shape(items);\n const exist = tplCache.get(strs);\n if (exist?.shape === shape) {\n frag = document.importNode(exist.el.content, true);\n if (items && items.length > 0) {\n _scan(\n frag,\n items,\n wraps,\n (_node, nodeIndex, itemIndex) => nodeIndex === exist.indexes[itemIndex],\n );\n }\n } else {\n const template = document.createElement('template');\n template.innerHTML = _text(strs, ...items);\n const tpl: Tpl = {el: template, indexes: [], shape};\n frag = document.importNode(template.content, true);\n\n if (items && items.length > 0) {\n _scan(\n frag,\n items,\n wraps,\n (node) =>\n node.nodeType === Node.ELEMENT_NODE\n ? _hasMark(node as Element)\n : node.nodeType === Node.COMMENT_NODE &&\n _isViewMark(node as Comment),\n tpl.indexes,\n );\n }\n\n tplCache.set(strs, tpl);\n }\n\n if (wraps.length !== items.length) err('E12');\n\n wraps.forEach(({item, node}) => {\n if (item.type === 'patch') commitPatch(item, node);\n else commitView(item, node);\n });\n const children = wraps.map((w) => w.item);\n const boundary = toBoundary(frag);\n\n return {\n type: 'view',\n node: frag,\n children,\n boundary: () => {\n // A view swapping its own contents changes the node at the edge, so when\n // the template begins or ends with an interpolation track that edge.\n const last = strs.length - 1;\n if (!strs[0]) {\n const first = children[0];\n if (first?.type === 'view') boundary.start = first.boundary().start;\n }\n if (!strs[last]) {\n const endChild = children[last - 1];\n if (endChild?.type === 'view') boundary.end = endChild.boundary().end;\n }\n return boundary;\n },\n cleanBinds: () => {\n children.forEach((child) => {\n child.cleanBinds();\n });\n },\n };\n};\n\nconst _text = (strs: TemplateStringsArray, ...parts: (Patch | AnyView)[]) => {\n let text = strs[0] ?? '';\n for (let i = 0; i < parts.length; i++) {\n text += _toMark(at(parts, i)) + (strs[i + 1] ?? '');\n }\n return text;\n};\n","import {type AnyView, at, type View} from './core';\n\n/**\n * Renders a fixed array in order. `viewFn` is called once per item with the item\n * and its 0-based index, and each returned `AnyView` is appended in sequence.\n * There is no keying or reconciliation and no reactive source; any reactivity\n * comes from the views `viewFn` returns. An empty array renders\n * `<!--empty-list-->`.\n *\n * @typeParam T - the item type.\n * @param items - the items to render.\n * @param viewFn - builds the view for an item and its index.\n * @returns a `View` rendering the items.\n * @example\n * ```ts\n * html`<ul>${list(items, (item, i) => html`<li>${i}: ${text(item)}</li>`)}</ul>`;\n * ```\n * @group Control flow\n */\nexport const list = <T>(\n items: readonly T[],\n viewFn: (item: T, index: number) => AnyView,\n): View => {\n if (items.length === 0) {\n const empty = document.createComment('empty-list');\n return {\n type: 'view',\n node: empty,\n boundary: () => ({start: empty, end: empty}),\n cleanBinds: () => {},\n };\n }\n\n const frag = document.createDocumentFragment();\n const views: AnyView[] = [];\n\n items.forEach((item, index) => {\n const view = viewFn(item, index);\n views.push(view);\n frag.appendChild(view.node);\n });\n\n return {\n type: 'view',\n node: frag,\n // Derive the boundary from the child views on demand: an edge view() can\n // swap its root node, and a boundary captured at construction would point\n // at the detached old node, leaking on teardown.\n boundary: () => {\n const first = at(views, 0);\n const last = at(views, views.length - 1);\n return {start: first.boundary().start, end: last.boundary().end};\n },\n cleanBinds: () => {\n views.forEach((view) => {\n view.cleanBinds();\n });\n },\n };\n};\n","import {\n type Cmd,\n err,\n type Patch,\n type PatchContext,\n type Reactive,\n type Sig,\n type ToAnyPatchItem,\n type ToPatchItem,\n} from './core';\n\n/**\n * Object form for {@link patch}, desugared into commands in key order:\n * `id`, `val`, `class` (per entry, via `toggleClass`), `style` (per entry,\n * via `style`), `styleProp` (per entry), `on` (per entry), and any other key\n * via `attr`. A key whose value is `undefined` is skipped.\n *\n * @group DOM bindings\n */\nexport interface PatchProps {\n /** Sets the element's `id`. */\n id?: Reactive<string>;\n /** Sets the element's `value` property. */\n val?: Reactive<string>;\n /** Toggles each class from the truthiness of its value. */\n class?: Record<string, Reactive<boolean>>;\n /** Sets inline style properties by typed name. */\n style?: Partial<Record<WritableStyleKey, Reactive<string>>>;\n /** Sets style properties via `setProperty` (custom properties, untyped names). */\n styleProp?: Record<string, Reactive<string>>;\n /** Registers DOM event listeners. */\n on?: {\n [K in keyof HTMLElementEventMap]?: (ev: HTMLElementEventMap[K]) => void;\n };\n /** Any other key is set as an attribute via `attr`. */\n [attr: string]: unknown;\n}\n\nconst _noop = (): void => {};\n\n/**\n * Declares one or more bindings to apply to the same element; must be\n * interpolated in an attribute position. Each command receives a plain value\n * (applied once) or a `Sig` (applied on mount and re-applied on change).\n *\n * The first argument may be a {@link PatchProps} object, desugared into the\n * commands below in key order, optionally followed by command items.\n *\n * @param props - a props object.\n * @param items - command items applied after the props.\n * @returns a `Patch` for `html` to commit.\n * @example\n * ```ts\n * html`<input ${patch({val: name, placeholder: 'name'})} />`;\n * ```\n * @group DOM bindings\n */\nexport function patch(props: PatchProps, ...items: ToAnyPatchItem[]): Patch;\n/**\n * Declares one or more command bindings to apply to the same element.\n *\n * @param toPatchItems - the command items to apply.\n * @returns a `Patch` for `html` to commit.\n * @example\n * ```ts\n * html`<input ${patch(val(name), attr('name', placeholder))} />`;\n * ```\n * @group DOM bindings\n */\nexport function patch(...toPatchItems: ToAnyPatchItem[]): Patch;\nexport function patch(\n first?: PatchProps | ToAnyPatchItem,\n ...rest: ToAnyPatchItem[]\n): Patch {\n const toPatchItems =\n typeof first === 'function'\n ? [first, ...rest]\n : first\n ? [..._propsToItems(first), ...rest]\n : rest;\n return {type: 'patch', toPatchItems, cleanBinds: _noop};\n}\n\n// Every patch item is the same shape -- bind `source` to `elem` plus whatever\n// arguments the command needs -- so the whole body lives here once.\nconst _toPatchItem =\n <T>(\n source: T | Sig<T>,\n extra: unknown[] | undefined,\n cmd: Cmd<T, PatchContext>,\n ): ToPatchItem<T> =>\n (elem) => ({\n source,\n context: extra ? {node: elem, extra} : {node: elem},\n cmd,\n });\n\n// most commands take their attribute/style/class name as the first extra\nconst _key = (ctx: PatchContext): string => {\n const key = ctx.extra?.[0];\n if (!key) err('E4');\n return key as string;\n};\n\nconst idCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as Element).id = String(val);\n};\n\n/**\n * Sets the element's `id`.\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const id = <T>(source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, undefined, idCmd);\n\nconst valCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as unknown as {value: string}).value = String(val);\n};\n\n/**\n * Sets the element's `value` property (form controls).\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const val = <T>(source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, undefined, valCmd);\n\nconst attrCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as Element).setAttribute(_key(ctx), String(val));\n};\n\n/**\n * Sets attribute `key`. Use this for boolean/ARIA/data attributes.\n *\n * @typeParam T - the value type.\n * @param key - the attribute name.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const attr = <T>(key: string, source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, [key], attrCmd);\n\n/**\n * The union of `CSSStyleDeclaration` keys whose values are strings.\n *\n * @group DOM bindings\n */\nexport type WritableStyleKey = {\n [K in keyof CSSStyleDeclaration]: CSSStyleDeclaration[K] extends string\n ? K\n : never;\n}[keyof CSSStyleDeclaration];\n\nconst styleCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as HTMLElement).style[_key(ctx) as WritableStyleKey] = String(val);\n};\n\n/**\n * Sets an inline style property by typed name.\n *\n * @typeParam T - the value type.\n * @param key - the typed style property name.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @example\n * ```ts\n * html`<span ${patch(style('color', color))}>text</span>`;\n * ```\n * @group DOM bindings\n */\nexport const style = <T>(\n key: WritableStyleKey,\n source: T | Sig<T>,\n): ToPatchItem<T> => _toPatchItem(source, [key], styleCmd);\n\nconst stylePropCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as HTMLElement).style.setProperty(_key(ctx), String(val));\n};\n\n/**\n * Sets a style property via `CSSStyleDeclaration.setProperty`; use this for\n * custom properties (`--my-var`) or untyped names.\n *\n * @typeParam T - the value type.\n * @param key - the style property name.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @example\n * ```ts\n * html`<div ${patch(styleProp('--size', size))}></div>`;\n * ```\n * @group DOM bindings\n */\nexport const styleProp = <T>(key: string, source: T | Sig<T>): ToPatchItem<T> =>\n _toPatchItem(source, [key], stylePropCmd);\n\nconst toggleClassCmd = <T>(val: T, ctx: PatchContext) => {\n (ctx.node as Element).classList.toggle(_key(ctx), Boolean(val));\n};\n\n/**\n * Toggles a single class from the truthiness of the value.\n *\n * @typeParam T - the value type.\n * @param token - the class token.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const toggleClass = <T>(\n token: string,\n source: T | Sig<T>,\n): ToPatchItem<T> => _toPatchItem(source, [token], toggleClassCmd);\n\nconst toggleClassesCmd = <T>(val: T, ctx: PatchContext) => {\n ctx.extra?.forEach((token) => {\n (ctx.node as Element).classList.toggle(token as string, Boolean(val));\n });\n};\n\n/**\n * Toggles several classes from one value.\n *\n * @typeParam T - the value type.\n * @param tokens - the class tokens.\n * @param source - a plain value or a `Sig`.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const toggleClasses = <T>(\n tokens: readonly string[],\n source: T | Sig<T>,\n): ToPatchItem<T> => _toPatchItem(source, [...tokens], toggleClassesCmd);\n\n/**\n * A custom patch callback run on mount and on change.\n *\n * @typeParam T - the value type.\n * @group DOM bindings\n */\nexport type ActFn<T> = (elem: Element, val?: T) => void;\n\nconst actCmd = <T>(val: T, ctx: PatchContext) => {\n const fn = ctx.extra?.[0] as ActFn<T> | undefined;\n if (!fn) err('E5');\n fn(ctx.node as Element, val);\n};\n\n/**\n * Runs arbitrary code with the bound node and value, on mount and again on\n * change. The escape hatch for anything the built-in commands do not cover.\n *\n * @typeParam T - the value type.\n * @param source - a plain value or a `Sig`.\n * @param fn - called with the node and current value.\n * @returns a deferred patch item.\n * @example\n * ```ts\n * html`<canvas ${patch(act(frame, (node, v) => draw(node, v)))}></canvas>`;\n * ```\n * @group DOM bindings\n */\nexport const act = <T>(source: T | Sig<T>, fn: ActFn<T>): ToPatchItem<T> =>\n _toPatchItem(source, [fn], actCmd);\n\ntype _Listener<K extends keyof HTMLElementEventMap> = (\n this: HTMLElement,\n ev: HTMLElementEventMap[K],\n) => unknown;\n\nconst onCmd = (listener: unknown, ctx: PatchContext) => {\n const type = ctx.extra?.[0] as string | undefined;\n const options = ctx.extra?.[1] as\n | boolean\n | AddEventListenerOptions\n | undefined;\n if (!type) err('E6');\n ctx.node.addEventListener(\n type,\n listener as EventListenerOrEventListenerObject,\n options,\n );\n};\n\n/**\n * Adds a DOM event listener. The listener is registered once at mount and is\n * not a reactive source; combine it with `sig` writes to drive updates.\n *\n * @typeParam K - the event type.\n * @param type - the event name.\n * @param listener - the event listener.\n * @param options - standard `addEventListener` options.\n * @returns a deferred patch item.\n * @group DOM bindings\n */\nexport const on = <K extends keyof HTMLElementEventMap>(\n type: K,\n listener: _Listener<K>,\n options?: boolean | AddEventListenerOptions,\n): ToPatchItem<_Listener<K>> => _toPatchItem(listener, [type, options], onCmd);\n\nconst _propsToItems = (props: PatchProps): ToAnyPatchItem[] => {\n const items: ToAnyPatchItem[] = [];\n for (const [key, value] of Object.entries(props)) {\n if (value === undefined) continue;\n switch (key) {\n case 'id':\n items.push(id(value as NonNullable<Reactive<string>>));\n break;\n case 'val':\n items.push(val(value as NonNullable<Reactive<string>>));\n break;\n case 'class':\n for (const [token, v] of Object.entries(\n value as Record<string, Reactive<boolean>>,\n )) {\n if (v !== undefined) items.push(toggleClass(token, v));\n }\n break;\n case 'style':\n for (const [name, v] of Object.entries(\n value as Partial<Record<WritableStyleKey, Reactive<string>>>,\n )) {\n if (v !== undefined) items.push(style(name as WritableStyleKey, v));\n }\n break;\n case 'styleProp':\n for (const [name, v] of Object.entries(\n value as Record<string, Reactive<string>>,\n )) {\n if (v !== undefined) items.push(styleProp(name, v));\n }\n break;\n case 'on':\n for (const [type, listener] of Object.entries(\n value as Record<string, _Listener<keyof HTMLElementEventMap>>,\n )) {\n if (listener !== undefined) {\n items.push(on(type as keyof HTMLElementEventMap, listener));\n }\n }\n break;\n default:\n items.push(attr(key, value));\n }\n }\n return items;\n};\n","import {\n type AnyView,\n type Boundary,\n type CmdContext,\n createBind,\n removeBind,\n replaceWithNode,\n Sig,\n toBoundary,\n} from './core';\n\ninterface RawContext extends CmdContext {\n boundary: Boundary;\n}\n\n// Parse trusted HTML through a detached <template>. Assigning innerHTML does\n// not run scripts, but the parsed nodes are later connected to the document, so\n// inline handlers and other vectors still apply and callers must sanitize\n// untrusted input. An empty string parses to no nodes; append an empty text\n// node so the fragment (and thus the boundary) always has a parent and anchor.\nconst _parse = (source: string): DocumentFragment => {\n const template = document.createElement('template');\n template.innerHTML = source;\n const content = template.content;\n if (!content.firstChild) content.appendChild(document.createTextNode(''));\n return content;\n};\n\nconst rawCmd = (val: string, ctx: RawContext) => {\n ctx.boundary = replaceWithNode(ctx.boundary, _parse(val));\n};\n\n/**\n * Parses its value as HTML and mounts the resulting nodes with no wrapper\n * element. Unlike `text`, the value is **not** escaped, so only pass trusted\n * HTML; inline handlers and other vectors still apply once the nodes connect.\n * A `Sig` re-parses and replaces the content on change; an empty string renders\n * nothing.\n *\n * @param source - an HTML string or a `Sig` of one.\n * @returns a content-position `View`.\n * @example\n * ```ts\n * html`<article>${raw(post.bodyHtml)}</article>`;\n * ```\n * @group Templates\n */\nexport const raw = (source: string | Sig<string>): AnyView => {\n const node = _parse(source instanceof Sig ? source.get() : source);\n const ctx: RawContext = {boundary: toBoundary(node)};\n const bind =\n source instanceof Sig ? createBind(source, ctx, rawCmd) : undefined;\n\n return {\n type: 'view',\n node,\n bind,\n boundary: () => ctx.boundary,\n cleanBinds: () => {\n if (bind) removeBind(bind);\n },\n };\n};\n","import {type AnyView, removeBoundary} from './core';\n\n/**\n * Mounts a view into `node` by appending its `node`. Accepts a `View` directly\n * or a factory function that returns one. Returns a disposer that detaches every\n * bind in the tree and removes the nodes from `node`; calling it twice is a\n * no-op.\n *\n * @param viewArg - the view, or a function returning one.\n * @param node - the node to mount into.\n * @returns a disposer that unmounts the view.\n * @example\n * ```ts\n * const dispose = render(App(), document.querySelector('#app')!);\n * dispose();\n * ```\n * @group Rendering\n */\nexport const render = (\n viewArg: AnyView | (() => AnyView),\n node: Node,\n): (() => void) => {\n const view = typeof viewArg === 'function' ? viewArg() : viewArg;\n node.appendChild(view.node);\n\n return () => {\n removeBoundary(view.boundary());\n view.cleanBinds();\n };\n};\n","import {\n type AnyView,\n at,\n type Boundary,\n type CmdContext,\n createBind,\n eq,\n err,\n removeBind,\n removeBoundary,\n replaceWithNode,\n replaceWithView,\n type Sig,\n toBoundary,\n type View,\n walkBoundary,\n} from './core';\n\n/**\n * Options for {@link repeat}.\n *\n * @typeParam T - the item type.\n * @group Control flow\n */\nexport type RepeatProp<T> = {\n /** Returns the unique, stable key for an item. */\n key: (item: T) => string;\n /** Builds the view for an item. */\n view: (item: T) => AnyView;\n /**\n * Item comparator.\n *\n * @defaultValue `eq`\n */\n eq?: (a: T, b: T) => boolean;\n};\n\ninterface Container {\n parent: ParentNode;\n startFence: Node;\n endFence: Node;\n}\n\ninterface Track<T> {\n key: string;\n item: T;\n view: AnyView;\n checked?: boolean;\n cleaned?: boolean;\n}\n\n/**\n * Context for the `repeat` command.\n *\n * @typeParam T - the item type.\n * @group Control flow\n */\nexport interface RepeatContext<T> extends CmdContext {\n /** The repeat options. */\n prop: RepeatProp<T>;\n /** The current node boundary. */\n boundary: Boundary;\n /** The tracked items and their views. */\n tracks: Track<T>[];\n}\n\nconst _cleanTrack = <T>(track: Track<T>) => {\n removeBoundary(track.view.boundary());\n track.view.cleanBinds();\n track.cleaned = true;\n};\n\nconst repeatCmd = <T>(items: T[], ctx: RepeatContext<T>) => {\n if (!Array.isArray(items) || items.length === 0) {\n const newFrag = document.createDocumentFragment();\n newFrag.appendChild(document.createComment('empty-list'));\n const newBoundary = replaceWithNode(ctx.boundary, newFrag);\n ctx.boundary = newBoundary;\n ctx.tracks.forEach(_cleanTrack);\n ctx.tracks = [];\n return;\n }\n const newTracks: Track<T>[] = [];\n if (!Array.isArray(ctx.tracks) || ctx.tracks.length === 0) {\n const newFrag = _init(items, ctx.prop, newTracks);\n const newBoundary = replaceWithNode(ctx.boundary, newFrag);\n ctx.boundary = newBoundary;\n ctx.tracks = newTracks;\n return;\n }\n\n const start = ctx.boundary.start;\n const end = ctx.boundary.end;\n const parent = start.parentNode;\n if (!parent) err('E7');\n\n const compare = ctx.prop.eq ?? eq;\n const newKeys = items.map((item) => ctx.prop.key(item));\n const tracks = ctx.tracks;\n\n // Nothing changed: same keys, same order, equal items. Bail out before\n // touching the DOM so a redundant re-render costs zero DOM mutations\n // instead of a fence insert/remove pair.\n if (tracks.length === items.length) {\n const unchanged = tracks.every((track, i) => {\n const item = items[i] as T;\n return track.key === newKeys[i] && compare(track.item, item);\n });\n if (unchanged) return;\n }\n\n const startFence = document.createComment('repeat-start-fence');\n const endFence = document.createComment('repeat-end-fence');\n\n parent.insertBefore(startFence, start);\n parent.insertBefore(endFence, end.nextSibling);\n\n const container: Container = {\n parent,\n startFence,\n endFence,\n };\n\n const oldKeys = tracks.map((track) => track.key);\n\n let newKeyToIndexMap: Map<unknown, number> | undefined;\n let oldKeyToIndexMap: Map<unknown, number> | undefined;\n\n let oldHead = 0;\n let oldTail = ctx.tracks.length - 1;\n let newHead = 0;\n let newTail = items.length - 1;\n\n while (oldHead <= oldTail && newHead <= newTail) {\n if (ctx.tracks[oldHead]?.checked) {\n oldHead++;\n } else if (ctx.tracks[oldTail]?.checked) {\n oldTail--;\n } else if (ctx.tracks[oldHead]?.key === newKeys[newHead]) {\n // old head matches new head; update in place\n newTracks[newHead] = _setTrack(\n at(ctx.tracks, oldHead),\n at(items, newHead),\n ctx.prop,\n compare,\n );\n oldHead++;\n newHead++;\n } else if (ctx.tracks[oldTail]?.key === newKeys[newTail]) {\n // old tail matches new tail; update in place\n newTracks[newTail] = _setTrack(\n at(ctx.tracks, oldTail),\n at(items, newTail),\n ctx.prop,\n compare,\n );\n oldTail--;\n newTail--;\n } else if (ctx.tracks[oldHead]?.key === newKeys[newTail]) {\n // old head matches new tail; update and move to new tail\n newTracks[newTail] = _setTrack(\n at(ctx.tracks, oldHead),\n at(items, newTail),\n ctx.prop,\n compare,\n );\n _moveTrack(\n container,\n at(newTracks, newTail),\n _beforeFence(container, newTracks[newTail + 1]),\n );\n oldHead++;\n newTail--;\n } else if (ctx.tracks[oldTail]?.key === newKeys[newHead]) {\n // old tail matches new head; update and move to new head\n newTracks[newHead] = _setTrack(\n at(ctx.tracks, oldTail),\n at(items, newHead),\n ctx.prop,\n compare,\n );\n _moveTrack(\n container,\n at(newTracks, newHead),\n _afterFence(container, newTracks[newHead - 1]),\n );\n oldTail--;\n newHead++;\n } else {\n if (newKeyToIndexMap === undefined || oldKeyToIndexMap === undefined) {\n newKeyToIndexMap = _generateMap(newKeys, newHead, newTail);\n oldKeyToIndexMap = _generateMap(oldKeys, oldHead, oldTail);\n }\n if (!newKeyToIndexMap.has(oldKeys[oldHead])) {\n _cleanTrack(at(ctx.tracks, oldHead));\n oldHead++;\n } else if (!newKeyToIndexMap.has(oldKeys[oldTail])) {\n _cleanTrack(at(ctx.tracks, oldTail));\n oldTail--;\n } else {\n const oldIndex = oldKeyToIndexMap.get(newKeys[newHead]);\n const oldTrack = oldIndex !== undefined ? ctx.tracks[oldIndex] : null;\n if (oldTrack) {\n newTracks[newHead] = _setTrack(\n oldTrack,\n at(items, newHead),\n ctx.prop,\n compare,\n );\n _moveTrack(\n container,\n at(newTracks, newHead),\n _afterFence(container, newTracks[newHead - 1]),\n );\n oldTrack.checked = true;\n } else {\n newTracks[newHead] = _insertNewTrack(\n container,\n at(items, newHead),\n ctx.prop,\n _afterFence(container, newTracks[newHead - 1]),\n );\n }\n newHead++;\n }\n }\n }\n\n while (newHead <= newTail) {\n newTracks[newHead] = _insertNewTrack(\n container,\n at(items, newHead),\n ctx.prop,\n _afterFence(container, newTracks[newHead - 1]),\n );\n newHead++;\n }\n\n while (oldHead <= oldTail) {\n if (!ctx.tracks[oldHead]?.cleaned && !ctx.tracks[oldHead]?.checked)\n _cleanTrack(at(ctx.tracks, oldHead));\n oldHead++;\n }\n\n if (!container.startFence.nextSibling || !container.endFence.previousSibling)\n err('E8');\n\n ctx.boundary = {\n start: container.startFence.nextSibling,\n end: container.endFence.previousSibling,\n };\n container.parent.removeChild(container.startFence);\n container.parent.removeChild(container.endFence);\n ctx.tracks = newTracks;\n};\n\nconst _generateMap = (list: unknown[], start: number, end: number) => {\n const map = new Map<unknown, number>();\n for (let i = start; i <= end; i++) {\n map.set(list[i], i);\n }\n return map;\n};\n\nconst _beforeFence = <T>(container: Container, track?: Track<T>): Node =>\n track ? track.view.boundary().start : container.endFence;\nconst _afterFence = <T>(container: Container, track?: Track<T>): Node => {\n const node = track ? track.view.boundary().end : container.startFence;\n if (!node.nextSibling) err('E9');\n return node.nextSibling;\n};\n\nconst _mvNodeBefore = (parent: ParentNode, node: Node, child: Node | null) => {\n if (parent.moveBefore) parent.moveBefore(node, child);\n else parent.insertBefore(node, child);\n};\n\nconst _moveTrack = <T>(container: Container, track: Track<T>, fence: Node) => {\n const parent = container.parent;\n walkBoundary(track.view.boundary(), (node) =>\n _mvNodeBefore(parent, node, fence),\n );\n};\n\nconst _insertNewTrack = <T>(\n container: Container,\n item: T,\n prop: RepeatProp<T>,\n fence: Node,\n): Track<T> => {\n const view = prop.view(item);\n container.parent.insertBefore(view.node, fence);\n return {\n key: prop.key(item),\n item,\n view,\n };\n};\n\nconst _setTrack = <T>(\n old: Track<T>,\n item: T,\n prop: RepeatProp<T>,\n compare: (a: T, b: T) => boolean,\n): Track<T> => {\n if (compare(old.item, item)) {\n return {\n ...old,\n checked: false,\n cleaned: false,\n };\n }\n\n const oldBoundary = old.view.boundary();\n const view = prop.view(item);\n replaceWithView(oldBoundary, view);\n _cleanTrack(old);\n\n const newTrack: Track<T> = {\n key: prop.key(item),\n item,\n view,\n };\n\n return newTrack;\n};\n\nconst _init = <T>(\n items: T[],\n prop: RepeatProp<T>,\n tracks: Track<T>[],\n): DocumentFragment => {\n const frag = document.createDocumentFragment();\n items.forEach((item) => {\n const view = prop.view(item);\n const key = prop.key(item);\n\n tracks.push({\n key,\n item,\n view,\n });\n frag.appendChild(view.node);\n });\n\n if (frag.childNodes.length === 0) {\n frag.appendChild(document.createComment('empty-list'));\n }\n return frag;\n};\n\n/**\n * Keyed list rendering. On each change `repeat` matches items by `key`, then\n * reuses, moves, creates, or removes as few DOM nodes as possible. The item\n * comparator defaults to `eq`; when an item is deeply equal to the track it\n * already occupies, the track is reused without rebuilding its view. An empty\n * array renders `<!--empty-list-->`.\n *\n * @typeParam T - the item type.\n * @param sig - the signal holding the items.\n * @param prop - the key/view/eq options.\n * @returns a `View` rendering the list.\n * @example\n * ```ts\n * html`<ul>${repeat(todos, {\n * key: (item) => item.id.toString(),\n * view: (item) => html`<li>${text(item.label)}</li>`,\n * })}</ul>`;\n * ```\n * @group Control flow\n */\nexport const repeat = <T>(\n sig: Sig<T[]>,\n prop: RepeatProp<T>,\n): View<T[], RepeatContext<T>> => {\n const tracks: Track<T>[] = [];\n const frag = _init(sig.get(), prop, tracks);\n\n const ctx: RepeatContext<T> = {prop, tracks, boundary: toBoundary(frag)};\n const bind = createBind(sig, ctx, repeatCmd);\n\n return {\n type: 'view',\n node: frag,\n bind,\n boundary: () => ctx.boundary,\n cleanBinds: () => {\n removeBind(bind);\n ctx.tracks.forEach((t) => {\n t.view.cleanBinds();\n });\n },\n };\n};\n","import {\n type AnyView,\n createBind,\n removeBind,\n replaceWithView,\n type Sig,\n type View,\n type ViewContext,\n} from './core';\n\nconst viewCmd = <T>(val: T, ctx: ViewContext<T>) => {\n const oldBoundary = ctx.inner.boundary();\n const newInner = ctx.viewFn(val);\n replaceWithView(oldBoundary, newInner);\n ctx.inner.cleanBinds();\n ctx.inner = newInner;\n};\n\n/**\n * Conditionally renders one view or another. Whenever `sig` changes, `viewFn`\n * runs with the new value, the previous view is torn down, and a new one is\n * mounted in its place.\n *\n * @typeParam T - the value type.\n * @param sig - the signal to switch on.\n * @param viewFn - builds the view for a value.\n * @returns a `View` that swaps its contents.\n * @example\n * ```ts\n * html`<div>${view(isEmpty, (v) => (v ? text('empty') : listView))}</div>`;\n * ```\n * @group Control flow\n */\nexport const view = <T>(\n sig: Sig<T>,\n viewFn: (val: T) => AnyView,\n): View<T, ViewContext<T>> => {\n const inner = viewFn(sig.get());\n\n const ctx: ViewContext<T> = {\n inner,\n viewFn,\n };\n\n const bind = createBind(sig, ctx, viewCmd);\n\n return {\n type: 'view',\n node: inner.node,\n bind,\n boundary: () => ctx.inner.boundary(),\n cleanBinds: () => {\n removeBind(bind);\n ctx.inner.cleanBinds();\n },\n };\n};\n"],"mappings":"AAWA,SAAgBA,EAAI,EAAqB,CACvC,MAAU,MAAMC,CAAI,CACtB,CCUA,MAAaC,GAAgB,EAAa,IAA6B,CACrE,IAAI,EAAiBC,EAAE,MACvB,KAAO,GAAG,CACR,IAAMC,EAAoB,EAAE,YAE5B,GADAC,EAAG,CAAC,EACA,IAAMF,EAAE,IAAK,MACjB,EAAIC,CACN,CACF,EAQaE,EAAkB,GAAgB,CAC7C,IAAMC,EAASJ,EAAE,MAAM,WAClBI,GACLL,EAAaC,EAAI,GAASI,EAAO,YAAYC,CAAI,CAAC,CACpD,EAUaC,EAAc,GAAyB,CAClD,IAAMN,EACJK,EAAK,WAAa,KAAK,uBACnB,CAAC,MAAOA,EAAK,WAAY,IAAKA,EAAK,SAAS,EAC5C,CAAC,MAAOA,EAAM,IAAKA,CAAI,EAE7B,OADI,CAACL,EAAE,OAAS,CAACA,EAAE,MAAKH,EAAI,IAAI,EACzBG,CACT,EAWaO,GAAmB,EAAe,IAAyB,CACtE,IAAMC,EAAcF,EAAWD,CAAI,EAC7BD,EAASK,EAAI,MAAM,WAGzB,GAFKL,GAAQP,EAAI,IAAI,EAEjBY,EAAI,QAAUA,EAAI,IACpBL,EAAO,aAAaC,EAAMI,EAAI,KAAK,MAC9B,CACL,IAAIC,EAAID,EAAI,MAAM,YAElB,IADAL,EAAO,aAAaC,EAAMI,EAAI,KAAK,EAC5BC,GAAG,CACR,IAAMT,EAAOS,EAAE,YAEf,GADAN,EAAO,YAAYM,CAAC,EAChBA,IAAMD,EAAI,IAAK,MACnB,EAAIR,CACN,CACF,CAEA,OAAOO,CACT,ECxEMG,EAAe,GACnB,OAAOC,GAAU,YACjBA,GACA,WAAYA,GACZ,OAAOA,EAAM,QAAW,WAqBbC,GAAS,EAAM,IAAkB,CAC5C,GAAIC,IAAMd,EAAG,MAAO,GAGpB,GAFI,OAAOc,GAAM,OAAOd,GAEpBc,IAAM,MAAQd,IAAM,MAAQ,OAAOc,GAAM,SAAU,MAAO,GAE9D,GAAIH,EAAYG,CAAC,EAAG,OAAOA,EAAE,OAAOd,CAAC,EAIrC,GAAI,MAAM,QAAQc,CAAC,GAAK,MAAM,QAAQd,CAAC,EAAG,CACxC,GAAIc,EAAE,SAAWd,EAAE,OAAQ,MAAO,GAClC,IAAK,IAAIe,EAAI,EAAGA,EAAID,EAAE,OAAQ,IAC5B,GAAI,CAACD,EAAGC,EAAEC,GAAIf,EAAEe,EAAE,EAAG,MAAO,GAE9B,MAAO,EACT,CAGA,GAAID,aAAa,MAAQd,aAAa,KACpC,OAAOc,EAAE,QAAQ,IAAMd,EAAE,QAAQ,EAGnC,GAAIc,aAAa,QAAUd,aAAa,OACtC,OAAOc,EAAE,SAAS,IAAMd,EAAE,SAAS,EAIrC,GAAIc,aAAa,KAAOd,aAAa,IAAK,CACxC,GAAIc,EAAE,OAASd,EAAE,KAAM,MAAO,GAC9B,IAAK,GAAM,CAACgB,EAAKC,KAAQH,EACvB,GAAI,CAACd,EAAE,IAAIgB,CAAG,GAAK,CAACH,EAAGI,EAAKjB,EAAE,IAAIgB,CAAG,CAAC,EAAG,MAAO,GAElD,MAAO,EACT,CAGA,GAAIF,aAAa,KAAOd,aAAa,IAAK,CACxC,GAAIc,EAAE,OAASd,EAAE,KAAM,MAAO,GAC9B,IAAMkB,EAAO,MAAM,KAAKJ,CAAC,EACnBK,EAAO,MAAM,KAAKnB,CAAC,EACzB,OAAOa,EAAGK,EAAMC,CAAI,CACtB,CASA,GAAI,OAAO,eAAeL,CAAC,IAAM,OAAO,eAAed,CAAC,EAAG,MAAO,GAKlE,IAAMoB,EAAKN,EACLO,EAAKrB,EAELsB,EAAQ,OAAO,KAAKF,CAAE,EACtBG,EAAQ,OAAO,KAAKF,CAAE,EAC5B,GAAIC,EAAM,SAAWC,EAAM,OAAQ,MAAO,GAE1C,IAAK,IAAIR,EAAI,EAAGA,EAAIO,EAAM,OAAQ,IAAK,CACrC,IAAMN,EAAMM,EAAMP,GAElB,GADI,CAAC,OAAO,OAAOM,EAAIL,CAAG,GACtB,CAACH,EAAGO,EAAGJ,GAAMK,EAAGL,EAAI,EAAG,MAAO,EACpC,CAEA,MAAO,EACT,ECvBMQ,EAAQ,IAAI,KA1DN,CACV,OAA4B,CAAC,EAC7B,KAAe,EACf,QAAkB,GAClB,UAAoB,GAEpB,OAAO,EAAiC,CACtC,IAAK,IAAMC,KAAQC,EACbD,EAAK,SACT,EAAK,OAAS,GACd,KAAK,OAAO,KAAKA,CAAI,GAGvB,OADI,KAAK,OAAO,OAAS,KAAK,MAAM,KAAK,KAAK,EACvC,IACT,CAEA,MAAqB,CACf,KAAK,SAAW,KAAK,YACzB,KAAK,UAAY,GACjB,mBAAqB,CACnB,KAAK,QAAU,GACf,KAAK,UAAY,GACjB,KAAK,MAAM,CACb,CAAC,EACH,CAEA,OAAsB,CACpB,KAAK,QAAU,GACf,GAAI,CACF,KAAO,KAAK,KAAO,KAAK,OAAO,QAAQ,CACrC,IAAMA,EAAO,KAAK,OAAO,KAAK,QAC9B,GAAI,CACF,GAAM,CAAC,UAAS,MAAK,UAAS,OAAOA,EAChCE,GAASC,EAAIC,EAAI,IAAI,EAAGC,CAAO,CACtC,OAASjC,EAAK,CACZ,QAAQ,MAAM,uBAAwBA,EAAK4B,CAAI,CACjD,QAAU,CAIR,EAAK,OAAS,EAChB,CACF,CACF,QAAU,CACR,KAAK,QAAU,GACX,KAAK,KAAO,KAAK,OAAO,QAE1B,KAAK,OAAS,KAAK,OAAO,MAAM,KAAK,IAAI,EACzC,KAAK,KAAO,EACZ,KAAK,KAAK,IAEV,KAAK,OAAO,OAAS,EACrB,KAAK,KAAO,EAEhB,CACF,CACF,EAWA,IAAaM,EAAb,MAAaA,CAA4B,CACvC,KACA,OAA4B,CAAC,EAC7B,IAEA,YAAY,EAAQ,EAAqB,CACvC,KAAK,KAAOd,EACZ,KAAK,IAAMe,GAAM,IAAMnB,CACzB,CAGA,OAAO,EAAY,CAEjB,OADIb,aAAa+B,GAAY,KAAK,IAAI,KAAK,IAAI,EAAG/B,EAAE,IAAI,CAAC,CAE3D,CAGA,KAAS,CACP,OAAO,KAAK,IACd,CAGA,QAAS,CACPwB,EAAM,OAAO,KAAK,MAAM,CAC1B,CAGA,YAAY,EAAM,CAChB,KAAK,KAAOS,EACZ,KAAK,OAAO,CACd,CAGA,OAAO,EAAM,CACP,KAAK,IAAIA,EAAG,KAAK,IAAI,GACzB,KAAK,YAAYA,CAAC,CACpB,CAGA,MAAM,EAAiB,CACrB,KAAK,OAAO/B,EAAG,KAAK,IAAI,CAAC,CAC3B,CAGA,QAA8B,EAAkB,CAC9C,KAAK,OAAO,KAAKuB,CAAI,CACvB,CAGA,WAAiC,EAAkB,CACjD,IAAMS,EAAQ,KAAK,OAAO,QAAQT,CAAI,EAClCS,GAAS,GAAG,KAAK,OAAO,OAAOA,EAAO,CAAC,EACvC,KAAK,OAAO,SAAW,GACzB,KAAK,QAAQ,CAEjB,CAGA,UAAkC,CAChC,OAAO,KAAK,MACd,CAKA,SAAU,CAAC,CACb,EAWaC,EAAb,cAAmCJ,CAAO,CACxC,WAAgC,CAAC,EACjC,QAAkB,GAGlB,YAAqC,EAAkB,CACrD,KAAK,WAAW,KAAKN,CAAI,CAC3B,CAYA,QAAuC,EAAkB,CAEvD,GADA,MAAM,QAAQA,CAAI,EACd,KAAK,QAAS,OAClB,KAAK,QAAU,GACf,IAAK,IAAIV,EAAI,EAAGA,EAAI,KAAK,WAAW,OAAQ,IAAK,CAC/C,IAAMqB,EAAI,KAAK,WAAWrB,GAC1B,KAAK,WAAWA,GAAKsB,EAAWD,EAAE,IAAKA,EAAE,QAASA,EAAE,GAAG,CACzD,CAGA,IAAME,EAAQ,KAAK,WAAW,GAC1BA,GAAOA,EAAM,IAAIA,EAAM,IAAI,IAAI,EAAGA,EAAM,OAAO,CACrD,CAGA,SAAmB,CACjB,GAAK,KAAK,QACV,MAAK,QAAU,GACf,IAAK,IAAMtC,KAAK,KAAK,WAAYuC,EAAWvC,CAAC,CAD9B,CAEjB,CACF,EAgBA,MAAa6B,GAAU,EAAM,IAAwB,IAAIE,EAAIE,EAAGD,CAAI,EAUvDO,EAAuC,GAAqB,CACvE,EAAK,QAAU,GACfd,EAAK,IAAI,WAAWA,CAAI,CAC1B,EAaaY,GACX,EACA,EACA,IACe,CACf,IAAMZ,EAAmB,CAAC,MAAK,UAAS,MAAK,QAAS,GAAO,OAAQ,EAAK,EAE1E,OADAI,EAAI,QAAQJ,CAAI,EACTA,CACT,EClOMe,GAAoB,EAAM,IAA8B,CAC5DC,EAAI,OAAO,OAAOA,EAAI,GAAGC,CAAC,CAAC,CAC7B,EAEMC,GACJ,EACA,IACG,CACH,IAAMC,EAAgC,CAAC,EACvC,IAAK,GAAM,CAACC,EAAGH,KAAMD,EAAI,QAAS,EAAKI,GAAKH,EAAE,IAAI,EAClDD,EAAI,OAAO,OAAOA,EAAI,GAAGG,CAAoB,CAAC,CAChD,EAEME,GAAkB,EAAgB,IAAmC,CACzE,IAAMC,EAAS,IAAIZ,EAAWjC,EAAG8C,EAAO,IAAI,CAAC,CAAC,EACxCP,EAA4B,CAAC,SAAQ,IAAE,EAE7C,OADAM,EAAO,YAAYV,EAAWW,EAAQP,EAAKD,CAAU,CAAC,EAC/CO,CACT,EAEME,GACJ,EACA,IACkB,CAClB,IAAMC,EAA0B,CAAC,EAC3BN,EAAgC,CAAC,EACvC,IAAK,GAAM,CAACC,EAAGH,KAAM,OAAO,QAAQM,CAAM,EACnCH,GAAMH,IACXQ,EAAQ,KAAK,CAACL,EAAGH,CAAC,CAAC,EACnB,EAAKG,GAAKH,EAAE,IAAI,GAGlB,IAAMK,EAAS,IAAIZ,EAAWjC,EAAG0C,CAAoB,CAAC,EAChDH,EAAkC,CAAC,SAAQ,KAAI,SAAO,EAE5D,IAAK,IAAMU,KAASD,EAClBH,EAAO,YAAYV,EAAWc,EAAM,GAAIV,EAAKE,CAAgB,CAAC,EAGhE,OAAOI,CACT,EAuCA,SAAgBK,EAAQ,EAAa,EAAsC,CACzE,OAAOJ,aAAkBjB,EACrBe,EAASE,EAAQ9C,CAAE,EACnB+C,EAAeD,EAAQ9C,CAAE,CAC/B,CCjHA,MAAamD,GAAS,EAAU,IAAqB,CACnD,IAAMpB,EAAIqB,EAAIpB,GACd,GAAID,IAAM,IAAA,GAAW,MAAU,WAAW,MAAMC,GAAO,EACvD,OAAOD,CACT,ECqDasB,GAAmB,EAAe,IAC7ChD,EAAgBE,EAAK+C,EAAK,IAAI,ECnDnBC,GAAQ,GAAGC,IAA2B,CACjD,GAAIA,EAAM,SAAW,EAAG,CACtB,IAAMC,EAAQ,SAAS,eAAe,EAAE,EACxC,MAAO,CACL,KAAM,OACN,KAAMA,EACN,cAAiB,CAAC,MAAOA,EAAO,IAAKA,CAAK,GAC1C,eAAkB,CAAC,CACrB,CACF,CAEA,IAAMtD,EAAO,SAAS,uBAAuB,EAK7C,OAJAqD,EAAM,QAAS,GAAS,CACtBrD,EAAK,YAAYmD,EAAK,IAAI,CAC5B,CAAC,EAEM,CACL,KAAM,OACN,OAIA,aAAgB,CACd,IAAMlB,EAAQe,EAAGK,EAAO,CAAC,EACnBE,EAAOP,EAAGK,EAAOA,EAAM,OAAS,CAAC,EACvC,MAAO,CAAC,MAAOpB,EAAM,SAAS,CAAC,CAAC,MAAO,IAAKsB,EAAK,SAAS,CAAC,CAAC,GAAG,CACjE,EACA,eAAkB,CAChBF,EAAM,QAAS,GAAS,CACtBF,EAAK,WAAW,CAClB,CAAC,CACH,CACF,CACF,ECxCMK,GAAc,EAAQ,IAAsB,CAChD,EAAI,KAAK,YAAc,OAAO5C,CAAG,CACnC,EAea6C,EAAW,GAA8C,CACpE,IAAMA,EAAO,SAAS,eACpBd,aAAkBjB,EAAM,OAAOiB,EAAO,IAAI,CAAC,EAAI,OAAOA,CAAM,CAC9D,EACMP,EAAoB,CAAC,KAAMqB,CAAI,EAC/BrC,EACJuB,aAAkBjB,EAAMM,EAAWW,EAAQP,EAAKoB,CAAO,EAAI,IAAA,GACvDE,EAAWzD,EAAWwD,CAAI,EAChC,MAAO,CACL,KAAM,OACN,KAAMA,EACN,OACA,aAAgBC,EAChB,eAAkB,CACZtC,GAAMc,EAAWd,CAAI,CAC3B,CACF,CACF,EC3BMuC,EAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAc/CC,kBAAW,IAAI,QAErB,IAAIC,EAIJ,MAAMC,QACJ,IAAW,SAAS,iBAClB,SACA,WAAW,aAAe,WAAW,YACvC,EACOD,GAGHE,GAAW,GACfC,EAAK,OAAS,QAAUL,EAAO,OAAOA,EAAK,KAWvCM,GAAU,GAAyD,CACvE,GAAIC,EAAM,OAAS,GAAkB,CACnC,IAAIC,EAAQ,GACZ,IAAK,IAAMH,KAAQE,EAAO,GAASF,EAAK,OAAS,QAAU,IAAM,IACjE,OAAOG,CACT,CACA,IAAIC,EAAO,EACX,IAAK,IAAI1D,EAAI,EAAGA,EAAIwD,EAAM,OAAQ,IAC5BA,EAAMxD,EAAE,EAAE,OAAS,UAAS,GAAQ,GAAKA,GAE/C,OAAO0D,CACT,EAEMC,GAAY,GAAgBC,EAAG,aAAaX,CAAI,EAChDY,GAAW,GAAgBD,EAAG,gBAAgBX,CAAI,EAClDa,GAAe,GAAkBR,EAAK,KAAK,KAAK,IAAML,EAEtDc,GAAW,GACf,OAAOT,GAAS,YAChBA,GACCA,EAAyB,OAAS,QAE/BU,EAAU,GACd,OAAOV,GAAS,YAChBA,GACCA,EAAyB,OAAS,OAE/BW,GAAW,GACfF,GAAQT,CAAI,GAAKU,EAAOV,CAAI,EAAIA,EAAOP,EAAKO,CAAI,EAE5CY,IAAuC,EAAkB,IAAe,CAC5E5E,EAAkB,YAAYmD,EAAK,IAAI,CACzC,EAEM0B,GAAe,EAAc,IAAe,CAChD,IAAMxD,EAAuC,CAAC,EAC9CyD,EAAM,aAAa,QAAS,GAAgB,CAC1C,IAAMd,EAAOe,EAAY/E,CAAe,EACpCgE,EAAK,kBAAkBtC,GACzBsC,EAAK,IAAIA,EAAK,OAAO,IAAI,EAAGA,EAAK,OAAO,EACxC3C,EAAM,KAAKW,EAAWgC,EAAK,OAAQA,EAAK,QAASA,EAAK,GAAG,CAAC,GAE1DA,EAAK,IAAIA,EAAK,OAAQA,EAAK,OAAO,CAEtC,CAAC,EAED,EAAM,eAAmB,CACvB3C,EAAM,QAAQa,CAAU,CAC1B,CACF,EAKM8C,GACJ,EACA,EACA,EACA,EACA,IACG,CACH,IAAMC,EAAInB,GAAQ,EAClB,EAAE,YAAcV,EAChB,IAAIpD,EAAOiF,EAAE,SAAS,EAClBC,EAAY,EACZC,EAAY,EAChB,KAAOnF,IAAS,MAAQmF,EAAYjB,EAAM,QACpCkB,EAAIpF,EAAMkF,EAAWC,CAAS,IAChCE,EAAM,KAAK,CAAC,KAAMrC,EAAGkB,EAAOiB,CAAS,EAAG,MAAI,CAAC,EACzCG,GAASA,EAAQ,KAAKJ,CAAS,EACnC,IACIlF,EAAK,WAAa,KAAK,cAAcuE,GAAQvE,CAAe,GAElE,EAAOiF,EAAE,SAAS,EAClB,IAKF,EAAE,YAAc,QAClB,EA8BaM,GACX,EACA,GAAGC,IACM,CACLC,EAAK,QAAU,GAAK,CAACA,IAAO,IAAIjG,EAAI,KAAK,EAC7C,IAAMkG,EAAQD,EAAK,OAAS,EACxBD,EAAS,SAAWE,GAAOlG,EAAI,OAAOkG,EAAM,GAAGF,EAAS,QAAQ,EAEpE,IAAMtB,EAAQsB,EAAS,IAAIb,EAAO,EAE9BvB,EACEiC,EAAqC,CAAC,EAEtClB,EAAQF,GAAOC,CAAK,EACpByB,EAAQ/B,EAAS,IAAI6B,CAAI,EAC/B,GAAIE,GAAO,QAAUxB,EACnB,EAAO,SAAS,WAAWwB,EAAM,GAAG,QAAS,EAAI,EAC7CzB,GAASA,EAAM,OAAS,GAC1Bc,EACE5B,EACAc,EACAmB,GACC,EAAO,EAAW,IAAcH,IAAcS,EAAM,QAAQR,EAC/D,MAEG,CACL,IAAMS,EAAW,SAAS,cAAc,UAAU,EAClD,EAAS,UAAYC,EAAMJ,EAAM,GAAGvB,CAAK,EACzC,IAAM4B,EAAW,CAAC,GAAIF,EAAU,QAAS,CAAC,EAAG,OAAK,EAClD,EAAO,SAAS,WAAWA,EAAS,QAAS,EAAI,EAE7C1B,GAASA,EAAM,OAAS,GAC1Bc,EACE5B,EACAc,EACAmB,EACC,GACCrF,EAAK,WAAa,KAAK,aACnBqE,GAASrE,CAAe,EACxBA,EAAK,WAAa,KAAK,cACvBwE,GAAYxE,CAAe,EACjC8F,EAAI,OACN,EAGFlC,EAAS,IAAI6B,EAAMK,CAAG,CACxB,CAEIT,EAAM,SAAWnB,EAAM,QAAQ1E,EAAI,KAAK,EAE5C6F,EAAM,SAAS,CAAC,OAAM,UAAU,CAC1BrB,EAAK,OAAS,QAASa,EAAYb,EAAMhE,CAAI,EAC5C4E,GAAWZ,EAAMhE,CAAI,CAC5B,CAAC,EACD,IAAM+F,EAAWV,EAAM,IAAK,GAAMJ,EAAE,IAAI,EAClCvB,EAAWzD,EAAWmD,CAAI,EAEhC,MAAO,CACL,KAAM,OACN,KAAMA,EACN,WACA,aAAgB,CAGd,IAAMG,EAAOkC,EAAK,OAAS,EAC3B,GAAI,CAACA,EAAK,GAAI,CACZ,IAAMxD,EAAQ8D,EAAS,GACnB9D,GAAO,OAAS,SAAQ,EAAS,MAAQA,EAAM,SAAS,CAAC,CAAC,MAChE,CACA,GAAI,CAACwD,EAAKlC,GAAO,CACf,IAAMyC,EAAWD,EAASxC,EAAO,GAC7ByC,GAAU,OAAS,SAAQ,EAAS,IAAMA,EAAS,SAAS,CAAC,CAAC,IACpE,CACA,OAAOtC,CACT,EACA,eAAkB,CAChBqC,EAAS,QAAS,GAAU,CAC1BE,EAAM,WAAW,CACnB,CAAC,CACH,CACF,CACF,EAEMJ,GAAS,EAA4B,GAAGK,IAA+B,CAC3E,IAAIzC,EAAOgC,EAAK,IAAM,GACtB,IAAK,IAAI/E,EAAI,EAAGA,EAAIwF,EAAM,OAAQ,IAChC,GAAQnC,GAAQf,EAAGkD,EAAOxF,CAAC,CAAC,GAAK+E,EAAK/E,EAAI,IAAM,IAElD,OAAO+C,CACT,EC5Oa0C,GACX,EACA,IACS,CACT,GAAIjC,EAAM,SAAW,EAAG,CACtB,IAAMZ,EAAQ,SAAS,cAAc,YAAY,EACjD,MAAO,CACL,KAAM,OACN,KAAMA,EACN,cAAiB,CAAC,MAAOA,EAAO,IAAKA,CAAK,GAC1C,eAAkB,CAAC,CACrB,CACF,CAEA,IAAMF,EAAO,SAAS,uBAAuB,EACvCC,EAAmB,CAAC,EAQ1B,OANAa,EAAM,SAAS,EAAM,IAAU,CAC7B,IAAMf,EAAOiD,EAAOpC,EAAMnC,CAAK,EAC/BwB,EAAM,KAAKF,CAAI,EACfC,EAAK,YAAYD,EAAK,IAAI,CAC5B,CAAC,EAEM,CACL,KAAM,OACN,KAAMC,EAIN,aAAgB,CACd,IAAMnB,EAAQe,EAAGK,EAAO,CAAC,EACnBE,EAAOP,EAAGK,EAAOA,EAAM,OAAS,CAAC,EACvC,MAAO,CAAC,MAAOpB,EAAM,SAAS,CAAC,CAAC,MAAO,IAAKsB,EAAK,SAAS,CAAC,CAAC,GAAG,CACjE,EACA,eAAkB,CAChBF,EAAM,QAAS,GAAS,CACtBF,EAAK,WAAW,CAClB,CAAC,CACH,CACF,CACF,ECrBMkD,OAAoB,CAAC,EAgC3B,SAAgBvB,GACd,EACA,GAAGwB,EACI,CAOP,MAAO,CAAC,KAAM,QAAS,aALrB,OAAOrE,GAAU,WACb,CAACA,EAAO,GAAGqE,CAAI,EACfrE,EACE,CAAC,GAAGsE,GAActE,CAAK,EAAG,GAAGqE,CAAI,EACjCA,EAC6B,WAAYD,EAAK,CACxD,CAIA,MAAMG,GAEF,EACA,EACA,IAED,IAAU,CACT,SACA,QAASC,EAAQ,CAAC,KAAMC,EAAM,OAAK,EAAI,CAAC,KAAMA,CAAI,EAClD,KACF,GAGIC,EAAQ,GAA8B,CAC1C,IAAMhG,EAAMyB,EAAI,QAAQ,GAExB,OADKzB,GAAKnB,EAAI,IAAI,EACXmB,CACT,EAEMiG,IAAY,EAAQ,IAAsB,CAC9C,EAAK,KAAiB,GAAK,OAAOhG,CAAG,CACvC,EAUaiG,EAAS,GACpBL,EAAa7D,EAAQ,IAAA,GAAWiE,EAAK,EAEjCE,GAAa,EAAQ,IAAsB,CAC/C,EAAK,KAAoC,MAAQ,OAAOlG,CAAG,CAC7D,EAUaA,EAAU,GACrB4F,EAAa7D,EAAQ,IAAA,GAAWmE,CAAM,EAElCC,GAAc,EAAQ,IAAsB,CAChD3E,EAAK,KAAiB,aAAauE,EAAKvE,CAAG,EAAG,OAAOxB,CAAG,CAAC,CAC3D,EAWaoG,GAAW,EAAa,IACnCR,EAAa7D,EAAQ,CAAChC,CAAG,EAAGoG,CAAO,EAa/BE,GAAe,EAAQ,IAAsB,CACjD,EAAK,KAAqB,MAAMN,EAAKvE,CAAG,GAAyB,OAAOxB,CAAG,CAC7E,EAeasG,GACX,EACA,IACmBV,EAAa7D,EAAQ,CAAChC,CAAG,EAAGsG,CAAQ,EAEnDE,GAAmB,EAAQ,IAAsB,CACrD/E,EAAK,KAAqB,MAAM,YAAYuE,EAAKvE,CAAG,EAAG,OAAOxB,CAAG,CAAC,CACpE,EAgBawG,GAAgB,EAAa,IACxCZ,EAAa7D,EAAQ,CAAChC,CAAG,EAAGwG,CAAY,EAEpCE,GAAqB,EAAQ,IAAsB,CACvDjF,EAAK,KAAiB,UAAU,OAAOuE,EAAKvE,CAAG,EAAG,EAAQxB,CAAI,CAChE,EAWa0G,GACX,EACA,IACmBd,EAAa7D,EAAQ,CAAC4E,CAAK,EAAGF,CAAc,EAE3DG,IAAuB,EAAQ,IAAsB,CACzDpF,EAAI,OAAO,QAAS,GAAU,CAC5BA,EAAK,KAAiB,UAAU,OAAOmF,EAAiB,EAAQ3G,CAAI,CACtE,CAAC,CACH,EAWa6G,IACX,EACA,IACmBjB,EAAa7D,EAAQ,CAAC,GAAG+E,CAAM,EAAGF,EAAgB,EAUjEG,IAAa,EAAQ,IAAsB,CAC/C,IAAM9H,EAAKuC,EAAI,QAAQ,GAClBvC,GAAIL,EAAI,IAAI,EACjBK,EAAGuC,EAAI,KAAiBxB,CAAG,CAC7B,EAgBagH,IAAU,EAAoB,IACzCpB,EAAa7D,EAAQ,CAAC9C,CAAE,EAAG8H,EAAM,EAO7BE,IAAS,EAAmB,IAAsB,CACtD,IAAMC,EAAO1F,EAAI,QAAQ,GACnB2F,EAAU3F,EAAI,QAAQ,GAIvB0F,GAAMtI,EAAI,IAAI,EACnB4C,EAAI,KAAK,iBACP0F,EACAE,EACAD,CACF,CACF,EAaaE,GACX,EACA,EACA,IAC8BzB,EAAawB,EAAU,CAACF,EAAMC,CAAO,EAAGF,EAAK,EAEvEtB,GAAiB,GAAwC,CAC7D,IAAMrC,EAA0B,CAAC,EACjC,IAAK,GAAM,CAACvD,EAAKJ,KAAU,OAAO,QAAQ2H,CAAK,EAC7C,GAAI3H,IAAU,IAAA,GACd,OAAQI,EAAR,CACE,IAAK,KACHuD,EAAM,KAAK2C,EAAGtG,CAAsC,CAAC,EACrD,MACF,IAAK,MACH2D,EAAM,KAAKtD,EAAIL,CAAsC,CAAC,EACtD,MACF,IAAK,QACH,IAAK,GAAM,CAACgH,EAAO3F,KAAM,OAAO,QAC9BrB,CACF,EACMqB,IAAM,IAAA,IAAWsC,EAAM,KAAKoD,EAAYC,EAAO3F,CAAC,CAAC,EAEvD,MACF,IAAK,QACH,IAAK,GAAM,CAACuG,EAAMvG,KAAM,OAAO,QAC7BrB,CACF,EACMqB,IAAM,IAAA,IAAWsC,EAAM,KAAKgD,EAAMiB,EAA0BvG,CAAC,CAAC,EAEpE,MACF,IAAK,YACH,IAAK,GAAM,CAACuG,EAAMvG,KAAM,OAAO,QAC7BrB,CACF,EACMqB,IAAM,IAAA,IAAWsC,EAAM,KAAKkD,EAAUe,EAAMvG,CAAC,CAAC,EAEpD,MACF,IAAK,KACH,IAAK,GAAM,CAACkG,EAAME,KAAa,OAAO,QACpCzH,CACF,EACMyH,IAAa,IAAA,IACf9D,EAAM,KAAK+D,EAAGH,EAAmCE,CAAQ,CAAC,EAG9D,MACF,QACE9D,EAAM,KAAK8C,EAAKrG,EAAKJ,CAAK,CAAC,CAC/B,CAEF,OAAO2D,CACT,EC/UMkE,EAAU,GAAqC,CACnD,IAAMxC,EAAW,SAAS,cAAc,UAAU,EAClD,EAAS,UAAYjD,EACrB,IAAM0F,EAAUzC,EAAS,QAEzB,OADKyC,EAAQ,YAAYA,EAAQ,YAAY,SAAS,eAAe,EAAE,CAAC,EACjEA,CACT,EAEMC,IAAU,EAAa,IAAoB,CAC/C,EAAI,SAAWpI,EAAgBkC,EAAI,SAAUgG,EAAOxH,CAAG,CAAC,CAC1D,EAiBa2H,GAAO,GAA0C,CAC5D,IAAMvI,EAAOoI,EAAOzF,aAAkBjB,EAAMiB,EAAO,IAAI,EAAIA,CAAM,EAC3DP,EAAkB,CAAC,SAAUnC,EAAWD,CAAI,CAAC,EAC7CoB,EACJuB,aAAkBjB,EAAMM,EAAWW,EAAQP,EAAKkG,EAAM,EAAI,IAAA,GAE5D,MAAO,CACL,KAAM,OACN,OACA,OACA,aAAgBlG,EAAI,SACpB,eAAkB,CACZhB,GAAMc,EAAWd,CAAI,CAC3B,CACF,CACF,EC5CaoH,IACX,EACA,IACiB,CACjB,IAAMrF,EAAO,OAAOsF,GAAY,WAAaA,EAAQ,EAAIA,EAGzD,OAFAzI,EAAK,YAAYmD,EAAK,IAAI,MAEb,CACXrD,EAAeqD,EAAK,SAAS,CAAC,EAC9BA,EAAK,WAAW,CAClB,CACF,ECqCMuF,EAAkB,GAAoB,CAC1C5I,EAAe6I,EAAM,KAAK,SAAS,CAAC,EACpCA,EAAM,KAAK,WAAW,EACtB,EAAM,QAAU,EAClB,EAEMC,IAAgB,EAAY,IAA0B,CAC1D,GAAI,CAAC,MAAM,QAAQ1E,CAAK,GAAKA,EAAM,SAAW,EAAG,CAC/C,IAAM2E,EAAU,SAAS,uBAAuB,EAChDA,EAAQ,YAAY,SAAS,cAAc,YAAY,CAAC,EAExD,EAAI,SADgB3I,EAAgBkC,EAAI,SAAUyG,CACzB,EACzBzG,EAAI,OAAO,QAAQsG,CAAW,EAC9B,EAAI,OAAS,CAAC,EACd,MACF,CACA,IAAMI,EAAwB,CAAC,EAC/B,GAAI,CAAC,MAAM,QAAQ1G,EAAI,MAAM,GAAKA,EAAI,OAAO,SAAW,EAAG,CACzD,IAAMyG,EAAUE,EAAM7E,EAAO9B,EAAI,KAAM0G,CAAS,EAEhD,EAAI,SADgB5I,EAAgBkC,EAAI,SAAUyG,CACzB,EACzB,EAAI,OAASC,EACb,MACF,CAEA,IAAME,EAAQ5G,EAAI,SAAS,MACrB6G,EAAM7G,EAAI,SAAS,IACnBrC,EAASiJ,EAAM,WAChBjJ,GAAQP,EAAI,IAAI,EAErB,IAAM0J,EAAU9G,EAAI,KAAK,IAAM5B,EACzB2I,EAAUjF,EAAM,IAAK,GAAS9B,EAAI,KAAK,IAAI4B,CAAI,CAAC,EAChDoF,EAAShH,EAAI,OAKnB,GAAIgH,EAAO,SAAWlF,EAAM,QACRkF,EAAO,OAAO,EAAO,IAAM,CAC3C,IAAMpF,EAAOE,EAAMxD,GACnB,OAAOiI,EAAM,MAAQQ,EAAQzI,IAAMwI,EAAQP,EAAM,KAAM3E,CAAI,CAC7D,CACY,EAAG,OAGjB,IAAMqF,EAAa,SAAS,cAAc,oBAAoB,EACxDC,EAAW,SAAS,cAAc,kBAAkB,EAE1DvJ,EAAO,aAAasJ,EAAYL,CAAK,EACrCjJ,EAAO,aAAauJ,EAAUL,EAAI,WAAW,EAE7C,IAAMM,EAAuB,CAC3B,SACA,aACA,UACF,EAEMC,EAAUJ,EAAO,IAAK,GAAUT,EAAM,GAAG,EAE3Cc,EACAC,EAEAC,EAAU,EACVC,EAAUxH,EAAI,OAAO,OAAS,EAC9ByH,EAAU,EACVC,EAAU5F,EAAM,OAAS,EAE7B,KAAOyF,GAAWC,GAAWC,GAAWC,GACtC,GAAI1H,EAAI,OAAOuH,EAAQ,EAAE,QACvB,SACK,GAAIvH,EAAI,OAAOwH,EAAQ,EAAE,QAC9B,SACK,GAAIxH,EAAI,OAAOuH,EAAQ,EAAE,MAAQR,EAAQU,GAE9C,EAAUA,GAAWE,EACnB/G,EAAGZ,EAAI,OAAQuH,CAAO,EACtB3G,EAAGkB,EAAO2F,CAAO,EACjBzH,EAAI,KACJ8G,CACF,EACA,IACA,SACK,GAAI9G,EAAI,OAAOwH,EAAQ,EAAE,MAAQT,EAAQW,GAE9C,EAAUA,GAAWC,EACnB/G,EAAGZ,EAAI,OAAQwH,CAAO,EACtB5G,EAAGkB,EAAO4F,CAAO,EACjB1H,EAAI,KACJ8G,CACF,EACA,IACA,SACK,GAAI9G,EAAI,OAAOuH,EAAQ,EAAE,MAAQR,EAAQW,GAE9C,EAAUA,GAAWC,EACnB/G,EAAGZ,EAAI,OAAQuH,CAAO,EACtB3G,EAAGkB,EAAO4F,CAAO,EACjB1H,EAAI,KACJ8G,CACF,EACAc,EACET,EACAvG,EAAG8F,EAAWgB,CAAO,EACrBG,GAAaV,EAAWT,EAAUgB,EAAU,EAAE,CAChD,EACA,IACA,SACK,GAAI1H,EAAI,OAAOwH,EAAQ,EAAE,MAAQT,EAAQU,GAE9C,EAAUA,GAAWE,EACnB/G,EAAGZ,EAAI,OAAQwH,CAAO,EACtB5G,EAAGkB,EAAO2F,CAAO,EACjBzH,EAAI,KACJ8G,CACF,EACAc,EACET,EACAvG,EAAG8F,EAAWe,CAAO,EACrBK,EAAYX,EAAWT,EAAUe,EAAU,EAAE,CAC/C,EACA,IACA,SAMA,IAJIJ,IAAqB,IAAA,IAAaC,IAAqB,IAAA,MACzD,EAAmBS,EAAahB,EAASU,EAASC,CAAO,EACzD,EAAmBK,EAAaX,EAASG,EAASC,CAAO,GAEvD,CAACH,EAAiB,IAAID,EAAQG,EAAQ,EACxCjB,EAAY1F,EAAGZ,EAAI,OAAQuH,CAAO,CAAC,EACnC,SACK,GAAI,CAACF,EAAiB,IAAID,EAAQI,EAAQ,EAC/ClB,EAAY1F,EAAGZ,EAAI,OAAQwH,CAAO,CAAC,EACnC,QACK,CACL,IAAMQ,EAAWV,EAAiB,IAAIP,EAAQU,EAAQ,EAChDQ,EAAWD,IAAa,IAAA,GAAmC,KAAvBhI,EAAI,OAAOgI,GACjDC,GACF,EAAUR,GAAWE,EACnBM,EACArH,EAAGkB,EAAO2F,CAAO,EACjBzH,EAAI,KACJ8G,CACF,EACAc,EACET,EACAvG,EAAG8F,EAAWe,CAAO,EACrBK,EAAYX,EAAWT,EAAUe,EAAU,EAAE,CAC/C,EACA,EAAS,QAAU,IAEnB,EAAUA,GAAWS,EACnBf,EACAvG,EAAGkB,EAAO2F,CAAO,EACjBzH,EAAI,KACJ8H,EAAYX,EAAWT,EAAUe,EAAU,EAAE,CAC/C,EAEF,GACF,CAIJ,KAAOA,GAAWC,GAChB,EAAUD,GAAWS,EACnBf,EACAvG,EAAGkB,EAAO2F,CAAO,EACjBzH,EAAI,KACJ8H,EAAYX,EAAWT,EAAUe,EAAU,EAAE,CAC/C,EACA,IAGF,KAAOF,GAAWC,GACZ,CAACxH,EAAI,OAAOuH,EAAQ,EAAE,SAAW,CAACvH,EAAI,OAAOuH,EAAQ,EAAE,SACzDjB,EAAY1F,EAAGZ,EAAI,OAAQuH,CAAO,CAAC,EACrC,KAGE,CAACJ,EAAU,WAAW,aAAe,CAACA,EAAU,SAAS,kBAC3D/J,EAAI,IAAI,EAEV,EAAI,SAAW,CACb,MAAO+J,EAAU,WAAW,YAC5B,IAAKA,EAAU,SAAS,eAC1B,EACAA,EAAU,OAAO,YAAYA,EAAU,UAAU,EACjDA,EAAU,OAAO,YAAYA,EAAU,QAAQ,EAC/C,EAAI,OAAST,CACf,EAEMqB,GAAgB,EAAiB,EAAe,IAAgB,CACpE,IAAMI,kBAAM,IAAI,IAChB,IAAK,IAAI,EAAIvB,EAAO,GAAKC,EAAK,IAC5BsB,EAAI,IAAIpE,EAAK,GAAI,CAAC,EAEpB,OAAOoE,CACT,EAEMN,IAAmB,EAAsB,IAC7CtB,EAAQA,EAAM,KAAK,SAAS,CAAC,CAAC,MAAQY,EAAU,SAC5CW,GAAkB,EAAsB,IAA2B,CACvE,IAAMlK,EAAO2I,EAAQA,EAAM,KAAK,SAAS,CAAC,CAAC,IAAMY,EAAU,WAE3D,OADKvJ,EAAK,aAAaR,EAAI,IAAI,EACxBQ,EAAK,WACd,EAEMwK,IAAiB,EAAoB,EAAY,IAAuB,CACxEzK,EAAO,WAAYA,EAAO,WAAWC,EAAMiG,CAAK,EAC/ClG,EAAO,aAAaC,EAAMiG,CAAK,CACtC,EAEM+D,GAAiB,EAAsB,EAAiB,IAAgB,CAC5E,IAAMjK,EAASwJ,EAAU,OACzB7J,EAAaiJ,EAAM,KAAK,SAAS,EAAI,GACnC6B,GAAczK,EAAQC,EAAMyK,CAAK,CACnC,CACF,EAEMH,GACJ,EACA,EACA,EACA,IACa,CACb,IAAMnH,EAAOuH,EAAK,KAAK1G,CAAI,EAE3B,OADAuF,EAAU,OAAO,aAAapG,EAAK,KAAMsH,CAAK,EACvC,CACL,IAAKC,EAAK,IAAI1G,CAAI,EAClB,OACA,MACF,CACF,EAEM+F,GACJ,EACA,EACA,EACA,IACa,CACb,GAAIb,EAAQ9I,EAAI,KAAM4D,CAAI,EACxB,MAAO,CACL,GAAG5D,EACH,QAAS,GACT,QAAS,EACX,EAGF,IAAMuK,EAAcvK,EAAI,KAAK,SAAS,EAChC+C,EAAOuH,EAAK,KAAK1G,CAAI,EAU3B,OATAd,EAAgByH,EAAaxH,CAAI,EACjCuF,EAAYtI,CAAG,EAQR,CALL,IAAKsK,EAAK,IAAI1G,CAAI,EAClB,OACA,MAGY,CAChB,EAEM+E,GACJ,EACA,EACA,IACqB,CACrB,IAAM3F,EAAO,SAAS,uBAAuB,EAgB7C,OAfAc,EAAM,QAAS,GAAS,CACtB,IAAMf,EAAOuH,EAAK,KAAK1G,CAAI,EACrBrD,EAAM+J,EAAK,IAAI1G,CAAI,EAEzBoF,EAAO,KAAK,CACV,MACA,OACA,MACF,CAAC,EACDhG,EAAK,YAAYD,EAAK,IAAI,CAC5B,CAAC,EAEGC,EAAK,WAAW,SAAW,GAC7BA,EAAK,YAAY,SAAS,cAAc,YAAY,CAAC,EAEhDA,CACT,EAsBawH,IACX,EACA,IACgC,CAChC,IAAMxB,EAAqB,CAAC,EACtBhG,EAAO2F,EAAMvH,EAAI,IAAI,EAAGkJ,EAAMtB,CAAM,EAEpChH,EAAwB,CAAC,OAAM,SAAQ,SAAUnC,EAAWmD,CAAI,CAAC,EACjEhC,EAAOY,EAAWR,EAAKY,EAAKwG,EAAS,EAE3C,MAAO,CACL,KAAM,OACN,KAAMxF,EACN,OACA,aAAgBhB,EAAI,SACpB,eAAkB,CAChBF,EAAWd,CAAI,EACfgB,EAAI,OAAO,QAAS,GAAM,CACxByI,EAAE,KAAK,WAAW,CACpB,CAAC,CACH,CACF,CACF,EC/XMC,IAAc,EAAQ,IAAwB,CAClD,IAAMH,EAAcvI,EAAI,MAAM,SAAS,EACjC2I,EAAW3I,EAAI,OAAOxB,CAAG,EAC/BsC,EAAgByH,EAAaI,CAAQ,EACrC3I,EAAI,MAAM,WAAW,EACrB,EAAI,MAAQ2I,CACd,EAiBa5H,IACX,EACA,IAC4B,CAC5B,IAAM6H,EAAQ5E,EAAO5E,EAAI,IAAI,CAAC,EAExBY,EAAsB,CAC1B,QACA,QACF,EAEMhB,EAAOY,EAAWR,EAAKY,EAAK0I,EAAO,EAEzC,MAAO,CACL,KAAM,OACN,KAAME,EAAM,KACZ,OACA,aAAgB5I,EAAI,MAAM,SAAS,EACnC,eAAkB,CAChBF,EAAWd,CAAI,EACfgB,EAAI,MAAM,WAAW,CACvB,CACF,CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigula",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "author": "zjh <zhanjh@126.com>",
5
5
  "description": "Tiny web framework with fine-grained signal reactivity.",
6
6
  "license": "MIT",