kerfjs 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ All notable changes to **kerf** are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.6.0] - 2026-05-11
8
+
9
+
10
+ - Public `morph(liveRoot, template)` export for standalone DOM reconciliation
11
+ - New `data-morph-preserve` attribute to opt elements out of morphing
12
+ - New `data-morph-skip-children` attribute — morph host attrs but leave subtree intact
13
+ - Drop-in AI-tool config files (`kerf.cursorrules`, `kerf.claude-skill.md`) for Cursor and Claude Code
14
+
15
+ ## [Unreleased]
16
+
17
+
18
+ - Add `data-morph-skip-children` attribute — morphs attributes on the host but leaves its subtree alone. For client-hydrated slots whose loading / state classes still need to flow through. Companion to existing `data-morph-skip`; decision matrix in `docs/4-render.md` §4.3 (KF-152).
19
+ - Add `data-morph-preserve` attribute — an unmatched live element with this attribute is skipped by the morph's trailing-removal pass instead of removed. Lets imperatively-injected nodes (autoplay video, tooltip overlays, analytics pixels) survive across renders without `data-morph-skip` on the parent. Scope is strictly end-of-list-discard: keyed-match moves and attribute/child morphing still apply when the element IS in the new template (KF-151).
20
+ - **New public export `morph(liveRoot, template)`** — one-shot in-place DOM reconciliation. Same algorithm `mount()` uses internally, exported for consumers that have an already-populated element and need to reconcile it against a freshly-built template (SSR-fragment hydration, page-refresh diffs, third-party widget remounts). Accepts an `Element`, `SafeHtml`, or raw HTML string for the template. Honors every short-circuit `mount()`'s pipeline uses (`data-morph-skip`, `data-morph-skip-children`, `data-morph-preserve`, focused-input value/selection preservation, focused-`[contenteditable]` subtree preservation, `<details>` `open`). Renamed the internal module `src/diff.ts` → `src/morph.ts` and the function `diff()` → `morph()` in the same change so the public name matches the file name and the internal-vs-public split is gone (KF-150).
21
+ - Convention: use American-English spelling everywhere — prose, comments, identifiers, test names. CLAUDE.md notes the rule; the existing codebase was swept in the same change (KF-153).
22
+ - Docs: add a `/kerf/migrating/` comparison hub with one page per source framework (React, Alpine, Lit, vanjs). KF-132 ships the index (comparison matrix + perf snapshot), the sidebar `Migrating` section, and a `Coming from React?` hero CTA on the homepage. KF-156/157/158/159 fill in the per-framework pages — bundle delta, mental-model translations, side-by-side TodoMVC, gotchas, and perf numbers. New requirements doc at `docs/10-migrating.md` (KF-132 + KF-156/157/158/159).
23
+
7
24
  ## [0.5.1] - 2026-05-11
8
25
 
9
26
 
@@ -14,7 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
14
31
 
15
32
  - Add `arraySignal` (`kerfjs/array-signal` subpath) — granular collection signal that drives O(patches) DOM updates for keyed lists
16
33
  - Faster keyed-list updates: bulk-parse contiguous insert runs and consecutive update patches in the granular reconcile path
17
- - Perf optimisations on the `each()` / `mount()` update path; benchmarks now competitive with Solid/Vue on swap/remove/clear
34
+ - Perf optimizations on the `each()` / `mount()` update path; benchmarks now competitive with Solid/Vue on swap/remove/clear
18
35
  - Preserve uncontrolled `<details open>` and `<dialog open>` state across re-renders
19
36
  - `each()` now reconciles correctly when list rows have non-list siblings under the same parent
20
37
  - Enforce the "exactly one top-level element per row" contract in `each()` with clearer errors
@@ -58,7 +75,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
58
75
 
59
76
 
60
77
  - Rebuilt render pipeline with structured segments and a native keyed-list diff, replacing the morphdom dependency
61
- - Added `each()` for keyed list iteration with per-item HTML memoisation by object identity
78
+ - Added `each()` for keyed list iteration with per-item HTML memoization by object identity
62
79
 
63
80
  ## [0.2.1] - 2026-05-07
64
81
 
@@ -88,7 +105,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
88
105
 
89
106
  - **Focus was sometimes lost on `each()` reorders (KF-65).** When the keyed list reconciler moved a row whose descendant held focus, `insertBefore` blurred the element on engines that don't preserve focus across DOM moves (older Safari, happy-dom). The element survived in the live tree, but `document.activeElement` reverted to `<body>` and the user's typing was interrupted. The reconciler now snapshots the active element + its selection range (when applicable) before the move pass and re-applies them after, so focus and caret position survive a reorder uniformly across engines. Engines that already preserve focus across moves see a no-op — the snapshot only takes effect when the active element changed. `docs/4-render.md` §4.4 and `docs/8-api-reference.md` updated. New regression tests in `tests/unit/mount.test.ts` cover reorder, top-insert, focused-row removal, non-text focused elements, selection-API rejection (e.g. `type=number`), and the "active element is outside the list" path.
90
107
  - **`Fragment` was missing from the `kerfjs` barrel (KF-24).** `Fragment` was implemented in `src/jsx-runtime.ts`, exported from `kerfjs/jsx-runtime`, and present in the shared chunk — but the barrel `src/index.ts` didn't re-export it. Importing `Fragment` from `'kerfjs'` resolved to `undefined`, so a manual `<Fragment>...</Fragment>` rendered as `<undefined>...</undefined>`. The `<>...</>` shorthand was unaffected because the JSX transform pulls `Fragment` from `kerfjs/jsx-runtime` directly. Added `Fragment` to the barrel re-export, and pinned the entire public-API contract with a new `tests/dist/barrel-completeness.test.ts` so any future omission fails CI loudly. Docs updated to list `Fragment` in the public API surface (`CLAUDE.md`, `llms.txt`, `docs/ai/usage-guide.md`, `docs/ai/code-summary.md`, `docs/6-jsx-runtime.md`, `docs/8-api-reference.md`).
91
- - **Focused contenteditable was being morphed, clobbering in-progress edits (KF-19).** The docs claimed contenteditable elements got focus + selection preservation alongside `<input>` and `<textarea>`, but the implementation only handled the latter two — a focused contenteditable's typed content was overwritten by morphdom on the next re-render. `mount()` now short-circuits the morph entirely when the active element is a contenteditable (same mechanism as `data-morph-skip`), so the user's edit, caret position, and any multi-range selection survive verbatim. Attribute updates are deferred until the next render after blur — that's the explicit trade-off, and matches what you want for in-progress rich-text editing. `docs/4-render.md` §4.4 and `docs/8-api-reference.md` §8.7 updated to describe the per-element-kind behaviour. The check uses the `contenteditable` attribute directly (the spec's source of truth) rather than the derived `isContentEditable` property, so test environments that don't populate the latter still get correct behaviour.
108
+ - **Focused contenteditable was being morphed, clobbering in-progress edits (KF-19).** The docs claimed contenteditable elements got focus + selection preservation alongside `<input>` and `<textarea>`, but the implementation only handled the latter two — a focused contenteditable's typed content was overwritten by morphdom on the next re-render. `mount()` now short-circuits the morph entirely when the active element is a contenteditable (same mechanism as `data-morph-skip`), so the user's edit, caret position, and any multi-range selection survive verbatim. Attribute updates are deferred until the next render after blur — that's the explicit trade-off, and matches what you want for in-progress rich-text editing. `docs/4-render.md` §4.4 and `docs/8-api-reference.md` §8.7 updated to describe the per-element-kind behavior. The check uses the `contenteditable` attribute directly (the spec's source of truth) rather than the derived `isContentEditable` property, so test environments that don't populate the latter still get correct behavior.
92
109
  - **`clearStoreRegistry` was a no-op in the published bundle (KF-15).** `dist/testing.js` shipped an empty function body. Root cause: `tsup` bundled each entry independently with `splitting: false`, so the testing entry tree-shook the module-level `REGISTRY` array out as unreferenced — leaving `REGISTRY.length = 0` as dead code. Same root cause as KF-14. Fixed by enabling `splitting: true` in `tsup.config.ts`: shared modules now live in chunk files that all entries import, so `defineStore`'s registry and `clearStoreRegistry`'s reference are the same array. Side benefit: the duplicate `SafeHtml` class definition is gone too — there's now exactly one copy across the whole dist. Build output now includes `dist/chunk-*.js` files (covered by the existing `"files": ["dist"]` in `package.json`). New regression test in `tests/dist/store-registry-shared.test.ts` exercises the cross-entry registry from the built bundles.
93
110
  - **`SafeHtml` cross-bundle identity (KF-14).** When a consumer's bundler ended up loading two copies of kerf — for example, the barrel (`kerfjs`) and the JSX-runtime entry (`kerfjs/jsx-runtime`) resolving as separate modules — `instanceof SafeHtml` failed inside the JSX runtime because the two `SafeHtml` classes were structurally identical but referentially distinct. The renderer would then throw `JSX: unsupported child of type object (SafeHtml)` on perfectly valid JSX. `SafeHtml` instances now carry a `Symbol.for('kerfjs.SafeHtml')` brand and the runtime checks for the brand instead of using `instanceof`. New unit tests simulate the duplicate-class scenario, and a new `npm run test:dist` job exercises the actual built bundles in CI.
94
111
 
@@ -98,10 +115,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
98
115
 
99
116
  ### Added
100
117
 
101
- - **`each(items, render, key?)` list primitive** exported from `kerfjs`. Keyed list iteration with per-item memoisation: skips re-running `render` for items whose object identity (and optional `key`) are unchanged since the previous call. Targets the partial-update / select-row / swap-rows perf path, where today's `mount()` re-runs the render for the full list on any signal change. On the js-framework-benchmark suite this drops kerfjs's partial-update from 87 → 64 ms (-27%), select-row from 69 → 42 ms (-38%), swap-rows from 86 → 58 ms (-33%), and remove-row from 49 → 35 ms (-29%); creates and bundle size are unaffected (+0.2 KB gz for the WeakMap memoiser). See `docs/8-api-reference.md` §8.3 and `bench/` for the benchmark harness.
118
+ - **`each(items, render, key?)` list primitive** exported from `kerfjs`. Keyed list iteration with per-item memoization: skips re-running `render` for items whose object identity (and optional `key`) are unchanged since the previous call. Targets the partial-update / select-row / swap-rows perf path, where today's `mount()` re-runs the render for the full list on any signal change. On the js-framework-benchmark suite this drops kerfjs's partial-update from 87 → 64 ms (-27%), select-row from 69 → 42 ms (-38%), swap-rows from 86 → 58 ms (-33%), and remove-row from 49 → 35 ms (-29%); creates and bundle size are unaffected (+0.2 KB gz for the WeakMap memoiser). See `docs/8-api-reference.md` §8.3 and `bench/` for the benchmark harness.
102
119
  - **`isSafeHtml(value)` type guard** exported from `kerfjs`. Use this rather than `instanceof SafeHtml` when inspecting JSX values from your own code — it works across module copies.
103
120
  - **End-to-end test coverage of the published bundle (KF-16).** New `npm run test:dist:full` re-runs the entire unit + integration suite against `dist/` instead of `src/` via a tiny vitest plugin that rewrites `../../src/<name>.js` imports to the equivalent dist entry point. Wired into the CI `build` job. Combined with the existing `test:dist` (focused dist regression suite), CI now proves the exact bytes we publish pass every test we have, not just the source they were built from.
104
- - **Four behavioural-guarantee tests (KF-17)** pinning documented contracts that previously had no test: signals are not deep-reactive (§2.6), `batch()` inside an action coalesces notifications (§3.5), `mount()` disposer leaves the rendered DOM in place (§4), and direct event listeners inside `data-morph-skip` subtrees survive parent re-renders (Tier 3, §5).
121
+ - **Four behavioral-guarantee tests (KF-17)** pinning documented contracts that previously had no test: signals are not deep-reactive (§2.6), `batch()` inside an action coalesces notifications (§3.5), `mount()` disposer leaves the rendered DOM in place (§4), and direct event listeners inside `data-morph-skip` subtrees survive parent re-renders (Tier 3, §5).
105
122
 
106
123
  ### Changed
107
124
 
package/README.md CHANGED
@@ -31,7 +31,7 @@ That's it. Your JSX renders to HTML strings, kerf's native diff applies the mini
31
31
 
32
32
  ## Why Kerf
33
33
 
34
- 1. **Built for the AI-assisted era.** Tiny public surface (15 exports), no compiler magic, no hidden lifecycle. An LLM holds the framework in context and predicts behaviour — your AI agent generates code that works the first time. Ships [`llms.txt`](./llms.txt) and a dedicated AI usage guide; the [Built by an AI · Pomodoro](https://brianwestphal.github.io/kerf/examples/complete/built-by-an-ai/) example is a working app one-shotted by Claude with `llms.txt` as its only kerf knowledge.
34
+ 1. **Built for the AI-assisted era.** Tiny public surface (~16 exports), no compiler magic, no hidden lifecycle. An LLM holds the framework in context and predicts behavior — your AI agent generates code that works the first time. Ships [`llms.txt`](./llms.txt) and a dedicated AI usage guide; the [Built by an AI · Pomodoro](https://brianwestphal.github.io/kerf/examples/complete/built-by-an-ai/) example is a working app one-shotted by Claude with `llms.txt` as its only kerf knowledge.
35
35
 
36
36
  2. **Smallest cut.** 6.1 KB gzipped including signals (6.5 KB with `arraySignal`). Fine-grained reactivity re-runs only what changed; the diff touches only the DOM nodes that differ. On the [krausest js-framework-benchmark](./bench/results.md) kerf is competitive with Solid and Vue on swap-rows, remove-row, and clear — no compiler required.
37
37
 
@@ -127,6 +127,20 @@ rows.move(0, 1); // 1 move patch
127
127
 
128
128
  The class lives in its own subpath so apps that don't need it shed ~1 KB. Reads on `rows.value` are tracking, so `computed(() => rows.value.filter(...))` works as expected. See [`docs/2-reactivity.md`](./docs/2-reactivity.md) §2.6.
129
129
 
130
+ ### One-shot reconcile: `morph`
131
+
132
+ `mount()` wraps `effect()` so the render re-runs on signal changes. Sometimes you have a freshly-built template and an already-populated element and you just want to reconcile them once — no subscription, no re-render loop. That's `morph`:
133
+
134
+ ```ts
135
+ import { morph, raw } from 'kerfjs';
136
+
137
+ morph(liveCard, freshlyBuiltCardEl); // Element template
138
+ morph(liveCard, '<article class="card">…</article>'); // raw HTML string
139
+ morph(liveCard, raw(htmlFromServer)); // SafeHtml
140
+ ```
141
+
142
+ Same algorithm `mount()` uses internally — `data-morph-skip`, `data-morph-skip-children`, `data-morph-preserve`, focused-input value + selection preservation, the `<details>` / `<dialog>` user-agent-owned `open` rule all carry over. Use it for SSR-fragment hydration, page-refresh diffs, third-party widget remounts. See [`docs/4-render.md`](./docs/4-render.md) §4.4.3.
143
+
130
144
  ## Install
131
145
 
132
146
  ```bash
@@ -147,6 +161,7 @@ npm install kerfjs
147
161
 
148
162
  - **Site:** [brianwestphal.github.io/kerf](https://brianwestphal.github.io/kerf/)
149
163
  - **Docs:** [`docs/`](./docs/) — overview · reactivity · stores · render · events · jsx · svg · [API reference](./docs/8-api-reference.md)
164
+ - **Migrating:** [coming from React / Alpine / Lit / vanjs?](https://brianwestphal.github.io/kerf/migrating/) — side-by-side TodoMVC translations + per-framework gotchas
150
165
  - **AI guide:** [`docs/ai/usage-guide.md`](./docs/ai/usage-guide.md) — read once before writing kerf code with an LLM
151
166
  - **Demo:** [live demo](https://brianwestphal.github.io/kerf/demo/) — eight sections exercising every primitive (counter, store-backed cart, focus survival, keyed list, morph-skip, SVG render, Tier-2 capture, `arraySignal` patches)
152
167
  - **Repo:** [github.com/brianwestphal/kerf](https://github.com/brianwestphal/kerf)
@@ -6,7 +6,7 @@ var ArraySignal = class {
6
6
  _items;
7
7
  _version;
8
8
  _patches;
9
- // Branded so `isArraySignal()` recognises instances from any copy of this module.
9
+ // Branded so `isArraySignal()` recognizes instances from any copy of this module.
10
10
  [ARRAY_SIGNAL_BRAND] = true;
11
11
  constructor(initial = []) {
12
12
  this._items = [...initial];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/array-signal.ts"],"names":[],"mappings":";;;AA4CO,IAAM,kBAAA,mBAAqB,MAAA,CAAO,GAAA,CAAI,oBAAoB;AAE1D,IAAM,cAAN,MAAqB;AAAA,EAClB,MAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAER,CAAU,kBAAkB,IAAI,IAAA;AAAA,EAEhC,WAAA,CAAY,OAAA,GAAwB,EAAC,EAAG;AACtC,IAAA,IAAA,CAAK,MAAA,GAAS,CAAC,GAAG,OAAO,CAAA;AACzB,IAAA,IAAA,CAAK,QAAA,GAAW,OAAO,CAAC,CAAA;AACxB,IAAA,IAAA,CAAK,WAAW,EAAC;AAAA,EACnB;AAAA;AAAA,EAGA,IAAI,KAAA,GAAsB;AAExB,IAAA,KAAK,KAAK,QAAA,CAAS,KAAA;AACnB,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA,EAGA,MAAA,CAAO,OAAe,EAAA,EAA0B;AAC9C,IAAA,IAAI,KAAA,GAAQ,CAAA,IAAK,KAAA,IAAS,IAAA,CAAK,OAAO,MAAA,EAAQ;AAC5C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,0BAAA,EAA6B,KAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,OAAO,MAAM,CAAA,EAAA;AAAA,OAC5E;AAAA,IACF;AACA,IAAA,MAAM,IAAA,GAAO,EAAA,CAAG,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAClC,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,GAAI,IAAA;AACrB,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,UAAU,KAAA,EAAO,IAAA,EAAM,MAAM,CAAA;AACxD,IAAA,IAAA,CAAK,QAAA,CAAS,KAAA,EAAA;AAAA,EAChB;AAAA;AAAA,EAGA,MAAA,CAAO,OAAe,IAAA,EAAe;AACnC,IAAA,IAAI,KAAA,GAAQ,CAAA,IAAK,KAAA,GAAQ,IAAA,CAAK,OAAO,MAAA,EAAQ;AAC3C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,0BAAA,EAA6B,KAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,OAAO,MAAM,CAAA,EAAA;AAAA,OAC5E;AAAA,IACF;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,CAAA,EAAG,IAAI,CAAA;AACjC,IAAA,IAAA,CAAK,SAAS,IAAA,CAAK,EAAE,MAAM,QAAA,EAAU,KAAA,EAAO,MAAM,CAAA;AAClD,IAAA,IAAA,CAAK,QAAA,CAAS,KAAA,EAAA;AAAA,EAChB;AAAA;AAAA,EAGA,KAAK,IAAA,EAAe;AAClB,IAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,IAAI,CAAA;AAAA,EACtC;AAAA;AAAA,EAGA,OAAO,KAAA,EAAkB;AACvB,IAAA,IAAI,KAAA,GAAQ,CAAA,IAAK,KAAA,IAAS,IAAA,CAAK,OAAO,MAAA,EAAQ;AAC5C,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,0BAAA,EAA6B,KAAK,CAAA,mBAAA,EAAsB,IAAA,CAAK,OAAO,MAAM,CAAA,EAAA;AAAA,OAC5E;AAAA,IACF;AACA,IAAA,MAAM,CAAC,OAAO,CAAA,GAAI,KAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAC,CAAA;AAC7C,IAAA,IAAA,CAAK,SAAS,IAAA,CAAK,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,CAAA;AAC5C,IAAA,IAAA,CAAK,QAAA,CAAS,KAAA,EAAA;AACd,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA,EAGA,IAAA,CAAK,MAAc,EAAA,EAAkB;AACnC,IAAA,IAAI,SAAS,EAAA,EAAI;AACjB,IAAA,IAAI,IAAA,GAAO,CAAA,IAAK,IAAA,IAAQ,IAAA,CAAK,MAAA,CAAO,MAAA,IAAU,EAAA,GAAK,CAAA,IAAK,EAAA,IAAM,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ;AAChF,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,iDAAiD,IAAI,CAAA,KAAA,EAAQ,EAAE,CAAA,SAAA,EAAY,IAAA,CAAK,OAAO,MAAM,CAAA,EAAA;AAAA,OAC/F;AAAA,IACF;AACA,IAAA,MAAM,CAAC,IAAI,CAAA,GAAI,KAAK,MAAA,CAAO,MAAA,CAAO,MAAM,CAAC,CAAA;AACzC,IAAA,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,EAAA,EAAI,CAAA,EAAG,IAAI,CAAA;AAC9B,IAAA,IAAA,CAAK,SAAS,IAAA,CAAK,EAAE,MAAM,MAAA,EAAQ,IAAA,EAAM,IAAI,CAAA;AAC7C,IAAA,IAAA,CAAK,QAAA,CAAS,KAAA,EAAA;AAAA,EAChB;AAAA;AAAA,EAGA,QAAQ,KAAA,EAA2B;AACjC,IAAA,IAAA,CAAK,MAAA,GAAS,CAAC,GAAG,KAAK,CAAA;AACvB,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,EAAE,IAAA,EAAM,WAAW,KAAA,EAAO,IAAA,CAAK,QAAQ,CAAA;AAC1D,IAAA,IAAA,CAAK,QAAA,CAAS,KAAA,EAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAA,GAAmC;AACjC,IAAA,MAAM,MAAM,IAAA,CAAK,QAAA;AACjB,IAAA,IAAA,CAAK,WAAW,EAAC;AACjB,IAAA,OAAO,GAAA;AAAA,EACT;AACF;AAGO,SAAS,WAAA,CAAe,OAAA,GAAwB,EAAC,EAAmB;AACzE,EAAA,OAAO,IAAI,YAAY,OAAO,CAAA;AAChC","file":"array-signal.js","sourcesContent":["/**\n * `arraySignal(initial)` — granular collection signal.\n *\n * A keyed-list-friendly variant of `signal()` that emits typed patch events\n * for every mutation (update / insert / remove / move / replace). When such\n * a signal is bound to `each(...)` inside a `mount()`, the keyed list\n * reconciler applies just the patches against the live DOM — no per-item\n * iteration, no `classifyItems` Map build, no LIS pass over unchanged rows.\n *\n * const rows = arraySignal<Row>([]);\n *\n * rows.update(42, (r) => ({ ...r, label: 'changed' })); // 1 update event\n * rows.insert(0, { id: 'x', ... }); // 1 insert event\n * rows.remove(7); // 1 remove event\n * rows.move(3, 0); // 1 move event\n * rows.replace([...]); // falls back to snapshot reconcile\n *\n * Read-side semantics match a regular signal: `arraySig.value` is a\n * snapshot, and reads inside `effect()` / `computed()` register as\n * dependencies, so derived values keep working.\n */\n\nimport type { Signal } from './reactive.js';\nimport { signal } from './reactive.js';\n\n/** A single granular mutation event. */\nexport type ArrayPatch<T> =\n | { type: 'update'; index: number; item: T }\n | { type: 'insert'; index: number; item: T }\n | { type: 'remove'; index: number }\n | { type: 'move'; from: number; to: number }\n | { type: 'replace'; items: readonly T[] };\n\n/**\n * Cross-bundle brand for `ArraySignal` instances. `each()` and the\n * granular reconciler check for this brand instead of `instanceof\n * ArraySignal`, so the main `kerfjs` barrel can detect arraySignal\n * inputs without importing the class at runtime — the class lives\n * only in the `kerfjs/array-signal` subpath, so apps that don't need\n * granular collections shed ~1 KB.\n *\n * Same `Symbol.for(...)`-based pattern as `SafeHtml` (KF-14): cross-\n * bundle-safe, zero-cost runtime check.\n */\nexport const ARRAY_SIGNAL_BRAND = Symbol.for('kerfjs.ArraySignal');\n\nexport class ArraySignal<T> {\n private _items: T[];\n private _version: Signal<number>;\n private _patches: ArrayPatch<T>[];\n // Branded so `isArraySignal()` recognises instances from any copy of this module.\n readonly [ARRAY_SIGNAL_BRAND] = true as const;\n\n constructor(initial: readonly T[] = []) {\n this._items = [...initial];\n this._version = signal(0);\n this._patches = [];\n }\n\n /** Read-only snapshot. Reads inside an effect/computed register a dependency. */\n get value(): readonly T[] {\n // Touch the version signal so signals-core treats reads as tracked.\n void this._version.value;\n return this._items;\n }\n\n /** Replace the item at `index` with `fn(currentItem)`. Emits one `update` patch. */\n update(index: number, fn: (item: T) => T): void {\n if (index < 0 || index >= this._items.length) {\n throw new Error(\n `arraySignal.update: index ${index} out of bounds [0, ${this._items.length}).`,\n );\n }\n const next = fn(this._items[index]);\n this._items[index] = next;\n this._patches.push({ type: 'update', index, item: next });\n this._version.value++;\n }\n\n /** Insert `item` at `index`. Existing items at index..N shift right. Emits one `insert` patch. */\n insert(index: number, item: T): void {\n if (index < 0 || index > this._items.length) {\n throw new Error(\n `arraySignal.insert: index ${index} out of bounds [0, ${this._items.length}].`,\n );\n }\n this._items.splice(index, 0, item);\n this._patches.push({ type: 'insert', index, item });\n this._version.value++;\n }\n\n /** Append `item` at the end. Sugar for `insert(items.length, item)`. */\n push(item: T): void {\n this.insert(this._items.length, item);\n }\n\n /** Remove and return the item at `index`. Emits one `remove` patch. */\n remove(index: number): T {\n if (index < 0 || index >= this._items.length) {\n throw new Error(\n `arraySignal.remove: index ${index} out of bounds [0, ${this._items.length}).`,\n );\n }\n const [removed] = this._items.splice(index, 1);\n this._patches.push({ type: 'remove', index });\n this._version.value++;\n return removed;\n }\n\n /** Move the item at `from` to position `to`. Emits one `move` patch (no-op when from === to). */\n move(from: number, to: number): void {\n if (from === to) return;\n if (from < 0 || from >= this._items.length || to < 0 || to >= this._items.length) {\n throw new Error(\n `arraySignal.move: indices out of bounds (from=${from}, to=${to}, length=${this._items.length}).`,\n );\n }\n const [item] = this._items.splice(from, 1);\n this._items.splice(to, 0, item);\n this._patches.push({ type: 'move', from, to });\n this._version.value++;\n }\n\n /** Replace every item. Emits one `replace` patch — the granular reconciler falls back to a full keyed diff for this case. */\n replace(items: readonly T[]): void {\n this._items = [...items];\n this._patches.push({ type: 'replace', items: this._items });\n this._version.value++;\n }\n\n /**\n * @internal Used by `each()` when binding this signal to a list. Returns\n * the queue of granular patches issued since the previous call, then\n * clears the queue. Best paired with a single binding — a second consumer\n * in the same render gets an empty array (which forces the snapshot\n * fall-back path, which is correct but slower).\n */\n _consumePatches(): ArrayPatch<T>[] {\n const out = this._patches;\n this._patches = [];\n return out;\n }\n}\n\n/** Construct an array signal seeded with `initial`. */\nexport function arraySignal<T>(initial: readonly T[] = []): ArraySignal<T> {\n return new ArraySignal(initial);\n}\n"]}
1
+ {"version":3,"sources":["../src/array-signal.ts"],"names":[],"mappings":"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","file":"array-signal.js","sourcesContent":["/**\n * `arraySignal(initial)` — granular collection signal.\n *\n * A keyed-list-friendly variant of `signal()` that emits typed patch events\n * for every mutation (update / insert / remove / move / replace). When such\n * a signal is bound to `each(...)` inside a `mount()`, the keyed list\n * reconciler applies just the patches against the live DOM — no per-item\n * iteration, no `classifyItems` Map build, no LIS pass over unchanged rows.\n *\n * const rows = arraySignal<Row>([]);\n *\n * rows.update(42, (r) => ({ ...r, label: 'changed' })); // 1 update event\n * rows.insert(0, { id: 'x', ... }); // 1 insert event\n * rows.remove(7); // 1 remove event\n * rows.move(3, 0); // 1 move event\n * rows.replace([...]); // falls back to snapshot reconcile\n *\n * Read-side semantics match a regular signal: `arraySig.value` is a\n * snapshot, and reads inside `effect()` / `computed()` register as\n * dependencies, so derived values keep working.\n */\n\nimport type { Signal } from './reactive.js';\nimport { signal } from './reactive.js';\n\n/** A single granular mutation event. */\nexport type ArrayPatch<T> =\n | { type: 'update'; index: number; item: T }\n | { type: 'insert'; index: number; item: T }\n | { type: 'remove'; index: number }\n | { type: 'move'; from: number; to: number }\n | { type: 'replace'; items: readonly T[] };\n\n/**\n * Cross-bundle brand for `ArraySignal` instances. `each()` and the\n * granular reconciler check for this brand instead of `instanceof\n * ArraySignal`, so the main `kerfjs` barrel can detect arraySignal\n * inputs without importing the class at runtime — the class lives\n * only in the `kerfjs/array-signal` subpath, so apps that don't need\n * granular collections shed ~1 KB.\n *\n * Same `Symbol.for(...)`-based pattern as `SafeHtml` (KF-14): cross-\n * bundle-safe, zero-cost runtime check.\n */\nexport const ARRAY_SIGNAL_BRAND = Symbol.for('kerfjs.ArraySignal');\n\nexport class ArraySignal<T> {\n private _items: T[];\n private _version: Signal<number>;\n private _patches: ArrayPatch<T>[];\n // Branded so `isArraySignal()` recognizes instances from any copy of this module.\n readonly [ARRAY_SIGNAL_BRAND] = true as const;\n\n constructor(initial: readonly T[] = []) {\n this._items = [...initial];\n this._version = signal(0);\n this._patches = [];\n }\n\n /** Read-only snapshot. Reads inside an effect/computed register a dependency. */\n get value(): readonly T[] {\n // Touch the version signal so signals-core treats reads as tracked.\n void this._version.value;\n return this._items;\n }\n\n /** Replace the item at `index` with `fn(currentItem)`. Emits one `update` patch. */\n update(index: number, fn: (item: T) => T): void {\n if (index < 0 || index >= this._items.length) {\n throw new Error(\n `arraySignal.update: index ${index} out of bounds [0, ${this._items.length}).`,\n );\n }\n const next = fn(this._items[index]);\n this._items[index] = next;\n this._patches.push({ type: 'update', index, item: next });\n this._version.value++;\n }\n\n /** Insert `item` at `index`. Existing items at index..N shift right. Emits one `insert` patch. */\n insert(index: number, item: T): void {\n if (index < 0 || index > this._items.length) {\n throw new Error(\n `arraySignal.insert: index ${index} out of bounds [0, ${this._items.length}].`,\n );\n }\n this._items.splice(index, 0, item);\n this._patches.push({ type: 'insert', index, item });\n this._version.value++;\n }\n\n /** Append `item` at the end. Sugar for `insert(items.length, item)`. */\n push(item: T): void {\n this.insert(this._items.length, item);\n }\n\n /** Remove and return the item at `index`. Emits one `remove` patch. */\n remove(index: number): T {\n if (index < 0 || index >= this._items.length) {\n throw new Error(\n `arraySignal.remove: index ${index} out of bounds [0, ${this._items.length}).`,\n );\n }\n const [removed] = this._items.splice(index, 1);\n this._patches.push({ type: 'remove', index });\n this._version.value++;\n return removed;\n }\n\n /** Move the item at `from` to position `to`. Emits one `move` patch (no-op when from === to). */\n move(from: number, to: number): void {\n if (from === to) return;\n if (from < 0 || from >= this._items.length || to < 0 || to >= this._items.length) {\n throw new Error(\n `arraySignal.move: indices out of bounds (from=${from}, to=${to}, length=${this._items.length}).`,\n );\n }\n const [item] = this._items.splice(from, 1);\n this._items.splice(to, 0, item);\n this._patches.push({ type: 'move', from, to });\n this._version.value++;\n }\n\n /** Replace every item. Emits one `replace` patch — the granular reconciler falls back to a full keyed diff for this case. */\n replace(items: readonly T[]): void {\n this._items = [...items];\n this._patches.push({ type: 'replace', items: this._items });\n this._version.value++;\n }\n\n /**\n * @internal Used by `each()` when binding this signal to a list. Returns\n * the queue of granular patches issued since the previous call, then\n * clears the queue. Best paired with a single binding — a second consumer\n * in the same render gets an empty array (which forces the snapshot\n * fall-back path, which is correct but slower).\n */\n _consumePatches(): ArrayPatch<T>[] {\n const out = this._patches;\n this._patches = [];\n return out;\n }\n}\n\n/** Construct an array signal seeded with `initial`. */\nexport function arraySignal<T>(initial: readonly T[] = []): ArraySignal<T> {\n return new ArraySignal(initial);\n}\n"]}
@@ -177,7 +177,7 @@ var SAFE_HTML_BRAND = /* @__PURE__ */ Symbol.for("kerfjs.SafeHtml");
177
177
  var SafeHtml = class {
178
178
  __html;
179
179
  __segment;
180
- // Branded so `isSafeHtml()` recognises instances from any copy of this module.
180
+ // Branded so `isSafeHtml()` recognizes instances from any copy of this module.
181
181
  [SAFE_HTML_BRAND] = true;
182
182
  constructor(input) {
183
183
  if (typeof input === "string") {
@@ -259,7 +259,7 @@ function renderAttr(key, value) {
259
259
  } else if (typeof value === "string") {
260
260
  if (URL_ATTRS.has(name) && DANGEROUS_URL_RE.test(value)) {
261
261
  console.warn(
262
- `JSX: dropped dangerous URL value for ${name}=${JSON.stringify(value.slice(0, 80))}. kerf blocks javascript:, vbscript:, and data:text/html URLs in href/src/formaction/action/xlink:href by default. Wrap in raw() if this is intentional (e.g. bookmarklets), or sanitise upstream.`
262
+ `JSX: dropped dangerous URL value for ${name}=${JSON.stringify(value.slice(0, 80))}. kerf blocks javascript:, vbscript:, and data:text/html URLs in href/src/formaction/action/xlink:href by default. Wrap in raw() if this is intentional (e.g. bookmarklets), or sanitize upstream.`
263
263
  );
264
264
  return "";
265
265
  }
@@ -284,5 +284,5 @@ function Fragment({ children }) {
284
284
  }
285
285
 
286
286
  export { Fragment, SafeHtml, collectLists, flatten, flattenWithoutListItems, granularListSafeHtml, isSafeHtml, jsx, listSafeHtml, raw };
287
- //# sourceMappingURL=chunk-KFOSUCCC.js.map
288
- //# sourceMappingURL=chunk-KFOSUCCC.js.map
287
+ //# sourceMappingURL=chunk-LADH5GVQ.js.map
288
+ //# sourceMappingURL=chunk-LADH5GVQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/segment.ts","../src/utils/escapeHtml.ts","../src/utils/jsx-attr-aliases.ts","../src/jsx-runtime.ts"],"names":[],"mappings":"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","file":"chunk-KFOSUCCC.js","sourcesContent":["/**\n * `Segment` — kerf's structured render output.\n *\n * The JSX runtime emits a `SafeHtml` wrapping a `Segment`. Most renders\n * produce a single static segment (just an HTML string), which behaves\n * exactly like a string for backward compatibility. When the tree\n * contains a list (`each()`) or a parent whose children include a list,\n * the runtime emits a structured segment that `mount()` can dispatch\n * on — running its native keyed reconciler for the list parts and\n * leaving the static surrounds to the general-purpose diff.\n *\n * Why have a structured form at all: the perf bottleneck for huge\n * keyed lists isn't the per-row JSX work (which `each()` already\n * memoises). It's that flattening every render's whole tree to one\n * big HTML string forces a full `innerHTML` parse and a tree walk\n * over rows we know are unchanged. The segment shape lets mount()\n * skip both for the list parts.\n */\n\nexport type Segment = StaticSegment | ListSegment | MixedSegment;\n\nexport interface StaticSegment {\n kind: 'static';\n html: string;\n}\n\nexport interface ListItem {\n /**\n * The row's object identity. Used by the reconciler to match new items\n * against live DOM nodes across renders. Unchanged ref → reuse the\n * existing live node; replaced ref → build a fresh node.\n */\n ref: object;\n /**\n * Optional cache-invalidation key that captures external state affecting\n * this row's render (e.g. selection class). Different cacheKey on the\n * same `ref` triggers a cache miss for that row. `undefined` when the\n * user didn't pass a `key` callback to `each()`.\n */\n cacheKey: unknown;\n html: string;\n}\n\nexport interface ListSegment {\n kind: 'list';\n id: string;\n items: ListItem[];\n /**\n * Optional granular patches (KF-92). When present, the list reconciler\n * applies these directly to the existing binding instead of doing a\n * full classify+reconcile pass. Emitted by `each()` when bound to an\n * `arraySignal`. Mutually exclusive with the `items` snapshot in the\n * sense that the snapshot is treated as informational/fall-back when\n * patches are present.\n */\n patches?: ArrayPatchInternal[];\n}\n\n/**\n * Internal patch shape used inside list segments. Mirrors `ArrayPatch<T>`\n * from `array-signal.ts` but typed against `object` so the segment layer\n * doesn't need to be generic. `update` / `insert` patches carry the row's\n * pre-rendered HTML — `each()` renders them at JSX-evaluation time inside a\n * try/catch so a throwing render falls back to the snapshot path (KF-99)\n * instead of leaving the signal and DOM divergent.\n */\nexport type ArrayPatchInternal =\n | { type: 'update'; index: number; item: object; html: string }\n | { type: 'insert'; index: number; item: object; html: string }\n | { type: 'remove'; index: number }\n | { type: 'move'; from: number; to: number }\n | { type: 'replace'; items: readonly object[] };\n\nexport interface MixedSegment {\n kind: 'mixed';\n parts: Segment[];\n}\n\n/**\n * Flatten a segment to a complete HTML string. Used for first render\n * (bulk innerHTML), for SSR-style consumption via `toString()`, and\n * for diagnostics.\n *\n * If `withMarkers` is set, list segments are wrapped in\n * `<!--kf-list:{id}-->` comments so the post-parse walk can find each\n * list's live parent. Plain (non-marker) flatten is what JSX consumers\n * see when they call `.toString()` on the SafeHtml.\n */\nexport function flatten(segment: Segment, withMarkers: boolean): string {\n if (segment.kind === 'static') return segment.html;\n if (segment.kind === 'list') {\n const items = segment.items.map((i) => i.html).join('');\n return withMarkers ? `<!--kf-list:${segment.id}-->${items}` : items;\n }\n return segment.parts.map((p) => flatten(p, withMarkers)).join('');\n}\n\n/**\n * Variant of `flatten` for the static-only diff path on subsequent\n * renders. Lists are reduced to a single marker comment with no items\n * inside — the actual list children stay in the live DOM and are\n * reconciled separately. Keeping list items out of this string is\n * what makes the morph cheap on huge lists where most rows are\n * unchanged.\n */\nexport function flattenWithoutListItems(segment: Segment): string {\n if (segment.kind === 'static') return segment.html;\n if (segment.kind === 'list') return `<!--kf-list:${segment.id}-->`;\n return segment.parts.map(flattenWithoutListItems).join('');\n}\n\n/** Collect every `ListSegment` in the tree, keyed by its id. */\nexport function collectLists(\n segment: Segment,\n out: Map<string, ListSegment> = new Map(),\n): Map<string, ListSegment> {\n if (segment.kind === 'list') out.set(segment.id, segment);\n else if (segment.kind === 'mixed') {\n for (const part of segment.parts) collectLists(part, out);\n }\n return out;\n}\n\n/**\n * Combine a list of child segments into the smallest equivalent\n * representation: collapses adjacent statics into one static, returns\n * a single static if everything is static, otherwise a mixed segment\n * with statics coalesced.\n */\nexport function mergeChildSegments(parts: Segment[]): Segment {\n if (parts.length === 0) return { kind: 'static', html: '' };\n if (parts.every((p) => p.kind === 'static')) {\n return {\n kind: 'static',\n html: parts.map((p) => (p as StaticSegment).html).join(''),\n };\n }\n const merged: Segment[] = [];\n let coalesced = '';\n for (const p of parts) {\n if (p.kind === 'static') {\n coalesced += p.html;\n } else {\n if (coalesced !== '') {\n merged.push({ kind: 'static', html: coalesced });\n coalesced = '';\n }\n merged.push(p);\n }\n }\n if (coalesced !== '') merged.push({ kind: 'static', html: coalesced });\n return { kind: 'mixed', parts: merged };\n}\n\n/**\n * Wrap a child segment with surrounding open/close tags from the\n * parent JSX element. Used by the JSX runtime when constructing\n * `_jsx(tag, ...)` output.\n */\nexport function wrapWithTags(child: Segment, openTag: string, closeTag: string): Segment {\n if (child.kind === 'static') {\n return { kind: 'static', html: openTag + child.html + closeTag };\n }\n if (child.kind === 'mixed') {\n return {\n kind: 'mixed',\n parts: [\n { kind: 'static', html: openTag },\n ...child.parts,\n { kind: 'static', html: closeTag },\n ],\n };\n }\n return {\n kind: 'mixed',\n parts: [\n { kind: 'static', html: openTag },\n child,\n { kind: 'static', html: closeTag },\n ],\n };\n}\n","/**\n * HTML / attribute escaping for the JSX runtime. Identical to the helpers\n * used in any reasonable HTML emitter — included here so kerf has no extra\n * runtime dependencies beyond `@preact/signals-core`.\n */\n\nexport function escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nexport function escapeAttr(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n","/**\n * JSX → HTML / SVG attribute name aliases.\n *\n * The JSX runtime translates camelCase attributes (React convention) to\n * the kebab-case / colon-form names the browser actually wants. Anything\n * not in this map is passed through verbatim — `data-*`, `aria-*`, and\n * any custom attribute work without ceremony.\n *\n * Lives in its own module so `src/jsx-runtime.ts` can stay under the\n * 200-LOC project guideline; the bulk of `jsx-runtime.ts` was this table.\n */\n\nexport const ATTR_ALIASES: Record<string, string> = {\n // HTML attributes\n className: 'class',\n htmlFor: 'for',\n httpEquiv: 'http-equiv',\n acceptCharset: 'accept-charset',\n accessKey: 'accesskey',\n autoCapitalize: 'autocapitalize',\n autoComplete: 'autocomplete',\n autoFocus: 'autofocus',\n autoPlay: 'autoplay',\n colSpan: 'colspan',\n contentEditable: 'contenteditable',\n crossOrigin: 'crossorigin',\n dateTime: 'datetime',\n defaultChecked: 'checked',\n defaultValue: 'value',\n encType: 'enctype',\n formAction: 'formaction',\n formEncType: 'formenctype',\n formMethod: 'formmethod',\n formNoValidate: 'formnovalidate',\n formTarget: 'formtarget',\n hrefLang: 'hreflang',\n inputMode: 'inputmode',\n maxLength: 'maxlength',\n minLength: 'minlength',\n noModule: 'nomodule',\n noValidate: 'novalidate',\n readOnly: 'readonly',\n referrerPolicy: 'referrerpolicy',\n rowSpan: 'rowspan',\n spellCheck: 'spellcheck',\n srcDoc: 'srcdoc',\n srcLang: 'srclang',\n srcSet: 'srcset',\n tabIndex: 'tabindex',\n useMap: 'usemap',\n\n // SVG presentation attributes (camelCase → kebab-case)\n strokeWidth: 'stroke-width',\n strokeLinecap: 'stroke-linecap',\n strokeLinejoin: 'stroke-linejoin',\n strokeDasharray: 'stroke-dasharray',\n strokeDashoffset: 'stroke-dashoffset',\n strokeMiterlimit: 'stroke-miterlimit',\n strokeOpacity: 'stroke-opacity',\n fillOpacity: 'fill-opacity',\n fillRule: 'fill-rule',\n clipPath: 'clip-path',\n clipRule: 'clip-rule',\n colorInterpolation: 'color-interpolation',\n colorInterpolationFilters: 'color-interpolation-filters',\n floodColor: 'flood-color',\n floodOpacity: 'flood-opacity',\n lightingColor: 'lighting-color',\n stopColor: 'stop-color',\n stopOpacity: 'stop-opacity',\n shapeRendering: 'shape-rendering',\n imageRendering: 'image-rendering',\n textRendering: 'text-rendering',\n pointerEvents: 'pointer-events',\n vectorEffect: 'vector-effect',\n paintOrder: 'paint-order',\n\n // SVG text/font attributes\n fontFamily: 'font-family',\n fontSize: 'font-size',\n fontStyle: 'font-style',\n fontVariant: 'font-variant',\n fontWeight: 'font-weight',\n fontStretch: 'font-stretch',\n textAnchor: 'text-anchor',\n textDecoration: 'text-decoration',\n dominantBaseline: 'dominant-baseline',\n alignmentBaseline: 'alignment-baseline',\n baselineShift: 'baseline-shift',\n letterSpacing: 'letter-spacing',\n wordSpacing: 'word-spacing',\n writingMode: 'writing-mode',\n\n // SVG marker attributes\n markerStart: 'marker-start',\n markerMid: 'marker-mid',\n markerEnd: 'marker-end',\n\n // SVG xlink (legacy but still used)\n xlinkHref: 'xlink:href',\n xlinkShow: 'xlink:show',\n xlinkActuate: 'xlink:actuate',\n xlinkType: 'xlink:type',\n xlinkRole: 'xlink:role',\n xlinkTitle: 'xlink:title',\n xlinkArcrole: 'xlink:arcrole',\n xmlBase: 'xml:base',\n xmlLang: 'xml:lang',\n xmlSpace: 'xml:space',\n xmlnsXlink: 'xmlns:xlink',\n};\n","/**\n * kerf JSX runtime.\n *\n * JSX renders to `SafeHtml`, which wraps both:\n * - `__html`: the flattened HTML string (what `toString()` returns; what\n * legacy/SSR consumers care about)\n * - `__segment`: a structured representation that distinguishes \"static\n * html\", \"keyed list\", and \"mixed\" content.\n *\n * Most renders are pure-static and the segment is just `{kind:'static',html}`.\n * When the tree contains a list (via `each()`) or a parent whose children\n * include a non-static segment, the runtime threads that structure up so\n * `mount()` can dispatch on it — running its native keyed reconciler for\n * the list parts and leaving the static surrounds to the general-purpose\n * diff.\n *\n * Configure in your `tsconfig.json`:\n *\n * \"jsx\": \"react-jsx\",\n * \"jsxImportSource\": \"kerfjs\"\n *\n * Then write JSX as you normally would — kerf provides the `jsx` /\n * `jsxs` / `jsxDEV` / `Fragment` exports the JSX transform looks for.\n */\n\nimport type { KerfBuiltinIntrinsicElements } from './jsx-types.js';\nimport {\n flatten,\n type ListSegment,\n mergeChildSegments,\n type Segment,\n wrapWithTags,\n} from './segment.js';\nimport { escapeAttr, escapeHtml } from './utils/escapeHtml.js';\nimport { ATTR_ALIASES } from './utils/jsx-attr-aliases.js';\n\n// Cross-realm/cross-bundle brand. Using `Symbol.for` (the global registry)\n// means two `SafeHtml` classes from different module copies still recognise\n// each other. Same approach React uses for `$$typeof: Symbol.for('react.element')`.\n// Without this, `instanceof SafeHtml` fails when the consumer's bundler ends\n// up loading two copies of kerf (separate barrel + jsx-runtime entries,\n// monorepo dedup misses, ESM/CJS interop, etc.).\nconst SAFE_HTML_BRAND = Symbol.for('kerfjs.SafeHtml');\n\nexport class SafeHtml {\n readonly __html: string;\n readonly __segment: Segment;\n // Branded so `isSafeHtml()` recognises instances from any copy of this module.\n readonly [SAFE_HTML_BRAND] = true as const;\n constructor(input: string | Segment) {\n if (typeof input === 'string') {\n this.__segment = { kind: 'static', html: input };\n this.__html = input;\n } else {\n this.__segment = input;\n this.__html = flatten(input, false);\n }\n }\n toString(): string {\n return this.__html;\n }\n}\n\n/**\n * Type guard for `SafeHtml`. Prefer this over `instanceof SafeHtml` — it works\n * across module copies (e.g. when the consumer's bundler loads kerf's barrel\n * and JSX-runtime entries as independent modules).\n */\nexport function isSafeHtml(value: unknown): value is SafeHtml {\n return typeof value === 'object'\n && value !== null\n && (value as Record<symbol, unknown>)[SAFE_HTML_BRAND] === true;\n}\n\n/** Inject a pre-escaped HTML string. Use sparingly — caller is responsible for escaping. */\nexport function raw(html: string): SafeHtml {\n return new SafeHtml(html);\n}\n\n/**\n * Internal: build a `SafeHtml` representing a list segment. Used by\n * `each()` so the JSX runtime is the sole owner of `SafeHtml` construction.\n */\nexport function listSafeHtml(id: string, items: ListSegment['items']): SafeHtml {\n return new SafeHtml({ kind: 'list', id, items });\n}\n\n/**\n * Internal: build a `SafeHtml` representing a granular list segment with\n * patches (KF-92). The reconciler applies the patches to the existing\n * binding directly, skipping the per-item iteration that the snapshot\n * `listSafeHtml` requires. `items` is included for fall-through paths\n * (toString during SSR, fall-back when the binding doesn't exist yet).\n *\n * Patch HTML is rendered upstream (in `each()`) inside a try/catch — see\n * KF-99 — so by the time we get here every `update` / `insert` patch\n * already carries a `html` string, and the reconciler does no further\n * row rendering.\n */\nexport function granularListSafeHtml(\n id: string,\n items: ListSegment['items'],\n patches: NonNullable<ListSegment['patches']>,\n): SafeHtml {\n return new SafeHtml({ kind: 'list', id, items, patches });\n}\n\ntype Child = SafeHtml | string | number | boolean | null | undefined;\ntype Children = Child | Children[];\n\ninterface Props {\n children?: Children;\n [key: string]: unknown;\n}\n\nconst VOID_TAGS = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'source', 'track', 'wbr',\n]);\n\n/**\n * Convert a single JSX child into a Segment. Handles SafeHtml passthrough,\n * primitive coercion + escaping, arrays (recursive), and the nullish/false\n * skip cases.\n */\nfunction toSegment(child: Children): Segment {\n if (child == null || typeof child === 'boolean') return { kind: 'static', html: '' };\n if (isSafeHtml(child)) {\n // Cross-bundle SafeHtml shims (KF-14 case) may have only `__html`.\n return child.__segment ?? { kind: 'static', html: child.__html };\n }\n if (typeof child === 'string') return { kind: 'static', html: escapeHtml(child) };\n if (typeof child === 'number') return { kind: 'static', html: String(child) };\n if (Array.isArray(child)) return mergeChildSegments(child.map(toSegment));\n // Catch the common mistake of passing a DOM element (e.g. the result of\n // toElement(...)) as a JSX child. The runtime renders to HTML strings, so\n // DOM nodes can't be composed — they'd silently serialize to \"\" and their\n // event listeners would be lost. Throw loudly so this can't sneak in.\n const maybeNode = child as unknown;\n if (typeof maybeNode === 'object' && maybeNode !== null\n && ('nodeType' in maybeNode || 'outerHTML' in maybeNode)) {\n throw new Error(\n 'JSX: DOM elements cannot be passed as children (the JSX runtime renders to HTML strings). '\n + 'Build the tree in one JSX expression and use querySelector after toElement() to get element refs.',\n );\n }\n throw new Error(\n `JSX: unsupported child of type ${describeValue(child)}. `\n + 'Children must be SafeHtml, string, number, boolean, null, undefined, or an array of those. '\n + 'Common mistakes: passing a Signal/Store object directly (use signal.value or store.state.value), '\n + 'passing a function (call it first), or passing a Promise (await it before render).',\n );\n}\n\nfunction describeValue(v: unknown): string {\n if (Array.isArray(v)) return 'array';\n if (typeof v === 'object' && v !== null) {\n const ctor = (v as { constructor?: { name?: string } }).constructor?.name;\n return ctor && ctor !== 'Object' ? `object (${ctor})` : 'object';\n }\n return typeof v;\n}\n\n// URL-bearing HTML/SVG attributes. Plain-string values written here are\n// screened against `DANGEROUS_URL_RE` so a stored-XSS payload like\n// `<a href={userInput}>` with `userInput === 'javascript:alert(1)'` produces\n// a dropped attribute (and a console.warn) rather than a clickable script\n// vector. `SafeHtml` values (i.e. `raw(...)`) bypass the screen — that's the\n// documented opt-out for legitimate cases (bookmarklet builders, sanitised\n// inputs from a separate trust layer).\nconst URL_ATTRS = new Set(['href', 'src', 'xlink:href', 'formaction', 'action']);\nconst DANGEROUS_URL_RE = /^\\s*(?:(?:java|vb)script:|data:text\\/html[;,])/i;\n\nfunction renderAttr(key: string, value: unknown): string {\n const name = ATTR_ALIASES[key] ?? key;\n if (value == null || value === false) return '';\n if (value === true) return ` ${name}`;\n let strValue: string;\n if (isSafeHtml(value)) {\n strValue = value.__html;\n } else if (typeof value === 'number') {\n strValue = String(value);\n } else if (typeof value === 'string') {\n if (URL_ATTRS.has(name) && DANGEROUS_URL_RE.test(value)) {\n console.warn(\n `JSX: dropped dangerous URL value for ${name}=${JSON.stringify(value.slice(0, 80))}. `\n + 'kerf blocks javascript:, vbscript:, and data:text/html URLs in href/src/formaction/action/xlink:href by default. '\n + 'Wrap in raw() if this is intentional (e.g. bookmarklets), or sanitise upstream.',\n );\n return '';\n }\n strValue = escapeAttr(value);\n } else {\n throw new Error(\n `JSX: unsupported value for attribute \"${key}\" — got ${describeValue(value)}. `\n + 'Attribute values must be string, number, boolean, null, undefined, or SafeHtml. '\n + 'Did you mean to read .value off a Signal, or stringify the object first?',\n );\n }\n return ` ${name}=\"${strValue}\"`;\n}\n\nexport function jsx(tag: string | ((props: Props) => SafeHtml), props: Props): SafeHtml {\n if (typeof tag === 'function') return tag(props);\n\n const { children, ...attrs } = props;\n const attrStr = Object.entries(attrs)\n .map(([k, v]) => renderAttr(k, v))\n .join('');\n\n if (VOID_TAGS.has(tag)) return new SafeHtml(`<${tag}${attrStr}>`);\n\n const childSegment: Segment = children != null\n ? toSegment(children)\n : { kind: 'static', html: '' };\n return new SafeHtml(wrapWithTags(childSegment, `<${tag}${attrStr}>`, `</${tag}>`));\n}\n\nexport { jsx as jsxs };\n// vitest's dev-mode JSX transform emits `jsxDEV(tag, props, ...)`; the\n// alias lets tests import this module without the production build pipeline\n// caring.\nexport { jsx as jsxDEV };\n\nexport function Fragment({ children }: { children?: Children }): SafeHtml {\n return new SafeHtml(children != null ? toSegment(children) : { kind: 'static', html: '' });\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace JSX {\n export type Element = SafeHtml;\n export interface ElementChildrenAttribute {\n children: unknown;\n }\n // Per-tag attribute contracts live in `./jsx-types.ts` as\n // `KerfBuiltinIntrinsicElements`. Re-exposed as an **interface** (not a\n // type alias) so consumers can declaration-merge custom-element tags\n // (KF-100):\n //\n // declare module 'kerfjs/jsx-runtime' {\n // namespace JSX {\n // interface IntrinsicElements {\n // 'my-element': KerfCustomElement & { foo?: string };\n // }\n // }\n // }\n //\n // KF-123: the imported interface is named `KerfBuiltinIntrinsicElements`\n // upstream so tsup/tsc cannot strip an import alias and end up emitting\n // `interface IntrinsicElements extends IntrinsicElements {}` in the .d.ts\n // — that shadowed form self-resolves to empty and breaks every `<tag>` in\n // consumer .tsx with TS2339. Verified against `dist/jsx-runtime.d.ts` by\n // `tests/dist/jsx-typing/` on every `npm run build`.\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n export interface IntrinsicElements extends KerfBuiltinIntrinsicElements {}\n}\n\n/**\n * Public re-exports of the JSX type primitives so consumers can compose\n * attribute interfaces for custom elements without reaching into\n * `kerfjs/jsx-types` (which is intentionally not in `package.json#exports`).\n */\nexport type {\n AttrLike,\n AttrValue,\n DataAriaAttrs,\n KerfBaseAttrs,\n KerfCustomElement,\n} from './jsx-types.js';\n"]}
1
+ {"version":3,"sources":["../src/segment.ts","../src/utils/escapeHtml.ts","../src/utils/jsx-attr-aliases.ts","../src/jsx-runtime.ts"],"names":[],"mappings":"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","file":"chunk-LADH5GVQ.js","sourcesContent":["/**\n * `Segment` — kerf's structured render output.\n *\n * The JSX runtime emits a `SafeHtml` wrapping a `Segment`. Most renders\n * produce a single static segment (just an HTML string), which behaves\n * exactly like a string for backward compatibility. When the tree\n * contains a list (`each()`) or a parent whose children include a list,\n * the runtime emits a structured segment that `mount()` can dispatch\n * on — running its native keyed reconciler for the list parts and\n * leaving the static surrounds to the general-purpose diff.\n *\n * Why have a structured form at all: the perf bottleneck for huge\n * keyed lists isn't the per-row JSX work (which `each()` already\n * memoizes). It's that flattening every render's whole tree to one\n * big HTML string forces a full `innerHTML` parse and a tree walk\n * over rows we know are unchanged. The segment shape lets mount()\n * skip both for the list parts.\n */\n\nexport type Segment = StaticSegment | ListSegment | MixedSegment;\n\nexport interface StaticSegment {\n kind: 'static';\n html: string;\n}\n\nexport interface ListItem {\n /**\n * The row's object identity. Used by the reconciler to match new items\n * against live DOM nodes across renders. Unchanged ref → reuse the\n * existing live node; replaced ref → build a fresh node.\n */\n ref: object;\n /**\n * Optional cache-invalidation key that captures external state affecting\n * this row's render (e.g. selection class). Different cacheKey on the\n * same `ref` triggers a cache miss for that row. `undefined` when the\n * user didn't pass a `key` callback to `each()`.\n */\n cacheKey: unknown;\n html: string;\n}\n\nexport interface ListSegment {\n kind: 'list';\n id: string;\n items: ListItem[];\n /**\n * Optional granular patches (KF-92). When present, the list reconciler\n * applies these directly to the existing binding instead of doing a\n * full classify+reconcile pass. Emitted by `each()` when bound to an\n * `arraySignal`. Mutually exclusive with the `items` snapshot in the\n * sense that the snapshot is treated as informational/fall-back when\n * patches are present.\n */\n patches?: ArrayPatchInternal[];\n}\n\n/**\n * Internal patch shape used inside list segments. Mirrors `ArrayPatch<T>`\n * from `array-signal.ts` but typed against `object` so the segment layer\n * doesn't need to be generic. `update` / `insert` patches carry the row's\n * pre-rendered HTML — `each()` renders them at JSX-evaluation time inside a\n * try/catch so a throwing render falls back to the snapshot path (KF-99)\n * instead of leaving the signal and DOM divergent.\n */\nexport type ArrayPatchInternal =\n | { type: 'update'; index: number; item: object; html: string }\n | { type: 'insert'; index: number; item: object; html: string }\n | { type: 'remove'; index: number }\n | { type: 'move'; from: number; to: number }\n | { type: 'replace'; items: readonly object[] };\n\nexport interface MixedSegment {\n kind: 'mixed';\n parts: Segment[];\n}\n\n/**\n * Flatten a segment to a complete HTML string. Used for first render\n * (bulk innerHTML), for SSR-style consumption via `toString()`, and\n * for diagnostics.\n *\n * If `withMarkers` is set, list segments are wrapped in\n * `<!--kf-list:{id}-->` comments so the post-parse walk can find each\n * list's live parent. Plain (non-marker) flatten is what JSX consumers\n * see when they call `.toString()` on the SafeHtml.\n */\nexport function flatten(segment: Segment, withMarkers: boolean): string {\n if (segment.kind === 'static') return segment.html;\n if (segment.kind === 'list') {\n const items = segment.items.map((i) => i.html).join('');\n return withMarkers ? `<!--kf-list:${segment.id}-->${items}` : items;\n }\n return segment.parts.map((p) => flatten(p, withMarkers)).join('');\n}\n\n/**\n * Variant of `flatten` for the static-only diff path on subsequent\n * renders. Lists are reduced to a single marker comment with no items\n * inside — the actual list children stay in the live DOM and are\n * reconciled separately. Keeping list items out of this string is\n * what makes the morph cheap on huge lists where most rows are\n * unchanged.\n */\nexport function flattenWithoutListItems(segment: Segment): string {\n if (segment.kind === 'static') return segment.html;\n if (segment.kind === 'list') return `<!--kf-list:${segment.id}-->`;\n return segment.parts.map(flattenWithoutListItems).join('');\n}\n\n/** Collect every `ListSegment` in the tree, keyed by its id. */\nexport function collectLists(\n segment: Segment,\n out: Map<string, ListSegment> = new Map(),\n): Map<string, ListSegment> {\n if (segment.kind === 'list') out.set(segment.id, segment);\n else if (segment.kind === 'mixed') {\n for (const part of segment.parts) collectLists(part, out);\n }\n return out;\n}\n\n/**\n * Combine a list of child segments into the smallest equivalent\n * representation: collapses adjacent statics into one static, returns\n * a single static if everything is static, otherwise a mixed segment\n * with statics coalesced.\n */\nexport function mergeChildSegments(parts: Segment[]): Segment {\n if (parts.length === 0) return { kind: 'static', html: '' };\n if (parts.every((p) => p.kind === 'static')) {\n return {\n kind: 'static',\n html: parts.map((p) => (p as StaticSegment).html).join(''),\n };\n }\n const merged: Segment[] = [];\n let coalesced = '';\n for (const p of parts) {\n if (p.kind === 'static') {\n coalesced += p.html;\n } else {\n if (coalesced !== '') {\n merged.push({ kind: 'static', html: coalesced });\n coalesced = '';\n }\n merged.push(p);\n }\n }\n if (coalesced !== '') merged.push({ kind: 'static', html: coalesced });\n return { kind: 'mixed', parts: merged };\n}\n\n/**\n * Wrap a child segment with surrounding open/close tags from the\n * parent JSX element. Used by the JSX runtime when constructing\n * `_jsx(tag, ...)` output.\n */\nexport function wrapWithTags(child: Segment, openTag: string, closeTag: string): Segment {\n if (child.kind === 'static') {\n return { kind: 'static', html: openTag + child.html + closeTag };\n }\n if (child.kind === 'mixed') {\n return {\n kind: 'mixed',\n parts: [\n { kind: 'static', html: openTag },\n ...child.parts,\n { kind: 'static', html: closeTag },\n ],\n };\n }\n return {\n kind: 'mixed',\n parts: [\n { kind: 'static', html: openTag },\n child,\n { kind: 'static', html: closeTag },\n ],\n };\n}\n","/**\n * HTML / attribute escaping for the JSX runtime. Identical to the helpers\n * used in any reasonable HTML emitter — included here so kerf has no extra\n * runtime dependencies beyond `@preact/signals-core`.\n */\n\nexport function escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nexport function escapeAttr(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n","/**\n * JSX → HTML / SVG attribute name aliases.\n *\n * The JSX runtime translates camelCase attributes (React convention) to\n * the kebab-case / colon-form names the browser actually wants. Anything\n * not in this map is passed through verbatim — `data-*`, `aria-*`, and\n * any custom attribute work without ceremony.\n *\n * Lives in its own module so `src/jsx-runtime.ts` can stay under the\n * 200-LOC project guideline; the bulk of `jsx-runtime.ts` was this table.\n */\n\nexport const ATTR_ALIASES: Record<string, string> = {\n // HTML attributes\n className: 'class',\n htmlFor: 'for',\n httpEquiv: 'http-equiv',\n acceptCharset: 'accept-charset',\n accessKey: 'accesskey',\n autoCapitalize: 'autocapitalize',\n autoComplete: 'autocomplete',\n autoFocus: 'autofocus',\n autoPlay: 'autoplay',\n colSpan: 'colspan',\n contentEditable: 'contenteditable',\n crossOrigin: 'crossorigin',\n dateTime: 'datetime',\n defaultChecked: 'checked',\n defaultValue: 'value',\n encType: 'enctype',\n formAction: 'formaction',\n formEncType: 'formenctype',\n formMethod: 'formmethod',\n formNoValidate: 'formnovalidate',\n formTarget: 'formtarget',\n hrefLang: 'hreflang',\n inputMode: 'inputmode',\n maxLength: 'maxlength',\n minLength: 'minlength',\n noModule: 'nomodule',\n noValidate: 'novalidate',\n readOnly: 'readonly',\n referrerPolicy: 'referrerpolicy',\n rowSpan: 'rowspan',\n spellCheck: 'spellcheck',\n srcDoc: 'srcdoc',\n srcLang: 'srclang',\n srcSet: 'srcset',\n tabIndex: 'tabindex',\n useMap: 'usemap',\n\n // SVG presentation attributes (camelCase → kebab-case)\n strokeWidth: 'stroke-width',\n strokeLinecap: 'stroke-linecap',\n strokeLinejoin: 'stroke-linejoin',\n strokeDasharray: 'stroke-dasharray',\n strokeDashoffset: 'stroke-dashoffset',\n strokeMiterlimit: 'stroke-miterlimit',\n strokeOpacity: 'stroke-opacity',\n fillOpacity: 'fill-opacity',\n fillRule: 'fill-rule',\n clipPath: 'clip-path',\n clipRule: 'clip-rule',\n colorInterpolation: 'color-interpolation',\n colorInterpolationFilters: 'color-interpolation-filters',\n floodColor: 'flood-color',\n floodOpacity: 'flood-opacity',\n lightingColor: 'lighting-color',\n stopColor: 'stop-color',\n stopOpacity: 'stop-opacity',\n shapeRendering: 'shape-rendering',\n imageRendering: 'image-rendering',\n textRendering: 'text-rendering',\n pointerEvents: 'pointer-events',\n vectorEffect: 'vector-effect',\n paintOrder: 'paint-order',\n\n // SVG text/font attributes\n fontFamily: 'font-family',\n fontSize: 'font-size',\n fontStyle: 'font-style',\n fontVariant: 'font-variant',\n fontWeight: 'font-weight',\n fontStretch: 'font-stretch',\n textAnchor: 'text-anchor',\n textDecoration: 'text-decoration',\n dominantBaseline: 'dominant-baseline',\n alignmentBaseline: 'alignment-baseline',\n baselineShift: 'baseline-shift',\n letterSpacing: 'letter-spacing',\n wordSpacing: 'word-spacing',\n writingMode: 'writing-mode',\n\n // SVG marker attributes\n markerStart: 'marker-start',\n markerMid: 'marker-mid',\n markerEnd: 'marker-end',\n\n // SVG xlink (legacy but still used)\n xlinkHref: 'xlink:href',\n xlinkShow: 'xlink:show',\n xlinkActuate: 'xlink:actuate',\n xlinkType: 'xlink:type',\n xlinkRole: 'xlink:role',\n xlinkTitle: 'xlink:title',\n xlinkArcrole: 'xlink:arcrole',\n xmlBase: 'xml:base',\n xmlLang: 'xml:lang',\n xmlSpace: 'xml:space',\n xmlnsXlink: 'xmlns:xlink',\n};\n","/**\n * kerf JSX runtime.\n *\n * JSX renders to `SafeHtml`, which wraps both:\n * - `__html`: the flattened HTML string (what `toString()` returns; what\n * legacy/SSR consumers care about)\n * - `__segment`: a structured representation that distinguishes \"static\n * html\", \"keyed list\", and \"mixed\" content.\n *\n * Most renders are pure-static and the segment is just `{kind:'static',html}`.\n * When the tree contains a list (via `each()`) or a parent whose children\n * include a non-static segment, the runtime threads that structure up so\n * `mount()` can dispatch on it — running its native keyed reconciler for\n * the list parts and leaving the static surrounds to the general-purpose\n * diff.\n *\n * Configure in your `tsconfig.json`:\n *\n * \"jsx\": \"react-jsx\",\n * \"jsxImportSource\": \"kerfjs\"\n *\n * Then write JSX as you normally would — kerf provides the `jsx` /\n * `jsxs` / `jsxDEV` / `Fragment` exports the JSX transform looks for.\n */\n\nimport type { KerfBuiltinIntrinsicElements } from './jsx-types.js';\nimport {\n flatten,\n type ListSegment,\n mergeChildSegments,\n type Segment,\n wrapWithTags,\n} from './segment.js';\nimport { escapeAttr, escapeHtml } from './utils/escapeHtml.js';\nimport { ATTR_ALIASES } from './utils/jsx-attr-aliases.js';\n\n// Cross-realm/cross-bundle brand. Using `Symbol.for` (the global registry)\n// means two `SafeHtml` classes from different module copies still recognize\n// each other. Same approach React uses for `$$typeof: Symbol.for('react.element')`.\n// Without this, `instanceof SafeHtml` fails when the consumer's bundler ends\n// up loading two copies of kerf (separate barrel + jsx-runtime entries,\n// monorepo dedup misses, ESM/CJS interop, etc.).\nconst SAFE_HTML_BRAND = Symbol.for('kerfjs.SafeHtml');\n\nexport class SafeHtml {\n readonly __html: string;\n readonly __segment: Segment;\n // Branded so `isSafeHtml()` recognizes instances from any copy of this module.\n readonly [SAFE_HTML_BRAND] = true as const;\n constructor(input: string | Segment) {\n if (typeof input === 'string') {\n this.__segment = { kind: 'static', html: input };\n this.__html = input;\n } else {\n this.__segment = input;\n this.__html = flatten(input, false);\n }\n }\n toString(): string {\n return this.__html;\n }\n}\n\n/**\n * Type guard for `SafeHtml`. Prefer this over `instanceof SafeHtml` — it works\n * across module copies (e.g. when the consumer's bundler loads kerf's barrel\n * and JSX-runtime entries as independent modules).\n */\nexport function isSafeHtml(value: unknown): value is SafeHtml {\n return typeof value === 'object'\n && value !== null\n && (value as Record<symbol, unknown>)[SAFE_HTML_BRAND] === true;\n}\n\n/** Inject a pre-escaped HTML string. Use sparingly — caller is responsible for escaping. */\nexport function raw(html: string): SafeHtml {\n return new SafeHtml(html);\n}\n\n/**\n * Internal: build a `SafeHtml` representing a list segment. Used by\n * `each()` so the JSX runtime is the sole owner of `SafeHtml` construction.\n */\nexport function listSafeHtml(id: string, items: ListSegment['items']): SafeHtml {\n return new SafeHtml({ kind: 'list', id, items });\n}\n\n/**\n * Internal: build a `SafeHtml` representing a granular list segment with\n * patches (KF-92). The reconciler applies the patches to the existing\n * binding directly, skipping the per-item iteration that the snapshot\n * `listSafeHtml` requires. `items` is included for fall-through paths\n * (toString during SSR, fall-back when the binding doesn't exist yet).\n *\n * Patch HTML is rendered upstream (in `each()`) inside a try/catch — see\n * KF-99 — so by the time we get here every `update` / `insert` patch\n * already carries a `html` string, and the reconciler does no further\n * row rendering.\n */\nexport function granularListSafeHtml(\n id: string,\n items: ListSegment['items'],\n patches: NonNullable<ListSegment['patches']>,\n): SafeHtml {\n return new SafeHtml({ kind: 'list', id, items, patches });\n}\n\ntype Child = SafeHtml | string | number | boolean | null | undefined;\ntype Children = Child | Children[];\n\ninterface Props {\n children?: Children;\n [key: string]: unknown;\n}\n\nconst VOID_TAGS = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'source', 'track', 'wbr',\n]);\n\n/**\n * Convert a single JSX child into a Segment. Handles SafeHtml passthrough,\n * primitive coercion + escaping, arrays (recursive), and the nullish/false\n * skip cases.\n */\nfunction toSegment(child: Children): Segment {\n if (child == null || typeof child === 'boolean') return { kind: 'static', html: '' };\n if (isSafeHtml(child)) {\n // Cross-bundle SafeHtml shims (KF-14 case) may have only `__html`.\n return child.__segment ?? { kind: 'static', html: child.__html };\n }\n if (typeof child === 'string') return { kind: 'static', html: escapeHtml(child) };\n if (typeof child === 'number') return { kind: 'static', html: String(child) };\n if (Array.isArray(child)) return mergeChildSegments(child.map(toSegment));\n // Catch the common mistake of passing a DOM element (e.g. the result of\n // toElement(...)) as a JSX child. The runtime renders to HTML strings, so\n // DOM nodes can't be composed — they'd silently serialize to \"\" and their\n // event listeners would be lost. Throw loudly so this can't sneak in.\n const maybeNode = child as unknown;\n if (typeof maybeNode === 'object' && maybeNode !== null\n && ('nodeType' in maybeNode || 'outerHTML' in maybeNode)) {\n throw new Error(\n 'JSX: DOM elements cannot be passed as children (the JSX runtime renders to HTML strings). '\n + 'Build the tree in one JSX expression and use querySelector after toElement() to get element refs.',\n );\n }\n throw new Error(\n `JSX: unsupported child of type ${describeValue(child)}. `\n + 'Children must be SafeHtml, string, number, boolean, null, undefined, or an array of those. '\n + 'Common mistakes: passing a Signal/Store object directly (use signal.value or store.state.value), '\n + 'passing a function (call it first), or passing a Promise (await it before render).',\n );\n}\n\nfunction describeValue(v: unknown): string {\n if (Array.isArray(v)) return 'array';\n if (typeof v === 'object' && v !== null) {\n const ctor = (v as { constructor?: { name?: string } }).constructor?.name;\n return ctor && ctor !== 'Object' ? `object (${ctor})` : 'object';\n }\n return typeof v;\n}\n\n// URL-bearing HTML/SVG attributes. Plain-string values written here are\n// screened against `DANGEROUS_URL_RE` so a stored-XSS payload like\n// `<a href={userInput}>` with `userInput === 'javascript:alert(1)'` produces\n// a dropped attribute (and a console.warn) rather than a clickable script\n// vector. `SafeHtml` values (i.e. `raw(...)`) bypass the screen — that's the\n// documented opt-out for legitimate cases (bookmarklet builders, sanitized\n// inputs from a separate trust layer).\nconst URL_ATTRS = new Set(['href', 'src', 'xlink:href', 'formaction', 'action']);\nconst DANGEROUS_URL_RE = /^\\s*(?:(?:java|vb)script:|data:text\\/html[;,])/i;\n\nfunction renderAttr(key: string, value: unknown): string {\n const name = ATTR_ALIASES[key] ?? key;\n if (value == null || value === false) return '';\n if (value === true) return ` ${name}`;\n let strValue: string;\n if (isSafeHtml(value)) {\n strValue = value.__html;\n } else if (typeof value === 'number') {\n strValue = String(value);\n } else if (typeof value === 'string') {\n if (URL_ATTRS.has(name) && DANGEROUS_URL_RE.test(value)) {\n console.warn(\n `JSX: dropped dangerous URL value for ${name}=${JSON.stringify(value.slice(0, 80))}. `\n + 'kerf blocks javascript:, vbscript:, and data:text/html URLs in href/src/formaction/action/xlink:href by default. '\n + 'Wrap in raw() if this is intentional (e.g. bookmarklets), or sanitize upstream.',\n );\n return '';\n }\n strValue = escapeAttr(value);\n } else {\n throw new Error(\n `JSX: unsupported value for attribute \"${key}\" — got ${describeValue(value)}. `\n + 'Attribute values must be string, number, boolean, null, undefined, or SafeHtml. '\n + 'Did you mean to read .value off a Signal, or stringify the object first?',\n );\n }\n return ` ${name}=\"${strValue}\"`;\n}\n\nexport function jsx(tag: string | ((props: Props) => SafeHtml), props: Props): SafeHtml {\n if (typeof tag === 'function') return tag(props);\n\n const { children, ...attrs } = props;\n const attrStr = Object.entries(attrs)\n .map(([k, v]) => renderAttr(k, v))\n .join('');\n\n if (VOID_TAGS.has(tag)) return new SafeHtml(`<${tag}${attrStr}>`);\n\n const childSegment: Segment = children != null\n ? toSegment(children)\n : { kind: 'static', html: '' };\n return new SafeHtml(wrapWithTags(childSegment, `<${tag}${attrStr}>`, `</${tag}>`));\n}\n\nexport { jsx as jsxs };\n// vitest's dev-mode JSX transform emits `jsxDEV(tag, props, ...)`; the\n// alias lets tests import this module without the production build pipeline\n// caring.\nexport { jsx as jsxDEV };\n\nexport function Fragment({ children }: { children?: Children }): SafeHtml {\n return new SafeHtml(children != null ? toSegment(children) : { kind: 'static', html: '' });\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace JSX {\n export type Element = SafeHtml;\n export interface ElementChildrenAttribute {\n children: unknown;\n }\n // Per-tag attribute contracts live in `./jsx-types.ts` as\n // `KerfBuiltinIntrinsicElements`. Re-exposed as an **interface** (not a\n // type alias) so consumers can declaration-merge custom-element tags\n // (KF-100):\n //\n // declare module 'kerfjs/jsx-runtime' {\n // namespace JSX {\n // interface IntrinsicElements {\n // 'my-element': KerfCustomElement & { foo?: string };\n // }\n // }\n // }\n //\n // KF-123: the imported interface is named `KerfBuiltinIntrinsicElements`\n // upstream so tsup/tsc cannot strip an import alias and end up emitting\n // `interface IntrinsicElements extends IntrinsicElements {}` in the .d.ts\n // — that shadowed form self-resolves to empty and breaks every `<tag>` in\n // consumer .tsx with TS2339. Verified against `dist/jsx-runtime.d.ts` by\n // `tests/dist/jsx-typing/` on every `npm run build`.\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n export interface IntrinsicElements extends KerfBuiltinIntrinsicElements {}\n}\n\n/**\n * Public re-exports of the JSX type primitives so consumers can compose\n * attribute interfaces for custom elements without reaching into\n * `kerfjs/jsx-types` (which is intentionally not in `package.json#exports`).\n */\nexport type {\n AttrLike,\n AttrValue,\n DataAriaAttrs,\n KerfBaseAttrs,\n KerfCustomElement,\n} from './jsx-types.js';\n"]}
package/dist/index.d.ts CHANGED
@@ -60,22 +60,22 @@ declare function delegate(rootEl: HTMLElement, type: string, selector: string, h
60
60
  declare function delegateCapture(rootEl: HTMLElement, type: string, selector: string, handler: Handler): () => void;
61
61
 
62
62
  /**
63
- * `each(items, render, key?)` — keyed list iteration with per-item memoisation.
63
+ * `each(items, render, key?)` — keyed list iteration with per-item memoization.
64
64
  *
65
65
  * Drops in as the body of a list-rendering JSX expression inside a `mount()`
66
66
  * render function. Returns a `SafeHtml` carrying a structured list segment,
67
67
  * so `mount()` can run a native keyed reconciler instead of the general-
68
68
  * purpose morph for these children.
69
69
  *
70
- * Two layers of optimisation:
70
+ * Two layers of optimization:
71
71
  *
72
- * 1. Per-item memoisation. `render(item)` is skipped for items whose object
72
+ * 1. Per-item memoization. `render(item)` is skipped for items whose object
73
73
  * identity (and optional `key`) are unchanged since the previous call.
74
74
  * Their HTML strings come from a `WeakMap` keyed by item reference. The
75
75
  * immutable-update style ("replace the row object" instead of "mutate it")
76
76
  * makes the cache work automatically.
77
77
  *
78
- * 2. Structural handoff. `mount()` recognises the list segment and bypasses
78
+ * 2. Structural handoff. `mount()` recognizes the list segment and bypasses
79
79
  * the parse-the-whole-table round trip: only fresh items get parsed (one
80
80
  * at a time, into the smallest detached element), and only changed rows
81
81
  * get patched in the live DOM. Unchanged rows are physically the same
@@ -94,6 +94,65 @@ declare function delegateCapture(rootEl: HTMLElement, type: string, selector: st
94
94
 
95
95
  declare function each<T extends object>(items: readonly T[] | ArraySignal<T>, render: (item: T, index: number) => SafeHtml | string, key?: (item: T, index: number) => unknown): SafeHtml;
96
96
 
97
+ /**
98
+ * `morph(liveRoot, template)` — minimum-mutation DOM reconciliation.
99
+ *
100
+ * Public primitive (KF-150): one-shot reconciliation against an
101
+ * already-populated element. `mount()` first paints by writing
102
+ * `innerHTML`; `morph()` is the "I have a live tree and a template,
103
+ * reconcile them in place" sibling. Use it for SSR hydration of static
104
+ * fragments, page-refresh diffs, third-party widget remounts, etc.
105
+ *
106
+ * Replaces our previous dependency on `morphdom`. The algorithm is the
107
+ * classic two-tree walk: match children by key (id, then data-key, then
108
+ * positional same-tag), morph matches in place, insert / remove / clone
109
+ * the rest. Specialized for what kerf needs:
110
+ *
111
+ * - `childrenOnly` is always true; the live root is never replaced.
112
+ * - Per-element short-circuits: `data-morph-skip` (library-owned, leave
113
+ * element AND subtree verbatim), `data-morph-skip-children` (KF-152 —
114
+ * morph attrs on the element, leave its subtree verbatim — for
115
+ * client-hydrated slots whose loading/state classes still need to flow
116
+ * through), and `isEqualNode` (byte-identical, no work needed).
117
+ * - **`data-morph-preserve`** (KF-151) is honored in the trailing-removal
118
+ * pass: an unmatched live element with this attribute is skipped instead
119
+ * of removed. Lets imperatively-injected nodes (autoplay `<video>`s,
120
+ * tour-widget tooltips, analytics pixels) survive across renders without
121
+ * having to `data-morph-skip` the entire parent.
122
+ * - **`ownedItems`** is the set of element nodes owned by an `each()`
123
+ * list reconciler. The morph skips them in every children walk —
124
+ * they're not added to the keyed-lookup map, the from-cursor advances
125
+ * past them, and the trailing-removal pass leaves them in place. This
126
+ * lets each() coexist with non-list siblings inside the same parent
127
+ * (KF-102 round 2): the morph still walks the parent's children to
128
+ * reconcile siblings, but never disturbs list rows. The parameter is an
129
+ * internal coordination channel between `mount()` and the reconciler;
130
+ * public callers should omit it (the default empty set is correct for
131
+ * any tree that isn't being managed by an active `mount()`).
132
+ * - Focused text inputs (`<input>`/`<textarea>`) keep their value +
133
+ * selection across the morph; focused `[contenteditable]` keeps its
134
+ * entire subtree (typed content + caret + multi-range selection).
135
+ *
136
+ * Algorithm credit: based on the design of
137
+ * https://github.com/patrick-steele-idem/morphdom by Patrick Steele-Idem
138
+ * (MIT licensed). Reimplemented here so kerf can specialize the hot paths
139
+ * (segment-aware list dispatch, lighter callback surface) and drop the
140
+ * runtime dependency. Original copyright preserved in `LICENSE`.
141
+ */
142
+
143
+ /**
144
+ * Reconcile the children of `liveRoot` to match `template`.
145
+ *
146
+ * `template` can be an `Element` (used directly), a `SafeHtml`, or a raw
147
+ * HTML string — the latter two are stringified and parsed into a transient
148
+ * element whose tag matches `liveRoot`. The active text-entry / focused-
149
+ * contenteditable preservation rules apply in all cases.
150
+ *
151
+ * `ownedItems` is an internal coordination channel for `mount()`'s list
152
+ * reconciler; public callers should omit it.
153
+ */
154
+ declare function morph(liveRoot: Element, template: Element | SafeHtml | string, ownedItems?: ReadonlySet<Element>): void;
155
+
97
156
  /**
98
157
  * `mount(rootEl, render)` — kerf's render primitive.
99
158
  *
@@ -106,7 +165,7 @@ declare function each<T extends object>(items: readonly T[] | ArraySignal<T>, re
106
165
  * Two phases per render:
107
166
  *
108
167
  * - Static surrounds (everything outside `each()` lists): kerf's native
109
- * `diff()` reconciler walks a freshly-built template against the live
168
+ * `morph()` reconciler walks a freshly-built template against the live
110
169
  * tree. Conventions: id/data-key matching, `data-morph-skip`, focus
111
170
  * preservation.
112
171
  *
@@ -163,4 +222,4 @@ declare function mount(rootEl: HTMLElement, render: () => MountResult): () => vo
163
222
 
164
223
  declare function toElement(jsx: SafeHtml | string): Element;
165
224
 
166
- export { type MountResult, SafeHtml, delegate, delegateCapture, each, mount, toElement };
225
+ export { type MountResult, SafeHtml, delegate, delegateCapture, each, morph, mount, toElement };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { isSafeHtml, listSafeHtml, flattenWithoutListItems, collectLists, flatten, granularListSafeHtml } from './chunk-KFOSUCCC.js';
2
- export { Fragment, SafeHtml, isSafeHtml, raw } from './chunk-KFOSUCCC.js';
1
+ import { isSafeHtml, listSafeHtml, flattenWithoutListItems, collectLists, flatten, granularListSafeHtml } from './chunk-LADH5GVQ.js';
2
+ export { Fragment, SafeHtml, isSafeHtml, raw } from './chunk-LADH5GVQ.js';
3
3
  export { defineStore, resetAllStores } from './chunk-GQGJFCWL.js';
4
4
  import { effect } from './chunk-FN2ID4QO.js';
5
5
  export { batch, computed, effect, signal } from './chunk-FN2ID4QO.js';
@@ -164,7 +164,7 @@ function eachSnapshotById(items, render, key, id) {
164
164
  return listSafeHtml(id, segItems);
165
165
  }
166
166
 
167
- // src/diff.ts
167
+ // src/morph.ts
168
168
  var ID_KEY_PREFIX = "id:";
169
169
  var DATA_KEY_PREFIX = "data-key:";
170
170
  var ELEMENT_NODE = 1;
@@ -179,8 +179,18 @@ function getNodeKey(node) {
179
179
  }
180
180
  return void 0;
181
181
  }
182
- function diff(liveRoot, templateRoot, ownedItems) {
183
- diffChildren(liveRoot, templateRoot, ownedItems);
182
+ var EMPTY_OWNED = /* @__PURE__ */ new Set();
183
+ function morph(liveRoot, template, ownedItems = EMPTY_OWNED) {
184
+ const templateEl = isElementNode(template) ? template : parseTemplate(liveRoot, template);
185
+ morphChildren(liveRoot, templateEl, ownedItems);
186
+ }
187
+ function isElementNode(t) {
188
+ return typeof t === "object" && t !== null && t.nodeType === ELEMENT_NODE;
189
+ }
190
+ function parseTemplate(liveRoot, template) {
191
+ const el = liveRoot.cloneNode(false);
192
+ el.innerHTML = String(template);
193
+ return el;
184
194
  }
185
195
  function skipOwned(node, ownedItems) {
186
196
  while (node !== null && node.nodeType === ELEMENT_NODE && ownedItems.has(node)) {
@@ -188,7 +198,7 @@ function skipOwned(node, ownedItems) {
188
198
  }
189
199
  return node;
190
200
  }
191
- function diffChildren(fromParent, toParent, ownedItems) {
201
+ function morphChildren(fromParent, toParent, ownedItems) {
192
202
  const keyed = /* @__PURE__ */ new Map();
193
203
  for (let c = fromParent.firstChild; c !== null; c = c.nextSibling) {
194
204
  if (c.nodeType === ELEMENT_NODE && ownedItems.has(c)) continue;
@@ -224,7 +234,12 @@ function diffChildren(fromParent, toParent, ownedItems) {
224
234
  }
225
235
  while (fromChild !== null) {
226
236
  const next = fromChild.nextSibling;
227
- if (fromChild.nodeType !== ELEMENT_NODE || !ownedItems.has(fromChild)) {
237
+ if (fromChild.nodeType === ELEMENT_NODE) {
238
+ const el = fromChild;
239
+ if (!ownedItems.has(el) && el.dataset.morphPreserve === void 0) {
240
+ fromParent.removeChild(fromChild);
241
+ }
242
+ } else {
228
243
  fromParent.removeChild(fromChild);
229
244
  }
230
245
  fromChild = next;
@@ -255,7 +270,8 @@ function morphElement(fromEl, toEl, ownedItems) {
255
270
  if (isTextInputOrTextarea(fromEl)) preserveTextEntryState(fromEl, toEl);
256
271
  }
257
272
  morphAttributes(fromEl, toEl);
258
- diffChildren(fromEl, toEl, ownedItems);
273
+ if (fromEl.dataset.morphSkipChildren !== void 0) return;
274
+ morphChildren(fromEl, toEl, ownedItems);
259
275
  }
260
276
  function isUserAgentOwnedAttr(tagName, name) {
261
277
  return name === "open" && (tagName === "DETAILS" || tagName === "DIALOG");
@@ -715,7 +731,7 @@ function runSubsequentRender(rootEl, segment, bindings, renderCtx, prevStaticHtm
715
731
  cleanupOrphanBindings(segment, bindings, renderCtx);
716
732
  const template = rootEl.cloneNode(false);
717
733
  template.innerHTML = currentStaticHtml;
718
- diff(rootEl, template, collectOwnedItems(bindings));
734
+ morph(rootEl, template, collectOwnedItems(bindings));
719
735
  bindListsFromMarkers(rootEl, segment, bindings, false);
720
736
  return currentStaticHtml;
721
737
  }
@@ -855,6 +871,6 @@ function toElement(jsx) {
855
871
  return child;
856
872
  }
857
873
 
858
- export { delegate, delegateCapture, each, mount, toElement };
874
+ export { delegate, delegateCapture, each, morph, mount, toElement };
859
875
  //# sourceMappingURL=index.js.map
860
876
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/delegate.ts","../src/each.ts","../src/diff.ts","../src/list-binding.ts","../src/list-reconcile-focus.ts","../src/utils/rowContract.ts","../src/list-reconcile-granular.ts","../src/list-reconcile-snapshot.ts","../src/list-reconcile.ts","../src/mount.ts","../src/toElement.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Tiny event-delegation helpers. Replace per-element `addEventListener` calls\n * (which don't survive morph re-renders for nodes the diff creates) with one\n * listener at the morph-root that dispatches via `closest()`.\n *\n * Three-tier listener model:\n *\n * - Tier 1 (bubbling events) — use `delegate()`.\n * click, input, change, submit, mousedown/up, keydown/up, pointerdown/up/move,\n * drag*, drop, contextmenu, wheel, copy/paste/cut, focusin/focusout.\n *\n * `delegate()` also auto-promotes the well-known non-bubbling event\n * types (`focus`, `blur`, `scroll`, `load`, `error`, `mouseenter`,\n * `mouseleave`) to the capture phase under the hood, so the call site\n * looks identical for \"interactive thing happens on a descendant\"\n * regardless of whether that event bubbles. Selector matching stays\n * `closest()`-style — the same as for bubbling events — so a wrapper\n * selector like `'.field-row'` still matches when the event fires on\n * a descendant `<input>`.\n *\n * - Tier 2 (explicit capture) — use `delegateCapture()`.\n * The escape hatch for cases the auto-promotion list doesn't cover, or\n * when you want capture-phase semantics and direct `matches()`-style\n * selector matching (no walk-up).\n *\n * - Tier 3 (per-element instances / library-owned subtrees) — mark the\n * host element with `data-morph-skip` and manage the library's\n * lifecycle directly. No delegation helper applies.\n */\n\ntype Handler = (event: Event, target: Element) => void;\n\n/**\n * Event types that don't bubble and so wouldn't reach a root-level\n * bubble-phase listener. `delegate()` flips to capture for these; the\n * caller doesn't need to know or care.\n *\n * Membership is conservative — it covers the cases that \"should obviously\n * work\" with delegate() but otherwise don't. For exotic non-bubbling events\n * (custom events, less-common DOM events) the explicit `delegateCapture()`\n * remains the escape hatch.\n */\nconst NON_BUBBLING = new Set<string>([\n 'focus',\n 'blur',\n 'scroll',\n 'load',\n 'error',\n 'mouseenter',\n 'mouseleave',\n]);\n\n/**\n * Validate a CSS selector at registration time, so a typo throws immediately\n * with the bad selector quoted instead of producing a cryptic DOMException\n * the first time a matching event fires.\n */\nfunction assertValidSelector(selector: string, fn: string): void {\n try {\n document.createElement('div').matches(selector);\n } catch {\n throw new Error(\n `${fn}: invalid selector \"${selector}\". `\n + 'Pass a valid CSS selector (e.g. \\'[data-action=\"add\"]\\', \\'.btn\\', \\'input\\').',\n );\n }\n}\n\n/**\n * Delegation that \"just works\" for both bubbling and the common non-bubbling\n * events. Installs ONE listener on `rootEl`; for known non-bubblers (see\n * `NON_BUBBLING` above) the listener is registered on the capture phase so\n * it actually reaches the target, otherwise on the bubble phase. Either way,\n * matching walks up from `event.target` via `closest(selector)` and fires\n * `handler(event, matched)` if the match is inside `rootEl`.\n *\n * Returns a disposer that removes the listener.\n *\n * Usage (pseudo-code — see examples for live ones):\n * delegate(rootEl, 'click', '[data-action=\"add\"]', handlerFn);\n * delegate(rootEl, 'focus', 'input', handlerFn); // auto-capture\n */\nexport function delegate(\n rootEl: HTMLElement,\n type: string,\n selector: string,\n handler: Handler,\n): () => void {\n assertValidSelector(selector, 'delegate');\n const listener = (event: Event): void => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n const matched = target.closest(selector);\n if (matched !== null && rootEl.contains(matched)) {\n handler(event, matched);\n }\n };\n const capture = NON_BUBBLING.has(type);\n rootEl.addEventListener(type, listener, capture);\n return () => {\n rootEl.removeEventListener(type, listener, capture);\n };\n}\n\n/**\n * Capture-phase delegation — for non-bubbling events (`focus`, `blur`,\n * `scroll`, `load`, `error`). Reaches descendants of `rootEl` that match\n * `selector` regardless of how many times the diff has rebuilt them.\n *\n * Usage (pseudo-code — see examples for live ones):\n * delegateCapture(rootEl, 'focus', 'input, textarea', handlerFn);\n */\nexport function delegateCapture(\n rootEl: HTMLElement,\n type: string,\n selector: string,\n handler: Handler,\n): () => void {\n assertValidSelector(selector, 'delegateCapture');\n const listener = (event: Event): void => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n if (target.matches(selector) && rootEl.contains(target)) {\n handler(event, target);\n }\n };\n rootEl.addEventListener(type, listener, true);\n return () => {\n rootEl.removeEventListener(type, listener, true);\n };\n}\n","/**\n * `each(items, render, key?)` — keyed list iteration with per-item memoisation.\n *\n * Drops in as the body of a list-rendering JSX expression inside a `mount()`\n * render function. Returns a `SafeHtml` carrying a structured list segment,\n * so `mount()` can run a native keyed reconciler instead of the general-\n * purpose morph for these children.\n *\n * Two layers of optimisation:\n *\n * 1. Per-item memoisation. `render(item)` is skipped for items whose object\n * identity (and optional `key`) are unchanged since the previous call.\n * Their HTML strings come from a `WeakMap` keyed by item reference. The\n * immutable-update style (\"replace the row object\" instead of \"mutate it\")\n * makes the cache work automatically.\n *\n * 2. Structural handoff. `mount()` recognises the list segment and bypasses\n * the parse-the-whole-table round trip: only fresh items get parsed (one\n * at a time, into the smallest detached element), and only changed rows\n * get patched in the live DOM. Unchanged rows are physically the same\n * nodes they were before — never visited.\n *\n * `key` covers the case where external state, not the item itself, drives\n * what the row should render (e.g. a \"currently selected\" id flips a CSS\n * class on one row). Same item identity but a different `key` value means\n * \"re-render this item.\" If you don't pass `key`, only identity changes\n * invalidate.\n *\n * Items must be objects (cache is a `WeakMap`); wrap primitives if you need\n * to iterate them. Each item's render output must produce exactly one\n * top-level element — the list reconciler binds one live DOM node per item.\n */\n\nimport type { ArraySignal } from './array-signal.js';\nimport type { SafeHtml } from './jsx-runtime.js';\nimport { granularListSafeHtml, isSafeHtml, listSafeHtml } from './jsx-runtime.js';\nimport type { ArrayPatchInternal } from './segment.js';\n\n/**\n * Cross-bundle brand check for `ArraySignal` instances (KF-95). The\n * `arraySignal` factory + class live in their own subpath\n * (`kerfjs/array-signal`); this module knows nothing about that\n * subpath at runtime — it identifies instances by the brand symbol\n * stamped on them. Apps that never import `arraySignal` shed the\n * ~1 KB of class code without breaking the structural contract here.\n */\nconst ARRAY_SIGNAL_BRAND = Symbol.for('kerfjs.ArraySignal');\n\nfunction isArraySignal<T extends object>(value: unknown): value is ArraySignal<T> {\n return typeof value === 'object'\n && value !== null\n && (value as Record<symbol, unknown>)[ARRAY_SIGNAL_BRAND] === true;\n}\n\ninterface CacheEntry {\n key: unknown;\n html: string;\n}\n\n/**\n * Per-render context passed in by `mount()` for the duration of one render\n * pass. Carries (a) a counter that assigns a stable list id to the n-th\n * `each()` call across renders within a mount, and (b) a per-mount cache map\n * keyed on those list ids.\n *\n * Why per-(mount, listId) keying for the cache:\n * - Same `each()` callsite across renders within a mount → same id → same\n * cache → cache hits work, even when the JSX render fn is an inline arrow\n * that's a fresh function reference on every closure run (the typical\n * pattern; KF-87 fixed the regression where this broke).\n * - Different `each()` callsites within the same mount → different ids →\n * separate caches → no cross-callsite collision (the case KF-73 fixed,\n * preserved here).\n * - Different mounts → different `RenderContext` instances (the cache map\n * lives on `mount()`'s closure) → separate caches.\n *\n * Outside a `mount()` render (e.g. `each(...).toString()` for SSR string\n * production) `context` is null and items are rendered every call —\n * caching is a `mount()` feature, not a global one.\n */\nexport interface RenderContext {\n counter: number;\n caches: Map<string, WeakMap<object, CacheEntry>>;\n /**\n * Per-list-id record of the binding's `items.length` after the most recent\n * successful reconcile. Maintained by `mount()` via `_setBindingCount`. The\n * granular path consults this to detect drift between the live binding and\n * the arraySignal — drift means a previous render threw mid-reconcile (or\n * a granular path was bypassed externally), so the next render forces a\n * snapshot rebuild rather than applying patches against a stale binding.\n */\n bindingCounts: Map<string, number>;\n}\n\nlet context: RenderContext | null = null;\n\nexport function _setRenderContext(c: RenderContext | null): void {\n context = c;\n}\n\nexport function each<T extends object>(\n items: readonly T[] | ArraySignal<T>,\n render: (item: T, index: number) => SafeHtml | string,\n key?: (item: T, index: number) => unknown,\n): SafeHtml {\n // KF-92 fast path: when items is an ArraySignal AND we're inside a mount\n // render context AND patches have queued since the last drain, emit a\n // granular list segment that the list reconciler applies in O(patches)\n // instead of O(N). Detection via the brand symbol (KF-95) — the\n // `arraySignal` class lives in the `kerfjs/array-signal` subpath and is\n // not imported here at runtime.\n if (isArraySignal<T>(items) && context !== null) {\n return eachGranular(items, render, key);\n }\n const snapshotItems: readonly T[] = isArraySignal<T>(items)\n ? items.value as readonly T[]\n : items;\n return eachSnapshot(snapshotItems, render, key);\n}\n\nfunction eachSnapshot<T extends object>(\n items: readonly T[],\n render: (item: T, index: number) => SafeHtml | string,\n key: ((item: T, index: number) => unknown) | undefined,\n): SafeHtml {\n let id: string;\n if (context !== null) {\n id = String(context.counter++);\n } else {\n id = 'orphan';\n }\n return eachSnapshotById(items, render, key, id);\n}\n\n/**\n * Granular path for `arraySignal`-backed lists. Drains queued patches and\n * emits a list segment that the reconciler applies to the existing binding\n * directly — no full iteration of the snapshot, no O(N) classify pass.\n *\n * On the very first render of a list, the binding doesn't exist yet, so\n * the reconciler falls through to the snapshot path. Subsequent renders\n * of the same list (where the binding now exists) take the granular path\n * whenever there are patches to apply.\n */\nfunction eachGranular<T extends object>(\n sig: ArraySignal<T>,\n render: (item: T, index: number) => SafeHtml | string,\n key: ((item: T, index: number) => unknown) | undefined,\n): SafeHtml {\n // We're inside a mount context (caller-checked).\n const ctx = context as RenderContext;\n const id = String(ctx.counter++);\n // KF-98: a tracked binding count means a prior render of this mount has\n // successfully reconciled this list. On the very first render (no count\n // recorded yet) the granular reconciler has no binding to apply patches\n // to, so any pre-mount mutations would silently produce an empty list.\n // Drain the queue (the snapshot already reflects those mutations) and\n // take the snapshot path; the count will be recorded for the next render.\n const previousBindingCount = ctx.bindingCounts.get(id);\n const patches = sig._consumePatches();\n const snapshot = sig.value as readonly T[];\n\n // First render of this list, no patches, or any 'replace' patch → snapshot.\n // No patches: typical re-render triggered by a non-arraySignal signal change.\n // 'replace': wholesale reset — granular can't help; the snapshot already\n // reflects the post-replace state (and any subsequent granular ops).\n if (previousBindingCount === undefined || patches.length === 0) {\n return eachSnapshotById(snapshot, render, key, id);\n }\n // KF-99: detect drift between the live binding and the arraySignal. After\n // a clean prior reconcile, `previousBindingCount + (#inserts - #removes)`\n // must equal `snapshot.length`. If it doesn't, a previous render threw\n // mid-reconcile and left the binding inconsistent with the signal — fall\n // back to the snapshot path, which classifies fresh against `snapshot`\n // and rebuilds the binding to match.\n let netDelta = 0;\n for (const p of patches) {\n if (p.type === 'insert') netDelta += 1;\n else if (p.type === 'remove') netDelta -= 1;\n else if (p.type === 'replace') {\n return eachSnapshotById(snapshot, render, key, id);\n }\n }\n // Defensive: triggered only when an external party drains `_consumePatches()`\n // or mutates `_items` behind arraySignal's back, OR when a previous reconcile\n // threw mid-DOM-op (rare; not naturally reachable in tests since apply* ops\n // don't throw on well-formed row HTML).\n /* c8 ignore next 3 */\n if (previousBindingCount + netDelta !== snapshot.length) {\n return eachSnapshotById(snapshot, render, key, id);\n }\n\n // Granular path: pre-render every insert/update HTML at JSX-eval time so\n // a throwing render is caught here and we can fall back to the snapshot\n // path (KF-99). Without this, a throw mid-batch would leave patches drained\n // (already done above), the signal mutated, and the live DOM unchanged —\n // permanent divergence with no recovery.\n const renderFnInternal = (item: object, index: number): string => {\n const out = render(item as T, index);\n return isSafeHtml(out) ? out.toString() : out;\n };\n const internalPatches = new Array<ArrayPatchInternal>(patches.length);\n try {\n for (let i = 0; i < patches.length; i++) {\n const p = patches[i];\n if (p.type === 'insert' || p.type === 'update') {\n internalPatches[i] = {\n type: p.type, index: p.index, item: p.item as object,\n html: renderFnInternal(p.item as object, p.index),\n };\n } else {\n internalPatches[i] = p as ArrayPatchInternal;\n }\n }\n } catch {\n // Pre-render threw. The snapshot already reflects every mutation\n // (arraySignal mutates _items eagerly at the call site), but the snapshot\n // path is going to throw on the same bad item too — leaving the binding\n // out of sync with the signal. Clear the binding count so the NEXT\n // render (after the user fixes the bad item) doesn't see the previous\n // render's count and falsely conclude there's no drift; instead it'll\n // take the snapshot path and rebuild from scratch.\n ctx.bindingCounts.delete(id);\n return eachSnapshotById(snapshot, render, key, id);\n }\n // The `items` field is left empty for the granular case — the reconciler\n // doesn't need it; every insert/update patch carries pre-rendered HTML.\n return granularListSafeHtml(id, [], internalPatches);\n}\n\n/** Like eachSnapshot but uses a pre-allocated id (caller already advanced the counter). */\nfunction eachSnapshotById<T extends object>(\n items: readonly T[],\n render: (item: T, index: number) => SafeHtml | string,\n key: ((item: T, index: number) => unknown) | undefined,\n id: string,\n): SafeHtml {\n let cache: WeakMap<object, CacheEntry> | null = null;\n if (context !== null) {\n let c = context.caches.get(id);\n if (c === undefined) {\n c = new WeakMap<object, CacheEntry>();\n context.caches.set(id, c);\n }\n cache = c;\n }\n const segItems = new Array<{ ref: object; cacheKey: unknown; html: string }>(items.length);\n const seen = new Set<object>();\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (typeof item !== 'object' || item === null) {\n throw new Error(\n `each(): items must be objects (the per-item HTML cache is a WeakMap), got ${item === null ? 'null' : typeof item} at index ${i}. `\n + 'Wrap primitives if you need to iterate them, e.g. items.map(v => ({ v })).',\n );\n }\n if (seen.has(item)) {\n throw new Error(\n `each(): the same object reference appears at multiple indices in items (first seen earlier, again at index ${i}). `\n + 'The per-item HTML cache is keyed on object identity, so duplicate references break the keyed reconciler and can leak DOM nodes on re-render. '\n + 'Use a fresh object per row (e.g. items.map(o => ({ ...o })) before passing to each()).',\n );\n }\n seen.add(item);\n const k = key ? key(item, i) : undefined;\n let html: string;\n const cached = cache !== null ? cache.get(item) : undefined;\n if (cached !== undefined && cached.key === k) {\n html = cached.html;\n } else {\n const out = render(item, i);\n html = isSafeHtml(out) ? out.toString() : out;\n if (cache !== null) cache.set(item, { key: k, html });\n }\n segItems[i] = { ref: item, cacheKey: k, html };\n }\n return listSafeHtml(id, segItems);\n}\n","/**\n * `diff(liveRoot, templateRoot, ownedItems)` — minimum-mutation DOM\n * reconciliation.\n *\n * Replaces our previous dependency on `morphdom`. The algorithm is the\n * classic two-tree walk: match children by key (id, then data-key, then\n * positional same-tag), morph matches in place, insert / remove / clone\n * the rest. Specialised for what kerf needs:\n *\n * - `childrenOnly` is always true; the live root is never replaced.\n * - Per-element short-circuits: `data-morph-skip` (library-owned, leave\n * verbatim) and `isEqualNode` (byte-identical, no work needed).\n * - **`ownedItems`** is the set of element nodes owned by an `each()`\n * list reconciler. The diff skips them in every children walk —\n * they're not added to the keyed-lookup map, the from-cursor advances\n * past them, and the trailing-removal pass leaves them in place. This\n * lets each() coexist with non-list siblings inside the same parent\n * (KF-102 round 2): the diff still walks the parent's children to\n * reconcile siblings, but never disturbs list rows.\n * - Focused text inputs (`<input>`/`<textarea>`) keep their value +\n * selection across the morph; focused `[contenteditable]` keeps its\n * entire subtree (typed content + caret + multi-range selection).\n *\n * Algorithm credit: based on the design of\n * https://github.com/patrick-steele-idem/morphdom by Patrick Steele-Idem\n * (MIT licensed). Reimplemented here so kerf can specialise the hot paths\n * (segment-aware list dispatch, lighter callback surface) and drop the\n * runtime dependency. Original copyright preserved in `LICENSE`.\n */\n\nconst ID_KEY_PREFIX = 'id:';\nconst DATA_KEY_PREFIX = 'data-key:';\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\n\nfunction getNodeKey(node: Node): string | undefined {\n if (node.nodeType !== ELEMENT_NODE) return undefined;\n const el = node as HTMLElement;\n if (el.id !== '') return `${ID_KEY_PREFIX}${el.id}`;\n if (el.dataset !== undefined && el.dataset.key !== undefined) {\n return `${DATA_KEY_PREFIX}${el.dataset.key}`;\n }\n return undefined;\n}\n\n/**\n * Reconcile the children of `liveRoot` to match the children of\n * `templateRoot`. `ownedItems` is the set of element nodes owned by `each()`\n * list reconcilers — the diff skips them in every children walk.\n */\nexport function diff(\n liveRoot: Element,\n templateRoot: Element,\n ownedItems: ReadonlySet<Element>,\n): void {\n diffChildren(liveRoot, templateRoot, ownedItems);\n}\n\n/**\n * Advance past any owned (list-reconciler-managed) element. Owned items\n * stay put across diffs — they're invisible to the diff's child cursor.\n */\nfunction skipOwned(node: Node | null, ownedItems: ReadonlySet<Element>): Node | null {\n while (node !== null && node.nodeType === ELEMENT_NODE\n && ownedItems.has(node as Element)) {\n node = node.nextSibling;\n }\n return node;\n}\n\nfunction diffChildren(\n fromParent: Element,\n toParent: Element,\n ownedItems: ReadonlySet<Element>,\n): void {\n // Build a keyed lookup from the live children so we can match by key\n // even after reorders. Owned items don't participate in keyed matching\n // (they're not visible to the diff).\n const keyed = new Map<string, Element>();\n for (let c = fromParent.firstChild; c !== null; c = c.nextSibling) {\n if (c.nodeType === ELEMENT_NODE && ownedItems.has(c as Element)) continue;\n const k = getNodeKey(c);\n if (k !== undefined) keyed.set(k, c as Element);\n }\n\n let fromChild: Node | null = skipOwned(fromParent.firstChild, ownedItems);\n let toChild: Node | null = toParent.firstChild;\n\n while (toChild !== null) {\n const toNext = toChild.nextSibling;\n let matched: Node | null = null;\n\n // 1. Try key match.\n const toKey = getNodeKey(toChild);\n if (toKey !== undefined && keyed.has(toKey)) {\n matched = keyed.get(toKey) as Element;\n keyed.delete(toKey);\n if (matched !== fromChild) {\n fromParent.insertBefore(matched, fromChild);\n } else {\n fromChild = skipOwned(fromChild.nextSibling, ownedItems);\n }\n }\n\n // 2. Fall back to positional match — same nodeType, same tag (for\n // elements), and the live node has no key (a keyed node only\n // matches by key, never positionally, so reorders work).\n if (matched === null && fromChild !== null\n && fromChild.nodeType === toChild.nodeType\n && (toChild.nodeType !== ELEMENT_NODE\n || ((fromChild as Element).tagName === (toChild as Element).tagName\n && getNodeKey(fromChild) === undefined))) {\n matched = fromChild;\n fromChild = skipOwned(fromChild.nextSibling, ownedItems);\n }\n\n if (matched !== null) {\n morphNode(matched, toChild, ownedItems);\n } else {\n // 3. No match — clone the new node and insert before fromChild\n // (which may be an owned item we deliberately stopped at; that's\n // fine — `insertBefore(node, ownedItem)` slots the new sibling\n // in immediately before the list region).\n const cloned = toChild.cloneNode(true);\n fromParent.insertBefore(cloned, fromChild);\n }\n\n toChild = toNext;\n }\n\n // 4. Anything past the cursor is unmatched — remove, except for owned\n // items (those stay; they belong to a list reconciler).\n while (fromChild !== null) {\n const next = fromChild.nextSibling;\n if (fromChild.nodeType !== ELEMENT_NODE\n || !ownedItems.has(fromChild as Element)) {\n fromParent.removeChild(fromChild);\n }\n fromChild = next;\n }\n}\n\nfunction morphNode(\n fromNode: Node,\n toNode: Node,\n ownedItems: ReadonlySet<Element>,\n): void {\n if (fromNode.nodeType === ELEMENT_NODE) {\n morphElement(fromNode as Element, toNode as Element, ownedItems);\n return;\n }\n if (fromNode.nodeType === TEXT_NODE || fromNode.nodeType === COMMENT_NODE) {\n const fromText = fromNode as CharacterData;\n const toText = toNode as CharacterData;\n if (fromText.data !== toText.data) fromText.data = toText.data;\n }\n}\n\nfunction morphElement(\n fromEl: Element,\n toEl: Element,\n ownedItems: ReadonlySet<Element>,\n): void {\n if (fromEl.tagName !== toEl.tagName) {\n const replacement = toEl.cloneNode(true);\n fromEl.parentNode?.replaceChild(replacement, fromEl);\n return;\n }\n // 1. Library-owned subtree — leave verbatim.\n if ((fromEl as HTMLElement).dataset.morphSkip !== undefined) return;\n // 2. Byte-identical — nothing to do.\n if (fromEl.isEqualNode(toEl)) return;\n // 3. Focused contenteditable — preserve user's in-progress edit.\n if (fromEl === document.activeElement) {\n const ce = fromEl.getAttribute('contenteditable');\n if (ce !== null && ce.toLowerCase() !== 'false') return;\n if (isTextInputOrTextarea(fromEl)) preserveTextEntryState(fromEl, toEl);\n }\n morphAttributes(fromEl, toEl);\n // 4. Recurse into children. List items inside `fromEl` (if any) are\n // skipped via `ownedItems` inside diffChildren — list reconciler\n // owns them — but non-list siblings are still diffed.\n diffChildren(fromEl, toEl, ownedItems);\n}\n\n/**\n * Attributes the user agent toggles in response to user interaction.\n * `<details>` and `<dialog>` add/remove `open=\"\"` themselves when the user\n * expands or closes the element. If the developer's JSX never mentions\n * `open`, treating that attribute as user-agent-owned and leaving it alone\n * during the morph keeps the user-driven state intact across re-renders.\n *\n * Trade-off (KF-84): controlled-style `<details open={signal.value}>` where\n * the signal flips false won't auto-collapse the element, because the\n * morph's remove pass no longer reaches `open`. Apps that need controlled\n * behaviour should drive `open` imperatively (e.g. `el.removeAttribute('open')`\n * inside an action) or wrap with a state-toggle pattern. The uncontrolled\n * case is the common one and the one that was silently broken before.\n */\nfunction isUserAgentOwnedAttr(tagName: string, name: string): boolean {\n return name === 'open' && (tagName === 'DETAILS' || tagName === 'DIALOG');\n}\n\nfunction morphAttributes(fromEl: Element, toEl: Element): void {\n // Set/update every attribute on toEl.\n const toAttrs = toEl.attributes;\n for (let i = 0; i < toAttrs.length; i++) {\n const attr = toAttrs[i];\n const ns = attr.namespaceURI;\n const name = attr.localName;\n const value = attr.value;\n if (ns !== null) {\n if (fromEl.getAttributeNS(ns, name) !== value) {\n fromEl.setAttributeNS(ns, attr.name, value);\n }\n } else if (fromEl.getAttribute(name) !== value) {\n fromEl.setAttribute(name, value);\n }\n }\n // Remove attributes that are no longer present on toEl.\n const fromAttrs = fromEl.attributes;\n const fromTag = fromEl.tagName;\n for (let i = fromAttrs.length - 1; i >= 0; i--) {\n const attr = fromAttrs[i];\n const ns = attr.namespaceURI;\n const name = attr.localName;\n if (ns !== null) {\n if (!toEl.hasAttributeNS(ns, name)) fromEl.removeAttributeNS(ns, name);\n } else if (!toEl.hasAttribute(name) && !isUserAgentOwnedAttr(fromTag, name)) {\n fromEl.removeAttribute(name);\n }\n }\n}\n\nfunction isTextInputOrTextarea(el: Element): boolean {\n if (el.tagName === 'TEXTAREA') return true;\n if (el.tagName === 'INPUT') {\n const type = (el as HTMLInputElement).type;\n return type === 'text' || type === 'search' || type === 'url' || type === 'email'\n || type === 'tel' || type === 'password' || type === '';\n }\n return false;\n}\n\nfunction preserveTextEntryState(fromEl: Element, toEl: Element): void {\n if (fromEl.tagName === 'TEXTAREA' || fromEl.tagName === 'INPUT') {\n const fromInput = fromEl as HTMLInputElement;\n const toInput = toEl as HTMLInputElement;\n toInput.value = fromInput.value;\n try {\n toInput.setSelectionRange(fromInput.selectionStart, fromInput.selectionEnd);\n } catch {\n // Some input types (number, range, color, …) reject selection APIs.\n }\n }\n}\n","/**\n * Per-list binding shape kept by `mount()` and consumed by both reconcile\n * paths in `list-reconcile-snapshot.ts` and `list-reconcile-granular.ts`.\n *\n * Living in its own file (not re-exported through `list-reconcile.ts`) so\n * the snapshot + granular paths can import it without creating a circular\n * dependency on `list-reconcile.ts` itself. ESM handles cycles via function\n * hoisting, but a cycle involving a non-function helper would be a temporal\n * dead zone — extracting the binding shape + `endAnchor` here keeps the\n * dependency graph acyclic.\n */\n\nexport interface BoundItem {\n ref: object;\n cacheKey: unknown;\n html: string;\n node: Element;\n}\n\nexport interface ListBinding {\n liveParent: Element;\n /**\n * One entry per item currently mounted under `liveParent`, in order.\n * Mirrors the segment's `items` length after each reconcile.\n */\n items: BoundItem[];\n /**\n * The list's `<!--kf-list:N-->` start marker, kept in the live DOM as\n * a permanent anchor (KF-102 round 2). The marker stays put across\n * static-surrounds diffs (it morphs as a comment node), so it gives\n * the list reconciler a stable \"begin\" position even when surrounding\n * siblings get inserted, removed, or reordered around the list.\n *\n * `endAnchor(binding)` derives the \"insert at end of list\" anchor from\n * `marker.nextElementSibling` (empty list) or\n * `items[last].node.nextElementSibling` (non-empty list) — picking up\n * any non-list element the diff inserted between the list and the\n * parent's tail.\n */\n marker: Comment;\n}\n\n/**\n * Compute the live-DOM anchor that comes after the list's last item, used\n * by the apply* functions when inserting at the tail of the list.\n *\n * - Empty list: `marker.nextElementSibling` — the next non-list element\n * after the marker, or `null` if the list is the last thing in `liveParent`.\n * - Non-empty list: `items[last].node.nextElementSibling` — derived\n * dynamically so that non-list siblings the diff inserted between the\n * list's last item and the parent's tail still anchor correctly.\n */\nexport function endAnchor(binding: ListBinding): Element | null {\n if (binding.items.length > 0) {\n return binding.items[binding.items.length - 1].node.nextElementSibling;\n }\n return binding.marker.nextElementSibling;\n}\n","/**\n * Focus snapshot/restore for the keyed list reconciler.\n *\n * Some engines (older Safari, happy-dom) drop focus state on `insertBefore`\n * even when the focused element survives the move connected to the document.\n * The reconciler snapshots the active element + selection range before its\n * move pass, then re-applies them afterwards. Engines that already preserve\n * focus across DOM moves see a no-op; engines that don't get a transparent\n * fix.\n *\n * Lives in its own file (rather than inside `list-reconcile.ts`) to keep that\n * file under the 200-LOC project guideline and to isolate the engine-quirk\n * handling described in `docs/4-render.md` §4.4.\n */\n\nexport interface FocusSnapshot {\n el: HTMLElement;\n selStart: number | null;\n selEnd: number | null;\n}\n\n/**\n * Capture focus + selection on a focused descendant of `liveParent`.\n *\n * Returns null when the active element is outside the list (the diff path\n * handles those cases) or when there's no useful focus state to capture.\n */\nexport function captureFocus(liveParent: Element): FocusSnapshot | null {\n const active = document.activeElement;\n if (active === null || active === document.body) return null;\n if (!liveParent.contains(active)) return null;\n const el = active as HTMLElement;\n let selStart: number | null = null;\n let selEnd: number | null = null;\n if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {\n try {\n selStart = (el as HTMLInputElement).selectionStart;\n selEnd = (el as HTMLInputElement).selectionEnd;\n } catch {\n // Some input types (number, range, color, …) reject selection APIs.\n }\n }\n return { el, selStart, selEnd };\n}\n\nexport function restoreFocus(snap: FocusSnapshot): void {\n if (document.activeElement === snap.el) return;\n if (!snap.el.isConnected) return;\n snap.el.focus();\n if (snap.selStart !== null && snap.selEnd !== null) {\n try {\n (snap.el as HTMLInputElement).setSelectionRange(snap.selStart, snap.selEnd);\n } catch {\n // Selection may have been clobbered by .focus(); not fatal.\n }\n }\n}\n","/**\n * Shared \"exactly one top-level element per row\" contract helpers (KF-103).\n *\n * The keyed-list reconciler in `list-reconcile.ts` and the first-render\n * binding path in `mount.ts` both enforce the same contract on `each()`\n * row HTML. Centralising the constants and helpers here keeps the three\n * call sites that build error snippets and the eight call sites that\n * parse a row's HTML into a template element from drifting (KF-111 +\n * KF-115).\n */\n\n/**\n * Truncation limit applied to row HTML when including it in a contract-\n * violation error message. Keeps the error readable when a row produced\n * megabytes of HTML by accident.\n */\nexport const ROW_HTML_SNIPPET_MAX = 120;\n\n/**\n * Truncate a row's HTML for inclusion in an error message. Returns the\n * raw string if it's short enough; otherwise the first\n * `ROW_HTML_SNIPPET_MAX` characters with a trailing ellipsis.\n */\nexport function truncateRowHtml(html: string): string {\n return html.length > ROW_HTML_SNIPPET_MAX\n ? html.slice(0, ROW_HTML_SNIPPET_MAX) + '…'\n : html;\n}\n\n/**\n * Parse a row's HTML into a `<template>` and report how many top-level\n * elements it produced. The reconciler uses the count to detect contract\n * violations (count !== 1) on both single-row and bulk-row paths.\n */\nexport function parseRowTemplate(html: string): { tpl: HTMLTemplateElement; count: number } {\n const tpl = document.createElement('template');\n tpl.innerHTML = html;\n return { tpl, count: tpl.content.children.length };\n}\n\n/**\n * Build a precise contract-violation `Error` for the row at `index` whose\n * render produced the given `html`. The thrown message mentions the row\n * index, the actual element count, and the (truncated) HTML so the author\n * can locate and fix the offending row quickly.\n */\nexport function rowContractError(index: number, html: string): Error {\n const { count } = parseRowTemplate(html);\n const reason = count === 0\n ? 'produced no top-level element'\n : `produced ${count} top-level elements; exactly one is required`;\n return new Error(\n `each(): row render at index ${index} ${reason}. `\n + 'Each item\\'s render must return exactly one element — '\n + 'wrap multiple roots in a single parent (e.g. <li>...</li>). '\n + `Got HTML: ${JSON.stringify(truncateRowHtml(html))}`,\n );\n}\n","/**\n * Granular reconcile path for `each(...)` bound to an `arraySignal` (KF-92).\n *\n * Applies the patch events emitted by `arraySignal` mutators directly to\n * the live DOM and to `binding.items`, without iterating the full snapshot\n * or doing a classify pass. Cost is O(patches), not O(N).\n *\n * Two perf optimisations:\n * - **KF-93**: contiguous insert runs (patches at index N, N+1, N+2, …) are\n * bulk-parsed in one `template.innerHTML` call and inserted as a single\n * fragment. Saves ~50 ms on append-1k.\n * - **KF-94**: consecutive update runs (any indices — `replaceChild`\n * operates on each row's existing live node independently) are bulk-\n * parsed in one `template.innerHTML` call. Saves the per-patch parse\n * cost on the krausest partial-update scenario.\n *\n * Patches with `type: 'replace'` are filtered out by `each()` upstream and\n * never reach this function (the runtime contract guarantees absence even\n * though the TypeScript type allows them).\n *\n * Internal to kerf — re-exported via `list-reconcile.ts`'s `reconcileList`.\n */\n\nimport { type BoundItem, endAnchor, type ListBinding } from './list-binding.js';\nimport { captureFocus, restoreFocus } from './list-reconcile-focus.js';\nimport type { ListSegment } from './segment.js';\nimport { parseRowTemplate, rowContractError, truncateRowHtml } from './utils/rowContract.js';\n\nexport function reconcileGranular(\n binding: ListBinding,\n patches: NonNullable<ListSegment['patches']>,\n): void {\n const { liveParent } = binding;\n const items = binding.items;\n\n // Capture/restore focus around the whole batch (mirrors the snapshot\n // path's KF-65 fix). Some engines (older Safari, happy-dom) blur a\n // focused descendant on `insertBefore` / `replaceChild` even when the\n // ancestor stays connected — covers the move patch (which moves an\n // existing row's <li>), and is a no-op on engines that already\n // preserve focus across DOM ops.\n const focusSnap = captureFocus(liveParent);\n\n let i = 0;\n while (i < patches.length) {\n const patch = patches[i];\n /* c8 ignore next 5 — replace is filtered upstream by each(); this branch\n is defensive type-completeness only. */\n if (patch.type === 'replace') {\n i += 1;\n continue;\n }\n if (patch.type === 'update') {\n // KF-94: detect a run of consecutive update patches (any indices —\n // replaceChild operates on each row's existing live node independently,\n // so contiguity isn't required) and bulk-parse all their HTML in a\n // single `template.innerHTML` call. Saves the per-patch parse overhead\n // on krausest's partial-update scenario (100 update patches at\n // indices 0, 10, 20, … — non-contiguous, so KF-93's run detector\n // doesn't kick in).\n let runEnd = i + 1;\n while (runEnd < patches.length && patches[runEnd].type === 'update') {\n runEnd += 1;\n }\n const runLen = runEnd - i;\n if (runLen === 1) {\n applySingleUpdate(liveParent, items, patch);\n } else {\n applyBulkUpdate(liveParent, items, patches, i, runEnd);\n }\n i = runEnd;\n continue;\n }\n if (patch.type === 'insert') {\n // KF-93: detect a contiguous run of inserts at adjacent indices (each\n // next insert at the previous one's index + 1) and bulk-parse all\n // their HTML in a single `template.innerHTML` call, followed by a\n // single `insertBefore(fragment, anchor)`.\n let runEnd = i + 1;\n while (runEnd < patches.length\n && patches[runEnd].type === 'insert'\n && (patches[runEnd] as { index: number }).index\n === (patches[runEnd - 1] as { index: number }).index + 1) {\n runEnd += 1;\n }\n const runLen = runEnd - i;\n if (runLen === 1) {\n applySingleInsert(liveParent, items, patch, endAnchor(binding));\n } else {\n applyBulkInsert(liveParent, items, patches, i, runEnd, endAnchor(binding));\n }\n i = runEnd;\n continue;\n }\n if (patch.type === 'remove') {\n const entry = items[patch.index];\n liveParent.removeChild(entry.node);\n items.splice(patch.index, 1);\n i += 1;\n continue;\n }\n if (patch.type === 'move') {\n const moved = items[patch.from];\n // Compute the anchor BEFORE we splice, so the index references the\n // pre-move state.\n let anchorIdx = patch.to;\n if (patch.from < patch.to) anchorIdx += 1; // account for upcoming splice removal\n const anchor = anchorIdx < items.length ? items[anchorIdx].node : endAnchor(binding);\n liveParent.insertBefore(moved.node, anchor);\n items.splice(patch.from, 1);\n items.splice(patch.to, 0, moved);\n i += 1;\n continue;\n }\n }\n\n if (focusSnap !== null) restoreFocus(focusSnap);\n}\n\nfunction applySingleInsert(\n liveParent: Element,\n items: BoundItem[],\n patch: { type: 'insert'; index: number; item: object; html: string },\n tailAnchor: Element | null,\n): void {\n const { html } = patch;\n const newNode = parseSingleRow(html);\n const anchor = patch.index < items.length ? items[patch.index].node : tailAnchor;\n liveParent.insertBefore(newNode, anchor);\n items.splice(patch.index, 0, {\n ref: patch.item, cacheKey: undefined, html, node: newNode,\n });\n}\n\nfunction applySingleUpdate(\n liveParent: Element,\n items: BoundItem[],\n patch: { type: 'update'; index: number; item: object; html: string },\n): void {\n const { html } = patch;\n const oldEntry = items[patch.index];\n if (html === oldEntry.html) return; // no-op (defensive: caller may emit redundant patches)\n const newNode = parseSingleRow(html);\n liveParent.replaceChild(newNode, oldEntry.node);\n items[patch.index] = { ref: patch.item, cacheKey: undefined, html, node: newNode };\n}\n\n/**\n * Bulk-parse a run of consecutive update patches (KF-94). Indices may be\n * scattered (non-contiguous). Renders all HTMLs first, filters out no-ops\n * where the new HTML matches the old, then bulk-parses the remaining HTMLs\n * in one `template.innerHTML` call. The replaceChild loop afterwards is\n * unavoidable (one DOM op per row), but we save the per-patch parse cost.\n */\nfunction applyBulkUpdate(\n liveParent: Element,\n items: BoundItem[],\n patches: NonNullable<ListSegment['patches']>,\n start: number,\n end: number,\n): void {\n // Patches already carry pre-rendered HTML (KF-99). Filter out no-ops where\n // the new HTML matches the existing entry's html.\n interface Change { patchIdx: number; html: string }\n const changes: Change[] = [];\n for (let k = start; k < end; k++) {\n const p = patches[k] as { type: 'update'; index: number; item: object; html: string };\n if (p.html !== items[p.index].html) {\n changes.push({ patchIdx: k, html: p.html });\n }\n }\n if (changes.length === 0) return; // every update was a no-op\n\n // Bulk-parse all real changes in one innerHTML call.\n const { tpl, count } = parseRowTemplate(changes.map((c) => c.html).join(''));\n if (count !== changes.length) {\n throw findOffendingChange(patches, changes);\n }\n // Count matches; walk children unconditionally.\n const newNodes = new Array<Element>(changes.length);\n let child = tpl.content.firstElementChild;\n for (let k = 0; k < newNodes.length; k++) {\n newNodes[k] = child as Element;\n child = (child as Element).nextElementSibling;\n }\n\n // Apply replaceChild for each real change.\n for (let k = 0; k < changes.length; k++) {\n const c = changes[k];\n const p = patches[c.patchIdx] as { type: 'update'; index: number; item: object; html: string };\n const oldEntry = items[p.index];\n liveParent.replaceChild(newNodes[k], oldEntry.node);\n items[p.index] = { ref: p.item, cacheKey: undefined, html: c.html, node: newNodes[k] };\n }\n}\n\n/**\n * Bulk-parse a contiguous run of insert patches (KF-93). The run starts at\n * `start` (inclusive) and ends at `end` (exclusive); every patch in that\n * range is type `insert` with index === previous.index + 1. We render each\n * row's HTML, concatenate, parse the lot in one `template.innerHTML`, and\n * insert the resulting fragment in a single DOM op.\n */\nfunction applyBulkInsert(\n liveParent: Element,\n items: BoundItem[],\n patches: NonNullable<ListSegment['patches']>,\n start: number,\n end: number,\n tailAnchor: Element | null,\n): void {\n const startIdx = (patches[start] as { index: number }).index;\n const htmls = new Array<string>(end - start);\n for (let k = start; k < end; k++) {\n const p = patches[k] as { type: 'insert'; index: number; item: object; html: string };\n htmls[k - start] = p.html;\n }\n const { tpl, count } = parseRowTemplate(htmls.join(''));\n if (count !== htmls.length) {\n throw findOffendingInsert(patches, start, htmls);\n }\n // Count matches; capture child refs BEFORE the fragment-insert empties\n // tpl.content. Walk unconditionally — count check above guarantees\n // `firstElementChild` is non-null and there are exactly `end - start`\n // children.\n const newNodes = new Array<Element>(end - start);\n let child = tpl.content.firstElementChild;\n for (let k = 0; k < newNodes.length; k++) {\n newNodes[k] = child as Element;\n child = (child as Element).nextElementSibling;\n }\n const anchor = startIdx < items.length ? items[startIdx].node : tailAnchor;\n liveParent.insertBefore(tpl.content, anchor);\n // Splice all new entries into binding.items at the run's start index.\n const newEntries = new Array<BoundItem>(end - start);\n for (let k = 0; k < newEntries.length; k++) {\n const p = patches[start + k] as { type: 'insert'; index: number; item: object; html: string };\n newEntries[k] = {\n ref: p.item, cacheKey: undefined, html: htmls[k], node: newNodes[k],\n };\n }\n items.splice(startIdx, 0, ...newEntries);\n}\n\n/**\n * Parse a single row's HTML string into one Element. Used by the granular\n * reconciler's single-row paths (`applySingleInsert`, `applySingleUpdate`).\n * Each row is expected to render exactly one top-level element (the same\n * contract `each()` enforces in the snapshot path).\n */\nfunction parseSingleRow(html: string): Element {\n const { tpl, count } = parseRowTemplate(html);\n if (count !== 1) {\n const reason = count === 0\n ? 'produced no top-level element'\n : `produced ${count} top-level elements; exactly one is required`;\n throw new Error(\n `each() granular reconcile: row render ${reason}. `\n + 'Each item\\'s render must return exactly one element. '\n + `Got HTML: ${JSON.stringify(truncateRowHtml(html))}`,\n );\n }\n return tpl.content.firstElementChild as Element;\n}\n\n/**\n * Slow-path helper for `applyBulkInsert`. Walks each pre-rendered insert\n * patch's html in isolation to find the offending row.\n */\nfunction findOffendingInsert(\n patches: NonNullable<ListSegment['patches']>,\n start: number,\n htmls: string[],\n): Error {\n for (let i = 0; i < htmls.length; i++) {\n if (parseRowTemplate(htmls[i]).count !== 1) {\n const p = patches[start + i] as { type: 'insert'; index: number };\n return rowContractError(p.index, htmls[i]);\n }\n }\n /* c8 ignore start */\n return new Error('each(): bulk-insert mismatch with no per-row offender (kerf bug).');\n}\n/* c8 ignore stop */\n\n/**\n * Slow-path helper for `applyBulkUpdate`. Walks each non-no-op change to\n * find the offending row.\n */\nfunction findOffendingChange(\n patches: NonNullable<ListSegment['patches']>,\n changes: { patchIdx: number; html: string }[],\n): Error {\n for (const c of changes) {\n if (parseRowTemplate(c.html).count !== 1) {\n const p = patches[c.patchIdx] as { type: 'update'; index: number };\n return rowContractError(p.index, c.html);\n }\n }\n /* c8 ignore start */\n return new Error('each(): bulk-update mismatch with no per-row offender (kerf bug).');\n}\n/* c8 ignore stop */\n","/**\n * Snapshot reconcile path for `each(...)` — the original (non-granular)\n * keyed-list algorithm. Used when:\n * - The list is rendered with a plain array (not an `arraySignal`).\n * - The list is rendered with an `arraySignal` but no patch queue is\n * present (first render, post-`replace()`, or post-drift recovery).\n *\n * Algorithm:\n * 1. Classify each new item as `stable` (cache hit on identity + html),\n * `replaced` (same ref, html changed), or `new` (never seen before).\n * 2. Bulk-parse every fresh row's HTML in ONE `innerHTML` call — for an\n * initial population of 10k rows that's 1 parse instead of 10k.\n * 3. Remove orphan refs (gone from the new list) + replaced rows' old nodes.\n * 4. Compute a longest-increasing-subsequence over old positions; items in\n * the LIS are already in the right relative order, so they don't move.\n * 5. Reverse-pass over the new record, `insertBefore` only the items that\n * didn't anchor the LIS.\n *\n * The KF-89 fast path short-circuits when nothing structural changed —\n * the live tree already matches the new segment, so we can return after\n * step 1 with just the binding update.\n *\n * Internal to kerf — re-exported via `list-reconcile.ts`'s `reconcileList`.\n */\n\nimport { type BoundItem, endAnchor, type ListBinding } from './list-binding.js';\nimport { captureFocus, restoreFocus } from './list-reconcile-focus.js';\nimport type { ListSegment } from './segment.js';\nimport { parseRowTemplate, rowContractError } from './utils/rowContract.js';\n\ninterface Classification {\n newRecord: BoundItem[];\n prevIdx: number[];\n replacedNodes: Element[];\n freshIndices: number[];\n freshHtmls: string[];\n}\n\n/**\n * Reconcile via the snapshot algorithm. Mutates `binding.items` to mirror\n * the new segment when done.\n *\n * Focus capture/restore lives in `list-reconcile-focus.ts` — `insertBefore`\n * of a focused descendant's ancestor blurs the element in some engines\n * (happy-dom, older Safari) even when it stays connected; the snapshot fixes\n * those engines and is a no-op on engines that already preserve focus.\n */\nexport function reconcileSnapshot(binding: ListBinding, listSeg: ListSegment): void {\n const { liveParent } = binding;\n const { newRecord, prevIdx, replacedNodes, freshIndices, freshHtmls }\n = classifyItems(binding.items, listSeg);\n\n // KF-89 fast path: if no items were replaced, none are fresh, and every\n // surviving item kept its original position, the live tree already matches\n // the new segment. Skip buildFreshNodes (nothing to build), removeOldNodes\n // (nothing to remove), the LIS pass (no reorder possible), and applyMoves'\n // reverse walk (no moves). For a 1k-row list whose only change is a signal\n // re-read with no item-array delta, this collapses ~10–15 ms of per-render\n // bookkeeping into a single classification pass + the binding update.\n if (replacedNodes.length === 0 && freshIndices.length === 0\n && isInOrder(prevIdx)) {\n binding.items = newRecord;\n return;\n }\n\n // Compute tail anchor BEFORE removing old nodes: once an item is\n // detached, its `.nextElementSibling` is null and we lose the\n // boundary. Capturing here uses the binding's current (pre-mutation)\n // items[last].node which is still attached.\n const tailAnchor = endAnchor(binding);\n buildFreshNodes(newRecord, freshIndices, freshHtmls);\n const focusSnap = captureFocus(liveParent);\n removeOldNodes(liveParent, replacedNodes);\n applyMoves(liveParent, newRecord, prevIdx, lis(prevIdx), tailAnchor);\n if (focusSnap !== null) restoreFocus(focusSnap);\n binding.items = newRecord;\n}\n\n/**\n * Classify each item in the new segment against the old binding. Items with\n * a cache-hit (same ref + same html) are reused; replaced/new items get a\n * placeholder `BoundItem` whose `node` is filled in by the bulk parse below.\n */\nfunction classifyItems(oldItems: BoundItem[], listSeg: ListSegment): Classification {\n // Single Map<ref, [item, index]> instead of two Maps over the same key set\n // (KF-90). Halves the .set() calls during the build, halves the lookup\n // probe count during classification. ~1-2 ms saved per render on 1k-row\n // lists.\n const oldByRef = new Map<object, [BoundItem, number]>();\n for (let i = 0; i < oldItems.length; i++) {\n oldByRef.set(oldItems[i].ref, [oldItems[i], i]);\n }\n\n const newRecord: BoundItem[] = new Array(listSeg.items.length);\n const prevIdx = new Array<number>(listSeg.items.length);\n const replacedNodes: Element[] = [];\n const freshIndices: number[] = [];\n const freshHtmls: string[] = [];\n\n for (let i = 0; i < listSeg.items.length; i++) {\n const ni = listSeg.items[i];\n const oi = oldByRef.get(ni.ref);\n if (oi !== undefined) {\n oldByRef.delete(ni.ref);\n if (oi[0].html === ni.html) {\n newRecord[i] = oi[0];\n prevIdx[i] = oi[1];\n continue;\n }\n replacedNodes.push(oi[0].node);\n }\n newRecord[i] = {\n ref: ni.ref, cacheKey: ni.cacheKey, html: ni.html, node: null as unknown as Element,\n };\n prevIdx[i] = -1;\n freshIndices.push(i);\n freshHtmls.push(ni.html);\n }\n\n // Whatever's left in oldByRef is an orphan ref that disappeared from the\n // new list. The caller removes those nodes alongside the replaced ones.\n for (const [, orphan] of oldByRef) replacedNodes.push(orphan[0].node);\n\n return { newRecord, prevIdx, replacedNodes, freshIndices, freshHtmls };\n}\n\n/**\n * Bulk-parse every fresh row's HTML in one `innerHTML` call, then walk the\n * parsed children in order and fill in each placeholder's `node` field.\n *\n * Enforces the \"exactly one top-level element per row\" contract (KF-103):\n * if the bulk parse produces a different number of top-level elements\n * than fresh rows, fall back to per-row parsing to identify the offending\n * row and throw a precise error. The success path stays a single parse.\n */\nfunction buildFreshNodes(\n newRecord: BoundItem[],\n freshIndices: number[],\n freshHtmls: string[],\n): void {\n if (freshHtmls.length === 0) return;\n const { tpl, count } = parseRowTemplate(freshHtmls.join(''));\n if (count !== freshHtmls.length) {\n throw findOffendingRow(newRecord, freshIndices, freshHtmls);\n }\n // After the count check above, we know `tpl.content.children.length`\n // equals `freshIndices.length`, so the walk below always finds an element\n // for every index. No defensive null-guard needed.\n let node = tpl.content.firstElementChild;\n for (const idx of freshIndices) {\n const next = (node as Element).nextElementSibling;\n newRecord[idx].node = node as Element;\n node = next;\n }\n}\n\n/**\n * Walk per-row to find the offending row that violated the contract,\n * returning a precise error to throw. Only invoked when the bulk parse\n * detected a count mismatch — the success path is one parse with no\n * per-row work.\n */\nfunction findOffendingRow(\n newRecord: BoundItem[],\n freshIndices: number[],\n freshHtmls: string[],\n): Error {\n for (let i = 0; i < freshHtmls.length; i++) {\n if (parseRowTemplate(freshHtmls[i]).count !== 1) {\n return rowContractError(freshIndices[i], newRecord[freshIndices[i]].html);\n }\n }\n /* c8 ignore next 2 — unreachable: bulk mismatch ⇒ at least one row violates. */\n return new Error('each(): bulk-parse mismatch with no per-row offender (kerf bug).');\n}\n\n/**\n * Remove every replaced/orphan node still attached to the live parent.\n */\nfunction removeOldNodes(liveParent: Element, replacedNodes: Element[]): void {\n for (const node of replacedNodes) {\n if (node.parentElement === liveParent) liveParent.removeChild(node);\n }\n}\n\n/**\n * `insertBefore` everything that's not in the LIS. Walks the new record in\n * reverse so each move's anchor (`nextSibling`) is already in its final\n * position by the time we reach earlier items.\n *\n * `tailAnchor` is the element that comes AFTER the list inside `liveParent`\n * (or `null` if the list is at the end). The reconciler computes it via\n * `endAnchor(binding)` so it picks up non-list siblings the diff may have\n * inserted between the list and the parent's tail (KF-102).\n */\nfunction applyMoves(\n liveParent: Element,\n newRecord: BoundItem[],\n prevIdx: number[],\n stable: ReadonlySet<number>,\n tailAnchor: Element | null,\n): void {\n let nextSibling: Element | null = tailAnchor;\n for (let i = newRecord.length - 1; i >= 0; i--) {\n const node = newRecord[i].node;\n if (prevIdx[i] === -1 || !stable.has(i)) {\n liveParent.insertBefore(node, nextSibling);\n }\n nextSibling = node;\n }\n}\n\n/**\n * Patience-sort LIS: returns the *set of indices* in `arr` that participate\n * in a longest strictly-increasing subsequence. `-1` entries (representing\n * brand-new items in the new list) are ignored — they can't anchor the\n * subsequence and shouldn't count as stable.\n */\nfunction lis(arr: ReadonlyArray<number>): ReadonlySet<number> {\n const tails: number[] = [];\n const tailIdx: number[] = [];\n const prev = new Array<number>(arr.length);\n for (let i = 0; i < arr.length; i++) {\n const v = arr[i];\n if (v === -1) {\n prev[i] = -1;\n continue;\n }\n let lo = 0;\n let hi = tails.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (tails[mid] < v) lo = mid + 1;\n else hi = mid;\n }\n prev[i] = lo > 0 ? tailIdx[lo - 1] : -1;\n tails[lo] = v;\n tailIdx[lo] = i;\n }\n const out = new Set<number>();\n let k = tailIdx.length > 0 ? tailIdx[tailIdx.length - 1] : -1;\n while (k !== -1) {\n out.add(k);\n k = prev[k];\n }\n return out;\n}\n\n/**\n * True iff `prevIdx` is `[0, 1, 2, …, n-1]` — every item kept the position it\n * had in the previous render. Used by `reconcileSnapshot` to short-circuit\n * the LIS + move pass when nothing structural changed.\n */\nfunction isInOrder(prevIdx: number[]): boolean {\n for (let i = 0; i < prevIdx.length; i++) {\n if (prevIdx[i] !== i) return false;\n }\n return true;\n}\n","/**\n * Keyed list reconciler — the engine behind `each(...)` inside `mount()`.\n *\n * Public surface (re-exported via the rest of the runtime):\n * - `BoundItem` / `ListBinding`: the binding shape `mount()` keeps\n * per-list, mapping `each()` items to their live DOM nodes.\n * Defined in `list-binding.ts` and re-exported here.\n * - `endAnchor(binding)`: dynamic \"insert at end of list\" anchor.\n * Also defined in `list-binding.ts` and re-exported here.\n * - `reconcileList(binding, listSeg)`: top-level dispatch.\n *\n * Implementation lives in two sibling files:\n * - `list-reconcile-snapshot.ts` — the original keyed algorithm\n * (classify / bulk-parse / LIS / move). Used for plain-array `each()`\n * and for arraySignal-backed `each()` when the patch path can't apply\n * (first render, post-`replace()`, post-drift recovery).\n * - `list-reconcile-granular.ts` — the KF-92 patch-driven path used\n * when an `arraySignal`'s queued patches can be applied directly to\n * the existing binding without iterating the snapshot.\n *\n * The split mirrors the two-axis nature of the reconciler: snapshot-vs-\n * granular path × shared bookkeeping (binding shape, end-of-list anchor,\n * focus capture/restore). The binding shape is in its own `list-binding.ts`\n * file so the two sibling reconcilers can import it without creating a\n * circular dependency back to `list-reconcile.ts`. Internal to kerf — not\n * part of the public API.\n */\n\nexport { type BoundItem, endAnchor, type ListBinding } from './list-binding.js';\nimport type { ListBinding } from './list-binding.js';\nimport { reconcileGranular } from './list-reconcile-granular.js';\nimport { reconcileSnapshot } from './list-reconcile-snapshot.js';\nimport type { ListSegment } from './segment.js';\n\n/**\n * Reconcile `binding`'s live parent against `listSeg`. Mutates `binding.items`\n * to mirror the new segment when done.\n *\n * Dispatch:\n * - **Granular (KF-92)**: an `arraySignal`-backed `each()` whose patch\n * queue is non-empty AND the binding has at least one row. Applies\n * patches directly. `each()` filters `replace` patches upstream so the\n * patches reaching here are guaranteed to be update/insert/remove/move\n * only.\n * - **Snapshot**: every other case — first render of a list, plain-array\n * `each()`, post-`replace()`, post-drift recovery. Runs the keyed\n * classify/build/move algorithm.\n */\nexport function reconcileList(binding: ListBinding, listSeg: ListSegment): void {\n if (listSeg.patches !== undefined && binding.items.length > 0) {\n reconcileGranular(binding, listSeg.patches);\n return;\n }\n reconcileSnapshot(binding, listSeg);\n}\n","/**\n * `mount(rootEl, render)` — kerf's render primitive.\n *\n * Wraps `effect()` so that whenever any signal read inside `render()`\n * changes, we re-run `render()` and apply the minimum DOM mutations against\n * the live tree. Element identity (and thus focus, selection, in-flight\n * pointer interactions, and event listeners on preserved nodes) is preserved\n * wherever the keyed/positional diff matches.\n *\n * Two phases per render:\n *\n * - Static surrounds (everything outside `each()` lists): kerf's native\n * `diff()` reconciler walks a freshly-built template against the live\n * tree. Conventions: id/data-key matching, `data-morph-skip`, focus\n * preservation.\n *\n * - List interiors (children of every `each()` parent): native keyed\n * reconciler operates directly on the live parent's children. No\n * re-parse, no morph walk for cache-hit rows. Cost is O(changes), not\n * O(rows).\n *\n * Compared to a `replaceChildren(...rows.map(toElement))` rebuild pattern,\n * the user-visible win is that an `<input>` the user is typing into\n * survives an unrelated re-render — its DOM node, focus state, and cursor\n * position are not destroyed and recreated on each tick.\n */\n\nimport { diff } from './diff.js';\nimport { _setRenderContext, type RenderContext } from './each.js';\nimport type { SafeHtml } from './jsx-runtime.js';\nimport { isSafeHtml } from './jsx-runtime.js';\nimport {\n type BoundItem,\n type ListBinding,\n reconcileList,\n} from './list-reconcile.js';\nimport { effect } from './reactive.js';\nimport {\n collectLists,\n flatten,\n flattenWithoutListItems,\n type ListSegment,\n type Segment,\n} from './segment.js';\nimport { parseRowTemplate, rowContractError } from './utils/rowContract.js';\n\nconst LIST_MARKER_PREFIX = 'kf-list:';\n\n/**\n * Bind `render()` to the children of `rootEl`. Re-runs whenever any signal\n * read inside `render()` changes. Returns a disposer that tears down the\n * effect; call it when the host element is removed from the DOM.\n *\n * Conventions:\n *\n * - Diff keys: `id` and `data-key` are matched across the morph by key\n * rather than positionally, so list reorders move existing nodes instead\n * of churning unrelated siblings.\n * - `data-morph-skip`: any element with this attribute is left untouched\n * inside on subsequent renders. Used for library-owned subtrees (xterm-\n * style widgets, charts, third-party editors) where the library's own\n * lifecycle manages the children.\n * - Focused text-entry inputs (`<input>` of typing kinds, `<textarea>`)\n * keep their current value + selection range across morphs while focused.\n * The user never sees their cursor jump mid-keystroke.\n * - Focused `[contenteditable]` elements have their entire subtree\n * skipped (same mechanism as `data-morph-skip`). The user's in-progress\n * edit — typed content, caret position, multi-range selections, anything\n * else they did to the DOM — survives verbatim. The next render after\n * blur catches up.\n */\nexport type MountResult = SafeHtml | string | number | boolean | null | undefined;\n\nexport function mount(rootEl: HTMLElement, render: () => MountResult): () => void {\n if (rootEl == null) {\n throw new Error(\n 'mount: rootEl is null/undefined — pass the live element, e.g. mount(document.getElementById(\"app\")!, render). '\n + 'A common cause is a typo in the id or selector that returns null at runtime even though the TypeScript types say HTMLElement.',\n );\n }\n const bindings = new Map<string, ListBinding>();\n // Per-mount render context: the list-id counter is reset at the start of\n // each render (so the n-th `each()` call gets the same id every render);\n // the `caches` map persists across renders so unchanged items skip the\n // JSX work via cache hits even when the JSX render function is an inline\n // arrow that's a fresh function reference on every closure run (KF-87).\n const renderCtx: RenderContext = {\n counter: 0,\n caches: new Map(),\n bindingCounts: new Map(),\n };\n let isFirst = true;\n // KF-88: the static-surrounds HTML string from the previous render. If a\n // re-render produces the same string (the common case when a signal flips\n // a class on one row but the page chrome is unchanged), we skip the\n // template clone, the innerHTML re-parse, and the diff() walk entirely\n // and go straight to the per-list reconcilers. Saves ~8 ms per update-\n // path render against the krausest harness.\n let prevStaticHtml = '';\n\n return effect(() => {\n renderCtx.counter = 0;\n _setRenderContext(renderCtx);\n let result: MountResult;\n try {\n result = render();\n } finally {\n _setRenderContext(null);\n }\n\n // The `MountResult` union covers `null`, `undefined`, `false`, `true`,\n // and `number` so consumers can write `() => cond ? <jsx/> : null` and\n // `() => cond && <jsx/>` without a cast. `coerceRenderResult` collapses\n // nullish + boolean to `''` (render nothing) and stringifies numbers.\n const segment: Segment = isSafeHtml(result)\n ? (result.__segment ?? { kind: 'static', html: result.__html })\n : { kind: 'static', html: coerceRenderResult(result) };\n\n if (isFirst) {\n runFirstRender(rootEl, segment, bindings);\n prevStaticHtml = flattenWithoutListItems(segment);\n isFirst = false;\n } else {\n prevStaticHtml = runSubsequentRender(rootEl, segment, bindings, renderCtx, prevStaticHtml);\n }\n\n for (const listSeg of collectLists(segment).values()) {\n const binding = bindings.get(listSeg.id) as ListBinding;\n reconcileList(binding, listSeg);\n // KF-99: record the post-reconcile binding length so the next render's\n // granular path can detect drift (a prior render that threw mid-batch\n // leaves the binding shorter than the signal expects).\n renderCtx.bindingCounts.set(listSeg.id, binding.items.length);\n }\n });\n}\n\n/**\n * First render of a mount: bulk-flatten the segment (items inlined, markers\n * around each list) into `rootEl.innerHTML`, then walk the markers to\n * register a `ListBinding` per list. The subsequent `reconcileList` pass is\n * a no-op (every row's a cache hit on the just-bound items).\n */\nfunction runFirstRender(\n rootEl: HTMLElement,\n segment: Segment,\n bindings: Map<string, ListBinding>,\n): void {\n rootEl.innerHTML = flatten(segment, true);\n bindListsFromMarkers(rootEl, segment, bindings, true);\n}\n\n/**\n * Subsequent render of a mount. Returns the new `prevStaticHtml` so the\n * caller can carry it forward.\n *\n * Two paths:\n *\n * - **KF-88 fast path**: when the static-surrounds string didn't change\n * byte-for-byte, `bindListsFromMarkers` has nothing to discover and the\n * diff would short-circuit on `isEqualNode` for every element it visited —\n * but the visit itself isn't free. Skip both to save ~8 ms per partial-\n * update / select-row / swap-rows render against the krausest harness.\n *\n * Trade-off (KF-117, documented in `docs/4-render.md` §4.4.2): any\n * attribute or child set imperatively on a kerf-managed element (e.g.\n * `el.setAttribute(...)`) survives across no-op re-renders because the\n * diff doesn't run to wipe it. When the surrounds DO change, the diff\n * runs and `morphAttributes` removes anything the JSX didn't authorise.\n * This matches the framework's \"smallest cut\" model: don't touch what\n * JSX didn't change.\n *\n * - **Surrounds-changed path**: clean up orphan bindings (lists that\n * disappeared from this render's segment), build a template from the\n * static-only HTML, run `diff()` over the surrounds with the\n * list-owned items as `ownedItems` (KF-102 round 2 — the diff skips\n * owned items individually but still walks every parent so non-list\n * siblings around an each() reconcile correctly), then bind any\n * newly-appearing lists.\n */\nfunction runSubsequentRender(\n rootEl: HTMLElement,\n segment: Segment,\n bindings: Map<string, ListBinding>,\n renderCtx: RenderContext,\n prevStaticHtml: string,\n): string {\n const currentStaticHtml = flattenWithoutListItems(segment);\n if (currentStaticHtml === prevStaticHtml) {\n return prevStaticHtml;\n }\n cleanupOrphanBindings(segment, bindings, renderCtx);\n const template = rootEl.cloneNode(false) as HTMLElement;\n template.innerHTML = currentStaticHtml;\n diff(rootEl, template, collectOwnedItems(bindings));\n bindListsFromMarkers(rootEl, segment, bindings, false);\n return currentStaticHtml;\n}\n\n/**\n * Coerce a non-`SafeHtml` render result to a safe HTML string. Nullish\n * values and booleans become `''` (render nothing) — matches the React /\n * Solid convention so `{cond ? <jsx/> : null}` and `{cond && <jsx/>}`\n * patterns work without each consumer adding a sentinel. Everything else\n * is stringified (numbers → `\"42\"`, strings pass through).\n */\nfunction coerceRenderResult(result: unknown): string {\n if (result === null || result === undefined) return '';\n if (result === false || result === true) return '';\n return String(result);\n}\n\n/**\n * Walk the live tree's comment nodes; every `<!--kf-list:{id}-->` marker\n * is the start anchor of a list inside `liveParent`. Bind the list (parent +\n * already-rendered item nodes between the marker and the tail). The marker\n * stays in the live DOM (KF-102 round 2): keeping it as a permanent\n * comment-node anchor lets the static-surrounds diff insert/remove/morph\n * non-list siblings around the list without needing to re-establish the\n * list's begin position.\n *\n * `inlinedItems` distinguishes the first-render path (where `flatten(seg,\n * true)` inlines item HTML right after the marker, so the marker's element\n * siblings *are* the list rows) from subsequent renders that newly\n * introduce a list (where `flattenWithoutListItems` emits only the marker\n * and the list reconciler populates items afterwards).\n *\n * Existing bindings whose marker is still in the DOM are left intact —\n * `bindings.has(id)` skips re-binding so the prior render's item nodes\n * survive across static-surrounds diffs.\n */\nfunction bindListsFromMarkers(\n rootEl: Element,\n segment: Segment,\n bindings: Map<string, ListBinding>,\n inlinedItems: boolean,\n): void {\n const lists = collectLists(segment);\n const found: Comment[] = [];\n collectComments(rootEl, found);\n for (const marker of found) {\n if (!marker.data.startsWith(LIST_MARKER_PREFIX)) continue;\n const id = marker.data.slice(LIST_MARKER_PREFIX.length);\n if (bindings.has(id)) continue; // existing binding survives the diff\n const listSeg = lists.get(id) as ListSegment;\n const liveParent = marker.parentElement as Element;\n const items: BoundItem[] = [];\n if (inlinedItems) {\n // KF-103: enforce the \"exactly one top-level element per row\" contract\n // on first render too. Without this check, a multi-root row inlined\n // via `flatten(seg, true)` would silently misalign the binding (each\n // bound item.node points at only the first of a row's 2+ elements,\n // and the leftover elements are picked up as \"next\" rows). The check\n // is per-row so we can pinpoint the offender by index.\n let next: Element | null = marker.nextElementSibling;\n for (let i = 0; i < listSeg.items.length && next !== null; i++) {\n validateInlinedRowMatch(listSeg.items[i].html, i, next);\n items.push({\n ref: listSeg.items[i].ref,\n cacheKey: listSeg.items[i].cacheKey,\n html: listSeg.items[i].html,\n node: next,\n });\n next = next.nextElementSibling;\n }\n }\n bindings.set(id, { liveParent, items, marker });\n }\n}\n\n/**\n * KF-103: validate that `expectedHtml` (one row's render output) matches\n * the live `boundEl`'s `outerHTML` — confirming the row produced exactly\n * one top-level element. If they differ, parse the row in isolation and\n * throw a precise error mentioning the row index and the actual count.\n *\n * Fast path: outerHTML compare is a string equality check (zero allocs in\n * happy-dom; one alloc in V8). Only when they DON'T match (multi-root or\n * subtle browser-normalised single-root case) do we fall back to a full\n * per-row parse for the precise count.\n */\nfunction validateInlinedRowMatch(\n expectedHtml: string,\n index: number,\n boundEl: Element,\n): void {\n if (boundEl.outerHTML === expectedHtml) return;\n // The bound element's outerHTML differs from what we emitted. Parse the\n // expected html in isolation; if it's still single-root the difference\n // is whitespace / browser-normalisation (e.g. `<br/>` → `<br>`) and\n // we proceed silently. Otherwise build the precise contract-violation\n // error from the shared helper.\n const { count } = parseRowTemplate(expectedHtml);\n if (count === 1) return;\n throw rowContractError(index, expectedHtml);\n}\n\n/**\n * Build the set of element nodes owned by `each()` list reconcilers, the\n * union of every binding's `items[].node`. The static-surrounds diff\n * skips these so list rows are invisible to the parent walk while\n * sibling reconciliation continues normally (KF-102 round 2).\n */\nfunction collectOwnedItems(bindings: Map<string, ListBinding>): Set<Element> {\n const owned = new Set<Element>();\n for (const b of bindings.values()) {\n for (const item of b.items) owned.add(item.node);\n }\n return owned;\n}\n\n/**\n * Remove items + binding entries for any list that's no longer present in\n * the new segment. The diff's trailing-removal pass would have removed the\n * marker (since the new template no longer emits one for this id), but\n * items are owned and stay protected from removal — so we drop them\n * explicitly here before the diff runs.\n */\nfunction cleanupOrphanBindings(\n segment: Segment,\n bindings: Map<string, ListBinding>,\n renderCtx: RenderContext,\n): void {\n const liveIds = collectLists(segment);\n for (const [id, binding] of bindings) {\n if (liveIds.has(id)) continue;\n for (const item of binding.items) {\n if (item.node.parentElement !== null) {\n item.node.parentElement.removeChild(item.node);\n }\n }\n if (binding.marker.parentElement !== null) {\n binding.marker.parentElement.removeChild(binding.marker);\n }\n bindings.delete(id);\n renderCtx.bindingCounts.delete(id);\n renderCtx.caches.delete(id);\n }\n}\n\n/**\n * Recursive collector for comment nodes — happy-dom's `TreeWalker` doesn't\n * surface `Node.COMMENT_NODE` despite accepting `NodeFilter.SHOW_COMMENT`,\n * so we walk children directly. Cheap (O(elements)) and portable.\n */\nfunction collectComments(node: Node, out: Comment[]): void {\n for (let c: Node | null = node.firstChild; c !== null; c = c.nextSibling) {\n if (c.nodeType === Node.COMMENT_NODE) out.push(c as Comment);\n else if (c.nodeType === Node.ELEMENT_NODE) collectComments(c, out);\n }\n}\n\n\n","/**\n * `toElement(jsx)` — JSX → DOM, with SVG-aware namespace handling.\n *\n * The naive implementation parses JSX through a `<template>` element's\n * `innerHTML`. That works for HTML and for SVG fragments whose root tag is\n * `<svg>` (the parser switches to \"foreign content\" mode). It silently\n * fails for SVG fragments WITHOUT an `<svg>` wrapper — descendants come out\n * as `HTMLUnknownElement` and never paint.\n *\n * `toElement` detects SVG content and routes through `DOMParser` with the\n * `image/svg+xml` MIME, which guarantees correct namespacing for all\n * descendants. HTML content takes the original `<template>` path unchanged.\n */\n\nimport type { SafeHtml } from './jsx-runtime.js';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\nconst SVG_FRAGMENT_TAGS = new Set([\n 'g', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline', 'ellipse',\n 'text', 'tspan', 'defs', 'use', 'symbol', 'clipPath', 'mask', 'pattern',\n 'filter', 'marker', 'linearGradient', 'radialGradient', 'stop', 'image',\n 'foreignObject',\n]);\n\nconst EXCERPT_MAX_LEN = 100;\n\nfunction leadingTag(html: string): string | null {\n const match = /^\\s*<([a-zA-Z][a-zA-Z0-9]*)\\b/.exec(html);\n return match !== null ? match[1] : null;\n}\n\nfunction excerpt(html: string): string {\n const trimmed = html.trim();\n return trimmed.length > EXCERPT_MAX_LEN ? `${trimmed.slice(0, EXCERPT_MAX_LEN)}…` : trimmed;\n}\n\nfunction parseSvgOrThrow(html: string, label: string, originalHtml: string): Document {\n const doc = new DOMParser().parseFromString(html, 'image/svg+xml');\n const err = doc.querySelector('parsererror');\n if (err !== null) {\n throw new Error(`toElement: ${label} parse error — ${err.textContent}\\n input: ${excerpt(originalHtml)}`);\n }\n return doc;\n}\n\nexport function toElement(jsx: SafeHtml | string): Element {\n const html = typeof jsx === 'string' ? jsx : jsx.toString();\n const tag = leadingTag(html);\n\n if (tag === 'svg') {\n // SVG root — parse as XML to guarantee namespace propagation.\n return parseSvgOrThrow(html, 'SVG', html).documentElement;\n }\n\n if (tag !== null && SVG_FRAGMENT_TAGS.has(tag)) {\n // SVG fragment without an <svg> wrapper — wrap, parse, unwrap.\n const wrapped = `<svg xmlns=\"${SVG_NS}\">${html}</svg>`;\n const doc = parseSvgOrThrow(wrapped, 'SVG fragment', html);\n const first = doc.documentElement.firstElementChild;\n /* c8 ignore next 2 — defensive: a successful XML parse of a wrapped svg always yields ≥1 child. */\n if (first === null) throw new Error(`toElement: SVG fragment produced no element\\n input: ${excerpt(html)}`);\n return first;\n }\n\n // HTML — `<template>`-based parse.\n const t = document.createElement('template');\n t.innerHTML = html;\n const child = t.content.firstElementChild;\n if (child === null) throw new Error(`toElement: produced no element\\n input: ${excerpt(html)}`);\n return child;\n}\n"]}
1
+ {"version":3,"sources":["../src/delegate.ts","../src/each.ts","../src/morph.ts","../src/list-binding.ts","../src/list-reconcile-focus.ts","../src/utils/rowContract.ts","../src/list-reconcile-granular.ts","../src/list-reconcile-snapshot.ts","../src/list-reconcile.ts","../src/mount.ts","../src/toElement.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Tiny event-delegation helpers. Replace per-element `addEventListener` calls\n * (which don't survive morph re-renders for nodes the diff creates) with one\n * listener at the morph-root that dispatches via `closest()`.\n *\n * Three-tier listener model:\n *\n * - Tier 1 (bubbling events) — use `delegate()`.\n * click, input, change, submit, mousedown/up, keydown/up, pointerdown/up/move,\n * drag*, drop, contextmenu, wheel, copy/paste/cut, focusin/focusout.\n *\n * `delegate()` also auto-promotes the well-known non-bubbling event\n * types (`focus`, `blur`, `scroll`, `load`, `error`, `mouseenter`,\n * `mouseleave`) to the capture phase under the hood, so the call site\n * looks identical for \"interactive thing happens on a descendant\"\n * regardless of whether that event bubbles. Selector matching stays\n * `closest()`-style — the same as for bubbling events — so a wrapper\n * selector like `'.field-row'` still matches when the event fires on\n * a descendant `<input>`.\n *\n * - Tier 2 (explicit capture) — use `delegateCapture()`.\n * The escape hatch for cases the auto-promotion list doesn't cover, or\n * when you want capture-phase semantics and direct `matches()`-style\n * selector matching (no walk-up).\n *\n * - Tier 3 (per-element instances / library-owned subtrees) — mark the\n * host element with `data-morph-skip` and manage the library's\n * lifecycle directly. No delegation helper applies.\n */\n\ntype Handler = (event: Event, target: Element) => void;\n\n/**\n * Event types that don't bubble and so wouldn't reach a root-level\n * bubble-phase listener. `delegate()` flips to capture for these; the\n * caller doesn't need to know or care.\n *\n * Membership is conservative — it covers the cases that \"should obviously\n * work\" with delegate() but otherwise don't. For exotic non-bubbling events\n * (custom events, less-common DOM events) the explicit `delegateCapture()`\n * remains the escape hatch.\n */\nconst NON_BUBBLING = new Set<string>([\n 'focus',\n 'blur',\n 'scroll',\n 'load',\n 'error',\n 'mouseenter',\n 'mouseleave',\n]);\n\n/**\n * Validate a CSS selector at registration time, so a typo throws immediately\n * with the bad selector quoted instead of producing a cryptic DOMException\n * the first time a matching event fires.\n */\nfunction assertValidSelector(selector: string, fn: string): void {\n try {\n document.createElement('div').matches(selector);\n } catch {\n throw new Error(\n `${fn}: invalid selector \"${selector}\". `\n + 'Pass a valid CSS selector (e.g. \\'[data-action=\"add\"]\\', \\'.btn\\', \\'input\\').',\n );\n }\n}\n\n/**\n * Delegation that \"just works\" for both bubbling and the common non-bubbling\n * events. Installs ONE listener on `rootEl`; for known non-bubblers (see\n * `NON_BUBBLING` above) the listener is registered on the capture phase so\n * it actually reaches the target, otherwise on the bubble phase. Either way,\n * matching walks up from `event.target` via `closest(selector)` and fires\n * `handler(event, matched)` if the match is inside `rootEl`.\n *\n * Returns a disposer that removes the listener.\n *\n * Usage (pseudo-code — see examples for live ones):\n * delegate(rootEl, 'click', '[data-action=\"add\"]', handlerFn);\n * delegate(rootEl, 'focus', 'input', handlerFn); // auto-capture\n */\nexport function delegate(\n rootEl: HTMLElement,\n type: string,\n selector: string,\n handler: Handler,\n): () => void {\n assertValidSelector(selector, 'delegate');\n const listener = (event: Event): void => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n const matched = target.closest(selector);\n if (matched !== null && rootEl.contains(matched)) {\n handler(event, matched);\n }\n };\n const capture = NON_BUBBLING.has(type);\n rootEl.addEventListener(type, listener, capture);\n return () => {\n rootEl.removeEventListener(type, listener, capture);\n };\n}\n\n/**\n * Capture-phase delegation — for non-bubbling events (`focus`, `blur`,\n * `scroll`, `load`, `error`). Reaches descendants of `rootEl` that match\n * `selector` regardless of how many times the diff has rebuilt them.\n *\n * Usage (pseudo-code — see examples for live ones):\n * delegateCapture(rootEl, 'focus', 'input, textarea', handlerFn);\n */\nexport function delegateCapture(\n rootEl: HTMLElement,\n type: string,\n selector: string,\n handler: Handler,\n): () => void {\n assertValidSelector(selector, 'delegateCapture');\n const listener = (event: Event): void => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n if (target.matches(selector) && rootEl.contains(target)) {\n handler(event, target);\n }\n };\n rootEl.addEventListener(type, listener, true);\n return () => {\n rootEl.removeEventListener(type, listener, true);\n };\n}\n","/**\n * `each(items, render, key?)` — keyed list iteration with per-item memoization.\n *\n * Drops in as the body of a list-rendering JSX expression inside a `mount()`\n * render function. Returns a `SafeHtml` carrying a structured list segment,\n * so `mount()` can run a native keyed reconciler instead of the general-\n * purpose morph for these children.\n *\n * Two layers of optimization:\n *\n * 1. Per-item memoization. `render(item)` is skipped for items whose object\n * identity (and optional `key`) are unchanged since the previous call.\n * Their HTML strings come from a `WeakMap` keyed by item reference. The\n * immutable-update style (\"replace the row object\" instead of \"mutate it\")\n * makes the cache work automatically.\n *\n * 2. Structural handoff. `mount()` recognizes the list segment and bypasses\n * the parse-the-whole-table round trip: only fresh items get parsed (one\n * at a time, into the smallest detached element), and only changed rows\n * get patched in the live DOM. Unchanged rows are physically the same\n * nodes they were before — never visited.\n *\n * `key` covers the case where external state, not the item itself, drives\n * what the row should render (e.g. a \"currently selected\" id flips a CSS\n * class on one row). Same item identity but a different `key` value means\n * \"re-render this item.\" If you don't pass `key`, only identity changes\n * invalidate.\n *\n * Items must be objects (cache is a `WeakMap`); wrap primitives if you need\n * to iterate them. Each item's render output must produce exactly one\n * top-level element — the list reconciler binds one live DOM node per item.\n */\n\nimport type { ArraySignal } from './array-signal.js';\nimport type { SafeHtml } from './jsx-runtime.js';\nimport { granularListSafeHtml, isSafeHtml, listSafeHtml } from './jsx-runtime.js';\nimport type { ArrayPatchInternal } from './segment.js';\n\n/**\n * Cross-bundle brand check for `ArraySignal` instances (KF-95). The\n * `arraySignal` factory + class live in their own subpath\n * (`kerfjs/array-signal`); this module knows nothing about that\n * subpath at runtime — it identifies instances by the brand symbol\n * stamped on them. Apps that never import `arraySignal` shed the\n * ~1 KB of class code without breaking the structural contract here.\n */\nconst ARRAY_SIGNAL_BRAND = Symbol.for('kerfjs.ArraySignal');\n\nfunction isArraySignal<T extends object>(value: unknown): value is ArraySignal<T> {\n return typeof value === 'object'\n && value !== null\n && (value as Record<symbol, unknown>)[ARRAY_SIGNAL_BRAND] === true;\n}\n\ninterface CacheEntry {\n key: unknown;\n html: string;\n}\n\n/**\n * Per-render context passed in by `mount()` for the duration of one render\n * pass. Carries (a) a counter that assigns a stable list id to the n-th\n * `each()` call across renders within a mount, and (b) a per-mount cache map\n * keyed on those list ids.\n *\n * Why per-(mount, listId) keying for the cache:\n * - Same `each()` callsite across renders within a mount → same id → same\n * cache → cache hits work, even when the JSX render fn is an inline arrow\n * that's a fresh function reference on every closure run (the typical\n * pattern; KF-87 fixed the regression where this broke).\n * - Different `each()` callsites within the same mount → different ids →\n * separate caches → no cross-callsite collision (the case KF-73 fixed,\n * preserved here).\n * - Different mounts → different `RenderContext` instances (the cache map\n * lives on `mount()`'s closure) → separate caches.\n *\n * Outside a `mount()` render (e.g. `each(...).toString()` for SSR string\n * production) `context` is null and items are rendered every call —\n * caching is a `mount()` feature, not a global one.\n */\nexport interface RenderContext {\n counter: number;\n caches: Map<string, WeakMap<object, CacheEntry>>;\n /**\n * Per-list-id record of the binding's `items.length` after the most recent\n * successful reconcile. Maintained by `mount()` via `_setBindingCount`. The\n * granular path consults this to detect drift between the live binding and\n * the arraySignal — drift means a previous render threw mid-reconcile (or\n * a granular path was bypassed externally), so the next render forces a\n * snapshot rebuild rather than applying patches against a stale binding.\n */\n bindingCounts: Map<string, number>;\n}\n\nlet context: RenderContext | null = null;\n\nexport function _setRenderContext(c: RenderContext | null): void {\n context = c;\n}\n\nexport function each<T extends object>(\n items: readonly T[] | ArraySignal<T>,\n render: (item: T, index: number) => SafeHtml | string,\n key?: (item: T, index: number) => unknown,\n): SafeHtml {\n // KF-92 fast path: when items is an ArraySignal AND we're inside a mount\n // render context AND patches have queued since the last drain, emit a\n // granular list segment that the list reconciler applies in O(patches)\n // instead of O(N). Detection via the brand symbol (KF-95) — the\n // `arraySignal` class lives in the `kerfjs/array-signal` subpath and is\n // not imported here at runtime.\n if (isArraySignal<T>(items) && context !== null) {\n return eachGranular(items, render, key);\n }\n const snapshotItems: readonly T[] = isArraySignal<T>(items)\n ? items.value as readonly T[]\n : items;\n return eachSnapshot(snapshotItems, render, key);\n}\n\nfunction eachSnapshot<T extends object>(\n items: readonly T[],\n render: (item: T, index: number) => SafeHtml | string,\n key: ((item: T, index: number) => unknown) | undefined,\n): SafeHtml {\n let id: string;\n if (context !== null) {\n id = String(context.counter++);\n } else {\n id = 'orphan';\n }\n return eachSnapshotById(items, render, key, id);\n}\n\n/**\n * Granular path for `arraySignal`-backed lists. Drains queued patches and\n * emits a list segment that the reconciler applies to the existing binding\n * directly — no full iteration of the snapshot, no O(N) classify pass.\n *\n * On the very first render of a list, the binding doesn't exist yet, so\n * the reconciler falls through to the snapshot path. Subsequent renders\n * of the same list (where the binding now exists) take the granular path\n * whenever there are patches to apply.\n */\nfunction eachGranular<T extends object>(\n sig: ArraySignal<T>,\n render: (item: T, index: number) => SafeHtml | string,\n key: ((item: T, index: number) => unknown) | undefined,\n): SafeHtml {\n // We're inside a mount context (caller-checked).\n const ctx = context as RenderContext;\n const id = String(ctx.counter++);\n // KF-98: a tracked binding count means a prior render of this mount has\n // successfully reconciled this list. On the very first render (no count\n // recorded yet) the granular reconciler has no binding to apply patches\n // to, so any pre-mount mutations would silently produce an empty list.\n // Drain the queue (the snapshot already reflects those mutations) and\n // take the snapshot path; the count will be recorded for the next render.\n const previousBindingCount = ctx.bindingCounts.get(id);\n const patches = sig._consumePatches();\n const snapshot = sig.value as readonly T[];\n\n // First render of this list, no patches, or any 'replace' patch → snapshot.\n // No patches: typical re-render triggered by a non-arraySignal signal change.\n // 'replace': wholesale reset — granular can't help; the snapshot already\n // reflects the post-replace state (and any subsequent granular ops).\n if (previousBindingCount === undefined || patches.length === 0) {\n return eachSnapshotById(snapshot, render, key, id);\n }\n // KF-99: detect drift between the live binding and the arraySignal. After\n // a clean prior reconcile, `previousBindingCount + (#inserts - #removes)`\n // must equal `snapshot.length`. If it doesn't, a previous render threw\n // mid-reconcile and left the binding inconsistent with the signal — fall\n // back to the snapshot path, which classifies fresh against `snapshot`\n // and rebuilds the binding to match.\n let netDelta = 0;\n for (const p of patches) {\n if (p.type === 'insert') netDelta += 1;\n else if (p.type === 'remove') netDelta -= 1;\n else if (p.type === 'replace') {\n return eachSnapshotById(snapshot, render, key, id);\n }\n }\n // Defensive: triggered only when an external party drains `_consumePatches()`\n // or mutates `_items` behind arraySignal's back, OR when a previous reconcile\n // threw mid-DOM-op (rare; not naturally reachable in tests since apply* ops\n // don't throw on well-formed row HTML).\n /* c8 ignore next 3 */\n if (previousBindingCount + netDelta !== snapshot.length) {\n return eachSnapshotById(snapshot, render, key, id);\n }\n\n // Granular path: pre-render every insert/update HTML at JSX-eval time so\n // a throwing render is caught here and we can fall back to the snapshot\n // path (KF-99). Without this, a throw mid-batch would leave patches drained\n // (already done above), the signal mutated, and the live DOM unchanged —\n // permanent divergence with no recovery.\n const renderFnInternal = (item: object, index: number): string => {\n const out = render(item as T, index);\n return isSafeHtml(out) ? out.toString() : out;\n };\n const internalPatches = new Array<ArrayPatchInternal>(patches.length);\n try {\n for (let i = 0; i < patches.length; i++) {\n const p = patches[i];\n if (p.type === 'insert' || p.type === 'update') {\n internalPatches[i] = {\n type: p.type, index: p.index, item: p.item as object,\n html: renderFnInternal(p.item as object, p.index),\n };\n } else {\n internalPatches[i] = p as ArrayPatchInternal;\n }\n }\n } catch {\n // Pre-render threw. The snapshot already reflects every mutation\n // (arraySignal mutates _items eagerly at the call site), but the snapshot\n // path is going to throw on the same bad item too — leaving the binding\n // out of sync with the signal. Clear the binding count so the NEXT\n // render (after the user fixes the bad item) doesn't see the previous\n // render's count and falsely conclude there's no drift; instead it'll\n // take the snapshot path and rebuild from scratch.\n ctx.bindingCounts.delete(id);\n return eachSnapshotById(snapshot, render, key, id);\n }\n // The `items` field is left empty for the granular case — the reconciler\n // doesn't need it; every insert/update patch carries pre-rendered HTML.\n return granularListSafeHtml(id, [], internalPatches);\n}\n\n/** Like eachSnapshot but uses a pre-allocated id (caller already advanced the counter). */\nfunction eachSnapshotById<T extends object>(\n items: readonly T[],\n render: (item: T, index: number) => SafeHtml | string,\n key: ((item: T, index: number) => unknown) | undefined,\n id: string,\n): SafeHtml {\n let cache: WeakMap<object, CacheEntry> | null = null;\n if (context !== null) {\n let c = context.caches.get(id);\n if (c === undefined) {\n c = new WeakMap<object, CacheEntry>();\n context.caches.set(id, c);\n }\n cache = c;\n }\n const segItems = new Array<{ ref: object; cacheKey: unknown; html: string }>(items.length);\n const seen = new Set<object>();\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (typeof item !== 'object' || item === null) {\n throw new Error(\n `each(): items must be objects (the per-item HTML cache is a WeakMap), got ${item === null ? 'null' : typeof item} at index ${i}. `\n + 'Wrap primitives if you need to iterate them, e.g. items.map(v => ({ v })).',\n );\n }\n if (seen.has(item)) {\n throw new Error(\n `each(): the same object reference appears at multiple indices in items (first seen earlier, again at index ${i}). `\n + 'The per-item HTML cache is keyed on object identity, so duplicate references break the keyed reconciler and can leak DOM nodes on re-render. '\n + 'Use a fresh object per row (e.g. items.map(o => ({ ...o })) before passing to each()).',\n );\n }\n seen.add(item);\n const k = key ? key(item, i) : undefined;\n let html: string;\n const cached = cache !== null ? cache.get(item) : undefined;\n if (cached !== undefined && cached.key === k) {\n html = cached.html;\n } else {\n const out = render(item, i);\n html = isSafeHtml(out) ? out.toString() : out;\n if (cache !== null) cache.set(item, { key: k, html });\n }\n segItems[i] = { ref: item, cacheKey: k, html };\n }\n return listSafeHtml(id, segItems);\n}\n","/**\n * `morph(liveRoot, template)` — minimum-mutation DOM reconciliation.\n *\n * Public primitive (KF-150): one-shot reconciliation against an\n * already-populated element. `mount()` first paints by writing\n * `innerHTML`; `morph()` is the \"I have a live tree and a template,\n * reconcile them in place\" sibling. Use it for SSR hydration of static\n * fragments, page-refresh diffs, third-party widget remounts, etc.\n *\n * Replaces our previous dependency on `morphdom`. The algorithm is the\n * classic two-tree walk: match children by key (id, then data-key, then\n * positional same-tag), morph matches in place, insert / remove / clone\n * the rest. Specialized for what kerf needs:\n *\n * - `childrenOnly` is always true; the live root is never replaced.\n * - Per-element short-circuits: `data-morph-skip` (library-owned, leave\n * element AND subtree verbatim), `data-morph-skip-children` (KF-152 —\n * morph attrs on the element, leave its subtree verbatim — for\n * client-hydrated slots whose loading/state classes still need to flow\n * through), and `isEqualNode` (byte-identical, no work needed).\n * - **`data-morph-preserve`** (KF-151) is honored in the trailing-removal\n * pass: an unmatched live element with this attribute is skipped instead\n * of removed. Lets imperatively-injected nodes (autoplay `<video>`s,\n * tour-widget tooltips, analytics pixels) survive across renders without\n * having to `data-morph-skip` the entire parent.\n * - **`ownedItems`** is the set of element nodes owned by an `each()`\n * list reconciler. The morph skips them in every children walk —\n * they're not added to the keyed-lookup map, the from-cursor advances\n * past them, and the trailing-removal pass leaves them in place. This\n * lets each() coexist with non-list siblings inside the same parent\n * (KF-102 round 2): the morph still walks the parent's children to\n * reconcile siblings, but never disturbs list rows. The parameter is an\n * internal coordination channel between `mount()` and the reconciler;\n * public callers should omit it (the default empty set is correct for\n * any tree that isn't being managed by an active `mount()`).\n * - Focused text inputs (`<input>`/`<textarea>`) keep their value +\n * selection across the morph; focused `[contenteditable]` keeps its\n * entire subtree (typed content + caret + multi-range selection).\n *\n * Algorithm credit: based on the design of\n * https://github.com/patrick-steele-idem/morphdom by Patrick Steele-Idem\n * (MIT licensed). Reimplemented here so kerf can specialize the hot paths\n * (segment-aware list dispatch, lighter callback surface) and drop the\n * runtime dependency. Original copyright preserved in `LICENSE`.\n */\n\nimport type { SafeHtml } from './jsx-runtime.js';\n\nconst ID_KEY_PREFIX = 'id:';\nconst DATA_KEY_PREFIX = 'data-key:';\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\n\nfunction getNodeKey(node: Node): string | undefined {\n if (node.nodeType !== ELEMENT_NODE) return undefined;\n const el = node as HTMLElement;\n if (el.id !== '') return `${ID_KEY_PREFIX}${el.id}`;\n if (el.dataset !== undefined && el.dataset.key !== undefined) {\n return `${DATA_KEY_PREFIX}${el.dataset.key}`;\n }\n return undefined;\n}\n\nconst EMPTY_OWNED: ReadonlySet<Element> = new Set();\n\n/**\n * Reconcile the children of `liveRoot` to match `template`.\n *\n * `template` can be an `Element` (used directly), a `SafeHtml`, or a raw\n * HTML string — the latter two are stringified and parsed into a transient\n * element whose tag matches `liveRoot`. The active text-entry / focused-\n * contenteditable preservation rules apply in all cases.\n *\n * `ownedItems` is an internal coordination channel for `mount()`'s list\n * reconciler; public callers should omit it.\n */\nexport function morph(\n liveRoot: Element,\n template: Element | SafeHtml | string,\n ownedItems: ReadonlySet<Element> = EMPTY_OWNED,\n): void {\n const templateEl: Element = isElementNode(template)\n ? template\n : parseTemplate(liveRoot, template);\n morphChildren(liveRoot, templateEl, ownedItems);\n}\n\nfunction isElementNode(t: Element | SafeHtml | string): t is Element {\n return typeof t === 'object' && t !== null\n && (t as Node).nodeType === ELEMENT_NODE;\n}\n\nfunction parseTemplate(liveRoot: Element, template: SafeHtml | string): Element {\n const el = liveRoot.cloneNode(false) as Element;\n el.innerHTML = String(template);\n return el;\n}\n\n/**\n * Advance past any owned (list-reconciler-managed) element. Owned items\n * stay put across morphs — they're invisible to the morph's child cursor.\n */\nfunction skipOwned(node: Node | null, ownedItems: ReadonlySet<Element>): Node | null {\n while (node !== null && node.nodeType === ELEMENT_NODE\n && ownedItems.has(node as Element)) {\n node = node.nextSibling;\n }\n return node;\n}\n\nfunction morphChildren(\n fromParent: Element,\n toParent: Element,\n ownedItems: ReadonlySet<Element>,\n): void {\n // Build a keyed lookup from the live children so we can match by key\n // even after reorders. Owned items don't participate in keyed matching\n // (they're not visible to the morph).\n const keyed = new Map<string, Element>();\n for (let c = fromParent.firstChild; c !== null; c = c.nextSibling) {\n if (c.nodeType === ELEMENT_NODE && ownedItems.has(c as Element)) continue;\n const k = getNodeKey(c);\n if (k !== undefined) keyed.set(k, c as Element);\n }\n\n let fromChild: Node | null = skipOwned(fromParent.firstChild, ownedItems);\n let toChild: Node | null = toParent.firstChild;\n\n while (toChild !== null) {\n const toNext = toChild.nextSibling;\n let matched: Node | null = null;\n\n // 1. Try key match.\n const toKey = getNodeKey(toChild);\n if (toKey !== undefined && keyed.has(toKey)) {\n matched = keyed.get(toKey) as Element;\n keyed.delete(toKey);\n if (matched !== fromChild) {\n fromParent.insertBefore(matched, fromChild);\n } else {\n fromChild = skipOwned(fromChild.nextSibling, ownedItems);\n }\n }\n\n // 2. Fall back to positional match — same nodeType, same tag (for\n // elements), and the live node has no key (a keyed node only\n // matches by key, never positionally, so reorders work).\n if (matched === null && fromChild !== null\n && fromChild.nodeType === toChild.nodeType\n && (toChild.nodeType !== ELEMENT_NODE\n || ((fromChild as Element).tagName === (toChild as Element).tagName\n && getNodeKey(fromChild) === undefined))) {\n matched = fromChild;\n fromChild = skipOwned(fromChild.nextSibling, ownedItems);\n }\n\n if (matched !== null) {\n morphNode(matched, toChild, ownedItems);\n } else {\n // 3. No match — clone the new node and insert before fromChild\n // (which may be an owned item we deliberately stopped at; that's\n // fine — `insertBefore(node, ownedItem)` slots the new sibling\n // in immediately before the list region).\n const cloned = toChild.cloneNode(true);\n fromParent.insertBefore(cloned, fromChild);\n }\n\n toChild = toNext;\n }\n\n // 4. Anything past the cursor is unmatched — remove, except for owned\n // items (those stay; they belong to a list reconciler) and elements\n // marked `data-morph-preserve` (KF-151 — imperatively-injected nodes\n // whose lifetime the consumer manages outside kerf).\n while (fromChild !== null) {\n const next = fromChild.nextSibling;\n if (fromChild.nodeType === ELEMENT_NODE) {\n const el = fromChild as Element;\n if (!ownedItems.has(el)\n && (el as HTMLElement).dataset.morphPreserve === undefined) {\n fromParent.removeChild(fromChild);\n }\n } else {\n fromParent.removeChild(fromChild);\n }\n fromChild = next;\n }\n}\n\nfunction morphNode(\n fromNode: Node,\n toNode: Node,\n ownedItems: ReadonlySet<Element>,\n): void {\n if (fromNode.nodeType === ELEMENT_NODE) {\n morphElement(fromNode as Element, toNode as Element, ownedItems);\n return;\n }\n if (fromNode.nodeType === TEXT_NODE || fromNode.nodeType === COMMENT_NODE) {\n const fromText = fromNode as CharacterData;\n const toText = toNode as CharacterData;\n if (fromText.data !== toText.data) fromText.data = toText.data;\n }\n}\n\nfunction morphElement(\n fromEl: Element,\n toEl: Element,\n ownedItems: ReadonlySet<Element>,\n): void {\n if (fromEl.tagName !== toEl.tagName) {\n const replacement = toEl.cloneNode(true);\n fromEl.parentNode?.replaceChild(replacement, fromEl);\n return;\n }\n // 1. Library-owned subtree — leave verbatim.\n if ((fromEl as HTMLElement).dataset.morphSkip !== undefined) return;\n // 2. Byte-identical — nothing to do.\n if (fromEl.isEqualNode(toEl)) return;\n // 3. Focused contenteditable — preserve user's in-progress edit.\n if (fromEl === document.activeElement) {\n const ce = fromEl.getAttribute('contenteditable');\n if (ce !== null && ce.toLowerCase() !== 'false') return;\n if (isTextInputOrTextarea(fromEl)) preserveTextEntryState(fromEl, toEl);\n }\n morphAttributes(fromEl, toEl);\n // 4. Subtree-only skip (KF-152) — attributes have already morphed; leave\n // the children alone. Use for client-hydrated slots whose loading /\n // state classes still need to flow through.\n if ((fromEl as HTMLElement).dataset.morphSkipChildren !== undefined) return;\n // 5. Recurse into children. List items inside `fromEl` (if any) are\n // skipped via `ownedItems` inside morphChildren — list reconciler\n // owns them — but non-list siblings are still morphed.\n morphChildren(fromEl, toEl, ownedItems);\n}\n\n/**\n * Attributes the user agent toggles in response to user interaction.\n * `<details>` and `<dialog>` add/remove `open=\"\"` themselves when the user\n * expands or closes the element. If the developer's JSX never mentions\n * `open`, treating that attribute as user-agent-owned and leaving it alone\n * during the morph keeps the user-driven state intact across re-renders.\n *\n * Trade-off (KF-84): controlled-style `<details open={signal.value}>` where\n * the signal flips false won't auto-collapse the element, because the\n * morph's remove pass no longer reaches `open`. Apps that need controlled\n * behavior should drive `open` imperatively (e.g. `el.removeAttribute('open')`\n * inside an action) or wrap with a state-toggle pattern. The uncontrolled\n * case is the common one and the one that was silently broken before.\n */\nfunction isUserAgentOwnedAttr(tagName: string, name: string): boolean {\n return name === 'open' && (tagName === 'DETAILS' || tagName === 'DIALOG');\n}\n\nfunction morphAttributes(fromEl: Element, toEl: Element): void {\n // Set/update every attribute on toEl.\n const toAttrs = toEl.attributes;\n for (let i = 0; i < toAttrs.length; i++) {\n const attr = toAttrs[i];\n const ns = attr.namespaceURI;\n const name = attr.localName;\n const value = attr.value;\n if (ns !== null) {\n if (fromEl.getAttributeNS(ns, name) !== value) {\n fromEl.setAttributeNS(ns, attr.name, value);\n }\n } else if (fromEl.getAttribute(name) !== value) {\n fromEl.setAttribute(name, value);\n }\n }\n // Remove attributes that are no longer present on toEl.\n const fromAttrs = fromEl.attributes;\n const fromTag = fromEl.tagName;\n for (let i = fromAttrs.length - 1; i >= 0; i--) {\n const attr = fromAttrs[i];\n const ns = attr.namespaceURI;\n const name = attr.localName;\n if (ns !== null) {\n if (!toEl.hasAttributeNS(ns, name)) fromEl.removeAttributeNS(ns, name);\n } else if (!toEl.hasAttribute(name) && !isUserAgentOwnedAttr(fromTag, name)) {\n fromEl.removeAttribute(name);\n }\n }\n}\n\nfunction isTextInputOrTextarea(el: Element): boolean {\n if (el.tagName === 'TEXTAREA') return true;\n if (el.tagName === 'INPUT') {\n const type = (el as HTMLInputElement).type;\n return type === 'text' || type === 'search' || type === 'url' || type === 'email'\n || type === 'tel' || type === 'password' || type === '';\n }\n return false;\n}\n\nfunction preserveTextEntryState(fromEl: Element, toEl: Element): void {\n if (fromEl.tagName === 'TEXTAREA' || fromEl.tagName === 'INPUT') {\n const fromInput = fromEl as HTMLInputElement;\n const toInput = toEl as HTMLInputElement;\n toInput.value = fromInput.value;\n try {\n toInput.setSelectionRange(fromInput.selectionStart, fromInput.selectionEnd);\n } catch {\n // Some input types (number, range, color, …) reject selection APIs.\n }\n }\n}\n","/**\n * Per-list binding shape kept by `mount()` and consumed by both reconcile\n * paths in `list-reconcile-snapshot.ts` and `list-reconcile-granular.ts`.\n *\n * Living in its own file (not re-exported through `list-reconcile.ts`) so\n * the snapshot + granular paths can import it without creating a circular\n * dependency on `list-reconcile.ts` itself. ESM handles cycles via function\n * hoisting, but a cycle involving a non-function helper would be a temporal\n * dead zone — extracting the binding shape + `endAnchor` here keeps the\n * dependency graph acyclic.\n */\n\nexport interface BoundItem {\n ref: object;\n cacheKey: unknown;\n html: string;\n node: Element;\n}\n\nexport interface ListBinding {\n liveParent: Element;\n /**\n * One entry per item currently mounted under `liveParent`, in order.\n * Mirrors the segment's `items` length after each reconcile.\n */\n items: BoundItem[];\n /**\n * The list's `<!--kf-list:N-->` start marker, kept in the live DOM as\n * a permanent anchor (KF-102 round 2). The marker stays put across\n * static-surrounds diffs (it morphs as a comment node), so it gives\n * the list reconciler a stable \"begin\" position even when surrounding\n * siblings get inserted, removed, or reordered around the list.\n *\n * `endAnchor(binding)` derives the \"insert at end of list\" anchor from\n * `marker.nextElementSibling` (empty list) or\n * `items[last].node.nextElementSibling` (non-empty list) — picking up\n * any non-list element the diff inserted between the list and the\n * parent's tail.\n */\n marker: Comment;\n}\n\n/**\n * Compute the live-DOM anchor that comes after the list's last item, used\n * by the apply* functions when inserting at the tail of the list.\n *\n * - Empty list: `marker.nextElementSibling` — the next non-list element\n * after the marker, or `null` if the list is the last thing in `liveParent`.\n * - Non-empty list: `items[last].node.nextElementSibling` — derived\n * dynamically so that non-list siblings the diff inserted between the\n * list's last item and the parent's tail still anchor correctly.\n */\nexport function endAnchor(binding: ListBinding): Element | null {\n if (binding.items.length > 0) {\n return binding.items[binding.items.length - 1].node.nextElementSibling;\n }\n return binding.marker.nextElementSibling;\n}\n","/**\n * Focus snapshot/restore for the keyed list reconciler.\n *\n * Some engines (older Safari, happy-dom) drop focus state on `insertBefore`\n * even when the focused element survives the move connected to the document.\n * The reconciler snapshots the active element + selection range before its\n * move pass, then re-applies them afterwards. Engines that already preserve\n * focus across DOM moves see a no-op; engines that don't get a transparent\n * fix.\n *\n * Lives in its own file (rather than inside `list-reconcile.ts`) to keep that\n * file under the 200-LOC project guideline and to isolate the engine-quirk\n * handling described in `docs/4-render.md` §4.4.\n */\n\nexport interface FocusSnapshot {\n el: HTMLElement;\n selStart: number | null;\n selEnd: number | null;\n}\n\n/**\n * Capture focus + selection on a focused descendant of `liveParent`.\n *\n * Returns null when the active element is outside the list (the diff path\n * handles those cases) or when there's no useful focus state to capture.\n */\nexport function captureFocus(liveParent: Element): FocusSnapshot | null {\n const active = document.activeElement;\n if (active === null || active === document.body) return null;\n if (!liveParent.contains(active)) return null;\n const el = active as HTMLElement;\n let selStart: number | null = null;\n let selEnd: number | null = null;\n if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {\n try {\n selStart = (el as HTMLInputElement).selectionStart;\n selEnd = (el as HTMLInputElement).selectionEnd;\n } catch {\n // Some input types (number, range, color, …) reject selection APIs.\n }\n }\n return { el, selStart, selEnd };\n}\n\nexport function restoreFocus(snap: FocusSnapshot): void {\n if (document.activeElement === snap.el) return;\n if (!snap.el.isConnected) return;\n snap.el.focus();\n if (snap.selStart !== null && snap.selEnd !== null) {\n try {\n (snap.el as HTMLInputElement).setSelectionRange(snap.selStart, snap.selEnd);\n } catch {\n // Selection may have been clobbered by .focus(); not fatal.\n }\n }\n}\n","/**\n * Shared \"exactly one top-level element per row\" contract helpers (KF-103).\n *\n * The keyed-list reconciler in `list-reconcile.ts` and the first-render\n * binding path in `mount.ts` both enforce the same contract on `each()`\n * row HTML. Centralising the constants and helpers here keeps the three\n * call sites that build error snippets and the eight call sites that\n * parse a row's HTML into a template element from drifting (KF-111 +\n * KF-115).\n */\n\n/**\n * Truncation limit applied to row HTML when including it in a contract-\n * violation error message. Keeps the error readable when a row produced\n * megabytes of HTML by accident.\n */\nexport const ROW_HTML_SNIPPET_MAX = 120;\n\n/**\n * Truncate a row's HTML for inclusion in an error message. Returns the\n * raw string if it's short enough; otherwise the first\n * `ROW_HTML_SNIPPET_MAX` characters with a trailing ellipsis.\n */\nexport function truncateRowHtml(html: string): string {\n return html.length > ROW_HTML_SNIPPET_MAX\n ? html.slice(0, ROW_HTML_SNIPPET_MAX) + '…'\n : html;\n}\n\n/**\n * Parse a row's HTML into a `<template>` and report how many top-level\n * elements it produced. The reconciler uses the count to detect contract\n * violations (count !== 1) on both single-row and bulk-row paths.\n */\nexport function parseRowTemplate(html: string): { tpl: HTMLTemplateElement; count: number } {\n const tpl = document.createElement('template');\n tpl.innerHTML = html;\n return { tpl, count: tpl.content.children.length };\n}\n\n/**\n * Build a precise contract-violation `Error` for the row at `index` whose\n * render produced the given `html`. The thrown message mentions the row\n * index, the actual element count, and the (truncated) HTML so the author\n * can locate and fix the offending row quickly.\n */\nexport function rowContractError(index: number, html: string): Error {\n const { count } = parseRowTemplate(html);\n const reason = count === 0\n ? 'produced no top-level element'\n : `produced ${count} top-level elements; exactly one is required`;\n return new Error(\n `each(): row render at index ${index} ${reason}. `\n + 'Each item\\'s render must return exactly one element — '\n + 'wrap multiple roots in a single parent (e.g. <li>...</li>). '\n + `Got HTML: ${JSON.stringify(truncateRowHtml(html))}`,\n );\n}\n","/**\n * Granular reconcile path for `each(...)` bound to an `arraySignal` (KF-92).\n *\n * Applies the patch events emitted by `arraySignal` mutators directly to\n * the live DOM and to `binding.items`, without iterating the full snapshot\n * or doing a classify pass. Cost is O(patches), not O(N).\n *\n * Two perf optimizations:\n * - **KF-93**: contiguous insert runs (patches at index N, N+1, N+2, …) are\n * bulk-parsed in one `template.innerHTML` call and inserted as a single\n * fragment. Saves ~50 ms on append-1k.\n * - **KF-94**: consecutive update runs (any indices — `replaceChild`\n * operates on each row's existing live node independently) are bulk-\n * parsed in one `template.innerHTML` call. Saves the per-patch parse\n * cost on the krausest partial-update scenario.\n *\n * Patches with `type: 'replace'` are filtered out by `each()` upstream and\n * never reach this function (the runtime contract guarantees absence even\n * though the TypeScript type allows them).\n *\n * Internal to kerf — re-exported via `list-reconcile.ts`'s `reconcileList`.\n */\n\nimport { type BoundItem, endAnchor, type ListBinding } from './list-binding.js';\nimport { captureFocus, restoreFocus } from './list-reconcile-focus.js';\nimport type { ListSegment } from './segment.js';\nimport { parseRowTemplate, rowContractError, truncateRowHtml } from './utils/rowContract.js';\n\nexport function reconcileGranular(\n binding: ListBinding,\n patches: NonNullable<ListSegment['patches']>,\n): void {\n const { liveParent } = binding;\n const items = binding.items;\n\n // Capture/restore focus around the whole batch (mirrors the snapshot\n // path's KF-65 fix). Some engines (older Safari, happy-dom) blur a\n // focused descendant on `insertBefore` / `replaceChild` even when the\n // ancestor stays connected — covers the move patch (which moves an\n // existing row's <li>), and is a no-op on engines that already\n // preserve focus across DOM ops.\n const focusSnap = captureFocus(liveParent);\n\n let i = 0;\n while (i < patches.length) {\n const patch = patches[i];\n /* c8 ignore next 5 — replace is filtered upstream by each(); this branch\n is defensive type-completeness only. */\n if (patch.type === 'replace') {\n i += 1;\n continue;\n }\n if (patch.type === 'update') {\n // KF-94: detect a run of consecutive update patches (any indices —\n // replaceChild operates on each row's existing live node independently,\n // so contiguity isn't required) and bulk-parse all their HTML in a\n // single `template.innerHTML` call. Saves the per-patch parse overhead\n // on krausest's partial-update scenario (100 update patches at\n // indices 0, 10, 20, … — non-contiguous, so KF-93's run detector\n // doesn't kick in).\n let runEnd = i + 1;\n while (runEnd < patches.length && patches[runEnd].type === 'update') {\n runEnd += 1;\n }\n const runLen = runEnd - i;\n if (runLen === 1) {\n applySingleUpdate(liveParent, items, patch);\n } else {\n applyBulkUpdate(liveParent, items, patches, i, runEnd);\n }\n i = runEnd;\n continue;\n }\n if (patch.type === 'insert') {\n // KF-93: detect a contiguous run of inserts at adjacent indices (each\n // next insert at the previous one's index + 1) and bulk-parse all\n // their HTML in a single `template.innerHTML` call, followed by a\n // single `insertBefore(fragment, anchor)`.\n let runEnd = i + 1;\n while (runEnd < patches.length\n && patches[runEnd].type === 'insert'\n && (patches[runEnd] as { index: number }).index\n === (patches[runEnd - 1] as { index: number }).index + 1) {\n runEnd += 1;\n }\n const runLen = runEnd - i;\n if (runLen === 1) {\n applySingleInsert(liveParent, items, patch, endAnchor(binding));\n } else {\n applyBulkInsert(liveParent, items, patches, i, runEnd, endAnchor(binding));\n }\n i = runEnd;\n continue;\n }\n if (patch.type === 'remove') {\n const entry = items[patch.index];\n liveParent.removeChild(entry.node);\n items.splice(patch.index, 1);\n i += 1;\n continue;\n }\n if (patch.type === 'move') {\n const moved = items[patch.from];\n // Compute the anchor BEFORE we splice, so the index references the\n // pre-move state.\n let anchorIdx = patch.to;\n if (patch.from < patch.to) anchorIdx += 1; // account for upcoming splice removal\n const anchor = anchorIdx < items.length ? items[anchorIdx].node : endAnchor(binding);\n liveParent.insertBefore(moved.node, anchor);\n items.splice(patch.from, 1);\n items.splice(patch.to, 0, moved);\n i += 1;\n continue;\n }\n }\n\n if (focusSnap !== null) restoreFocus(focusSnap);\n}\n\nfunction applySingleInsert(\n liveParent: Element,\n items: BoundItem[],\n patch: { type: 'insert'; index: number; item: object; html: string },\n tailAnchor: Element | null,\n): void {\n const { html } = patch;\n const newNode = parseSingleRow(html);\n const anchor = patch.index < items.length ? items[patch.index].node : tailAnchor;\n liveParent.insertBefore(newNode, anchor);\n items.splice(patch.index, 0, {\n ref: patch.item, cacheKey: undefined, html, node: newNode,\n });\n}\n\nfunction applySingleUpdate(\n liveParent: Element,\n items: BoundItem[],\n patch: { type: 'update'; index: number; item: object; html: string },\n): void {\n const { html } = patch;\n const oldEntry = items[patch.index];\n if (html === oldEntry.html) return; // no-op (defensive: caller may emit redundant patches)\n const newNode = parseSingleRow(html);\n liveParent.replaceChild(newNode, oldEntry.node);\n items[patch.index] = { ref: patch.item, cacheKey: undefined, html, node: newNode };\n}\n\n/**\n * Bulk-parse a run of consecutive update patches (KF-94). Indices may be\n * scattered (non-contiguous). Renders all HTMLs first, filters out no-ops\n * where the new HTML matches the old, then bulk-parses the remaining HTMLs\n * in one `template.innerHTML` call. The replaceChild loop afterwards is\n * unavoidable (one DOM op per row), but we save the per-patch parse cost.\n */\nfunction applyBulkUpdate(\n liveParent: Element,\n items: BoundItem[],\n patches: NonNullable<ListSegment['patches']>,\n start: number,\n end: number,\n): void {\n // Patches already carry pre-rendered HTML (KF-99). Filter out no-ops where\n // the new HTML matches the existing entry's html.\n interface Change { patchIdx: number; html: string }\n const changes: Change[] = [];\n for (let k = start; k < end; k++) {\n const p = patches[k] as { type: 'update'; index: number; item: object; html: string };\n if (p.html !== items[p.index].html) {\n changes.push({ patchIdx: k, html: p.html });\n }\n }\n if (changes.length === 0) return; // every update was a no-op\n\n // Bulk-parse all real changes in one innerHTML call.\n const { tpl, count } = parseRowTemplate(changes.map((c) => c.html).join(''));\n if (count !== changes.length) {\n throw findOffendingChange(patches, changes);\n }\n // Count matches; walk children unconditionally.\n const newNodes = new Array<Element>(changes.length);\n let child = tpl.content.firstElementChild;\n for (let k = 0; k < newNodes.length; k++) {\n newNodes[k] = child as Element;\n child = (child as Element).nextElementSibling;\n }\n\n // Apply replaceChild for each real change.\n for (let k = 0; k < changes.length; k++) {\n const c = changes[k];\n const p = patches[c.patchIdx] as { type: 'update'; index: number; item: object; html: string };\n const oldEntry = items[p.index];\n liveParent.replaceChild(newNodes[k], oldEntry.node);\n items[p.index] = { ref: p.item, cacheKey: undefined, html: c.html, node: newNodes[k] };\n }\n}\n\n/**\n * Bulk-parse a contiguous run of insert patches (KF-93). The run starts at\n * `start` (inclusive) and ends at `end` (exclusive); every patch in that\n * range is type `insert` with index === previous.index + 1. We render each\n * row's HTML, concatenate, parse the lot in one `template.innerHTML`, and\n * insert the resulting fragment in a single DOM op.\n */\nfunction applyBulkInsert(\n liveParent: Element,\n items: BoundItem[],\n patches: NonNullable<ListSegment['patches']>,\n start: number,\n end: number,\n tailAnchor: Element | null,\n): void {\n const startIdx = (patches[start] as { index: number }).index;\n const htmls = new Array<string>(end - start);\n for (let k = start; k < end; k++) {\n const p = patches[k] as { type: 'insert'; index: number; item: object; html: string };\n htmls[k - start] = p.html;\n }\n const { tpl, count } = parseRowTemplate(htmls.join(''));\n if (count !== htmls.length) {\n throw findOffendingInsert(patches, start, htmls);\n }\n // Count matches; capture child refs BEFORE the fragment-insert empties\n // tpl.content. Walk unconditionally — count check above guarantees\n // `firstElementChild` is non-null and there are exactly `end - start`\n // children.\n const newNodes = new Array<Element>(end - start);\n let child = tpl.content.firstElementChild;\n for (let k = 0; k < newNodes.length; k++) {\n newNodes[k] = child as Element;\n child = (child as Element).nextElementSibling;\n }\n const anchor = startIdx < items.length ? items[startIdx].node : tailAnchor;\n liveParent.insertBefore(tpl.content, anchor);\n // Splice all new entries into binding.items at the run's start index.\n const newEntries = new Array<BoundItem>(end - start);\n for (let k = 0; k < newEntries.length; k++) {\n const p = patches[start + k] as { type: 'insert'; index: number; item: object; html: string };\n newEntries[k] = {\n ref: p.item, cacheKey: undefined, html: htmls[k], node: newNodes[k],\n };\n }\n items.splice(startIdx, 0, ...newEntries);\n}\n\n/**\n * Parse a single row's HTML string into one Element. Used by the granular\n * reconciler's single-row paths (`applySingleInsert`, `applySingleUpdate`).\n * Each row is expected to render exactly one top-level element (the same\n * contract `each()` enforces in the snapshot path).\n */\nfunction parseSingleRow(html: string): Element {\n const { tpl, count } = parseRowTemplate(html);\n if (count !== 1) {\n const reason = count === 0\n ? 'produced no top-level element'\n : `produced ${count} top-level elements; exactly one is required`;\n throw new Error(\n `each() granular reconcile: row render ${reason}. `\n + 'Each item\\'s render must return exactly one element. '\n + `Got HTML: ${JSON.stringify(truncateRowHtml(html))}`,\n );\n }\n return tpl.content.firstElementChild as Element;\n}\n\n/**\n * Slow-path helper for `applyBulkInsert`. Walks each pre-rendered insert\n * patch's html in isolation to find the offending row.\n */\nfunction findOffendingInsert(\n patches: NonNullable<ListSegment['patches']>,\n start: number,\n htmls: string[],\n): Error {\n for (let i = 0; i < htmls.length; i++) {\n if (parseRowTemplate(htmls[i]).count !== 1) {\n const p = patches[start + i] as { type: 'insert'; index: number };\n return rowContractError(p.index, htmls[i]);\n }\n }\n /* c8 ignore start */\n return new Error('each(): bulk-insert mismatch with no per-row offender (kerf bug).');\n}\n/* c8 ignore stop */\n\n/**\n * Slow-path helper for `applyBulkUpdate`. Walks each non-no-op change to\n * find the offending row.\n */\nfunction findOffendingChange(\n patches: NonNullable<ListSegment['patches']>,\n changes: { patchIdx: number; html: string }[],\n): Error {\n for (const c of changes) {\n if (parseRowTemplate(c.html).count !== 1) {\n const p = patches[c.patchIdx] as { type: 'update'; index: number };\n return rowContractError(p.index, c.html);\n }\n }\n /* c8 ignore start */\n return new Error('each(): bulk-update mismatch with no per-row offender (kerf bug).');\n}\n/* c8 ignore stop */\n","/**\n * Snapshot reconcile path for `each(...)` — the original (non-granular)\n * keyed-list algorithm. Used when:\n * - The list is rendered with a plain array (not an `arraySignal`).\n * - The list is rendered with an `arraySignal` but no patch queue is\n * present (first render, post-`replace()`, or post-drift recovery).\n *\n * Algorithm:\n * 1. Classify each new item as `stable` (cache hit on identity + html),\n * `replaced` (same ref, html changed), or `new` (never seen before).\n * 2. Bulk-parse every fresh row's HTML in ONE `innerHTML` call — for an\n * initial population of 10k rows that's 1 parse instead of 10k.\n * 3. Remove orphan refs (gone from the new list) + replaced rows' old nodes.\n * 4. Compute a longest-increasing-subsequence over old positions; items in\n * the LIS are already in the right relative order, so they don't move.\n * 5. Reverse-pass over the new record, `insertBefore` only the items that\n * didn't anchor the LIS.\n *\n * The KF-89 fast path short-circuits when nothing structural changed —\n * the live tree already matches the new segment, so we can return after\n * step 1 with just the binding update.\n *\n * Internal to kerf — re-exported via `list-reconcile.ts`'s `reconcileList`.\n */\n\nimport { type BoundItem, endAnchor, type ListBinding } from './list-binding.js';\nimport { captureFocus, restoreFocus } from './list-reconcile-focus.js';\nimport type { ListSegment } from './segment.js';\nimport { parseRowTemplate, rowContractError } from './utils/rowContract.js';\n\ninterface Classification {\n newRecord: BoundItem[];\n prevIdx: number[];\n replacedNodes: Element[];\n freshIndices: number[];\n freshHtmls: string[];\n}\n\n/**\n * Reconcile via the snapshot algorithm. Mutates `binding.items` to mirror\n * the new segment when done.\n *\n * Focus capture/restore lives in `list-reconcile-focus.ts` — `insertBefore`\n * of a focused descendant's ancestor blurs the element in some engines\n * (happy-dom, older Safari) even when it stays connected; the snapshot fixes\n * those engines and is a no-op on engines that already preserve focus.\n */\nexport function reconcileSnapshot(binding: ListBinding, listSeg: ListSegment): void {\n const { liveParent } = binding;\n const { newRecord, prevIdx, replacedNodes, freshIndices, freshHtmls }\n = classifyItems(binding.items, listSeg);\n\n // KF-89 fast path: if no items were replaced, none are fresh, and every\n // surviving item kept its original position, the live tree already matches\n // the new segment. Skip buildFreshNodes (nothing to build), removeOldNodes\n // (nothing to remove), the LIS pass (no reorder possible), and applyMoves'\n // reverse walk (no moves). For a 1k-row list whose only change is a signal\n // re-read with no item-array delta, this collapses ~10–15 ms of per-render\n // bookkeeping into a single classification pass + the binding update.\n if (replacedNodes.length === 0 && freshIndices.length === 0\n && isInOrder(prevIdx)) {\n binding.items = newRecord;\n return;\n }\n\n // Compute tail anchor BEFORE removing old nodes: once an item is\n // detached, its `.nextElementSibling` is null and we lose the\n // boundary. Capturing here uses the binding's current (pre-mutation)\n // items[last].node which is still attached.\n const tailAnchor = endAnchor(binding);\n buildFreshNodes(newRecord, freshIndices, freshHtmls);\n const focusSnap = captureFocus(liveParent);\n removeOldNodes(liveParent, replacedNodes);\n applyMoves(liveParent, newRecord, prevIdx, lis(prevIdx), tailAnchor);\n if (focusSnap !== null) restoreFocus(focusSnap);\n binding.items = newRecord;\n}\n\n/**\n * Classify each item in the new segment against the old binding. Items with\n * a cache-hit (same ref + same html) are reused; replaced/new items get a\n * placeholder `BoundItem` whose `node` is filled in by the bulk parse below.\n */\nfunction classifyItems(oldItems: BoundItem[], listSeg: ListSegment): Classification {\n // Single Map<ref, [item, index]> instead of two Maps over the same key set\n // (KF-90). Halves the .set() calls during the build, halves the lookup\n // probe count during classification. ~1-2 ms saved per render on 1k-row\n // lists.\n const oldByRef = new Map<object, [BoundItem, number]>();\n for (let i = 0; i < oldItems.length; i++) {\n oldByRef.set(oldItems[i].ref, [oldItems[i], i]);\n }\n\n const newRecord: BoundItem[] = new Array(listSeg.items.length);\n const prevIdx = new Array<number>(listSeg.items.length);\n const replacedNodes: Element[] = [];\n const freshIndices: number[] = [];\n const freshHtmls: string[] = [];\n\n for (let i = 0; i < listSeg.items.length; i++) {\n const ni = listSeg.items[i];\n const oi = oldByRef.get(ni.ref);\n if (oi !== undefined) {\n oldByRef.delete(ni.ref);\n if (oi[0].html === ni.html) {\n newRecord[i] = oi[0];\n prevIdx[i] = oi[1];\n continue;\n }\n replacedNodes.push(oi[0].node);\n }\n newRecord[i] = {\n ref: ni.ref, cacheKey: ni.cacheKey, html: ni.html, node: null as unknown as Element,\n };\n prevIdx[i] = -1;\n freshIndices.push(i);\n freshHtmls.push(ni.html);\n }\n\n // Whatever's left in oldByRef is an orphan ref that disappeared from the\n // new list. The caller removes those nodes alongside the replaced ones.\n for (const [, orphan] of oldByRef) replacedNodes.push(orphan[0].node);\n\n return { newRecord, prevIdx, replacedNodes, freshIndices, freshHtmls };\n}\n\n/**\n * Bulk-parse every fresh row's HTML in one `innerHTML` call, then walk the\n * parsed children in order and fill in each placeholder's `node` field.\n *\n * Enforces the \"exactly one top-level element per row\" contract (KF-103):\n * if the bulk parse produces a different number of top-level elements\n * than fresh rows, fall back to per-row parsing to identify the offending\n * row and throw a precise error. The success path stays a single parse.\n */\nfunction buildFreshNodes(\n newRecord: BoundItem[],\n freshIndices: number[],\n freshHtmls: string[],\n): void {\n if (freshHtmls.length === 0) return;\n const { tpl, count } = parseRowTemplate(freshHtmls.join(''));\n if (count !== freshHtmls.length) {\n throw findOffendingRow(newRecord, freshIndices, freshHtmls);\n }\n // After the count check above, we know `tpl.content.children.length`\n // equals `freshIndices.length`, so the walk below always finds an element\n // for every index. No defensive null-guard needed.\n let node = tpl.content.firstElementChild;\n for (const idx of freshIndices) {\n const next = (node as Element).nextElementSibling;\n newRecord[idx].node = node as Element;\n node = next;\n }\n}\n\n/**\n * Walk per-row to find the offending row that violated the contract,\n * returning a precise error to throw. Only invoked when the bulk parse\n * detected a count mismatch — the success path is one parse with no\n * per-row work.\n */\nfunction findOffendingRow(\n newRecord: BoundItem[],\n freshIndices: number[],\n freshHtmls: string[],\n): Error {\n for (let i = 0; i < freshHtmls.length; i++) {\n if (parseRowTemplate(freshHtmls[i]).count !== 1) {\n return rowContractError(freshIndices[i], newRecord[freshIndices[i]].html);\n }\n }\n /* c8 ignore next 2 — unreachable: bulk mismatch ⇒ at least one row violates. */\n return new Error('each(): bulk-parse mismatch with no per-row offender (kerf bug).');\n}\n\n/**\n * Remove every replaced/orphan node still attached to the live parent.\n */\nfunction removeOldNodes(liveParent: Element, replacedNodes: Element[]): void {\n for (const node of replacedNodes) {\n if (node.parentElement === liveParent) liveParent.removeChild(node);\n }\n}\n\n/**\n * `insertBefore` everything that's not in the LIS. Walks the new record in\n * reverse so each move's anchor (`nextSibling`) is already in its final\n * position by the time we reach earlier items.\n *\n * `tailAnchor` is the element that comes AFTER the list inside `liveParent`\n * (or `null` if the list is at the end). The reconciler computes it via\n * `endAnchor(binding)` so it picks up non-list siblings the diff may have\n * inserted between the list and the parent's tail (KF-102).\n */\nfunction applyMoves(\n liveParent: Element,\n newRecord: BoundItem[],\n prevIdx: number[],\n stable: ReadonlySet<number>,\n tailAnchor: Element | null,\n): void {\n let nextSibling: Element | null = tailAnchor;\n for (let i = newRecord.length - 1; i >= 0; i--) {\n const node = newRecord[i].node;\n if (prevIdx[i] === -1 || !stable.has(i)) {\n liveParent.insertBefore(node, nextSibling);\n }\n nextSibling = node;\n }\n}\n\n/**\n * Patience-sort LIS: returns the *set of indices* in `arr` that participate\n * in a longest strictly-increasing subsequence. `-1` entries (representing\n * brand-new items in the new list) are ignored — they can't anchor the\n * subsequence and shouldn't count as stable.\n */\nfunction lis(arr: ReadonlyArray<number>): ReadonlySet<number> {\n const tails: number[] = [];\n const tailIdx: number[] = [];\n const prev = new Array<number>(arr.length);\n for (let i = 0; i < arr.length; i++) {\n const v = arr[i];\n if (v === -1) {\n prev[i] = -1;\n continue;\n }\n let lo = 0;\n let hi = tails.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (tails[mid] < v) lo = mid + 1;\n else hi = mid;\n }\n prev[i] = lo > 0 ? tailIdx[lo - 1] : -1;\n tails[lo] = v;\n tailIdx[lo] = i;\n }\n const out = new Set<number>();\n let k = tailIdx.length > 0 ? tailIdx[tailIdx.length - 1] : -1;\n while (k !== -1) {\n out.add(k);\n k = prev[k];\n }\n return out;\n}\n\n/**\n * True iff `prevIdx` is `[0, 1, 2, …, n-1]` — every item kept the position it\n * had in the previous render. Used by `reconcileSnapshot` to short-circuit\n * the LIS + move pass when nothing structural changed.\n */\nfunction isInOrder(prevIdx: number[]): boolean {\n for (let i = 0; i < prevIdx.length; i++) {\n if (prevIdx[i] !== i) return false;\n }\n return true;\n}\n","/**\n * Keyed list reconciler — the engine behind `each(...)` inside `mount()`.\n *\n * Public surface (re-exported via the rest of the runtime):\n * - `BoundItem` / `ListBinding`: the binding shape `mount()` keeps\n * per-list, mapping `each()` items to their live DOM nodes.\n * Defined in `list-binding.ts` and re-exported here.\n * - `endAnchor(binding)`: dynamic \"insert at end of list\" anchor.\n * Also defined in `list-binding.ts` and re-exported here.\n * - `reconcileList(binding, listSeg)`: top-level dispatch.\n *\n * Implementation lives in two sibling files:\n * - `list-reconcile-snapshot.ts` — the original keyed algorithm\n * (classify / bulk-parse / LIS / move). Used for plain-array `each()`\n * and for arraySignal-backed `each()` when the patch path can't apply\n * (first render, post-`replace()`, post-drift recovery).\n * - `list-reconcile-granular.ts` — the KF-92 patch-driven path used\n * when an `arraySignal`'s queued patches can be applied directly to\n * the existing binding without iterating the snapshot.\n *\n * The split mirrors the two-axis nature of the reconciler: snapshot-vs-\n * granular path × shared bookkeeping (binding shape, end-of-list anchor,\n * focus capture/restore). The binding shape is in its own `list-binding.ts`\n * file so the two sibling reconcilers can import it without creating a\n * circular dependency back to `list-reconcile.ts`. Internal to kerf — not\n * part of the public API.\n */\n\nexport { type BoundItem, endAnchor, type ListBinding } from './list-binding.js';\nimport type { ListBinding } from './list-binding.js';\nimport { reconcileGranular } from './list-reconcile-granular.js';\nimport { reconcileSnapshot } from './list-reconcile-snapshot.js';\nimport type { ListSegment } from './segment.js';\n\n/**\n * Reconcile `binding`'s live parent against `listSeg`. Mutates `binding.items`\n * to mirror the new segment when done.\n *\n * Dispatch:\n * - **Granular (KF-92)**: an `arraySignal`-backed `each()` whose patch\n * queue is non-empty AND the binding has at least one row. Applies\n * patches directly. `each()` filters `replace` patches upstream so the\n * patches reaching here are guaranteed to be update/insert/remove/move\n * only.\n * - **Snapshot**: every other case — first render of a list, plain-array\n * `each()`, post-`replace()`, post-drift recovery. Runs the keyed\n * classify/build/move algorithm.\n */\nexport function reconcileList(binding: ListBinding, listSeg: ListSegment): void {\n if (listSeg.patches !== undefined && binding.items.length > 0) {\n reconcileGranular(binding, listSeg.patches);\n return;\n }\n reconcileSnapshot(binding, listSeg);\n}\n","/**\n * `mount(rootEl, render)` — kerf's render primitive.\n *\n * Wraps `effect()` so that whenever any signal read inside `render()`\n * changes, we re-run `render()` and apply the minimum DOM mutations against\n * the live tree. Element identity (and thus focus, selection, in-flight\n * pointer interactions, and event listeners on preserved nodes) is preserved\n * wherever the keyed/positional diff matches.\n *\n * Two phases per render:\n *\n * - Static surrounds (everything outside `each()` lists): kerf's native\n * `morph()` reconciler walks a freshly-built template against the live\n * tree. Conventions: id/data-key matching, `data-morph-skip`, focus\n * preservation.\n *\n * - List interiors (children of every `each()` parent): native keyed\n * reconciler operates directly on the live parent's children. No\n * re-parse, no morph walk for cache-hit rows. Cost is O(changes), not\n * O(rows).\n *\n * Compared to a `replaceChildren(...rows.map(toElement))` rebuild pattern,\n * the user-visible win is that an `<input>` the user is typing into\n * survives an unrelated re-render — its DOM node, focus state, and cursor\n * position are not destroyed and recreated on each tick.\n */\n\nimport { _setRenderContext, type RenderContext } from './each.js';\nimport type { SafeHtml } from './jsx-runtime.js';\nimport { isSafeHtml } from './jsx-runtime.js';\nimport {\n type BoundItem,\n type ListBinding,\n reconcileList,\n} from './list-reconcile.js';\nimport { morph } from './morph.js';\nimport { effect } from './reactive.js';\nimport {\n collectLists,\n flatten,\n flattenWithoutListItems,\n type ListSegment,\n type Segment,\n} from './segment.js';\nimport { parseRowTemplate, rowContractError } from './utils/rowContract.js';\n\nconst LIST_MARKER_PREFIX = 'kf-list:';\n\n/**\n * Bind `render()` to the children of `rootEl`. Re-runs whenever any signal\n * read inside `render()` changes. Returns a disposer that tears down the\n * effect; call it when the host element is removed from the DOM.\n *\n * Conventions:\n *\n * - Diff keys: `id` and `data-key` are matched across the morph by key\n * rather than positionally, so list reorders move existing nodes instead\n * of churning unrelated siblings.\n * - `data-morph-skip`: any element with this attribute is left untouched\n * inside on subsequent renders. Used for library-owned subtrees (xterm-\n * style widgets, charts, third-party editors) where the library's own\n * lifecycle manages the children.\n * - Focused text-entry inputs (`<input>` of typing kinds, `<textarea>`)\n * keep their current value + selection range across morphs while focused.\n * The user never sees their cursor jump mid-keystroke.\n * - Focused `[contenteditable]` elements have their entire subtree\n * skipped (same mechanism as `data-morph-skip`). The user's in-progress\n * edit — typed content, caret position, multi-range selections, anything\n * else they did to the DOM — survives verbatim. The next render after\n * blur catches up.\n */\nexport type MountResult = SafeHtml | string | number | boolean | null | undefined;\n\nexport function mount(rootEl: HTMLElement, render: () => MountResult): () => void {\n if (rootEl == null) {\n throw new Error(\n 'mount: rootEl is null/undefined — pass the live element, e.g. mount(document.getElementById(\"app\")!, render). '\n + 'A common cause is a typo in the id or selector that returns null at runtime even though the TypeScript types say HTMLElement.',\n );\n }\n const bindings = new Map<string, ListBinding>();\n // Per-mount render context: the list-id counter is reset at the start of\n // each render (so the n-th `each()` call gets the same id every render);\n // the `caches` map persists across renders so unchanged items skip the\n // JSX work via cache hits even when the JSX render function is an inline\n // arrow that's a fresh function reference on every closure run (KF-87).\n const renderCtx: RenderContext = {\n counter: 0,\n caches: new Map(),\n bindingCounts: new Map(),\n };\n let isFirst = true;\n // KF-88: the static-surrounds HTML string from the previous render. If a\n // re-render produces the same string (the common case when a signal flips\n // a class on one row but the page chrome is unchanged), we skip the\n // template clone, the innerHTML re-parse, and the morph() walk entirely\n // and go straight to the per-list reconcilers. Saves ~8 ms per update-\n // path render against the krausest harness.\n let prevStaticHtml = '';\n\n return effect(() => {\n renderCtx.counter = 0;\n _setRenderContext(renderCtx);\n let result: MountResult;\n try {\n result = render();\n } finally {\n _setRenderContext(null);\n }\n\n // The `MountResult` union covers `null`, `undefined`, `false`, `true`,\n // and `number` so consumers can write `() => cond ? <jsx/> : null` and\n // `() => cond && <jsx/>` without a cast. `coerceRenderResult` collapses\n // nullish + boolean to `''` (render nothing) and stringifies numbers.\n const segment: Segment = isSafeHtml(result)\n ? (result.__segment ?? { kind: 'static', html: result.__html })\n : { kind: 'static', html: coerceRenderResult(result) };\n\n if (isFirst) {\n runFirstRender(rootEl, segment, bindings);\n prevStaticHtml = flattenWithoutListItems(segment);\n isFirst = false;\n } else {\n prevStaticHtml = runSubsequentRender(rootEl, segment, bindings, renderCtx, prevStaticHtml);\n }\n\n for (const listSeg of collectLists(segment).values()) {\n const binding = bindings.get(listSeg.id) as ListBinding;\n reconcileList(binding, listSeg);\n // KF-99: record the post-reconcile binding length so the next render's\n // granular path can detect drift (a prior render that threw mid-batch\n // leaves the binding shorter than the signal expects).\n renderCtx.bindingCounts.set(listSeg.id, binding.items.length);\n }\n });\n}\n\n/**\n * First render of a mount: bulk-flatten the segment (items inlined, markers\n * around each list) into `rootEl.innerHTML`, then walk the markers to\n * register a `ListBinding` per list. The subsequent `reconcileList` pass is\n * a no-op (every row's a cache hit on the just-bound items).\n */\nfunction runFirstRender(\n rootEl: HTMLElement,\n segment: Segment,\n bindings: Map<string, ListBinding>,\n): void {\n rootEl.innerHTML = flatten(segment, true);\n bindListsFromMarkers(rootEl, segment, bindings, true);\n}\n\n/**\n * Subsequent render of a mount. Returns the new `prevStaticHtml` so the\n * caller can carry it forward.\n *\n * Two paths:\n *\n * - **KF-88 fast path**: when the static-surrounds string didn't change\n * byte-for-byte, `bindListsFromMarkers` has nothing to discover and the\n * diff would short-circuit on `isEqualNode` for every element it visited —\n * but the visit itself isn't free. Skip both to save ~8 ms per partial-\n * update / select-row / swap-rows render against the krausest harness.\n *\n * Trade-off (KF-117, documented in `docs/4-render.md` §4.4.2): any\n * attribute or child set imperatively on a kerf-managed element (e.g.\n * `el.setAttribute(...)`) survives across no-op re-renders because the\n * diff doesn't run to wipe it. When the surrounds DO change, the diff\n * runs and `morphAttributes` removes anything the JSX didn't authorise.\n * This matches the framework's \"smallest cut\" model: don't touch what\n * JSX didn't change.\n *\n * - **Surrounds-changed path**: clean up orphan bindings (lists that\n * disappeared from this render's segment), build a template from the\n * static-only HTML, run `morph()` over the surrounds with the\n * list-owned items as `ownedItems` (KF-102 round 2 — the morph skips\n * owned items individually but still walks every parent so non-list\n * siblings around an each() reconcile correctly), then bind any\n * newly-appearing lists.\n */\nfunction runSubsequentRender(\n rootEl: HTMLElement,\n segment: Segment,\n bindings: Map<string, ListBinding>,\n renderCtx: RenderContext,\n prevStaticHtml: string,\n): string {\n const currentStaticHtml = flattenWithoutListItems(segment);\n if (currentStaticHtml === prevStaticHtml) {\n return prevStaticHtml;\n }\n cleanupOrphanBindings(segment, bindings, renderCtx);\n const template = rootEl.cloneNode(false) as HTMLElement;\n template.innerHTML = currentStaticHtml;\n morph(rootEl, template, collectOwnedItems(bindings));\n bindListsFromMarkers(rootEl, segment, bindings, false);\n return currentStaticHtml;\n}\n\n/**\n * Coerce a non-`SafeHtml` render result to a safe HTML string. Nullish\n * values and booleans become `''` (render nothing) — matches the React /\n * Solid convention so `{cond ? <jsx/> : null}` and `{cond && <jsx/>}`\n * patterns work without each consumer adding a sentinel. Everything else\n * is stringified (numbers → `\"42\"`, strings pass through).\n */\nfunction coerceRenderResult(result: unknown): string {\n if (result === null || result === undefined) return '';\n if (result === false || result === true) return '';\n return String(result);\n}\n\n/**\n * Walk the live tree's comment nodes; every `<!--kf-list:{id}-->` marker\n * is the start anchor of a list inside `liveParent`. Bind the list (parent +\n * already-rendered item nodes between the marker and the tail). The marker\n * stays in the live DOM (KF-102 round 2): keeping it as a permanent\n * comment-node anchor lets the static-surrounds diff insert/remove/morph\n * non-list siblings around the list without needing to re-establish the\n * list's begin position.\n *\n * `inlinedItems` distinguishes the first-render path (where `flatten(seg,\n * true)` inlines item HTML right after the marker, so the marker's element\n * siblings *are* the list rows) from subsequent renders that newly\n * introduce a list (where `flattenWithoutListItems` emits only the marker\n * and the list reconciler populates items afterwards).\n *\n * Existing bindings whose marker is still in the DOM are left intact —\n * `bindings.has(id)` skips re-binding so the prior render's item nodes\n * survive across static-surrounds diffs.\n */\nfunction bindListsFromMarkers(\n rootEl: Element,\n segment: Segment,\n bindings: Map<string, ListBinding>,\n inlinedItems: boolean,\n): void {\n const lists = collectLists(segment);\n const found: Comment[] = [];\n collectComments(rootEl, found);\n for (const marker of found) {\n if (!marker.data.startsWith(LIST_MARKER_PREFIX)) continue;\n const id = marker.data.slice(LIST_MARKER_PREFIX.length);\n if (bindings.has(id)) continue; // existing binding survives the diff\n const listSeg = lists.get(id) as ListSegment;\n const liveParent = marker.parentElement as Element;\n const items: BoundItem[] = [];\n if (inlinedItems) {\n // KF-103: enforce the \"exactly one top-level element per row\" contract\n // on first render too. Without this check, a multi-root row inlined\n // via `flatten(seg, true)` would silently misalign the binding (each\n // bound item.node points at only the first of a row's 2+ elements,\n // and the leftover elements are picked up as \"next\" rows). The check\n // is per-row so we can pinpoint the offender by index.\n let next: Element | null = marker.nextElementSibling;\n for (let i = 0; i < listSeg.items.length && next !== null; i++) {\n validateInlinedRowMatch(listSeg.items[i].html, i, next);\n items.push({\n ref: listSeg.items[i].ref,\n cacheKey: listSeg.items[i].cacheKey,\n html: listSeg.items[i].html,\n node: next,\n });\n next = next.nextElementSibling;\n }\n }\n bindings.set(id, { liveParent, items, marker });\n }\n}\n\n/**\n * KF-103: validate that `expectedHtml` (one row's render output) matches\n * the live `boundEl`'s `outerHTML` — confirming the row produced exactly\n * one top-level element. If they differ, parse the row in isolation and\n * throw a precise error mentioning the row index and the actual count.\n *\n * Fast path: outerHTML compare is a string equality check (zero allocs in\n * happy-dom; one alloc in V8). Only when they DON'T match (multi-root or\n * subtle browser-normalized single-root case) do we fall back to a full\n * per-row parse for the precise count.\n */\nfunction validateInlinedRowMatch(\n expectedHtml: string,\n index: number,\n boundEl: Element,\n): void {\n if (boundEl.outerHTML === expectedHtml) return;\n // The bound element's outerHTML differs from what we emitted. Parse the\n // expected html in isolation; if it's still single-root the difference\n // is whitespace / browser-normalization (e.g. `<br/>` → `<br>`) and\n // we proceed silently. Otherwise build the precise contract-violation\n // error from the shared helper.\n const { count } = parseRowTemplate(expectedHtml);\n if (count === 1) return;\n throw rowContractError(index, expectedHtml);\n}\n\n/**\n * Build the set of element nodes owned by `each()` list reconcilers, the\n * union of every binding's `items[].node`. The static-surrounds diff\n * skips these so list rows are invisible to the parent walk while\n * sibling reconciliation continues normally (KF-102 round 2).\n */\nfunction collectOwnedItems(bindings: Map<string, ListBinding>): Set<Element> {\n const owned = new Set<Element>();\n for (const b of bindings.values()) {\n for (const item of b.items) owned.add(item.node);\n }\n return owned;\n}\n\n/**\n * Remove items + binding entries for any list that's no longer present in\n * the new segment. The diff's trailing-removal pass would have removed the\n * marker (since the new template no longer emits one for this id), but\n * items are owned and stay protected from removal — so we drop them\n * explicitly here before the diff runs.\n */\nfunction cleanupOrphanBindings(\n segment: Segment,\n bindings: Map<string, ListBinding>,\n renderCtx: RenderContext,\n): void {\n const liveIds = collectLists(segment);\n for (const [id, binding] of bindings) {\n if (liveIds.has(id)) continue;\n for (const item of binding.items) {\n if (item.node.parentElement !== null) {\n item.node.parentElement.removeChild(item.node);\n }\n }\n if (binding.marker.parentElement !== null) {\n binding.marker.parentElement.removeChild(binding.marker);\n }\n bindings.delete(id);\n renderCtx.bindingCounts.delete(id);\n renderCtx.caches.delete(id);\n }\n}\n\n/**\n * Recursive collector for comment nodes — happy-dom's `TreeWalker` doesn't\n * surface `Node.COMMENT_NODE` despite accepting `NodeFilter.SHOW_COMMENT`,\n * so we walk children directly. Cheap (O(elements)) and portable.\n */\nfunction collectComments(node: Node, out: Comment[]): void {\n for (let c: Node | null = node.firstChild; c !== null; c = c.nextSibling) {\n if (c.nodeType === Node.COMMENT_NODE) out.push(c as Comment);\n else if (c.nodeType === Node.ELEMENT_NODE) collectComments(c, out);\n }\n}\n\n\n","/**\n * `toElement(jsx)` — JSX → DOM, with SVG-aware namespace handling.\n *\n * The naive implementation parses JSX through a `<template>` element's\n * `innerHTML`. That works for HTML and for SVG fragments whose root tag is\n * `<svg>` (the parser switches to \"foreign content\" mode). It silently\n * fails for SVG fragments WITHOUT an `<svg>` wrapper — descendants come out\n * as `HTMLUnknownElement` and never paint.\n *\n * `toElement` detects SVG content and routes through `DOMParser` with the\n * `image/svg+xml` MIME, which guarantees correct namespacing for all\n * descendants. HTML content takes the original `<template>` path unchanged.\n */\n\nimport type { SafeHtml } from './jsx-runtime.js';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\nconst SVG_FRAGMENT_TAGS = new Set([\n 'g', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline', 'ellipse',\n 'text', 'tspan', 'defs', 'use', 'symbol', 'clipPath', 'mask', 'pattern',\n 'filter', 'marker', 'linearGradient', 'radialGradient', 'stop', 'image',\n 'foreignObject',\n]);\n\nconst EXCERPT_MAX_LEN = 100;\n\nfunction leadingTag(html: string): string | null {\n const match = /^\\s*<([a-zA-Z][a-zA-Z0-9]*)\\b/.exec(html);\n return match !== null ? match[1] : null;\n}\n\nfunction excerpt(html: string): string {\n const trimmed = html.trim();\n return trimmed.length > EXCERPT_MAX_LEN ? `${trimmed.slice(0, EXCERPT_MAX_LEN)}…` : trimmed;\n}\n\nfunction parseSvgOrThrow(html: string, label: string, originalHtml: string): Document {\n const doc = new DOMParser().parseFromString(html, 'image/svg+xml');\n const err = doc.querySelector('parsererror');\n if (err !== null) {\n throw new Error(`toElement: ${label} parse error — ${err.textContent}\\n input: ${excerpt(originalHtml)}`);\n }\n return doc;\n}\n\nexport function toElement(jsx: SafeHtml | string): Element {\n const html = typeof jsx === 'string' ? jsx : jsx.toString();\n const tag = leadingTag(html);\n\n if (tag === 'svg') {\n // SVG root — parse as XML to guarantee namespace propagation.\n return parseSvgOrThrow(html, 'SVG', html).documentElement;\n }\n\n if (tag !== null && SVG_FRAGMENT_TAGS.has(tag)) {\n // SVG fragment without an <svg> wrapper — wrap, parse, unwrap.\n const wrapped = `<svg xmlns=\"${SVG_NS}\">${html}</svg>`;\n const doc = parseSvgOrThrow(wrapped, 'SVG fragment', html);\n const first = doc.documentElement.firstElementChild;\n /* c8 ignore next 2 — defensive: a successful XML parse of a wrapped svg always yields ≥1 child. */\n if (first === null) throw new Error(`toElement: SVG fragment produced no element\\n input: ${excerpt(html)}`);\n return first;\n }\n\n // HTML — `<template>`-based parse.\n const t = document.createElement('template');\n t.innerHTML = html;\n const child = t.content.firstElementChild;\n if (child === null) throw new Error(`toElement: produced no element\\n input: ${excerpt(html)}`);\n return child;\n}\n"]}
@@ -64,8 +64,12 @@ interface KerfBaseAttrs extends DataAriaAttrs {
64
64
  autoCapitalize?: AttrLike<'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters'>;
65
65
  autoFocus?: AttrLike<boolean>;
66
66
  accessKey?: AttrLike;
67
- /** `data-morph-skip` opts a subtree out of kerf's diff. Any value (incl. `true`) is treated as set. */
67
+ /** `data-morph-skip` opts a subtree out of kerf's morph. Any value (incl. `true`) is treated as set. */
68
68
  'data-morph-skip'?: AttrValue;
69
+ /** `data-morph-skip-children` (KF-152) — morph the element's attributes but leave its children verbatim. For client-hydrated slots whose loading/state classes still need to flow through. Any value (incl. `true`) is treated as set. */
70
+ 'data-morph-skip-children'?: AttrValue;
71
+ /** `data-morph-preserve` (KF-151) — an unmatched live element with this attribute is skipped by kerf's morph trailing-removal pass instead of removed. For imperatively-injected nodes (autoplay videos, tour overlays, analytics pixels) whose lifetime the consumer manages outside kerf. Does NOT block a keyed-match move; this is strictly an end-of-list-discard opt-out. Any value (incl. `true`) is treated as set. */
72
+ 'data-morph-preserve'?: AttrValue;
69
73
  children?: unknown;
70
74
  }
71
75
  /** Element-specific attribute interfaces. Each extends `KerfBaseAttrs`. */
@@ -640,7 +644,7 @@ interface KerfBuiltinIntrinsicElements {
640
644
  *
641
645
  * Why have a structured form at all: the perf bottleneck for huge
642
646
  * keyed lists isn't the per-row JSX work (which `each()` already
643
- * memoises). It's that flattening every render's whole tree to one
647
+ * memoizes). It's that flattening every render's whole tree to one
644
648
  * big HTML string forces a full `innerHTML` parse and a tree walk
645
649
  * over rows we know are unchanged. The segment shape lets mount()
646
650
  * skip both for the list parts.
@@ -1,3 +1,3 @@
1
- export { Fragment, SafeHtml, granularListSafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-KFOSUCCC.js';
1
+ export { Fragment, SafeHtml, granularListSafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-LADH5GVQ.js';
2
2
  //# sourceMappingURL=jsx-runtime.js.map
3
3
  //# sourceMappingURL=jsx-runtime.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kerfjs",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Tiny reactive UI framework — fine-grained signals + DOM morphing + JSX. Apply the smallest possible cut to update your DOM.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -69,9 +69,10 @@
69
69
  "test:browser": "npm run build && playwright test",
70
70
  "lint": "eslint src tests",
71
71
  "typecheck": "tsc --noEmit",
72
- "check": "npm run lint && npm run typecheck && node scripts/check-doc-test-inventory.mjs && npm test && npm run build && vitest run --config vitest.config.dist.ts && vitest run --config vitest.config.dist-full.ts && tsc -p tests/dist/jsx-typing/tsconfig.json",
72
+ "check": "npm run lint && npm run typecheck && node scripts/check-doc-test-inventory.mjs && node scripts/check-doc-api-coverage.mjs && npm test && npm run build && vitest run --config vitest.config.dist.ts && vitest run --config vitest.config.dist-full.ts && tsc -p tests/dist/jsx-typing/tsconfig.json",
73
73
  "check:full": "npm run check && playwright test",
74
74
  "check:docs:test-inventory": "node scripts/check-doc-test-inventory.mjs",
75
+ "check:docs:api-coverage": "node scripts/check-doc-api-coverage.mjs",
75
76
  "clean": "rm -rf dist coverage node_modules/.cache",
76
77
  "prepare": "husky",
77
78
  "release": "bash scripts/release.sh",