@vielzeug/ore 26.10.15 → 26.10.17
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/LICENSE +21 -0
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js.map +1 -1
- package/dist/base-element.cjs.map +1 -1
- package/dist/base-element.js.map +1 -1
- package/dist/context.cjs.map +1 -1
- package/dist/context.js +1 -1
- package/dist/context.js.map +1 -1
- package/dist/define.cjs.map +1 -1
- package/dist/define.js.map +1 -1
- package/dist/directives/classMap.cjs.map +1 -1
- package/dist/directives/classMap.js.map +1 -1
- package/dist/directives/each.cjs.map +1 -1
- package/dist/directives/each.js +1 -1
- package/dist/directives/each.js.map +1 -1
- package/dist/directives/live.cjs.map +1 -1
- package/dist/directives/live.js.map +1 -1
- package/dist/directives/model.cjs.map +1 -1
- package/dist/directives/model.js.map +1 -1
- package/dist/directives/styleMap.cjs.map +1 -1
- package/dist/directives/styleMap.js.map +1 -1
- package/dist/directives/unsafe-html.cjs.map +1 -1
- package/dist/directives/unsafe-html.js.map +1 -1
- package/dist/directives/when.cjs.map +1 -1
- package/dist/directives/when.js.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/forms/field.cjs.map +1 -1
- package/dist/forms/field.js +1 -1
- package/dist/forms/field.js.map +1 -1
- package/dist/host-bind.cjs.map +1 -1
- package/dist/host-bind.js +1 -1
- package/dist/host-bind.js.map +1 -1
- package/dist/ore.cjs +1 -1
- package/dist/ore.cjs.map +1 -1
- package/dist/ore.iife.js +1 -1
- package/dist/ore.iife.js.map +1 -1
- package/dist/ore.js +1180 -2
- package/dist/ore.js.map +1 -1
- package/dist/props.cjs.map +1 -1
- package/dist/props.js +1 -1
- package/dist/props.js.map +1 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/slots.cjs.map +1 -1
- package/dist/slots.js +1 -1
- package/dist/slots.js.map +1 -1
- package/dist/template/bindings.cjs +1 -1
- package/dist/template/bindings.cjs.map +1 -1
- package/dist/template/bindings.js +1 -1
- package/dist/template/bindings.js.map +1 -1
- package/dist/template/compiler.cjs.map +1 -1
- package/dist/template/compiler.js +1 -1
- package/dist/template/compiler.js.map +1 -1
- package/dist/template/instantiator.cjs +1 -1
- package/dist/template/instantiator.cjs.map +1 -1
- package/dist/template/instantiator.js +1 -1
- package/dist/template/instantiator.js.map +1 -1
- package/dist/template/result.cjs.map +1 -1
- package/dist/template/result.js.map +1 -1
- package/dist/testing/flush.cjs.map +1 -1
- package/dist/testing/flush.js.map +1 -1
- package/dist/testing/mount.cjs.map +1 -1
- package/dist/testing/mount.js.map +1 -1
- package/dist/testing/render-hook.cjs.map +1 -1
- package/dist/testing/render-hook.js +1 -1
- package/dist/testing/render-hook.js.map +1 -1
- package/dist/testing/reset.cjs.map +1 -1
- package/dist/testing/reset.js.map +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/utils/aria.cjs.map +1 -1
- package/dist/utils/aria.js.map +1 -1
- package/dist/utils/brand.cjs.map +1 -1
- package/dist/utils/brand.js.map +1 -1
- package/dist/utils/css.cjs.map +1 -1
- package/dist/utils/css.js +1 -1
- package/dist/utils/css.js.map +1 -1
- package/dist/utils/dom.cjs +1 -1
- package/dist/utils/dom.cjs.map +1 -1
- package/dist/utils/dom.js +1 -1
- package/dist/utils/dom.js.map +1 -1
- package/dist/utils/emit.cjs.map +1 -1
- package/dist/utils/emit.js.map +1 -1
- package/dist/utils/id.cjs.map +1 -1
- package/dist/utils/id.js.map +1 -1
- package/package.json +11 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","names":[],"sources":["../../src/directives/model.ts"],"sourcesContent":["import type { Signal } from '@vielzeug/ripple';\nimport { makeBrand } from '../utils/brand';\n\n/**\n * Options for `model()`. Every form control reads and writes differently; the\n * defaults cover native inputs, and `get`/`event` override them for anything else.\n */\nexport type ModelOptions<T = unknown> = {\n /**\n * Event that triggers the write-back from the control to the signal.\n * Defaults to `'change'` for checkboxes, radios, and `<select>`, and\n * `'input'` for everything else.\n */\n event?: string;\n /**\n * Reads the current value out of the element on each write-back event.\n * Defaults to `el.checked` for checkboxes/radios and `el.value` otherwise\n * (always a string for native text/number inputs: pass a `get` like\n * `(el) => Number(el.value)` to keep a numeric signal numeric).\n */\n get?: (el: HTMLElement) => T;\n};\n\n/**\n * Per-binding marker produced by `model()`. Like `live()`, the two-way behavior\n * belongs to this one binding site, never to the signal itself.\n *\n * @internal Consumed by the template binding layer (see `template/instantiator.ts`).\n */\nexport type ModelSource<T = unknown> = {\n readonly event?: string;\n readonly get?: (el: HTMLElement) => T;\n readonly source: Signal<T>;\n};\n\nconst modelBrand = makeBrand<ModelSource>('ore:model');\n\nexport const isModelSource = modelBrand.is;\n\n/** @internal Default value reader for `model()` (see template/instantiator.ts). */\nexport const modelDefaultGet = (el: HTMLElement): unknown => {\n if (el instanceof HTMLInputElement && (el.type === 'checkbox' || el.type === 'radio')) return el.checked;\n\n return (el as HTMLInputElement).value;\n};\n\n/** @internal Default write-back event for `model()` (see template/instantiator.ts). */\nexport const modelDefaultEvent = (el: HTMLElement): string =>\n el instanceof HTMLInputElement && (el.type === 'checkbox' || el.type === 'radio')\n ? 'change'\n : el instanceof HTMLSelectElement\n ? 'change'\n : 'input';\n\n/**\n * Two-way binding for a form control: `value=\"${model(signal)}\"`.\n *\n * Writes the signal to the control's `value`/`checked` property on every change,\n * and writes user input back into the signal on the control's change event\n * (`'change'` for checkboxes/radios/selects, `'input'` otherwise). This is the\n * complete controlled-input loop: the `live()` + manual `@input` handler pair it\n * replaces was easy to get half-wired.\n *\n * The signal is written with whatever `get` reads back (a string by default for\n * text inputs), so declare the signal with the matching type or pass `get`.\n *\n * @example\n * ```ts\n * const text = signal('');\n * const agree = signal(false);\n *\n * html`\n * <input value=\"${model(text)}\" />\n * <input type=\"checkbox\" checked=\"${model(agree)}\" />\n * <input type=\"number\" value=\"${model(count, { get: (el) => Number(el.value) })}\" />\n * `\n * ```\n */\nexport const model = <T>(source: Signal<T>, options?: ModelOptions<T>): ModelSource<T> =>\n modelBrand.stamp({ event: options?.event, get: options?.get, source }) as ModelSource<T>;\n"],"mappings":"8CAmCA,
|
|
1
|
+
{"version":3,"file":"model.js","names":["modelBrand","makeBrand","isModelSource","modelDefaultGet","el","modelDefaultEvent","model","options"],"sources":["../../src/directives/model.ts"],"sourcesContent":["import type { Signal } from '@vielzeug/ripple';\nimport { makeBrand } from '../utils/brand';\n\n/**\n * Options for `model()`. Every form control reads and writes differently; the\n * defaults cover native inputs, and `get`/`event` override them for anything else.\n */\nexport type ModelOptions<T = unknown> = {\n /**\n * Event that triggers the write-back from the control to the signal.\n * Defaults to `'change'` for checkboxes, radios, and `<select>`, and\n * `'input'` for everything else.\n */\n event?: string;\n /**\n * Reads the current value out of the element on each write-back event.\n * Defaults to `el.checked` for checkboxes/radios and `el.value` otherwise\n * (always a string for native text/number inputs: pass a `get` like\n * `(el) => Number(el.value)` to keep a numeric signal numeric).\n */\n get?: (el: HTMLElement) => T;\n};\n\n/**\n * Per-binding marker produced by `model()`. Like `live()`, the two-way behavior\n * belongs to this one binding site, never to the signal itself.\n *\n * @internal Consumed by the template binding layer (see `template/instantiator.ts`).\n */\nexport type ModelSource<T = unknown> = {\n readonly event?: string;\n readonly get?: (el: HTMLElement) => T;\n readonly source: Signal<T>;\n};\n\nconst modelBrand = makeBrand<ModelSource>('ore:model');\n\nexport const isModelSource = modelBrand.is;\n\n/** @internal Default value reader for `model()` (see template/instantiator.ts). */\nexport const modelDefaultGet = (el: HTMLElement): unknown => {\n if (el instanceof HTMLInputElement && (el.type === 'checkbox' || el.type === 'radio')) return el.checked;\n\n return (el as HTMLInputElement).value;\n};\n\n/** @internal Default write-back event for `model()` (see template/instantiator.ts). */\nexport const modelDefaultEvent = (el: HTMLElement): string =>\n el instanceof HTMLInputElement && (el.type === 'checkbox' || el.type === 'radio')\n ? 'change'\n : el instanceof HTMLSelectElement\n ? 'change'\n : 'input';\n\n/**\n * Two-way binding for a form control: `value=\"${model(signal)}\"`.\n *\n * Writes the signal to the control's `value`/`checked` property on every change,\n * and writes user input back into the signal on the control's change event\n * (`'change'` for checkboxes/radios/selects, `'input'` otherwise). This is the\n * complete controlled-input loop: the `live()` + manual `@input` handler pair it\n * replaces was easy to get half-wired.\n *\n * The signal is written with whatever `get` reads back (a string by default for\n * text inputs), so declare the signal with the matching type or pass `get`.\n *\n * @example\n * ```ts\n * const text = signal('');\n * const agree = signal(false);\n *\n * html`\n * <input value=\"${model(text)}\" />\n * <input type=\"checkbox\" checked=\"${model(agree)}\" />\n * <input type=\"number\" value=\"${model(count, { get: (el) => Number(el.value) })}\" />\n * `\n * ```\n */\nexport const model = <T>(source: Signal<T>, options?: ModelOptions<T>): ModelSource<T> =>\n modelBrand.stamp({ event: options?.event, get: options?.get, source }) as ModelSource<T>;\n"],"mappings":"A,8CAmCA,IAAMA,EAAaC,EAAuB,WAAW,EAExCC,EAAgBF,EAAW,GAG3BG,EAAmB,GAC1BC,aAAc,mBAAqBA,EAAG,OAAS,YAAcA,EAAG,OAAS,SAAiBA,EAAG,QAEzFA,EAAwB,MAIrBC,EAAqB,GAChCD,aAAc,mBAAqBA,EAAG,OAAS,YAAcA,EAAG,OAAS,UAErEA,aAAc,kBADd,SAGE,QA0BKE,GAAY,EAAmB,IAC1CN,EAAW,MAAM,CAAE,MAAOO,GAAS,MAAO,IAAKA,GAAS,IAAK,QAAO,CAAC,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styleMap.cjs","names":[],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\n\nimport { cssDeclarationName, cssDeclarationValue } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = cssDeclarationValue(input);\n\n if (!value) continue;\n\n const safeName = cssDeclarationName(name);\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"sEAiCA,
|
|
1
|
+
{"version":3,"file":"styleMap.cjs","names":["computed","cssDeclarationValue","cssDeclarationName","require_dom","_vielzeug_ripple","styleMap","declarations","name","input","record","value","safeName"],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\n\nimport { cssDeclarationName, cssDeclarationValue } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = cssDeclarationValue(input);\n\n if (!value) continue;\n\n const safeName = cssDeclarationName(name);\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"A,sEAiCA,IAAaK,EAAY,IACvB,EAAOL,EAAAA,SAAAA,KAAe,CACpB,IAAMM,EAAyB,CAAC,EAEhC,IAAK,GAAM,CAACC,EAAMC,KAAU,OAAO,QAAQC,CAAM,EAAG,CAClD,IAAMC,EAAQT,EAAAA,oBAAoBO,CAAK,EAEvC,GAAI,CAACE,EAAO,SAEZ,IAAMC,EAAWT,EAAAA,mBAAmBK,CAAI,EAEnCI,GAELL,EAAa,KAAK,GAAGK,EAAS,GAAGD,GAAO,CAC1C,CAEA,OAAOJ,EAAa,KAAK,GAAG,CAC9B,CAAC,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styleMap.js","names":[],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\n\nimport { cssDeclarationName, cssDeclarationValue } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = cssDeclarationValue(input);\n\n if (!value) continue;\n\n const safeName = cssDeclarationName(name);\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"0HAiCA,
|
|
1
|
+
{"version":3,"file":"styleMap.js","names":["styleMap","computed","declarations","name","input","record","value","cssDeclarationValue","safeName","cssDeclarationName"],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\n\nimport { cssDeclarationName, cssDeclarationValue } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = cssDeclarationValue(input);\n\n if (!value) continue;\n\n const safeName = cssDeclarationName(name);\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"A,0HAiCA,IAAaA,EAAY,GAChBC,MAAe,CACpB,IAAMC,EAAyB,CAAC,EAEhC,IAAK,GAAM,CAACC,EAAMC,KAAU,OAAO,QAAQC,CAAM,EAAG,CAClD,IAAMC,EAAQC,EAAoBH,CAAK,EAEvC,GAAI,CAACE,EAAO,SAEZ,IAAME,EAAWC,EAAmBN,CAAI,EAEnCK,GAELN,EAAa,KAAK,GAAGM,EAAS,GAAGF,GAAO,CAC1C,CAEA,OAAOJ,EAAa,KAAK,GAAG,CAC9B,CAAC,E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unsafe-html.cjs","names":[],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n const isFn = typeof value === 'function';\n const src: Readable<string> | null = isFn ? computed(value as () => string) : isReactive(value) ? value : null;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (src) {\n const slot = createReplaceableSlot();\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value as string, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"qIAMA,
|
|
1
|
+
{"version":3,"file":"unsafe-html.cjs","names":["computed","isReactive","createDirectiveResult","createReplaceableSlot","rawEffect","require_errors","require_dom","require_result","_vielzeug_ripple","parseHtml","tpl","html","nodes","node","parent","insertBefore","unsafeHtml","src","value","anchor","endMarker","slot","stop","registerCleanup"],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n const isFn = typeof value === 'function';\n const src: Readable<string> | null = isFn ? computed(value as () => string) : isReactive(value) ? value : null;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (src) {\n const slot = createReplaceableSlot();\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value as string, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"A,qIAMA,IAAMS,GAAa,EAAc,EAAoB,IAA+B,CAClF,IAAMC,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAYC,EAEhB,IAAMC,EAAQ,MAAM,KAAKF,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAMG,KAAQD,EAAOE,EAAO,aAAaD,EAAME,CAAY,EAEhE,OAAOH,CACT,EAYA,SAAgBI,EAAW,EAAqF,CAE9G,IAAMC,EADO,OAAOC,GAAU,YAAA,EACclB,EAAAA,SAAAA,CAASkB,CAAqB,GAAA,EAAIjB,EAAAA,WAAAA,CAAWiB,CAAK,EAAIA,EAAQ,KAE1G,OAAOhB,EAAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAMY,EAASK,EAAO,WAEtBd,EAAA,UAAUS,EAAQ,gDAAgD,EAElE,IAAMM,EAAY,SAAS,cAAc,iBAAiB,EAI1D,GAFAN,EAAO,aAAaM,EAAWD,EAAO,WAAW,EAE7CF,EAAK,CACP,IAAMI,EAAOlB,EAAAA,sBAAsB,EAE7BmB,GAAA,EAAOlB,EAAAA,OAAAA,KAAgB,CAC3BiB,EAAK,MAAM,EACXA,EAAK,SAASZ,EAAUQ,EAAI,MAAOH,EAAQM,CAAS,CAAC,CACvD,CAAC,EAEDG,MAAsBD,EAAK,QAAQ,CAAC,EACpCC,MAAsB,CACpBF,EAAK,MAAM,EACXD,EAAU,OAAO,CACnB,CAAC,CACH,MACEX,EAAUS,EAAiBJ,EAAQM,CAAS,EAE5CG,MAAsBH,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unsafe-html.js","names":[],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n const isFn = typeof value === 'function';\n const src: Readable<string> | null = isFn ? computed(value as () => string) : isReactive(value) ? value : null;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (src) {\n const slot = createReplaceableSlot();\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value as string, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"uOAMA,
|
|
1
|
+
{"version":3,"file":"unsafe-html.js","names":["rawEffect","parseHtml","tpl","html","nodes","node","parent","insertBefore","unsafeHtml","src","value","computed","isReactive","createDirectiveResult","anchor","invariant","endMarker","slot","createReplaceableSlot","stop","effect","registerCleanup"],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n const isFn = typeof value === 'function';\n const src: Readable<string> | null = isFn ? computed(value as () => string) : isReactive(value) ? value : null;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (src) {\n const slot = createReplaceableSlot();\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value as string, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"A,uOAMA,IAAMC,GAAa,EAAc,EAAoB,IAA+B,CAClF,IAAMC,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAYC,EAEhB,IAAMC,EAAQ,MAAM,KAAKF,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAMG,KAAQD,EAAOE,EAAO,aAAaD,EAAME,CAAY,EAEhE,OAAOH,CACT,EAYA,SAAgBI,EAAW,EAAqF,CAE9G,IAAMC,EADO,OAAOC,GAAU,WACcC,EAASD,CAAqB,EAAIE,EAAWF,CAAK,EAAIA,EAAQ,KAE1G,OAAOG,GAAuB,EAAQ,IAAoB,CACxD,IAAMP,EAASQ,EAAO,WAEtBC,EAAUT,EAAQ,gDAAgD,EAElE,IAAMU,EAAY,SAAS,cAAc,iBAAiB,EAI1D,GAFAV,EAAO,aAAaU,EAAWF,EAAO,WAAW,EAE7CL,EAAK,CACP,IAAMQ,EAAOC,EAAsB,EAE7BC,EAAOnB,MAAgB,CAC3BiB,EAAK,MAAM,EACXA,EAAK,SAAShB,EAAUQ,EAAI,MAAOH,EAAQU,CAAS,CAAC,CACvD,CAAC,EAEDK,MAAsBF,EAAK,QAAQ,CAAC,EACpCE,MAAsB,CACpBJ,EAAK,MAAM,EACXD,EAAU,OAAO,CACnB,CAAC,CACH,MACEf,EAAUS,EAAiBJ,EAAQU,CAAS,EAE5CK,MAAsBL,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"when.cjs","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, untrack } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../template/result';\nimport { createReplaceableSlot, type MaybeReactive, removeNodes } from '../utils/dom';\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = branch.mount(parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => branch.mount(parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"qIAQA,
|
|
1
|
+
{"version":3,"file":"when.cjs","names":["isReactive","createDirectiveResult","isHtmlResult","removeNodes","computed","createReplaceableSlot","rawEffect","untrack","require_errors","require_dom","require_result","_vielzeug_ripple","NO_PARENT_MSG","when","condition","branch","truthy","falsy","parent","anchor","nodes","registerCleanup","conditionSignal","endMarker","slot","sub","next"],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, untrack } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../template/result';\nimport { createReplaceableSlot, type MaybeReactive, removeNodes } from '../utils/dom';\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = branch.mount(parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => branch.mount(parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"A,qIAQA,IAAMY,EAAgB,2CActB,SAAgBC,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAOC,GAAc,YAAc,EAAA,EAACd,EAAAA,WAAAA,CAAWc,CAAS,EACnDb,EAAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAMc,EAASD,EAAYE,EAAO,EAAIC,EAAQA,EAAM,EAAI,KAExD,GAAI,CAACF,GAAU,CAACb,EAAAA,aAAaa,CAAM,EAAG,OAEtC,IAAMG,EAASC,EAAO,WAEtBX,EAAA,UAAUU,EAAQN,CAAa,EAE/B,IAAMQ,EAAQL,EAAO,MAAMG,EAAQC,EAAQE,CAAe,EAE1DA,MAAsBlB,EAAAA,YAAYiB,CAAK,CAAC,CAC1C,CAAC,EAGInB,EAAAA,uBAAuB,EAAQ,IAAoB,CAExD,IAAMqB,GADgB,OAAOR,GAAc,YAAA,EAAaV,EAAAA,SAAAA,CAASU,CAA0B,EAAI,OACrDA,EAEpCI,EAASC,EAAO,WAEtBX,EAAA,UAAUU,EAAQN,CAAa,EAE/B,IAAMW,EAAY,SAAS,cAAc,UAAU,EAEnDL,EAAO,aAAaK,EAAWJ,EAAO,WAAW,EAEjD,IAAMK,EAAOnB,EAAAA,sBAAsB,EAE7BoB,GAAA,EAAMnB,EAAAA,OAAAA,KAAgB,CAC1B,IAAMoB,EAAOJ,EAAgB,MAE7BE,EAAK,MAAM,EAEX,IAAMT,EAASW,EAAOV,EAAO,EAAIC,EAAQA,EAAM,EAAI,KAE9CF,GAAWb,EAAAA,aAAaa,CAAM,GAEnCS,EAAK,UAAA,EAASjB,EAAAA,QAAAA,KAAcQ,EAAO,MAAMG,EAAQK,EAAWC,EAAK,eAAe,CAAC,CAAC,CACpF,CAAC,EAEDH,MAAsBI,EAAI,QAAQ,CAAC,EACnCJ,MAAsB,CACpBG,EAAK,MAAM,EACXD,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH,C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, untrack } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../template/result';\nimport { createReplaceableSlot, type MaybeReactive, removeNodes } from '../utils/dom';\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = branch.mount(parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => branch.mount(parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"uRAQA,
|
|
1
|
+
{"version":3,"file":"when.js","names":["rawEffect","NO_PARENT_MSG","when","condition","isReactive","createDirectiveResult","branch","truthy","falsy","isHtmlResult","parent","anchor","invariant","nodes","registerCleanup","removeNodes","conditionSignal","computed","endMarker","slot","createReplaceableSlot","sub","effect","next","untrack"],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, untrack } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../template/result';\nimport { createReplaceableSlot, type MaybeReactive, removeNodes } from '../utils/dom';\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = branch.mount(parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => branch.mount(parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"A,uRAQA,IAAMC,EAAgB,2CActB,SAAgBC,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAOC,GAAc,YAAc,CAACC,EAAWD,CAAS,EACnDE,GAAuB,EAAQ,IAAoB,CACxD,IAAMC,EAASH,EAAYI,EAAO,EAAIC,EAAQA,EAAM,EAAI,KAExD,GAAI,CAACF,GAAU,CAACG,EAAaH,CAAM,EAAG,OAEtC,IAAMI,EAASC,EAAO,WAEtBC,EAAUF,EAAQT,CAAa,EAE/B,IAAMY,EAAQP,EAAO,MAAMI,EAAQC,EAAQG,CAAe,EAE1DA,MAAsBC,EAAYF,CAAK,CAAC,CAC1C,CAAC,EAGIR,GAAuB,EAAQ,IAAoB,CAExD,IAAMW,GADgB,OAAOb,GAAc,WAAac,EAASd,CAA0B,EAAI,OACrDA,EAEpCO,EAASC,EAAO,WAEtBC,EAAUF,EAAQT,CAAa,EAE/B,IAAMiB,EAAY,SAAS,cAAc,UAAU,EAEnDR,EAAO,aAAaQ,EAAWP,EAAO,WAAW,EAEjD,IAAMQ,EAAOC,EAAsB,EAE7BC,EAAMrB,MAAgB,CAC1B,IAAMuB,EAAOP,EAAgB,MAE7BG,EAAK,MAAM,EAEX,IAAMb,EAASiB,EAAOhB,EAAO,EAAIC,EAAQA,EAAM,EAAI,KAE9CF,GAAWG,EAAaH,CAAM,GAEnCa,EAAK,SAASK,MAAclB,EAAO,MAAMI,EAAQQ,EAAWC,EAAK,eAAe,CAAC,CAAC,CACpF,CAAC,EAEDL,MAAsBO,EAAI,QAAQ,CAAC,EACnCP,MAAsB,CACpBK,EAAK,MAAM,EACXD,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH,C"}
|
package/dist/errors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Error policy ─────────────────────────────────────────────────────────────\n// One rule for the whole package: decide by whose code failed and whether it\n// can continue, never ad hoc per call site:\n//\n// API misuse (wrong arguments, hook outside setup, duplicate define)\n// → throw `OreApiError`, immediately, every build.\n// User-authored code failing inside ore's execution (setup, onMounted,\n// onFormReset, each() reconciliation)\n// → wrap in `OreLifecycleError` and report via `reportRuntimeError()`\n// (`ore:error` DOM event + dev console) so other callbacks keep running.\n// Recoverable oddity (overwrite warnings, blocked attribute writes)\n// → dev `warn()`/`error()` and continue. Never swallow silently.\n// Internal impossibility (compiled template metadata out of sync)\n// → `invariant()` throws `OreInternalError`, every build.\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {}\n\n/**\n * Thrown when an internal invariant fails: e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'`: synchronous setup() threw\n * - `'mounted'`: an onMounted callback threw\n * - `'form-reset'`: an onFormReset callback threw\n * - `'each-reconcile'`: `each()` failed to reconcile a list update (e.g. duplicate keys)\n */\nexport type OreErrorPhase = 'each-reconcile' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n *\n * `target` only needs to be an `EventTarget` (not specifically an `HTMLElement`): component\n * lifecycle errors dispatch on the host element, but non-lifecycle failures (e.g. `each()`\n * reconciliation, which has no single \"component\" to attribute the error to) dispatch on\n * whatever live DOM node is available, such as the directive's own anchor `Comment`. Either way\n * the event still bubbles and crosses shadow boundaries (`composed: true`), so a listener on\n * `document`/`window` observes every report regardless of where it originated.\n *\n * The console log (via `_dev.ts`'s `error()`) is still dev-gated like the rest of the package's\n * console diagnostics, but the `ore:error` DOM event dispatch below is **not**: it fires in\n * every build, so consumers always have a way to observe runtime failures programmatically even\n * when console output is stripped in production.\n */\nexport function reportRuntimeError(error: OreLifecycleError, target: EventTarget): void {\n logError(`<${error.component}> lifecycle error (phase: ${error.phase}):`, error.cause);\n\n target.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\nexport const ORE_ERRORS = {\n asyncSetupUnsupported: 'setup() must return an HTMLResult or null; use reactive state for asynchronous work',\n defineDuplicate: (tag: string): string => `define('${tag}') called twice: custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n eventModifierUnknown: (eventName: string, modifier: string): string =>\n `@${eventName}.${modifier}: unknown event modifier \"${modifier}\". Supported: .stop, .prevent, .once, .capture`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n listenNullTarget: (eventName: string): string =>\n `listen() called with a null/undefined target for event \"${eventName}\": listener not attached`,\n modelRequiresValueBinding: (name: string): string =>\n `model(): \"${name}\" must be a plain value/checked attribute binding, not a boolean attribute. Bind it as ${name}=\\${model(sig)}, not ?${name}=\\${model(sig)}.`,\n propBindingForbiddenName: (name: string): string =>\n `html\\`...\\`: \".${name}\" is a forbidden property-binding name (prototype pollution guard)`,\n propInvalidReflect: 'Structured props cannot use reflect:true: use prop.json() with reflect:false',\n templateInterpolationInTag:\n 'html`...`: interpolations inside a tag must be named attributes, boolean attributes, events, or refs',\n useFieldAlreadyCalled: (tag: string): string =>\n `useField() was already called on <${tag}>. Call it only once per component.`,\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold: e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first: `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"sBAoBA,
|
|
1
|
+
{"version":3,"file":"errors.cjs","names":["error","OreError","message","opts","OreApiError","OreInternalError","OreLifecycleError","options","reportRuntimeError","error$1","target","ORE_ERRORS","tag","key","index","eventName","modifier","name","errors","invariant","condition"],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Error policy ─────────────────────────────────────────────────────────────\n// One rule for the whole package: decide by whose code failed and whether it\n// can continue, never ad hoc per call site:\n//\n// API misuse (wrong arguments, hook outside setup, duplicate define)\n// → throw `OreApiError`, immediately, every build.\n// User-authored code failing inside ore's execution (setup, onMounted,\n// onFormReset, each() reconciliation)\n// → wrap in `OreLifecycleError` and report via `reportRuntimeError()`\n// (`ore:error` DOM event + dev console) so other callbacks keep running.\n// Recoverable oddity (overwrite warnings, blocked attribute writes)\n// → dev `warn()`/`error()` and continue. Never swallow silently.\n// Internal impossibility (compiled template metadata out of sync)\n// → `invariant()` throws `OreInternalError`, every build.\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {}\n\n/**\n * Thrown when an internal invariant fails: e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'`: synchronous setup() threw\n * - `'mounted'`: an onMounted callback threw\n * - `'form-reset'`: an onFormReset callback threw\n * - `'each-reconcile'`: `each()` failed to reconcile a list update (e.g. duplicate keys)\n */\nexport type OreErrorPhase = 'each-reconcile' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n *\n * `target` only needs to be an `EventTarget` (not specifically an `HTMLElement`): component\n * lifecycle errors dispatch on the host element, but non-lifecycle failures (e.g. `each()`\n * reconciliation, which has no single \"component\" to attribute the error to) dispatch on\n * whatever live DOM node is available, such as the directive's own anchor `Comment`. Either way\n * the event still bubbles and crosses shadow boundaries (`composed: true`), so a listener on\n * `document`/`window` observes every report regardless of where it originated.\n *\n * The console log (via `_dev.ts`'s `error()`) is still dev-gated like the rest of the package's\n * console diagnostics, but the `ore:error` DOM event dispatch below is **not**: it fires in\n * every build, so consumers always have a way to observe runtime failures programmatically even\n * when console output is stripped in production.\n */\nexport function reportRuntimeError(error: OreLifecycleError, target: EventTarget): void {\n logError(`<${error.component}> lifecycle error (phase: ${error.phase}):`, error.cause);\n\n target.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\nexport const ORE_ERRORS = {\n asyncSetupUnsupported: 'setup() must return an HTMLResult or null; use reactive state for asynchronous work',\n defineDuplicate: (tag: string): string => `define('${tag}') called twice: custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n eventModifierUnknown: (eventName: string, modifier: string): string =>\n `@${eventName}.${modifier}: unknown event modifier \"${modifier}\". Supported: .stop, .prevent, .once, .capture`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n listenNullTarget: (eventName: string): string =>\n `listen() called with a null/undefined target for event \"${eventName}\": listener not attached`,\n modelRequiresValueBinding: (name: string): string =>\n `model(): \"${name}\" must be a plain value/checked attribute binding, not a boolean attribute. Bind it as ${name}=\\${model(sig)}, not ?${name}=\\${model(sig)}.`,\n propBindingForbiddenName: (name: string): string =>\n `html\\`...\\`: \".${name}\" is a forbidden property-binding name (prototype pollution guard)`,\n propInvalidReflect: 'Structured props cannot use reflect:true: use prop.json() with reflect:false',\n templateInterpolationInTag:\n 'html`...`: interpolations inside a tag must be named attributes, boolean attributes, events, or refs',\n useFieldAlreadyCalled: (tag: string): string =>\n `useField() was already called on <${tag}>. Call it only once per component.`,\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold: e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first: `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"A,sBAoBA,IAAaC,EAAb,cAA8B,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAMC,EAASC,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGaC,EAAb,cAAiCH,CAAS,CAAC,EAO9BI,EAAb,cAAsCJ,CAAS,CAAC,EAenCK,EAAb,cAAuCL,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAMC,EAAS,CAAE,MAAOK,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAYA,EAAQ,UACzB,KAAK,MAAQA,EAAQ,KACvB,CACF,EAiBA,SAAgBC,EAAmB,EAA0B,EAA2B,CAC7E,GAAIR,EAAM,UAAV,EAAgDA,EAAM,MAAtD,EAAiEA,EAAM,MAEhFU,EAAO,cACL,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQV,CACV,CAAC,CACH,CACF,CAIA,IAAaW,EAAa,CACxB,sBAAuB,sFACvB,gBAAkB,GAAwB,WAAWC,EAAI,oDACzD,kCAAoC,GAClC,+BAA+BA,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkCC,EAAI,aAAaC,IAC7G,sBAAuB,EAAmB,IACxC,IAAIC,EAAU,GAAGC,EAAS,4BAA4BA,EAAS,gDACjE,oBAAqB,EAAa,IAAwB,yCAAyCH,EAAI,QAAQD,EAAI,GACnH,kBAAoB,GAA4B,uBAAuBV,IACvE,sBAAuB,wDACvB,iBAAmB,GACjB,2DAA2Da,EAAU,0BACvE,0BAA4B,GAC1B,aAAaE,EAAK,yFAAyFA,EAAK,wBAAwBA,EAAK,kBAC/I,yBAA2B,GACzB,kBAAkBA,EAAK,oEACzB,mBAAoB,+EACpB,2BACE,uGACF,sBAAwB,GACtB,qCAAqCL,EAAI,qCAC3C,kBAAmB,EAAa,IAA6B,0BAA0BA,EAAI,MAAMM,EAAO,KAAK;CAAI,GACnH,EAYA,SAAgBC,EAAU,EAAoB,EAAoC,CAChF,GAAI,CAACC,EAAW,MAAM,IAAIf,EAAiBM,EAAW,kBAAkBT,CAAO,CAAC,CAClF,C"}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Error policy ─────────────────────────────────────────────────────────────\n// One rule for the whole package: decide by whose code failed and whether it\n// can continue, never ad hoc per call site:\n//\n// API misuse (wrong arguments, hook outside setup, duplicate define)\n// → throw `OreApiError`, immediately, every build.\n// User-authored code failing inside ore's execution (setup, onMounted,\n// onFormReset, each() reconciliation)\n// → wrap in `OreLifecycleError` and report via `reportRuntimeError()`\n// (`ore:error` DOM event + dev console) so other callbacks keep running.\n// Recoverable oddity (overwrite warnings, blocked attribute writes)\n// → dev `warn()`/`error()` and continue. Never swallow silently.\n// Internal impossibility (compiled template metadata out of sync)\n// → `invariant()` throws `OreInternalError`, every build.\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {}\n\n/**\n * Thrown when an internal invariant fails: e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'`: synchronous setup() threw\n * - `'mounted'`: an onMounted callback threw\n * - `'form-reset'`: an onFormReset callback threw\n * - `'each-reconcile'`: `each()` failed to reconcile a list update (e.g. duplicate keys)\n */\nexport type OreErrorPhase = 'each-reconcile' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n *\n * `target` only needs to be an `EventTarget` (not specifically an `HTMLElement`): component\n * lifecycle errors dispatch on the host element, but non-lifecycle failures (e.g. `each()`\n * reconciliation, which has no single \"component\" to attribute the error to) dispatch on\n * whatever live DOM node is available, such as the directive's own anchor `Comment`. Either way\n * the event still bubbles and crosses shadow boundaries (`composed: true`), so a listener on\n * `document`/`window` observes every report regardless of where it originated.\n *\n * The console log (via `_dev.ts`'s `error()`) is still dev-gated like the rest of the package's\n * console diagnostics, but the `ore:error` DOM event dispatch below is **not**: it fires in\n * every build, so consumers always have a way to observe runtime failures programmatically even\n * when console output is stripped in production.\n */\nexport function reportRuntimeError(error: OreLifecycleError, target: EventTarget): void {\n logError(`<${error.component}> lifecycle error (phase: ${error.phase}):`, error.cause);\n\n target.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\nexport const ORE_ERRORS = {\n asyncSetupUnsupported: 'setup() must return an HTMLResult or null; use reactive state for asynchronous work',\n defineDuplicate: (tag: string): string => `define('${tag}') called twice: custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n eventModifierUnknown: (eventName: string, modifier: string): string =>\n `@${eventName}.${modifier}: unknown event modifier \"${modifier}\". Supported: .stop, .prevent, .once, .capture`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n listenNullTarget: (eventName: string): string =>\n `listen() called with a null/undefined target for event \"${eventName}\": listener not attached`,\n modelRequiresValueBinding: (name: string): string =>\n `model(): \"${name}\" must be a plain value/checked attribute binding, not a boolean attribute. Bind it as ${name}=\\${model(sig)}, not ?${name}=\\${model(sig)}.`,\n propBindingForbiddenName: (name: string): string =>\n `html\\`...\\`: \".${name}\" is a forbidden property-binding name (prototype pollution guard)`,\n propInvalidReflect: 'Structured props cannot use reflect:true: use prop.json() with reflect:false',\n templateInterpolationInTag:\n 'html`...`: interpolations inside a tag must be named attributes, boolean attributes, events, or refs',\n useFieldAlreadyCalled: (tag: string): string =>\n `useField() was already called on <${tag}>. Call it only once per component.`,\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold: e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first: `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"kBAoBA,
|
|
1
|
+
{"version":3,"file":"errors.js","names":["error","OreError","message","opts","OreApiError","OreInternalError","OreLifecycleError","options","reportRuntimeError","error$1","target","ORE_ERRORS","tag","key","index","eventName","modifier","name","errors","invariant","condition"],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Error policy ─────────────────────────────────────────────────────────────\n// One rule for the whole package: decide by whose code failed and whether it\n// can continue, never ad hoc per call site:\n//\n// API misuse (wrong arguments, hook outside setup, duplicate define)\n// → throw `OreApiError`, immediately, every build.\n// User-authored code failing inside ore's execution (setup, onMounted,\n// onFormReset, each() reconciliation)\n// → wrap in `OreLifecycleError` and report via `reportRuntimeError()`\n// (`ore:error` DOM event + dev console) so other callbacks keep running.\n// Recoverable oddity (overwrite warnings, blocked attribute writes)\n// → dev `warn()`/`error()` and continue. Never swallow silently.\n// Internal impossibility (compiled template metadata out of sync)\n// → `invariant()` throws `OreInternalError`, every build.\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {}\n\n/**\n * Thrown when an internal invariant fails: e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'`: synchronous setup() threw\n * - `'mounted'`: an onMounted callback threw\n * - `'form-reset'`: an onFormReset callback threw\n * - `'each-reconcile'`: `each()` failed to reconcile a list update (e.g. duplicate keys)\n */\nexport type OreErrorPhase = 'each-reconcile' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n *\n * `target` only needs to be an `EventTarget` (not specifically an `HTMLElement`): component\n * lifecycle errors dispatch on the host element, but non-lifecycle failures (e.g. `each()`\n * reconciliation, which has no single \"component\" to attribute the error to) dispatch on\n * whatever live DOM node is available, such as the directive's own anchor `Comment`. Either way\n * the event still bubbles and crosses shadow boundaries (`composed: true`), so a listener on\n * `document`/`window` observes every report regardless of where it originated.\n *\n * The console log (via `_dev.ts`'s `error()`) is still dev-gated like the rest of the package's\n * console diagnostics, but the `ore:error` DOM event dispatch below is **not**: it fires in\n * every build, so consumers always have a way to observe runtime failures programmatically even\n * when console output is stripped in production.\n */\nexport function reportRuntimeError(error: OreLifecycleError, target: EventTarget): void {\n logError(`<${error.component}> lifecycle error (phase: ${error.phase}):`, error.cause);\n\n target.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\nexport const ORE_ERRORS = {\n asyncSetupUnsupported: 'setup() must return an HTMLResult or null; use reactive state for asynchronous work',\n defineDuplicate: (tag: string): string => `define('${tag}') called twice: custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n eventModifierUnknown: (eventName: string, modifier: string): string =>\n `@${eventName}.${modifier}: unknown event modifier \"${modifier}\". Supported: .stop, .prevent, .once, .capture`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n listenNullTarget: (eventName: string): string =>\n `listen() called with a null/undefined target for event \"${eventName}\": listener not attached`,\n modelRequiresValueBinding: (name: string): string =>\n `model(): \"${name}\" must be a plain value/checked attribute binding, not a boolean attribute. Bind it as ${name}=\\${model(sig)}, not ?${name}=\\${model(sig)}.`,\n propBindingForbiddenName: (name: string): string =>\n `html\\`...\\`: \".${name}\" is a forbidden property-binding name (prototype pollution guard)`,\n propInvalidReflect: 'Structured props cannot use reflect:true: use prop.json() with reflect:false',\n templateInterpolationInTag:\n 'html`...`: interpolations inside a tag must be named attributes, boolean attributes, events, or refs',\n useFieldAlreadyCalled: (tag: string): string =>\n `useField() was already called on <${tag}>. Call it only once per component.`,\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold: e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first: `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"A,kBAoBA,IAAaC,EAAb,cAA8B,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAMC,EAASC,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAGaC,EAAb,cAAiCH,CAAS,CAAC,EAO9BI,EAAb,cAAsCJ,CAAS,CAAC,EAenCK,EAAb,cAAuCL,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAMC,EAAS,CAAE,MAAOK,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAYA,EAAQ,UACzB,KAAK,MAAQA,EAAQ,KACvB,CACF,EAiBA,SAAgBC,EAAmB,EAA0B,EAA2B,CAC7E,GAAIR,EAAM,UAAV,EAAgDA,EAAM,MAAtD,EAAiEA,EAAM,MAEhFU,EAAO,cACL,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQV,CACV,CAAC,CACH,CACF,CAIA,IAAaW,EAAa,CACxB,sBAAuB,sFACvB,gBAAkB,GAAwB,WAAWC,EAAI,oDACzD,kCAAoC,GAClC,+BAA+BA,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkCC,EAAI,aAAaC,IAC7G,sBAAuB,EAAmB,IACxC,IAAIC,EAAU,GAAGC,EAAS,4BAA4BA,EAAS,gDACjE,oBAAqB,EAAa,IAAwB,yCAAyCH,EAAI,QAAQD,EAAI,GACnH,kBAAoB,GAA4B,uBAAuBV,IACvE,sBAAuB,wDACvB,iBAAmB,GACjB,2DAA2Da,EAAU,0BACvE,0BAA4B,GAC1B,aAAaE,EAAK,yFAAyFA,EAAK,wBAAwBA,EAAK,kBAC/I,yBAA2B,GACzB,kBAAkBA,EAAK,oEACzB,mBAAoB,+EACpB,2BACE,uGACF,sBAAwB,GACtB,qCAAqCL,EAAI,qCAC3C,kBAAmB,EAAa,IAA6B,0BAA0BA,EAAI,MAAMM,EAAO,KAAK;CAAI,GACnH,EAYA,SAAgBC,EAAU,EAAoB,EAAoC,CAChF,GAAI,CAACC,EAAW,MAAM,IAAIf,EAAiBM,EAAW,kBAAkBT,CAAO,CAAC,CAClF,C"}
|
package/dist/forms/field.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.cjs","names":[],"sources":["../../src/forms/field.ts"],"sourcesContent":["import type { Readable, Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS, OreApiError } from '../errors';\nimport { getHost, onCleanup, onFormReset, watchEffect } from '../runtime';\n\n/** @internal */\nconst internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n/** @internal */\nconst activeFieldRegistry = new WeakSet<HTMLElement>();\n\n/**\n * One field-validity state: the flags and the message travel together because\n * the platform's `setValidity()` contract couples them (flags without a\n * non-empty message throw). A single `{ flags, message } | null` input makes a\n * desynced pair unrepresentable, where the old split `validity` +\n * `validationMessage` options could drift apart.\n */\nexport type FormFieldValidity = { flags: ValidityStateFlags; message: string };\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: Readable<boolean>;\n /**\n * When `true`, a `null` or `undefined` value is submitted as an empty string\n * (`''`) instead of `null`. This keeps the field's key present in `FormData`\n * even when the value is absent: useful when the server expects the field to\n * always be included.\n *\n * @default false\n */\n emptyStringForNull?: boolean;\n /**\n * Called when the ancestor `<form>` is reset (see `onFormReset`). Use to restore\n * whatever local state backs `value`: `useField` itself owns no field state to reset.\n */\n onReset?: () => void;\n toFormValue?: (value: T) => File | FormData | string | null;\n /**\n * Recomputed reactively and passed straight to `internals.setValidity()`: `null`\n * (or omitting `validity` entirely) means always valid.\n *\n * @example\n * ```ts\n * validity: computed(() =>\n * required.value && isBlank(value.value)\n * ? { flags: { valueMissing: true }, message: 'Required.' }\n * : null,\n * ),\n * ```\n */\n validity?: Readable<FormFieldValidity | null>;\n value: Signal<T> | Readable<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n /**\n * Set (non-empty message) or clear (empty string) a custom validity error.\n * Guards the platform's throw-on-empty-message contract: prefer this over\n * calling `internals.setValidity` directly.\n */\n setCustomValidity: (message: string) => void;\n};\n\nexport const useField = <T = unknown>(options: FormFieldOptions<T>): FormFieldHandle => {\n const host = getHost();\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new OreApiError(ORE_ERRORS.defineFieldRequiresFormAssociated(host.localName));\n }\n\n if (activeFieldRegistry.has(host)) {\n throw new OreApiError(ORE_ERRORS.useFieldAlreadyCalled(host.localName));\n }\n\n // ElementInternals may only be attached once for an element's lifetime, while setup\n // legitimately runs again when a custom element is reconnected.\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n activeFieldRegistry.add(host);\n onCleanup(() => activeFieldRegistry.delete(host));\n\n const toFormValue =\n options.toFormValue ??\n ((v: T): File | FormData | string | null => {\n if (v == null) return options.emptyStringForNull ? '' : null;\n\n if (v instanceof File || v instanceof FormData) return v;\n\n return String(v);\n });\n\n watchEffect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n if (!('states' in internals)) {\n warn(\n 'useField(): ElementInternals.states (CustomStateSet) is not available in this environment: disabled state tracking skipped.',\n );\n } else {\n const states = internals.states as CustomStateSet;\n\n watchEffect(() => {\n if (disabled.value) states.add('disabled');\n else states.delete('disabled');\n });\n }\n }\n\n if (options.validity) {\n watchEffect(() => {\n const state = options.validity?.value;\n\n if (!state) {\n internals.setValidity({});\n\n return;\n }\n\n // Per spec, ElementInternals.setValidity() throws if any flag is true and the\n // message is empty. The FormFieldValidity shape makes that state rare, but a\n // runtime empty string is still expressible: fall back to a generic message\n // instead of crashing this effect in a real browser.\n const hasFlag = Object.values(state.flags).some(Boolean);\n\n internals.setValidity(state.flags, hasFlag && !state.message ? 'Invalid value.' : state.message);\n });\n }\n\n if (options.onReset) onFormReset(options.onReset);\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n };\n};\n"],"mappings":"oFAOA,
|
|
1
|
+
{"version":3,"file":"field.cjs","names":["getHost","OreApiError","ORE_ERRORS","require_errors","require_runtime","internalsRegistry","activeFieldRegistry","useField","host","internals","toFormValue","options","v","disabled","states","state","hasFlag","message"],"sources":["../../src/forms/field.ts"],"sourcesContent":["import type { Readable, Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS, OreApiError } from '../errors';\nimport { getHost, onCleanup, onFormReset, watchEffect } from '../runtime';\n\n/** @internal */\nconst internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n/** @internal */\nconst activeFieldRegistry = new WeakSet<HTMLElement>();\n\n/**\n * One field-validity state: the flags and the message travel together because\n * the platform's `setValidity()` contract couples them (flags without a\n * non-empty message throw). A single `{ flags, message } | null` input makes a\n * desynced pair unrepresentable, where the old split `validity` +\n * `validationMessage` options could drift apart.\n */\nexport type FormFieldValidity = { flags: ValidityStateFlags; message: string };\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: Readable<boolean>;\n /**\n * When `true`, a `null` or `undefined` value is submitted as an empty string\n * (`''`) instead of `null`. This keeps the field's key present in `FormData`\n * even when the value is absent: useful when the server expects the field to\n * always be included.\n *\n * @default false\n */\n emptyStringForNull?: boolean;\n /**\n * Called when the ancestor `<form>` is reset (see `onFormReset`). Use to restore\n * whatever local state backs `value`: `useField` itself owns no field state to reset.\n */\n onReset?: () => void;\n toFormValue?: (value: T) => File | FormData | string | null;\n /**\n * Recomputed reactively and passed straight to `internals.setValidity()`: `null`\n * (or omitting `validity` entirely) means always valid.\n *\n * @example\n * ```ts\n * validity: computed(() =>\n * required.value && isBlank(value.value)\n * ? { flags: { valueMissing: true }, message: 'Required.' }\n * : null,\n * ),\n * ```\n */\n validity?: Readable<FormFieldValidity | null>;\n value: Signal<T> | Readable<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n /**\n * Set (non-empty message) or clear (empty string) a custom validity error.\n * Guards the platform's throw-on-empty-message contract: prefer this over\n * calling `internals.setValidity` directly.\n */\n setCustomValidity: (message: string) => void;\n};\n\nexport const useField = <T = unknown>(options: FormFieldOptions<T>): FormFieldHandle => {\n const host = getHost();\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new OreApiError(ORE_ERRORS.defineFieldRequiresFormAssociated(host.localName));\n }\n\n if (activeFieldRegistry.has(host)) {\n throw new OreApiError(ORE_ERRORS.useFieldAlreadyCalled(host.localName));\n }\n\n // ElementInternals may only be attached once for an element's lifetime, while setup\n // legitimately runs again when a custom element is reconnected.\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n activeFieldRegistry.add(host);\n onCleanup(() => activeFieldRegistry.delete(host));\n\n const toFormValue =\n options.toFormValue ??\n ((v: T): File | FormData | string | null => {\n if (v == null) return options.emptyStringForNull ? '' : null;\n\n if (v instanceof File || v instanceof FormData) return v;\n\n return String(v);\n });\n\n watchEffect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n if (!('states' in internals)) {\n warn(\n 'useField(): ElementInternals.states (CustomStateSet) is not available in this environment: disabled state tracking skipped.',\n );\n } else {\n const states = internals.states as CustomStateSet;\n\n watchEffect(() => {\n if (disabled.value) states.add('disabled');\n else states.delete('disabled');\n });\n }\n }\n\n if (options.validity) {\n watchEffect(() => {\n const state = options.validity?.value;\n\n if (!state) {\n internals.setValidity({});\n\n return;\n }\n\n // Per spec, ElementInternals.setValidity() throws if any flag is true and the\n // message is empty. The FormFieldValidity shape makes that state rare, but a\n // runtime empty string is still expressible: fall back to a generic message\n // instead of crashing this effect in a real browser.\n const hasFlag = Object.values(state.flags).some(Boolean);\n\n internals.setValidity(state.flags, hasFlag && !state.message ? 'Invalid value.' : state.message);\n });\n }\n\n if (options.onReset) onFormReset(options.onReset);\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n };\n};\n"],"mappings":"A,oFAOA,IAAMK,EAAoB,IAAI,QAExBC,EAAsB,IAAI,QAyDnBC,EAAyB,GAAkD,CACtF,IAAMC,EAAOR,EAAAA,QAAQ,EAGrB,GAAI,CAFSQ,EAAK,YAER,eACR,MAAM,IAAIP,EAAAA,YAAYC,EAAAA,WAAW,kCAAkCM,EAAK,SAAS,CAAC,EAGpF,GAAIF,EAAoB,IAAIE,CAAI,EAC9B,MAAM,IAAIP,EAAAA,YAAYC,EAAAA,WAAW,sBAAsBM,EAAK,SAAS,CAAC,EAKxE,IAAMC,EAAYJ,EAAkB,IAAIG,CAAI,GAAKA,EAAK,gBAAgB,EAEtEH,EAAkB,IAAIG,EAAMC,CAAS,EACrCH,EAAoB,IAAIE,CAAI,EAC5BJ,EAAA,cAAgBE,EAAoB,OAAOE,CAAI,CAAC,EAEhD,IAAME,EACJC,EAAQ,cACN,GACIC,GAAK,KAAaD,EAAQ,mBAAqB,GAAK,KAEpDC,aAAa,MAAQA,aAAa,SAAiBA,EAEhD,OAAOA,CAAC,GAGnBR,EAAA,gBAAkB,CAChBK,EAAU,aAAaC,EAAYC,EAAQ,MAAM,KAAK,CAAC,CACzD,CAAC,EAED,IAAME,EAAWF,EAAQ,SAEzB,GAAIE,GACI,WAAYJ,EAIX,CACL,IAAMK,EAASL,EAAU,OAEzBL,EAAA,gBAAkB,CACZS,EAAS,MAAOC,EAAO,IAAI,UAAU,EACpCA,EAAO,OAAO,UAAU,CAC/B,CAAC,CACH,CA8BF,OA3BIH,EAAQ,UACVP,EAAA,gBAAkB,CAChB,IAAMW,EAAQJ,EAAQ,UAAU,MAEhC,GAAI,CAACI,EAAO,CACVN,EAAU,YAAY,CAAC,CAAC,EAExB,MACF,CAMA,IAAMO,EAAU,OAAO,OAAOD,EAAM,KAAK,CAAC,CAAC,KAAK,OAAO,EAEvDN,EAAU,YAAYM,EAAM,MAAOC,GAAW,CAACD,EAAM,QAAU,iBAAmBA,EAAM,OAAO,CACjG,CAAC,EAGCJ,EAAQ,SAASP,EAAA,YAAYO,EAAQ,OAAO,EAOzC,CACL,kBAN0BF,EAAU,cAAc,EAOlD,YACA,mBAP2BA,EAAU,eAAe,EAQpD,kBAPyB,GACzBQ,EAAUR,EAAU,YAAY,CAAE,YAAa,EAAK,EAAGQ,CAAO,EAAIR,EAAU,YAAY,CAAC,CAAC,CAO5F,CACF,E"}
|
package/dist/forms/field.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"../_dev.js";import{ORE_ERRORS as e,OreApiError as t}from"../errors.js";import{getHost as n,onCleanup as r,onFormReset as i,watchEffect as a}from"../runtime.js";var o
|
|
1
|
+
import"../_dev.js";import{ORE_ERRORS as e,OreApiError as t}from"../errors.js";import{getHost as n,onCleanup as r,onFormReset as i,watchEffect as a}from"../runtime.js";var o=/* @__PURE__ */ new WeakMap,s=/* @__PURE__ */ new WeakSet,c=c=>{let l=n();if(!l.constructor.formAssociated)throw new t(e.defineFieldRequiresFormAssociated(l.localName));if(s.has(l))throw new t(e.useFieldAlreadyCalled(l.localName));let u=o.get(l)??l.attachInternals();o.set(l,u),s.add(l),r(()=>s.delete(l));let d=c.toFormValue??(e=>e==null?c.emptyStringForNull?``:null:e instanceof File||e instanceof FormData?e:String(e));a(()=>{u.setFormValue(d(c.value.value))});let f=c.disabled;if(f&&`states`in u){let e=u.states;a(()=>{f.value?e.add(`disabled`):e.delete(`disabled`)})}return c.validity&&a(()=>{let e=c.validity?.value;if(!e){u.setValidity({});return}let t=Object.values(e.flags).some(Boolean);u.setValidity(e.flags,t&&!e.message?`Invalid value.`:e.message)}),c.onReset&&i(c.onReset),{checkValidity:()=>u.checkValidity(),internals:u,reportValidity:()=>u.reportValidity(),setCustomValidity:e=>e?u.setValidity({customError:!0},e):u.setValidity({})}};export{c as useField};
|
|
2
2
|
//# sourceMappingURL=field.js.map
|
package/dist/forms/field.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.js","names":[],"sources":["../../src/forms/field.ts"],"sourcesContent":["import type { Readable, Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS, OreApiError } from '../errors';\nimport { getHost, onCleanup, onFormReset, watchEffect } from '../runtime';\n\n/** @internal */\nconst internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n/** @internal */\nconst activeFieldRegistry = new WeakSet<HTMLElement>();\n\n/**\n * One field-validity state: the flags and the message travel together because\n * the platform's `setValidity()` contract couples them (flags without a\n * non-empty message throw). A single `{ flags, message } | null` input makes a\n * desynced pair unrepresentable, where the old split `validity` +\n * `validationMessage` options could drift apart.\n */\nexport type FormFieldValidity = { flags: ValidityStateFlags; message: string };\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: Readable<boolean>;\n /**\n * When `true`, a `null` or `undefined` value is submitted as an empty string\n * (`''`) instead of `null`. This keeps the field's key present in `FormData`\n * even when the value is absent: useful when the server expects the field to\n * always be included.\n *\n * @default false\n */\n emptyStringForNull?: boolean;\n /**\n * Called when the ancestor `<form>` is reset (see `onFormReset`). Use to restore\n * whatever local state backs `value`: `useField` itself owns no field state to reset.\n */\n onReset?: () => void;\n toFormValue?: (value: T) => File | FormData | string | null;\n /**\n * Recomputed reactively and passed straight to `internals.setValidity()`: `null`\n * (or omitting `validity` entirely) means always valid.\n *\n * @example\n * ```ts\n * validity: computed(() =>\n * required.value && isBlank(value.value)\n * ? { flags: { valueMissing: true }, message: 'Required.' }\n * : null,\n * ),\n * ```\n */\n validity?: Readable<FormFieldValidity | null>;\n value: Signal<T> | Readable<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n /**\n * Set (non-empty message) or clear (empty string) a custom validity error.\n * Guards the platform's throw-on-empty-message contract: prefer this over\n * calling `internals.setValidity` directly.\n */\n setCustomValidity: (message: string) => void;\n};\n\nexport const useField = <T = unknown>(options: FormFieldOptions<T>): FormFieldHandle => {\n const host = getHost();\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new OreApiError(ORE_ERRORS.defineFieldRequiresFormAssociated(host.localName));\n }\n\n if (activeFieldRegistry.has(host)) {\n throw new OreApiError(ORE_ERRORS.useFieldAlreadyCalled(host.localName));\n }\n\n // ElementInternals may only be attached once for an element's lifetime, while setup\n // legitimately runs again when a custom element is reconnected.\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n activeFieldRegistry.add(host);\n onCleanup(() => activeFieldRegistry.delete(host));\n\n const toFormValue =\n options.toFormValue ??\n ((v: T): File | FormData | string | null => {\n if (v == null) return options.emptyStringForNull ? '' : null;\n\n if (v instanceof File || v instanceof FormData) return v;\n\n return String(v);\n });\n\n watchEffect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n if (!('states' in internals)) {\n warn(\n 'useField(): ElementInternals.states (CustomStateSet) is not available in this environment: disabled state tracking skipped.',\n );\n } else {\n const states = internals.states as CustomStateSet;\n\n watchEffect(() => {\n if (disabled.value) states.add('disabled');\n else states.delete('disabled');\n });\n }\n }\n\n if (options.validity) {\n watchEffect(() => {\n const state = options.validity?.value;\n\n if (!state) {\n internals.setValidity({});\n\n return;\n }\n\n // Per spec, ElementInternals.setValidity() throws if any flag is true and the\n // message is empty. The FormFieldValidity shape makes that state rare, but a\n // runtime empty string is still expressible: fall back to a generic message\n // instead of crashing this effect in a real browser.\n const hasFlag = Object.values(state.flags).some(Boolean);\n\n internals.setValidity(state.flags, hasFlag && !state.message ? 'Invalid value.' : state.message);\n });\n }\n\n if (options.onReset) onFormReset(options.onReset);\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n };\n};\n"],"mappings":"uKAOA,
|
|
1
|
+
{"version":3,"file":"field.js","names":["internalsRegistry","activeFieldRegistry","useField","host","getHost","OreApiError","ORE_ERRORS","internals","onCleanup","toFormValue","options","v","watchEffect","disabled","states","state","hasFlag","onFormReset","message"],"sources":["../../src/forms/field.ts"],"sourcesContent":["import type { Readable, Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS, OreApiError } from '../errors';\nimport { getHost, onCleanup, onFormReset, watchEffect } from '../runtime';\n\n/** @internal */\nconst internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n/** @internal */\nconst activeFieldRegistry = new WeakSet<HTMLElement>();\n\n/**\n * One field-validity state: the flags and the message travel together because\n * the platform's `setValidity()` contract couples them (flags without a\n * non-empty message throw). A single `{ flags, message } | null` input makes a\n * desynced pair unrepresentable, where the old split `validity` +\n * `validationMessage` options could drift apart.\n */\nexport type FormFieldValidity = { flags: ValidityStateFlags; message: string };\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: Readable<boolean>;\n /**\n * When `true`, a `null` or `undefined` value is submitted as an empty string\n * (`''`) instead of `null`. This keeps the field's key present in `FormData`\n * even when the value is absent: useful when the server expects the field to\n * always be included.\n *\n * @default false\n */\n emptyStringForNull?: boolean;\n /**\n * Called when the ancestor `<form>` is reset (see `onFormReset`). Use to restore\n * whatever local state backs `value`: `useField` itself owns no field state to reset.\n */\n onReset?: () => void;\n toFormValue?: (value: T) => File | FormData | string | null;\n /**\n * Recomputed reactively and passed straight to `internals.setValidity()`: `null`\n * (or omitting `validity` entirely) means always valid.\n *\n * @example\n * ```ts\n * validity: computed(() =>\n * required.value && isBlank(value.value)\n * ? { flags: { valueMissing: true }, message: 'Required.' }\n * : null,\n * ),\n * ```\n */\n validity?: Readable<FormFieldValidity | null>;\n value: Signal<T> | Readable<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n /**\n * Set (non-empty message) or clear (empty string) a custom validity error.\n * Guards the platform's throw-on-empty-message contract: prefer this over\n * calling `internals.setValidity` directly.\n */\n setCustomValidity: (message: string) => void;\n};\n\nexport const useField = <T = unknown>(options: FormFieldOptions<T>): FormFieldHandle => {\n const host = getHost();\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new OreApiError(ORE_ERRORS.defineFieldRequiresFormAssociated(host.localName));\n }\n\n if (activeFieldRegistry.has(host)) {\n throw new OreApiError(ORE_ERRORS.useFieldAlreadyCalled(host.localName));\n }\n\n // ElementInternals may only be attached once for an element's lifetime, while setup\n // legitimately runs again when a custom element is reconnected.\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n activeFieldRegistry.add(host);\n onCleanup(() => activeFieldRegistry.delete(host));\n\n const toFormValue =\n options.toFormValue ??\n ((v: T): File | FormData | string | null => {\n if (v == null) return options.emptyStringForNull ? '' : null;\n\n if (v instanceof File || v instanceof FormData) return v;\n\n return String(v);\n });\n\n watchEffect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n if (!('states' in internals)) {\n warn(\n 'useField(): ElementInternals.states (CustomStateSet) is not available in this environment: disabled state tracking skipped.',\n );\n } else {\n const states = internals.states as CustomStateSet;\n\n watchEffect(() => {\n if (disabled.value) states.add('disabled');\n else states.delete('disabled');\n });\n }\n }\n\n if (options.validity) {\n watchEffect(() => {\n const state = options.validity?.value;\n\n if (!state) {\n internals.setValidity({});\n\n return;\n }\n\n // Per spec, ElementInternals.setValidity() throws if any flag is true and the\n // message is empty. The FormFieldValidity shape makes that state rare, but a\n // runtime empty string is still expressible: fall back to a generic message\n // instead of crashing this effect in a real browser.\n const hasFlag = Object.values(state.flags).some(Boolean);\n\n internals.setValidity(state.flags, hasFlag && !state.message ? 'Invalid value.' : state.message);\n });\n }\n\n if (options.onReset) onFormReset(options.onReset);\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n };\n};\n"],"mappings":"A,uKAOA,IAAMA,kBAAoB,IAAI,QAExBC,kBAAsB,IAAI,QAyDnBC,EAAyB,GAAkD,CACtF,IAAMC,EAAOC,EAAQ,EAGrB,GAAI,CAFSD,EAAK,YAER,eACR,MAAM,IAAIE,EAAYC,EAAW,kCAAkCH,EAAK,SAAS,CAAC,EAGpF,GAAIF,EAAoB,IAAIE,CAAI,EAC9B,MAAM,IAAIE,EAAYC,EAAW,sBAAsBH,EAAK,SAAS,CAAC,EAKxE,IAAMI,EAAYP,EAAkB,IAAIG,CAAI,GAAKA,EAAK,gBAAgB,EAEtEH,EAAkB,IAAIG,EAAMI,CAAS,EACrCN,EAAoB,IAAIE,CAAI,EAC5BK,MAAgBP,EAAoB,OAAOE,CAAI,CAAC,EAEhD,IAAMM,EACJC,EAAQ,cACN,GACIC,GAAK,KAAaD,EAAQ,mBAAqB,GAAK,KAEpDC,aAAa,MAAQA,aAAa,SAAiBA,EAEhD,OAAOA,CAAC,GAGnBC,MAAkB,CAChBL,EAAU,aAAaE,EAAYC,EAAQ,MAAM,KAAK,CAAC,CACzD,CAAC,EAED,IAAMG,EAAWH,EAAQ,SAEzB,GAAIG,GACI,WAAYN,EAIX,CACL,IAAMO,EAASP,EAAU,OAEzBK,MAAkB,CACZC,EAAS,MAAOC,EAAO,IAAI,UAAU,EACpCA,EAAO,OAAO,UAAU,CAC/B,CAAC,CACH,CA8BF,OA3BIJ,EAAQ,UACVE,MAAkB,CAChB,IAAMG,EAAQL,EAAQ,UAAU,MAEhC,GAAI,CAACK,EAAO,CACVR,EAAU,YAAY,CAAC,CAAC,EAExB,MACF,CAMA,IAAMS,EAAU,OAAO,OAAOD,EAAM,KAAK,CAAC,CAAC,KAAK,OAAO,EAEvDR,EAAU,YAAYQ,EAAM,MAAOC,GAAW,CAACD,EAAM,QAAU,iBAAmBA,EAAM,OAAO,CACjG,CAAC,EAGCL,EAAQ,SAASO,EAAYP,EAAQ,OAAO,EAOzC,CACL,kBAN0BH,EAAU,cAAc,EAOlD,YACA,mBAP2BA,EAAU,eAAe,EAQpD,kBAPyB,GACzBW,EAAUX,EAAU,YAAY,CAAE,YAAa,EAAK,EAAGW,CAAO,EAAIX,EAAU,YAAY,CAAC,CAAC,CAO5F,CACF,E"}
|
package/dist/host-bind.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-bind.cjs","names":[],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API: reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeHostAttrKey } from './utils/aria';\nimport {\n cssDeclarationName,\n cssDeclarationValue,\n listen,\n type MaybeReactive,\n resolveClassTokens,\n setAttr,\n} from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue = MaybeReactive<string | number | boolean | null | undefined>;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type AttributeBindings = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = MaybeReactive<boolean>;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n attr?: AttributeBindings;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | undefined => {\n if (typeof value === 'function') {\n return watchEffect(() => {\n updater(value());\n return undefined;\n });\n }\n\n if (isReactive(value)) {\n return watchEffect(() => {\n updater(value.value);\n return undefined;\n });\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n const cssName = cssDeclarationName(name);\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n const declaration = cssDeclarationValue(v);\n\n if (declaration) {\n owned = true;\n host.style.setProperty(cssName, declaration);\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => Object.fromEntries([...resolveClassTokens(value)].map((cls) => [cls, true]));\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"8HAwDA,
|
|
1
|
+
{"version":3,"file":"host-bind.cjs","names":["getHost","listen","normalizeHostAttrKey","watchEffect","isReactive","setAttr","cssDeclarationName","cssDeclarationValue","resolveClassTokens","require_dom","require_runtime","require_aria","_vielzeug_ripple","bind","el","options","disposers","config","key","value","dispose","applyAttribute","toHostAttr","applyClassMap","applyStyle","_t","listenerOptions","event","listener","cleanup","applyReactiveBinding","updater","host","name","next","cssName","owned","declaration","v","getMap","cls","prev","active"],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API: reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeHostAttrKey } from './utils/aria';\nimport {\n cssDeclarationName,\n cssDeclarationValue,\n listen,\n type MaybeReactive,\n resolveClassTokens,\n setAttr,\n} from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue = MaybeReactive<string | number | boolean | null | undefined>;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type AttributeBindings = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = MaybeReactive<boolean>;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n attr?: AttributeBindings;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | undefined => {\n if (typeof value === 'function') {\n return watchEffect(() => {\n updater(value());\n return undefined;\n });\n }\n\n if (isReactive(value)) {\n return watchEffect(() => {\n updater(value.value);\n return undefined;\n });\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n const cssName = cssDeclarationName(name);\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n const declaration = cssDeclarationValue(v);\n\n if (declaration) {\n owned = true;\n host.style.setProperty(cssName, declaration);\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => Object.fromEntries([...resolveClassTokens(value)].map((cls) => [cls, true]));\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"A,8HAwDA,IAAaa,GAAQ,EAAwB,IAAwC,CACnF,IAAMC,EAAMC,GAAS,QAAsCf,EAAAA,QAAQ,EAC7DgB,EAA+B,CAAC,EAEtC,GAAIC,EAAO,KACT,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQF,EAAO,IAAI,EAAG,CAEtD,IAAMG,EAAUC,EAAeP,EADlBQ,EAAWJ,CACW,EAAMC,CAAK,EAE1CC,GAASJ,EAAU,KAAKI,CAAO,CACrC,CAOF,GAJIH,EAAO,OACTD,EAAU,KAAKO,EAAcT,EAAIG,EAAO,KAAK,CAAC,EAG5CA,EAAO,MACT,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQF,EAAO,KAAK,EAAG,CACvD,IAAMG,EAAUI,EAAWV,EAAII,EAAKC,CAAK,EAErCC,GAASJ,EAAU,KAAKI,CAAO,CACrC,CAGF,GAAIH,EAAO,GAAI,CACb,GAAM,CAAE,OAAQQ,EAAI,GAAGC,GAAoBX,GAAW,CAAC,EAEvD,IAAK,IAAMY,KAAS,OAAO,KAAKV,EAAO,EAAE,EAAoC,CAC3E,IAAMW,EAAWX,EAAO,GAAGU,GAEtBC,GAELZ,EAAU,KAAKf,EAAAA,OAAOa,EAAIa,EAAiBC,EAA2BF,CAAe,CAAC,CACxF,CACF,CAEA,IAAMG,MAAsB,CAC1B,IAAK,IAAMT,KAAWJ,EAAWI,EAAQ,CAC3C,EAIA,OAFAV,EAAA,mBAAmBmB,CAAO,EAEnBA,CACT,EAEMP,EAAapB,EAAAA,qBAEb4B,GACJ,EACA,IAC6B,CAC7B,GAAI,OAAOX,GAAU,WACnB,OAAOhB,EAAAA,gBAAkB,CACvB4B,EAAQZ,EAAM,CAAC,CAEjB,CAAC,EAGH,IAAA,EAAIf,EAAAA,WAAAA,CAAWe,CAAK,EAClB,OAAOhB,EAAAA,gBAAkB,CACvB4B,EAAQZ,EAAM,KAAK,CAErB,CAAC,EAGHY,EAAQZ,CAAK,CACf,EAEA,SAASE,EAAe,EAAmB,EAAc,EAAmD,CAC1G,OAAOS,EAAqBX,EAAQ,GAASd,EAAAA,QAAQ2B,EAAMC,EAAMC,CAAI,CAAC,CACxE,CAEA,SAASV,EAAW,EAAmB,EAAc,EAAmD,CACtG,IAAMW,EAAU7B,EAAAA,mBAAmB2B,CAAI,EAEvC,GAAI,CAACE,EAAS,OAEd,IAAIC,EAAQ,GAUZ,OAAON,EAAqBX,EATV,GAA0D,CAC1E,IAAMkB,EAAc9B,EAAAA,oBAAoB+B,CAAC,EAErCD,GACF,EAAQ,GACRL,EAAK,MAAM,YAAYG,EAASE,CAAW,GAClCD,GAAOJ,EAAK,MAAM,eAAeG,CAAO,CACrD,CAE2C,CAC7C,CAEA,SAASZ,EACP,EACA,EACY,CACZ,IAAMgB,EACJ,OAAOpB,GAAU,WACbA,MAC+B,OAAO,YAAY,CAAC,GAAGX,EAAAA,mBAAmBW,CAAK,CAAC,CAAC,CAAC,IAAK,GAAQ,CAACqB,EAAK,EAAI,CAAC,CAAC,EAE5GC,EAAO,IAAI,IAkBf,OAhBYtC,EAAAA,gBAAkB,CAC5B,IAAM+B,EAAO,IAAI,IAEjB,IAAK,GAAM,CAACM,EAAKE,KAAW,OAAO,QAAQH,EAAO,CAAC,EAC5CG,IAELR,EAAK,IAAIM,CAAG,EAEPC,EAAK,IAAID,CAAG,GAAGR,EAAK,UAAU,IAAIQ,CAAG,GAE5C,IAAK,IAAMA,KAAOC,EACXP,EAAK,IAAIM,CAAG,GAAGR,EAAK,UAAU,OAAOQ,CAAG,EAE/C,EAAON,CACT,CAEO,CACT,C"}
|
package/dist/host-bind.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{cssDeclarationName as e,cssDeclarationValue as t,listen as n,resolveClassTokens as r,setAttr as i}from"./utils/dom.js";import{getHost as a,tryRegisterCleanup as o,watchEffect as s}from"./runtime.js";import{normalizeHostAttrKey as c}from"./utils/aria.js";import{isReactive as l}from"@vielzeug/ripple";var u=(e,t)=>{let r=t?.target??a(),i=[];if(e.attr)for(let[t,n]of Object.entries(e.attr)){let e=p(r,d(t),n);e&&i.push(e)}if(e.class&&i.push(h(r,e.class)),e.style)for(let[t,n]of Object.entries(e.style)){let e=m(r,t,n);e&&i.push(e)}if(e.on){let{target:a,...o}=t??{};for(let t of Object.keys(e.on)){let a=e.on[t];a&&i.push(n(r,t,a,o))}}let s=()=>{for(let e of i)e()};return o(s),s},d=c,f=(e,t)=>{if(typeof e==`function`)return s(()=>{t(e())});if(l(e))return s(()=>{t(e.value)});t(e)};function p(e,t,n){return f(n,n=>i(e,t,n))}function m(n,r,i){let a=e(r);if(!a)return;let o=!1;return f(i,e=>{let r=t(e);r?(o=!0,n.style.setProperty(a,r)):o&&n.style.removeProperty(a)})}function h(e,t){let n=typeof t==`function`?t:()=>Object.fromEntries([...r(t)].map(e=>[e,!0])),i
|
|
1
|
+
import{cssDeclarationName as e,cssDeclarationValue as t,listen as n,resolveClassTokens as r,setAttr as i}from"./utils/dom.js";import{getHost as a,tryRegisterCleanup as o,watchEffect as s}from"./runtime.js";import{normalizeHostAttrKey as c}from"./utils/aria.js";import{isReactive as l}from"@vielzeug/ripple";var u=(e,t)=>{let r=t?.target??a(),i=[];if(e.attr)for(let[t,n]of Object.entries(e.attr)){let e=p(r,d(t),n);e&&i.push(e)}if(e.class&&i.push(h(r,e.class)),e.style)for(let[t,n]of Object.entries(e.style)){let e=m(r,t,n);e&&i.push(e)}if(e.on){let{target:a,...o}=t??{};for(let t of Object.keys(e.on)){let a=e.on[t];a&&i.push(n(r,t,a,o))}}let s=()=>{for(let e of i)e()};return o(s),s},d=c,f=(e,t)=>{if(typeof e==`function`)return s(()=>{t(e())});if(l(e))return s(()=>{t(e.value)});t(e)};function p(e,t,n){return f(n,n=>i(e,t,n))}function m(n,r,i){let a=e(r);if(!a)return;let o=!1;return f(i,e=>{let r=t(e);r?(o=!0,n.style.setProperty(a,r)):o&&n.style.removeProperty(a)})}function h(e,t){let n=typeof t==`function`?t:()=>Object.fromEntries([...r(t)].map(e=>[e,!0])),i=/* @__PURE__ */ new Set;return s(()=>{let t=/* @__PURE__ */ new Set;for(let[r,a]of Object.entries(n()))a&&(t.add(r),i.has(r)||e.classList.add(r));for(let n of i)t.has(n)||e.classList.remove(n);i=t})}export{u as bind};
|
|
2
2
|
//# sourceMappingURL=host-bind.js.map
|
package/dist/host-bind.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-bind.js","names":[],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API: reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeHostAttrKey } from './utils/aria';\nimport {\n cssDeclarationName,\n cssDeclarationValue,\n listen,\n type MaybeReactive,\n resolveClassTokens,\n setAttr,\n} from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue = MaybeReactive<string | number | boolean | null | undefined>;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type AttributeBindings = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = MaybeReactive<boolean>;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n attr?: AttributeBindings;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | undefined => {\n if (typeof value === 'function') {\n return watchEffect(() => {\n updater(value());\n return undefined;\n });\n }\n\n if (isReactive(value)) {\n return watchEffect(() => {\n updater(value.value);\n return undefined;\n });\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n const cssName = cssDeclarationName(name);\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n const declaration = cssDeclarationValue(v);\n\n if (declaration) {\n owned = true;\n host.style.setProperty(cssName, declaration);\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => Object.fromEntries([...resolveClassTokens(value)].map((cls) => [cls, true]));\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"mTAwDA,
|
|
1
|
+
{"version":3,"file":"host-bind.js","names":["bind","el","options","getHost","disposers","config","key","value","dispose","applyAttribute","toHostAttr","applyClassMap","applyStyle","_t","listenerOptions","event","listener","listen","cleanup","tryRegisterCleanup","normalizeHostAttrKey","applyReactiveBinding","watchEffect","updater","isReactive","setAttr","host","name","next","cssName","cssDeclarationName","owned","declaration","cssDeclarationValue","v","getMap","resolveClassTokens","cls","prev","active"],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API: reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeHostAttrKey } from './utils/aria';\nimport {\n cssDeclarationName,\n cssDeclarationValue,\n listen,\n type MaybeReactive,\n resolveClassTokens,\n setAttr,\n} from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue = MaybeReactive<string | number | boolean | null | undefined>;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type AttributeBindings = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = MaybeReactive<boolean>;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n attr?: AttributeBindings;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | undefined => {\n if (typeof value === 'function') {\n return watchEffect(() => {\n updater(value());\n return undefined;\n });\n }\n\n if (isReactive(value)) {\n return watchEffect(() => {\n updater(value.value);\n return undefined;\n });\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n const cssName = cssDeclarationName(name);\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n const declaration = cssDeclarationValue(v);\n\n if (declaration) {\n owned = true;\n host.style.setProperty(cssName, declaration);\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => Object.fromEntries([...resolveClassTokens(value)].map((cls) => [cls, true]));\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"A,mTAwDA,IAAaA,GAAQ,EAAwB,IAAwC,CACnF,IAAMC,EAAMC,GAAS,QAAsCC,EAAQ,EAC7DC,EAA+B,CAAC,EAEtC,GAAIC,EAAO,KACT,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQF,EAAO,IAAI,EAAG,CAEtD,IAAMG,EAAUC,EAAeR,EADlBS,EAAWJ,CACW,EAAMC,CAAK,EAE1CC,GAASJ,EAAU,KAAKI,CAAO,CACrC,CAOF,GAJIH,EAAO,OACTD,EAAU,KAAKO,EAAcV,EAAII,EAAO,KAAK,CAAC,EAG5CA,EAAO,MACT,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQF,EAAO,KAAK,EAAG,CACvD,IAAMG,EAAUI,EAAWX,EAAIK,EAAKC,CAAK,EAErCC,GAASJ,EAAU,KAAKI,CAAO,CACrC,CAGF,GAAIH,EAAO,GAAI,CACb,GAAM,CAAE,OAAQQ,EAAI,GAAGC,GAAoBZ,GAAW,CAAC,EAEvD,IAAK,IAAMa,KAAS,OAAO,KAAKV,EAAO,EAAE,EAAoC,CAC3E,IAAMW,EAAWX,EAAO,GAAGU,GAEtBC,GAELZ,EAAU,KAAKa,EAAOhB,EAAIc,EAAiBC,EAA2BF,CAAe,CAAC,CACxF,CACF,CAEA,IAAMI,MAAsB,CAC1B,IAAK,IAAMV,KAAWJ,EAAWI,EAAQ,CAC3C,EAIA,OAFAW,EAAmBD,CAAO,EAEnBA,CACT,EAEMR,EAAaU,EAEbC,GACJ,EACA,IAC6B,CAC7B,GAAI,OAAOd,GAAU,WACnB,OAAOe,MAAkB,CACvBC,EAAQhB,EAAM,CAAC,CAEjB,CAAC,EAGH,GAAIiB,EAAWjB,CAAK,EAClB,OAAOe,MAAkB,CACvBC,EAAQhB,EAAM,KAAK,CAErB,CAAC,EAGHgB,EAAQhB,CAAK,CACf,EAEA,SAASE,EAAe,EAAmB,EAAc,EAAmD,CAC1G,OAAOY,EAAqBd,EAAQ,GAASkB,EAAQC,EAAMC,EAAMC,CAAI,CAAC,CACxE,CAEA,SAAShB,EAAW,EAAmB,EAAc,EAAmD,CACtG,IAAMiB,EAAUC,EAAmBH,CAAI,EAEvC,GAAI,CAACE,EAAS,OAEd,IAAIE,EAAQ,GAUZ,OAAOV,EAAqBd,EATV,GAA0D,CAC1E,IAAMyB,EAAcC,EAAoBC,CAAC,EAErCF,GACF,EAAQ,GACRN,EAAK,MAAM,YAAYG,EAASG,CAAW,GAClCD,GAAOL,EAAK,MAAM,eAAeG,CAAO,CACrD,CAE2C,CAC7C,CAEA,SAASlB,EACP,EACA,EACY,CACZ,IAAMwB,EACJ,OAAO5B,GAAU,WACbA,MAC+B,OAAO,YAAY,CAAC,GAAG6B,EAAmB7B,CAAK,CAAC,CAAC,CAAC,IAAK,GAAQ,CAAC8B,EAAK,EAAI,CAAC,CAAC,EAE5GC,kBAAO,IAAI,IAkBf,OAhBYhB,MAAkB,CAC5B,IAAMM,kBAAO,IAAI,IAEjB,IAAK,GAAM,CAACS,EAAKE,KAAW,OAAO,QAAQJ,EAAO,CAAC,EAC5CI,IAELX,EAAK,IAAIS,CAAG,EAEPC,EAAK,IAAID,CAAG,GAAGX,EAAK,UAAU,IAAIW,CAAG,GAE5C,IAAK,IAAMA,KAAOC,EACXV,EAAK,IAAIS,CAAG,GAAGX,EAAK,UAAU,OAAOW,CAAG,EAE/C,EAAOT,CACT,CAEO,CACT,C"}
|