kerfjs 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@ 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.3.1] - 2026-05-08
8
+
9
+
10
+ - Removed stale `morphdom` references; the bundled native diff is now the only reconciler
11
+
7
12
  ## [0.3.0] - 2026-05-08
8
13
 
9
14
 
package/README.md CHANGED
@@ -127,7 +127,7 @@ npm run example:reactivity-demo
127
127
 
128
128
  ## Status
129
129
 
130
- v0.1.x — early. API may evolve. See [CHANGELOG.md](./CHANGELOG.md) for what's shipped.
130
+ v0.3.x — early. API may evolve. See [CHANGELOG.md](./CHANGELOG.md) for what's shipped.
131
131
 
132
132
  ## License
133
133
 
@@ -273,5 +273,5 @@ function Fragment({ children }) {
273
273
  }
274
274
 
275
275
  export { Fragment, SafeHtml, collectLists, flatten, flattenWithoutListItems, isSafeHtml, jsx, listSafeHtml, raw };
276
- //# sourceMappingURL=chunk-ZLV35OHG.js.map
277
- //# sourceMappingURL=chunk-ZLV35OHG.js.map
276
+ //# sourceMappingURL=chunk-WK5D3OO7.js.map
277
+ //# sourceMappingURL=chunk-WK5D3OO7.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-ZLV35OHG.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\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` and `morphdom`.\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 {\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\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\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 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 export interface IntrinsicElements {\n [elemName: string]: Record<string, unknown>;\n }\n}\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-WK5D3OO7.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\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 {\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\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\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 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 export interface IntrinsicElements {\n [elemName: string]: Record<string, unknown>;\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { S as Store, d as defineStore, r as resetAllStores } from './testing-CdM
5
5
 
6
6
  /**
7
7
  * Tiny event-delegation helpers. Replace per-element `addEventListener` calls
8
- * (which don't survive morph re-renders for nodes morphdom creates) with one
8
+ * (which don't survive morph re-renders for nodes the diff creates) with one
9
9
  * listener at the morph-root that dispatches via `closest()`.
10
10
  *
11
11
  * Three-tier listener model:
@@ -40,7 +40,7 @@ declare function delegate(rootEl: HTMLElement, type: string, selector: string, h
40
40
  /**
41
41
  * Capture-phase delegation — for non-bubbling events (`focus`, `blur`,
42
42
  * `scroll`, `load`, `error`). Reaches descendants of `rootEl` that match
43
- * `selector` regardless of how many times morphdom has rebuilt them.
43
+ * `selector` regardless of how many times the diff has rebuilt them.
44
44
  *
45
45
  * Usage (pseudo-code — see examples for live ones):
46
46
  * delegateCapture(rootEl, 'focus', 'input, textarea', handlerFn);
@@ -93,9 +93,10 @@ declare function each<T extends object>(items: readonly T[], render: (item: T, i
93
93
  *
94
94
  * Two phases per render:
95
95
  *
96
- * - Static surrounds (everything outside `each()` lists): morphdom diffs
97
- * a freshly-built template against the live tree. Same conventions as
98
- * before — id/data-key matching, `data-morph-skip`, focus preservation.
96
+ * - Static surrounds (everything outside `each()` lists): kerf's native
97
+ * `diff()` reconciler walks a freshly-built template against the live
98
+ * tree. Conventions: id/data-key matching, `data-morph-skip`, focus
99
+ * preservation.
99
100
  *
100
101
  * - List interiors (children of every `each()` parent): native keyed
101
102
  * reconciler operates directly on the live parent's children. No
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { isSafeHtml, listSafeHtml, flatten, collectLists, flattenWithoutListItems } from './chunk-ZLV35OHG.js';
2
- export { Fragment, SafeHtml, isSafeHtml, raw } from './chunk-ZLV35OHG.js';
1
+ import { isSafeHtml, listSafeHtml, flatten, collectLists, flattenWithoutListItems } from './chunk-WK5D3OO7.js';
2
+ export { Fragment, SafeHtml, isSafeHtml, raw } from './chunk-WK5D3OO7.js';
3
3
  import { effect } from './chunk-IZJIKRCE.js';
4
4
  export { batch, computed, defineStore, effect, resetAllStores, signal } from './chunk-IZJIKRCE.js';
5
5
 
@@ -201,67 +201,8 @@ function preserveTextEntryState(fromEl, toEl) {
201
201
  }
202
202
  }
203
203
 
204
- // src/mount.ts
205
- var LIST_MARKER_PREFIX = "kf-list:";
206
- function mount(rootEl, render) {
207
- const bindings = /* @__PURE__ */ new Map();
208
- const counter = { value: 0 };
209
- let isFirst = true;
210
- return effect(() => {
211
- counter.value = 0;
212
- _setListCounter(counter);
213
- let result;
214
- try {
215
- result = render();
216
- } finally {
217
- _setListCounter(null);
218
- }
219
- const segment = isSafeHtml(result) ? result.__segment ?? { kind: "static", html: result.__html } : { kind: "static", html: result };
220
- if (isFirst) {
221
- rootEl.innerHTML = flatten(segment, true);
222
- bindListsFromMarkers(rootEl, segment, bindings);
223
- isFirst = false;
224
- } else {
225
- const template = rootEl.cloneNode(false);
226
- template.innerHTML = flattenWithoutListItems(segment);
227
- const listParents = /* @__PURE__ */ new Set();
228
- for (const b of bindings.values()) listParents.add(b.liveParent);
229
- diff(rootEl, template, listParents);
230
- bindListsFromMarkers(rootEl, segment, bindings);
231
- }
232
- for (const listSeg of collectLists(segment).values()) {
233
- const binding = bindings.get(listSeg.id);
234
- reconcileList(binding, listSeg);
235
- }
236
- });
237
- }
238
- function bindListsFromMarkers(rootEl, segment, bindings) {
239
- const lists = collectLists(segment);
240
- const found = [];
241
- collectComments(rootEl, found);
242
- for (const marker of found) {
243
- if (!marker.data.startsWith(LIST_MARKER_PREFIX)) continue;
244
- const id = marker.data.slice(LIST_MARKER_PREFIX.length);
245
- const listSeg = lists.get(id);
246
- const liveParent = marker.parentElement;
247
- const items = [];
248
- let next = marker.nextElementSibling;
249
- for (let i = 0; i < listSeg.items.length && next !== null; i++) {
250
- items.push({
251
- ref: listSeg.items[i].ref,
252
- cacheKey: listSeg.items[i].cacheKey,
253
- html: listSeg.items[i].html,
254
- node: next
255
- });
256
- next = next.nextElementSibling;
257
- }
258
- bindings.set(id, { liveParent, items });
259
- marker.remove();
260
- }
261
- }
262
- function reconcileList(binding, listSeg) {
263
- const { liveParent } = binding;
264
- const oldItems = binding.items;
204
+ // src/list-reconcile.ts
205
+ function classifyItems(oldItems, listSeg) {
265
206
  const oldByRef = /* @__PURE__ */ new Map();
266
207
  const oldIndex = /* @__PURE__ */ new Map();
267
208
  for (let i = 0; i < oldItems.length; i++) {
@@ -295,37 +236,39 @@ function reconcileList(binding, listSeg) {
295
236
  freshIndices.push(i);
296
237
  freshHtmls.push(ni.html);
297
238
  }
298
- if (freshHtmls.length > 0) {
299
- const tpl = document.createElement("template");
300
- tpl.innerHTML = freshHtmls.join("");
301
- let node = tpl.content.firstElementChild;
302
- for (const idx of freshIndices) {
303
- if (node === null) {
304
- throw new Error(
305
- `each(): row render produced no top-level element. Each item's render must return exactly one element. Got HTML: ${newRecord[idx].html.slice(0, 120)}`
306
- );
307
- }
308
- const next = node.nextElementSibling;
309
- newRecord[idx].node = node;
310
- node = next;
239
+ for (const [, orphan] of oldByRef) replacedNodes.push(orphan.node);
240
+ return { newRecord, prevIdx, replacedNodes, freshIndices, freshHtmls };
241
+ }
242
+ function buildFreshNodes(newRecord, freshIndices, freshHtmls) {
243
+ if (freshHtmls.length === 0) return;
244
+ const tpl = document.createElement("template");
245
+ tpl.innerHTML = freshHtmls.join("");
246
+ let node = tpl.content.firstElementChild;
247
+ for (const idx of freshIndices) {
248
+ if (node === null) {
249
+ throw new Error(
250
+ `each(): row render produced no top-level element. Each item's render must return exactly one element. Got HTML: ${newRecord[idx].html.slice(0, 120)}`
251
+ );
311
252
  }
253
+ const next = node.nextElementSibling;
254
+ newRecord[idx].node = node;
255
+ node = next;
312
256
  }
313
- for (const orphan of oldByRef.values()) {
314
- if (orphan.node.parentElement === liveParent) liveParent.removeChild(orphan.node);
315
- }
257
+ }
258
+ function removeOldNodes(liveParent, replacedNodes) {
316
259
  for (const node of replacedNodes) {
317
260
  if (node.parentElement === liveParent) liveParent.removeChild(node);
318
261
  }
319
- const stable = lis(prevIdx);
262
+ }
263
+ function applyMoves(liveParent, newRecord, prevIdx, stable) {
320
264
  let nextSibling = null;
321
265
  for (let i = newRecord.length - 1; i >= 0; i--) {
322
266
  const node = newRecord[i].node;
323
- if (prevIdx[i] !== -1 && stable.has(i)) ; else {
267
+ if (prevIdx[i] === -1 || !stable.has(i)) {
324
268
  liveParent.insertBefore(node, nextSibling);
325
269
  }
326
270
  nextSibling = node;
327
271
  }
328
- binding.items = newRecord;
329
272
  }
330
273
  function lis(arr) {
331
274
  const tails = [];
@@ -356,10 +299,77 @@ function lis(arr) {
356
299
  }
357
300
  return out;
358
301
  }
302
+ function reconcileList(binding, listSeg) {
303
+ const { liveParent } = binding;
304
+ const { newRecord, prevIdx, replacedNodes, freshIndices, freshHtmls } = classifyItems(binding.items, listSeg);
305
+ buildFreshNodes(newRecord, freshIndices, freshHtmls);
306
+ removeOldNodes(liveParent, replacedNodes);
307
+ applyMoves(liveParent, newRecord, prevIdx, lis(prevIdx));
308
+ binding.items = newRecord;
309
+ }
310
+
311
+ // src/mount.ts
312
+ var LIST_MARKER_PREFIX = "kf-list:";
313
+ function mount(rootEl, render) {
314
+ const bindings = /* @__PURE__ */ new Map();
315
+ const counter = { value: 0 };
316
+ let isFirst = true;
317
+ return effect(() => {
318
+ counter.value = 0;
319
+ _setListCounter(counter);
320
+ let result;
321
+ try {
322
+ result = render();
323
+ } finally {
324
+ _setListCounter(null);
325
+ }
326
+ const segment = isSafeHtml(result) ? result.__segment ?? { kind: "static", html: result.__html } : { kind: "static", html: result };
327
+ if (isFirst) {
328
+ rootEl.innerHTML = flatten(segment, true);
329
+ bindListsFromMarkers(rootEl, segment, bindings);
330
+ isFirst = false;
331
+ } else {
332
+ const template = rootEl.cloneNode(false);
333
+ template.innerHTML = flattenWithoutListItems(segment);
334
+ const listParents = /* @__PURE__ */ new Set();
335
+ for (const b of bindings.values()) listParents.add(b.liveParent);
336
+ diff(rootEl, template, listParents);
337
+ bindListsFromMarkers(rootEl, segment, bindings);
338
+ }
339
+ for (const listSeg of collectLists(segment).values()) {
340
+ const binding = bindings.get(listSeg.id);
341
+ reconcileList(binding, listSeg);
342
+ }
343
+ });
344
+ }
345
+ function bindListsFromMarkers(rootEl, segment, bindings) {
346
+ const lists = collectLists(segment);
347
+ const found = [];
348
+ collectComments(rootEl, found);
349
+ for (const marker of found) {
350
+ if (!marker.data.startsWith(LIST_MARKER_PREFIX)) continue;
351
+ const id = marker.data.slice(LIST_MARKER_PREFIX.length);
352
+ const listSeg = lists.get(id);
353
+ const liveParent = marker.parentElement;
354
+ const items = [];
355
+ let next = marker.nextElementSibling;
356
+ for (let i = 0; i < listSeg.items.length && next !== null; i++) {
357
+ items.push({
358
+ ref: listSeg.items[i].ref,
359
+ cacheKey: listSeg.items[i].cacheKey,
360
+ html: listSeg.items[i].html,
361
+ node: next
362
+ });
363
+ next = next.nextElementSibling;
364
+ }
365
+ bindings.set(id, { liveParent, items });
366
+ marker.remove();
367
+ }
368
+ }
359
369
  function collectComments(node, out) {
360
370
  for (let c = node.firstChild; c !== null; c = c.nextSibling) {
361
- if (c.nodeType === 8) out.push(c);
362
- else if (c.nodeType === 1) collectComments(c, out);
371
+ if (c.nodeType === Node.COMMENT_NODE) out.push(c);
372
+ else if (c.nodeType === Node.ELEMENT_NODE) collectComments(c, out);
363
373
  }
364
374
  }
365
375
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/delegate.ts","../src/each.ts","../src/diff.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 morphdom 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 * - Tier 2 (non-bubbling events) — use `delegateCapture()`.\n * focus, blur, scroll, load, error, mouseenter, mouseleave.\n * The capture phase fires on the way down from the root to the target,\n * so a root-level listener with `capture: true` reaches events that\n * wouldn't bubble back 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 * 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 * Bubble-phase delegation. Installs ONE listener on `rootEl` for the given\n * event type. When the event fires, walks up from `event.target` to the root\n * looking for an element matching `selector`; if found, fires `handler` with\n * the matched element as the second arg.\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 */\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 rootEl.addEventListener(type, listener);\n return () => {\n rootEl.removeEventListener(type, listener);\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 morphdom 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 { SafeHtml } from './jsx-runtime.js';\nimport { isSafeHtml, listSafeHtml } from './jsx-runtime.js';\n\ninterface CacheEntry {\n key: unknown;\n html: string;\n}\n\nconst ROW_CACHE = new WeakMap<object, CacheEntry>();\n\n/**\n * Per-mount counter for assigning stable list ids across renders. `mount()`\n * sets this at the start of each render so that the n-th `each()` call\n * produces id \"n\" every render — the binding to the live parent persists.\n *\n * Outside a mount() render, calls to `each()` still work but get the\n * sentinel id \"orphan\"; their output flattens correctly via `toString()`\n * but the structural fast-path doesn't apply (no `mount()` is watching).\n */\nlet listCounter: { value: number } | null = null;\n\nexport function _setListCounter(c: { value: number } | null): void {\n listCounter = c;\n}\n\nexport function each<T extends object>(\n items: readonly T[],\n render: (item: T, index: number) => SafeHtml | string,\n key?: (item: T, index: number) => unknown,\n): SafeHtml {\n const id = listCounter !== null ? String(listCounter.value++) : 'orphan';\n const segItems = new Array<{ ref: object; cacheKey: unknown; html: string }>(items.length);\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const k = key ? key(item, i) : undefined;\n const cached = ROW_CACHE.get(item);\n let html: string;\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 ROW_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, listParents)` — 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 * - Three short-circuit paths on each element:\n * 1. `data-morph-skip`: subtree is library-owned, leave verbatim.\n * 2. `isEqualNode`: subtree is byte-identical, no work needed.\n * 3. `listParents` membership: a kerf list reconciler owns this\n * element's children, so we morph attributes only and stop.\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`. `listParents` is the set of live elements whose children\n * are managed by `each()`'s reconciler — they get attribute morphing but\n * not children diffing.\n */\nexport function diff(\n liveRoot: Element,\n templateRoot: Element,\n listParents: ReadonlySet<Element>,\n): void {\n diffChildren(liveRoot, templateRoot, listParents);\n}\n\nfunction diffChildren(\n fromParent: Element,\n toParent: Element,\n listParents: ReadonlySet<Element>,\n): void {\n // Build a keyed lookup from the live children so we can match by key\n // even after reorders.\n const keyed = new Map<string, Element>();\n for (let c = fromParent.firstChild; c !== null; c = c.nextSibling) {\n const k = getNodeKey(c);\n if (k !== undefined) keyed.set(k, c as Element);\n }\n\n let fromChild: Node | null = fromParent.firstChild;\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 = fromChild.nextSibling;\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 = fromChild.nextSibling;\n }\n\n if (matched !== null) {\n morphNode(matched, toChild, listParents);\n } else {\n // 3. No match — clone the new node and insert.\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. Any keyed node that\n // wasn't matched in the toParent walk falls into this trailing range\n // by construction (matched keyed nodes get moved before the cursor;\n // unmatched ones stay at or after it), so we don't need a separate\n // orphan pass.\n while (fromChild !== null) {\n const next = fromChild.nextSibling;\n fromParent.removeChild(fromChild);\n fromChild = next;\n }\n}\n\nfunction morphNode(\n fromNode: Node,\n toNode: Node,\n listParents: ReadonlySet<Element>,\n): void {\n if (fromNode.nodeType === ELEMENT_NODE) {\n morphElement(fromNode as Element, toNode as Element, listParents);\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 listParents: 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. List parent — its children are managed by the each() reconciler;\n // diff stops here. We still ran morphAttributes above, so attribute\n // changes on the parent itself (id, class, data-* …) propagate.\n if (listParents.has(fromEl)) return;\n diffChildren(fromEl, toEl, listParents);\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 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)) {\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 * `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): morphdom diffs\n * a freshly-built template against the live tree. Same conventions as\n * before — id/data-key matching, `data-morph-skip`, focus 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 { _setListCounter } from './each.js';\nimport type { SafeHtml } from './jsx-runtime.js';\nimport { isSafeHtml } from './jsx-runtime.js';\nimport { effect } from './reactive.js';\nimport {\n collectLists,\n flatten,\n flattenWithoutListItems,\n type ListSegment,\n type Segment,\n} from './segment.js';\n\ninterface BoundItem {\n ref: object;\n cacheKey: unknown;\n html: string;\n node: Element;\n}\n\ninterface ListBinding {\n liveParent: Element;\n /**\n * One entry per item currently mounted under `liveParent`, in order.\n * Mirrors the current segment's `items` length after each reconcile.\n */\n items: BoundItem[];\n}\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 function mount(rootEl: HTMLElement, render: () => SafeHtml | string): () => void {\n const bindings = new Map<string, ListBinding>();\n const counter = { value: 0 };\n let isFirst = true;\n\n return effect(() => {\n counter.value = 0;\n _setListCounter(counter);\n let result: SafeHtml | string;\n try {\n result = render();\n } finally {\n _setListCounter(null);\n }\n\n const segment: Segment = isSafeHtml(result)\n ? (result.__segment ?? { kind: 'static', html: result.__html })\n : { kind: 'static', html: result };\n\n if (isFirst) {\n // Bulk-render with items inlined and a marker per list. The marker walk\n // afterwards binds each list to the rows already in the DOM, so the\n // first-render reconcile is a no-op (every item is a cache hit).\n rootEl.innerHTML = flatten(segment, true);\n bindListsFromMarkers(rootEl, segment, bindings);\n isFirst = false;\n } else {\n // Static-surrounds-only render: lists become marker-only in the\n // template. `diff()` skips bound list parents' children entirely\n // (so existing rows stay) and inserts the marker for any list that\n // didn't exist before. The marker walk afterwards binds those new\n // lists; the per-list reconcile below patches every list's items.\n const template = rootEl.cloneNode(false) as HTMLElement;\n template.innerHTML = flattenWithoutListItems(segment);\n const listParents = new Set<Element>();\n for (const b of bindings.values()) listParents.add(b.liveParent);\n diff(rootEl, template, listParents);\n bindListsFromMarkers(rootEl, segment, bindings);\n }\n\n for (const listSeg of collectLists(segment).values()) {\n const binding = bindings.get(listSeg.id) as ListBinding;\n reconcileList(binding, listSeg);\n }\n });\n}\n\n/**\n * Walk the live tree's comment nodes; every `<!--kf-list:{id}-->` marker\n * is the first child of a list parent. Record the binding (parent + the\n * already-rendered item nodes that follow the marker) and then remove the\n * marker — bindings live in JS, not in the DOM.\n */\nfunction bindListsFromMarkers(\n rootEl: Element,\n segment: Segment,\n bindings: Map<string, ListBinding>,\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 // Markers are only emitted by `flatten(..., true)` paired with a list\n // segment in the same render, so both lookups always succeed here.\n const listSeg = lists.get(id) as ListSegment;\n const liveParent = marker.parentElement as Element;\n // On first render, items are inlined right after the marker (so the\n // first element sibling is `items[0]`, the next is `items[1]`, etc.).\n // On subsequent renders for a list newly appearing, the list parent\n // is empty after the marker; the loop falls through with `items=[]`\n // and the reconcile phase below builds the items.\n const items: BoundItem[] = [];\n let next: Element | null = marker.nextElementSibling;\n for (let i = 0; i < listSeg.items.length && next !== null; i++) {\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 bindings.set(id, { liveParent, items });\n marker.remove();\n }\n}\n\nfunction reconcileList(binding: ListBinding, listSeg: ListSegment): void {\n const { liveParent } = binding;\n const oldItems = binding.items;\n const oldByRef = new Map<object, BoundItem>();\n const oldIndex = new Map<object, number>();\n for (let i = 0; i < oldItems.length; i++) {\n oldByRef.set(oldItems[i].ref, oldItems[i]);\n oldIndex.set(oldItems[i].ref, i);\n }\n\n // Build the new record. Per item, decide:\n // - \"stable\": cache hit (same ref, byte-identical html) — reuse the\n // existing live node. Captures its old position in `prevIdx` so the\n // LIS pass can decide whether the node also needs to move.\n // - \"replaced\": same ref but html changed — schedule a fresh node;\n // the old node will be removed before the move pass.\n // - \"new\": ref didn't exist before — schedule a fresh node.\n //\n // Fresh nodes aren't built one-at-a-time; instead we collect every fresh\n // item's HTML and parse them all in one `innerHTML` call below. For an\n // initial population of, say, 10k rows that's 1 parse instead of 10k.\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.html === ni.html) {\n newRecord[i] = oi;\n prevIdx[i] = oldIndex.get(ni.ref) as number;\n continue;\n }\n replacedNodes.push(oi.node);\n }\n // Placeholder; node is filled in by the bulk parse below.\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 if (freshHtmls.length > 0) {\n const tpl = document.createElement('template');\n tpl.innerHTML = freshHtmls.join('');\n let node = tpl.content.firstElementChild;\n for (const idx of freshIndices) {\n if (node === null) {\n throw new Error(\n `each(): row render produced no top-level element. Each item's render must return exactly one element. Got HTML: ${newRecord[idx].html.slice(0, 120)}`,\n );\n }\n const next = node.nextElementSibling;\n newRecord[idx].node = node;\n node = next;\n }\n }\n\n // Remove orphans (refs that disappeared from the new list) and the old\n // nodes for replaced items. Both are out of `oldByRef` already; replaced\n // ones were captured separately.\n for (const orphan of oldByRef.values()) {\n if (orphan.node.parentElement === liveParent) liveParent.removeChild(orphan.node);\n }\n for (const node of replacedNodes) {\n if (node.parentElement === liveParent) liveParent.removeChild(node);\n }\n\n // Compute the longest increasing subsequence of `prevIdx`. New positions\n // whose index is in the LIS are already in the right relative order — we\n // skip moving them. Everything else (replaced, new, or relatively-out-of-\n // order stable items) gets `insertBefore`d in a single reverse pass.\n const stable = lis(prevIdx);\n let nextSibling: Element | null = null;\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 // In LIS — already in the right place.\n } else {\n liveParent.insertBefore(node, nextSibling);\n }\n nextSibling = node;\n }\n\n binding.items = newRecord;\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 * 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 === 8) out.push(c as Comment);\n else if (c.nodeType === 1) 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/diff.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 * - Tier 2 (non-bubbling events) — use `delegateCapture()`.\n * focus, blur, scroll, load, error, mouseenter, mouseleave.\n * The capture phase fires on the way down from the root to the target,\n * so a root-level listener with `capture: true` reaches events that\n * wouldn't bubble back 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 * 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 * Bubble-phase delegation. Installs ONE listener on `rootEl` for the given\n * event type. When the event fires, walks up from `event.target` to the root\n * looking for an element matching `selector`; if found, fires `handler` with\n * the matched element as the second arg.\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 */\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 rootEl.addEventListener(type, listener);\n return () => {\n rootEl.removeEventListener(type, listener);\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 { SafeHtml } from './jsx-runtime.js';\nimport { isSafeHtml, listSafeHtml } from './jsx-runtime.js';\n\ninterface CacheEntry {\n key: unknown;\n html: string;\n}\n\nconst ROW_CACHE = new WeakMap<object, CacheEntry>();\n\n/**\n * Per-mount counter for assigning stable list ids across renders. `mount()`\n * sets this at the start of each render so that the n-th `each()` call\n * produces id \"n\" every render — the binding to the live parent persists.\n *\n * Outside a mount() render, calls to `each()` still work but get the\n * sentinel id \"orphan\"; their output flattens correctly via `toString()`\n * but the structural fast-path doesn't apply (no `mount()` is watching).\n */\nlet listCounter: { value: number } | null = null;\n\nexport function _setListCounter(c: { value: number } | null): void {\n listCounter = c;\n}\n\nexport function each<T extends object>(\n items: readonly T[],\n render: (item: T, index: number) => SafeHtml | string,\n key?: (item: T, index: number) => unknown,\n): SafeHtml {\n const id = listCounter !== null ? String(listCounter.value++) : 'orphan';\n const segItems = new Array<{ ref: object; cacheKey: unknown; html: string }>(items.length);\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const k = key ? key(item, i) : undefined;\n const cached = ROW_CACHE.get(item);\n let html: string;\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 ROW_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, listParents)` — 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 * - Three short-circuit paths on each element:\n * 1. `data-morph-skip`: subtree is library-owned, leave verbatim.\n * 2. `isEqualNode`: subtree is byte-identical, no work needed.\n * 3. `listParents` membership: a kerf list reconciler owns this\n * element's children, so we morph attributes only and stop.\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`. `listParents` is the set of live elements whose children\n * are managed by `each()`'s reconciler — they get attribute morphing but\n * not children diffing.\n */\nexport function diff(\n liveRoot: Element,\n templateRoot: Element,\n listParents: ReadonlySet<Element>,\n): void {\n diffChildren(liveRoot, templateRoot, listParents);\n}\n\nfunction diffChildren(\n fromParent: Element,\n toParent: Element,\n listParents: ReadonlySet<Element>,\n): void {\n // Build a keyed lookup from the live children so we can match by key\n // even after reorders.\n const keyed = new Map<string, Element>();\n for (let c = fromParent.firstChild; c !== null; c = c.nextSibling) {\n const k = getNodeKey(c);\n if (k !== undefined) keyed.set(k, c as Element);\n }\n\n let fromChild: Node | null = fromParent.firstChild;\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 = fromChild.nextSibling;\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 = fromChild.nextSibling;\n }\n\n if (matched !== null) {\n morphNode(matched, toChild, listParents);\n } else {\n // 3. No match — clone the new node and insert.\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. Any keyed node that\n // wasn't matched in the toParent walk falls into this trailing range\n // by construction (matched keyed nodes get moved before the cursor;\n // unmatched ones stay at or after it), so we don't need a separate\n // orphan pass.\n while (fromChild !== null) {\n const next = fromChild.nextSibling;\n fromParent.removeChild(fromChild);\n fromChild = next;\n }\n}\n\nfunction morphNode(\n fromNode: Node,\n toNode: Node,\n listParents: ReadonlySet<Element>,\n): void {\n if (fromNode.nodeType === ELEMENT_NODE) {\n morphElement(fromNode as Element, toNode as Element, listParents);\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 listParents: 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. List parent — its children are managed by the each() reconciler;\n // diff stops here. We still ran morphAttributes above, so attribute\n // changes on the parent itself (id, class, data-* …) propagate.\n if (listParents.has(fromEl)) return;\n diffChildren(fromEl, toEl, listParents);\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 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)) {\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 * Keyed list reconciler — the engine behind `each(...)` inside `mount()`.\n *\n * Given a `ListBinding` (the live parent + the items currently mounted under\n * it) and a fresh `ListSegment` from this render, mutate the live DOM with\n * the minimum number of operations:\n *\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 * Lives in its own file so `mount.ts` can stay an orchestrator under the\n * 200-LOC guideline. Internal to kerf — not part of the public API.\n */\n\nimport type { ListSegment } from './segment.js';\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\ninterface Classification {\n newRecord: BoundItem[];\n prevIdx: number[];\n replacedNodes: Element[];\n freshIndices: number[];\n freshHtmls: string[];\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 const oldByRef = new Map<object, BoundItem>();\n const oldIndex = new Map<object, number>();\n for (let i = 0; i < oldItems.length; i++) {\n oldByRef.set(oldItems[i].ref, oldItems[i]);\n oldIndex.set(oldItems[i].ref, 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.html === ni.html) {\n newRecord[i] = oi;\n prevIdx[i] = oldIndex.get(ni.ref) as number;\n continue;\n }\n replacedNodes.push(oi.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.\n for (const [, orphan] of oldByRef) replacedNodes.push(orphan.node);\n // Distinguish: replacedNodes here mixes \"old node for replaced row\" and\n // \"orphan node\". That's fine — the caller removes both unconditionally.\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 */\nfunction buildFreshNodes(\n newRecord: BoundItem[],\n freshIndices: number[],\n freshHtmls: string[],\n): void {\n if (freshHtmls.length === 0) return;\n const tpl = document.createElement('template');\n tpl.innerHTML = freshHtmls.join('');\n let node = tpl.content.firstElementChild;\n for (const idx of freshIndices) {\n if (node === null) {\n throw new Error(\n `each(): row render produced no top-level element. Each item's render must return exactly one element. Got HTML: ${newRecord[idx].html.slice(0, 120)}`,\n );\n }\n const next = node.nextElementSibling;\n newRecord[idx].node = node;\n node = next;\n }\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 */\nfunction applyMoves(\n liveParent: Element,\n newRecord: BoundItem[],\n prevIdx: number[],\n stable: ReadonlySet<number>,\n): void {\n let nextSibling: Element | null = null;\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 * Reconcile `binding`'s live parent against `listSeg`. Mutates `binding.items`\n * to mirror the new segment when done.\n */\nexport function reconcileList(binding: ListBinding, listSeg: ListSegment): void {\n const { liveParent } = binding;\n const { newRecord, prevIdx, replacedNodes, freshIndices, freshHtmls }\n = classifyItems(binding.items, listSeg);\n buildFreshNodes(newRecord, freshIndices, freshHtmls);\n removeOldNodes(liveParent, replacedNodes);\n applyMoves(liveParent, newRecord, prevIdx, lis(prevIdx));\n binding.items = newRecord;\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 { _setListCounter } 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';\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 function mount(rootEl: HTMLElement, render: () => SafeHtml | string): () => void {\n const bindings = new Map<string, ListBinding>();\n const counter = { value: 0 };\n let isFirst = true;\n\n return effect(() => {\n counter.value = 0;\n _setListCounter(counter);\n let result: SafeHtml | string;\n try {\n result = render();\n } finally {\n _setListCounter(null);\n }\n\n const segment: Segment = isSafeHtml(result)\n ? (result.__segment ?? { kind: 'static', html: result.__html })\n : { kind: 'static', html: result };\n\n if (isFirst) {\n // Bulk-render with items inlined and a marker per list. The marker walk\n // afterwards binds each list to the rows already in the DOM, so the\n // first-render reconcile is a no-op (every item is a cache hit).\n rootEl.innerHTML = flatten(segment, true);\n bindListsFromMarkers(rootEl, segment, bindings);\n isFirst = false;\n } else {\n // Static-surrounds-only render: lists become marker-only in the\n // template. `diff()` skips bound list parents' children entirely\n // (so existing rows stay) and inserts the marker for any list that\n // didn't exist before. The marker walk afterwards binds those new\n // lists; the per-list reconcile below patches every list's items.\n const template = rootEl.cloneNode(false) as HTMLElement;\n template.innerHTML = flattenWithoutListItems(segment);\n const listParents = new Set<Element>();\n for (const b of bindings.values()) listParents.add(b.liveParent);\n diff(rootEl, template, listParents);\n bindListsFromMarkers(rootEl, segment, bindings);\n }\n\n for (const listSeg of collectLists(segment).values()) {\n const binding = bindings.get(listSeg.id) as ListBinding;\n reconcileList(binding, listSeg);\n }\n });\n}\n\n/**\n * Walk the live tree's comment nodes; every `<!--kf-list:{id}-->` marker\n * is the first child of a list parent. Record the binding (parent + the\n * already-rendered item nodes that follow the marker) and then remove the\n * marker — bindings live in JS, not in the DOM.\n */\nfunction bindListsFromMarkers(\n rootEl: Element,\n segment: Segment,\n bindings: Map<string, ListBinding>,\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 // Markers are only emitted by `flatten(..., true)` paired with a list\n // segment in the same render, so both lookups always succeed here.\n const listSeg = lists.get(id) as ListSegment;\n const liveParent = marker.parentElement as Element;\n // On first render, items are inlined right after the marker (so the\n // first element sibling is `items[0]`, the next is `items[1]`, etc.).\n // On subsequent renders for a list newly appearing, the list parent\n // is empty after the marker; the loop falls through with `items=[]`\n // and the reconcile phase below builds the items.\n const items: BoundItem[] = [];\n let next: Element | null = marker.nextElementSibling;\n for (let i = 0; i < listSeg.items.length && next !== null; i++) {\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 bindings.set(id, { liveParent, items });\n marker.remove();\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,3 +1,3 @@
1
- export { Fragment, SafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-ZLV35OHG.js';
1
+ export { Fragment, SafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-WK5D3OO7.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.3.0",
3
+ "version": "0.3.1",
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,
@@ -17,7 +17,6 @@
17
17
  "keywords": [
18
18
  "reactive",
19
19
  "signals",
20
- "morphdom",
21
20
  "jsx",
22
21
  "dom",
23
22
  "ui-framework",