@vielzeug/craftit 2.1.0 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -124
- package/dist/controls/a11y-control.cjs +1 -1
- package/dist/controls/a11y-control.cjs.map +1 -1
- package/dist/controls/a11y-control.d.ts +1 -1
- package/dist/controls/a11y-control.d.ts.map +1 -1
- package/dist/controls/a11y-control.js +1 -1
- package/dist/controls/a11y-control.js.map +1 -1
- package/dist/controls/checkable-control.cjs +1 -1
- package/dist/controls/checkable-control.cjs.map +1 -1
- package/dist/controls/checkable-control.d.ts +7 -7
- package/dist/controls/checkable-control.d.ts.map +1 -1
- package/dist/controls/checkable-control.js +1 -1
- package/dist/controls/checkable-control.js.map +1 -1
- package/dist/controls/choice-field-control.cjs +2 -0
- package/dist/controls/choice-field-control.cjs.map +1 -0
- package/dist/controls/choice-field-control.d.ts +3 -0
- package/dist/controls/choice-field-control.d.ts.map +1 -0
- package/dist/controls/choice-field-control.js +2 -0
- package/dist/controls/choice-field-control.js.map +1 -0
- package/dist/controls/field-control.cjs +1 -1
- package/dist/controls/field-control.cjs.map +1 -1
- package/dist/controls/field-control.d.ts +28 -73
- package/dist/controls/field-control.d.ts.map +1 -1
- package/dist/controls/field-control.js +1 -1
- package/dist/controls/field-control.js.map +1 -1
- package/dist/controls/index.d.ts +11 -9
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/internal/control-state.cjs +1 -1
- package/dist/controls/internal/control-state.cjs.map +1 -1
- package/dist/controls/internal/control-state.d.ts +6 -4
- package/dist/controls/internal/control-state.d.ts.map +1 -1
- package/dist/controls/internal/control-state.js +1 -1
- package/dist/controls/internal/control-state.js.map +1 -1
- package/dist/controls/internal/keyboard-utils.cjs.map +1 -1
- package/dist/controls/internal/keyboard-utils.js.map +1 -1
- package/dist/controls/internal/number-utils.cjs.map +1 -1
- package/dist/controls/internal/number-utils.js.map +1 -1
- package/dist/controls/internal/validation-utils.cjs.map +1 -1
- package/dist/controls/internal/validation-utils.js.map +1 -1
- package/dist/controls/list-control.cjs +1 -1
- package/dist/controls/list-control.cjs.map +1 -1
- package/dist/controls/list-control.d.ts +10 -8
- package/dist/controls/list-control.d.ts.map +1 -1
- package/dist/controls/list-control.js +1 -1
- package/dist/controls/list-control.js.map +1 -1
- package/dist/controls/overlay-control.cjs +1 -1
- package/dist/controls/overlay-control.cjs.map +1 -1
- package/dist/controls/overlay-control.d.ts +17 -14
- package/dist/controls/overlay-control.d.ts.map +1 -1
- package/dist/controls/overlay-control.js +1 -1
- package/dist/controls/overlay-control.js.map +1 -1
- package/dist/controls/popup-list-control.cjs +2 -0
- package/dist/controls/popup-list-control.cjs.map +1 -0
- package/dist/controls/popup-list-control.d.ts +160 -0
- package/dist/controls/popup-list-control.d.ts.map +1 -0
- package/dist/controls/popup-list-control.js +2 -0
- package/dist/controls/popup-list-control.js.map +1 -0
- package/dist/controls/press-control.cjs.map +1 -1
- package/dist/controls/press-control.js.map +1 -1
- package/dist/controls/slider-control.cjs.map +1 -1
- package/dist/controls/slider-control.js.map +1 -1
- package/dist/controls/spinner-control.cjs.map +1 -1
- package/dist/controls/spinner-control.js.map +1 -1
- package/dist/controls/swipe-control.cjs +2 -0
- package/dist/controls/swipe-control.cjs.map +1 -0
- package/dist/controls/swipe-control.d.ts +32 -0
- package/dist/controls/swipe-control.d.ts.map +1 -0
- package/dist/controls/swipe-control.js +2 -0
- package/dist/controls/swipe-control.js.map +1 -0
- package/dist/controls/text-field-control.cjs +2 -0
- package/dist/controls/text-field-control.cjs.map +1 -0
- package/dist/controls/text-field-control.d.ts +3 -0
- package/dist/controls/text-field-control.d.ts.map +1 -0
- package/dist/controls/text-field-control.js +2 -0
- package/dist/controls/text-field-control.js.map +1 -0
- package/dist/controls.cjs +1 -1
- package/dist/controls.js +1 -1
- package/dist/craftit.cjs +1 -1
- package/dist/craftit.cjs.map +1 -1
- package/dist/craftit.js +1 -1
- package/dist/craftit.js.map +1 -1
- package/dist/directives/classMap.cjs +2 -0
- package/dist/directives/classMap.cjs.map +1 -0
- package/dist/directives/classMap.d.ts +19 -0
- package/dist/directives/classMap.d.ts.map +1 -0
- package/dist/directives/classMap.js +2 -0
- package/dist/directives/classMap.js.map +1 -0
- package/dist/directives/each.cjs +1 -1
- package/dist/directives/each.cjs.map +1 -1
- package/dist/directives/each.d.ts +5 -30
- package/dist/directives/each.d.ts.map +1 -1
- package/dist/directives/each.js +1 -1
- package/dist/directives/each.js.map +1 -1
- package/dist/directives/guard.cjs +2 -0
- package/dist/directives/guard.cjs.map +1 -0
- package/dist/directives/guard.d.ts +10 -0
- package/dist/directives/guard.d.ts.map +1 -0
- package/dist/directives/guard.js +2 -0
- package/dist/directives/guard.js.map +1 -0
- package/dist/directives/live.cjs +2 -0
- package/dist/directives/live.cjs.map +1 -0
- package/dist/directives/live.d.ts +23 -0
- package/dist/directives/live.d.ts.map +1 -0
- package/dist/directives/live.js +2 -0
- package/dist/directives/live.js.map +1 -0
- package/dist/directives/raw.cjs +1 -1
- package/dist/directives/raw.cjs.map +1 -1
- package/dist/directives/raw.d.ts +3 -5
- package/dist/directives/raw.d.ts.map +1 -1
- package/dist/directives/raw.js +1 -1
- package/dist/directives/raw.js.map +1 -1
- package/dist/directives/resource.cjs +2 -0
- package/dist/directives/resource.cjs.map +1 -0
- package/dist/directives/resource.d.ts +32 -0
- package/dist/directives/resource.d.ts.map +1 -0
- package/dist/directives/resource.js +2 -0
- package/dist/directives/resource.js.map +1 -0
- package/dist/directives/styleMap.cjs +2 -0
- package/dist/directives/styleMap.cjs.map +1 -0
- package/dist/directives/styleMap.d.ts +11 -0
- package/dist/directives/styleMap.d.ts.map +1 -0
- package/dist/directives/styleMap.js +2 -0
- package/dist/directives/styleMap.js.map +1 -0
- package/dist/directives/when.cjs +1 -1
- package/dist/directives/when.cjs.map +1 -1
- package/dist/directives/when.d.ts +6 -19
- package/dist/directives/when.d.ts.map +1 -1
- package/dist/directives/when.js +1 -1
- package/dist/directives/when.js.map +1 -1
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -0
- package/dist/form.cjs +1 -1
- package/dist/form.cjs.map +1 -1
- package/dist/form.d.ts +3 -17
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +1 -1
- package/dist/form.js.map +1 -1
- package/dist/host.cjs +1 -1
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.ts +40 -37
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +1 -1
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +16 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.cjs +1 -1
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.ts +60 -120
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/observers/index.d.ts +1 -0
- package/dist/observers/index.d.ts.map +1 -1
- package/dist/observers/intersection-observe.cjs +1 -1
- package/dist/observers/intersection-observe.cjs.map +1 -1
- package/dist/observers/intersection-observe.d.ts +1 -1
- package/dist/observers/intersection-observe.js +1 -1
- package/dist/observers/intersection-observe.js.map +1 -1
- package/dist/observers/media-observe.cjs +1 -1
- package/dist/observers/media-observe.cjs.map +1 -1
- package/dist/observers/media-observe.d.ts +1 -1
- package/dist/observers/media-observe.js +1 -1
- package/dist/observers/media-observe.js.map +1 -1
- package/dist/observers/mutation-observe.cjs +2 -0
- package/dist/observers/mutation-observe.cjs.map +1 -0
- package/dist/observers/mutation-observe.d.ts +10 -0
- package/dist/observers/mutation-observe.d.ts.map +1 -0
- package/dist/observers/mutation-observe.js +2 -0
- package/dist/observers/mutation-observe.js.map +1 -0
- package/dist/observers/resize-observe.cjs +1 -1
- package/dist/observers/resize-observe.cjs.map +1 -1
- package/dist/observers/resize-observe.d.ts +1 -1
- package/dist/observers/resize-observe.js +1 -1
- package/dist/observers/resize-observe.js.map +1 -1
- package/dist/observers.cjs +1 -1
- package/dist/observers.js +1 -1
- package/dist/props.cjs +1 -1
- package/dist/props.cjs.map +1 -1
- package/dist/props.d.ts +18 -31
- package/dist/props.d.ts.map +1 -1
- package/dist/props.js +1 -1
- package/dist/props.js.map +1 -1
- package/dist/registration.cjs +1 -1
- package/dist/registration.cjs.map +1 -1
- package/dist/registration.d.ts +27 -7
- package/dist/registration.d.ts.map +1 -1
- package/dist/registration.js +1 -1
- package/dist/registration.js.map +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.ts +29 -17
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/template-bindings.cjs +1 -1
- package/dist/template-bindings.cjs.map +1 -1
- package/dist/template-bindings.d.ts +10 -47
- package/dist/template-bindings.d.ts.map +1 -1
- package/dist/template-bindings.js +1 -1
- package/dist/template-bindings.js.map +1 -1
- package/dist/template-compiler.cjs +1 -1
- package/dist/template-compiler.cjs.map +1 -1
- package/dist/template-compiler.d.ts +1 -21
- package/dist/template-compiler.d.ts.map +1 -1
- package/dist/template-compiler.js +1 -1
- package/dist/template-compiler.js.map +1 -1
- package/dist/testing/testing.cjs +1 -1
- package/dist/testing/testing.cjs.map +1 -1
- package/dist/testing/testing.d.ts +12 -5
- package/dist/testing/testing.d.ts.map +1 -1
- package/dist/testing/testing.js +1 -1
- package/dist/testing/testing.js.map +1 -1
- package/package.json +6 -12
- package/dist/component.cjs +0 -2
- package/dist/component.cjs.map +0 -1
- package/dist/component.d.ts +0 -39
- package/dist/component.d.ts.map +0 -1
- package/dist/component.js +0 -2
- package/dist/component.js.map +0 -1
- package/dist/controls/list-key-control.cjs +0 -2
- package/dist/controls/list-key-control.cjs.map +0 -1
- package/dist/controls/list-key-control.d.ts +0 -14
- package/dist/controls/list-key-control.d.ts.map +0 -1
- package/dist/controls/list-key-control.js +0 -2
- package/dist/controls/list-key-control.js.map +0 -1
- package/dist/directives/attr.cjs +0 -2
- package/dist/directives/attr.cjs.map +0 -1
- package/dist/directives/attr.d.ts +0 -12
- package/dist/directives/attr.d.ts.map +0 -1
- package/dist/directives/attr.js +0 -2
- package/dist/directives/attr.js.map +0 -1
- package/dist/directives/bind.cjs +0 -2
- package/dist/directives/bind.cjs.map +0 -1
- package/dist/directives/bind.d.ts +0 -38
- package/dist/directives/bind.d.ts.map +0 -1
- package/dist/directives/bind.js +0 -2
- package/dist/directives/bind.js.map +0 -1
- package/dist/directives/choose.cjs +0 -2
- package/dist/directives/choose.cjs.map +0 -1
- package/dist/directives/choose.d.ts +0 -39
- package/dist/directives/choose.d.ts.map +0 -1
- package/dist/directives/choose.js +0 -2
- package/dist/directives/choose.js.map +0 -1
- package/dist/directives/classes.cjs +0 -2
- package/dist/directives/classes.cjs.map +0 -1
- package/dist/directives/classes.d.ts +0 -20
- package/dist/directives/classes.d.ts.map +0 -1
- package/dist/directives/classes.js +0 -2
- package/dist/directives/classes.js.map +0 -1
- package/dist/directives/index.d.ts +0 -13
- package/dist/directives/index.d.ts.map +0 -1
- package/dist/directives/memo.cjs +0 -2
- package/dist/directives/memo.cjs.map +0 -1
- package/dist/directives/memo.d.ts +0 -27
- package/dist/directives/memo.d.ts.map +0 -1
- package/dist/directives/memo.js +0 -2
- package/dist/directives/memo.js.map +0 -1
- package/dist/directives/on.cjs +0 -2
- package/dist/directives/on.cjs.map +0 -1
- package/dist/directives/on.d.ts +0 -25
- package/dist/directives/on.d.ts.map +0 -1
- package/dist/directives/on.js +0 -2
- package/dist/directives/on.js.map +0 -1
- package/dist/directives/spread.cjs +0 -2
- package/dist/directives/spread.cjs.map +0 -1
- package/dist/directives/spread.d.ts +0 -14
- package/dist/directives/spread.d.ts.map +0 -1
- package/dist/directives/spread.js +0 -2
- package/dist/directives/spread.js.map +0 -1
- package/dist/directives/style.cjs +0 -2
- package/dist/directives/style.cjs.map +0 -1
- package/dist/directives/style.d.ts +0 -22
- package/dist/directives/style.d.ts.map +0 -1
- package/dist/directives/style.js +0 -2
- package/dist/directives/style.js.map +0 -1
- package/dist/directives/until.cjs +0 -2
- package/dist/directives/until.cjs.map +0 -1
- package/dist/directives/until.d.ts +0 -26
- package/dist/directives/until.d.ts.map +0 -1
- package/dist/directives/until.js +0 -2
- package/dist/directives/until.js.map +0 -1
- package/dist/directives.cjs +0 -1
- package/dist/directives.js +0 -1
- package/dist/runtime-bindings.cjs +0 -2
- package/dist/runtime-bindings.cjs.map +0 -1
- package/dist/runtime-bindings.d.ts +0 -6
- package/dist/runtime-bindings.d.ts.map +0 -1
- package/dist/runtime-bindings.js +0 -2
- package/dist/runtime-bindings.js.map +0 -1
- package/dist/runtime-core.cjs +0 -2
- package/dist/runtime-core.cjs.map +0 -1
- package/dist/runtime-core.d.ts +0 -21
- package/dist/runtime-core.d.ts.map +0 -1
- package/dist/runtime-core.js +0 -2
- package/dist/runtime-core.js.map +0 -1
- package/dist/runtime-lifecycle.cjs +0 -2
- package/dist/runtime-lifecycle.cjs.map +0 -1
- package/dist/runtime-lifecycle.d.ts +0 -24
- package/dist/runtime-lifecycle.d.ts.map +0 -1
- package/dist/runtime-lifecycle.js +0 -2
- package/dist/runtime-lifecycle.js.map +0 -1
- package/dist/template-dom.cjs +0 -2
- package/dist/template-dom.cjs.map +0 -1
- package/dist/template-dom.d.ts +0 -13
- package/dist/template-dom.d.ts.map +0 -1
- package/dist/template-dom.js +0 -2
- package/dist/template-dom.js.map +0 -1
- package/dist/template-html.cjs +0 -2
- package/dist/template-html.cjs.map +0 -1
- package/dist/template-html.d.ts +0 -23
- package/dist/template-html.d.ts.map +0 -1
- package/dist/template-html.js +0 -2
- package/dist/template-html.js.map +0 -1
- package/dist/template.cjs +0 -2
- package/dist/template.cjs.map +0 -1
- package/dist/template.d.ts +0 -10
- package/dist/template.d.ts.map +0 -1
- package/dist/template.js +0 -2
- package/dist/template.js.map +0 -1
package/dist/registration.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registration.js","names":[],"sources":["../src/registration.ts"],"sourcesContent":["import { type CleanupFn, untrack } from '@vielzeug/stateit';\n\nimport { formCallbackRegistry } from './form';\nimport { type CSSResult, type HTMLResult, htmlResult, loadStylesheet, runAll } from './internal';\nimport { propRegistry } from './props';\nimport { runtimeStack, type ComponentRuntime } from './runtime-core';\nimport { applyBindingsInContainer, applyHtmlBinding } from './template';\nimport { type RegisterCleanup } from './template-bindings';\nimport { parseHTML } from './template-dom';\nimport { type KeyedNode } from './template-html';\n\nexport type ComponentRegistrationOptions = {\n /** Indicates if this should be a form-associated element */\n formAssociated?: boolean;\n /** Custom options for a host element (e.g. for aria-*) */\n host?: Record<string, string | boolean | number>;\n /** @internal — list of attribute names to observe via attributeChangedCallback */\n observedAttrs?: string[];\n /** Shadow root init options (mode is always 'open') — use e.g. `{ delegatesFocus: true }` for form controls */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles applied to the shadow root. Static — set at definition time, not per-render. */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\ntype ComponentSetupResult = string | HTMLResult;\n\nclass BaseElement extends HTMLElement {\n static _options?: ComponentRegistrationOptions;\n static _setup: () => ComponentSetupResult;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n shadow: ShadowRoot;\n private _appliedHtmlBindings = new Set<string>();\n private _keyedStates = new Map<string, Map<string | number, KeyedNode>>();\n private _mountFns: (() => CleanupFn | undefined | void)[] = [];\n private _runtime: ComponentRuntime;\n private _rendered = false;\n private _setupDone = false;\n private _template: ComponentSetupResult | null = null;\n\n constructor() {\n super();\n\n const options = (this.constructor as typeof BaseElement)._options;\n\n this.shadow = this.attachShadow({ mode: 'open', ...options?.shadow });\n this._runtime = {\n cleanups: [],\n el: this,\n errorHandlers: [],\n onMount: [],\n styles: options?.styles,\n };\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (!this._setupDone) this._runSetup();\n\n this._init();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const propMeta = propRegistry.get(this)?.get(name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n ) {\n propMeta.signal.value = parsed as never;\n }\n }\n\n disconnectedCallback(): void {\n runAll(this._runtime.cleanups);\n this._runtime.cleanups = [];\n this._runtime.onMount = this._mountFns.slice();\n this._appliedHtmlBindings.clear();\n this._keyedStates.clear();\n this._rendered = false;\n }\n\n formAssociatedCallback(form: HTMLFormElement | null): void {\n formCallbackRegistry.get(this)?.onAssociated?.(form);\n }\n\n formDisabledCallback(disabled: boolean): void {\n formCallbackRegistry.get(this)?.onDisabled?.(disabled);\n }\n\n formResetCallback(): void {\n formCallbackRegistry.get(this)?.onReset?.();\n }\n\n formStateRestoreCallback(state: unknown, mode: 'autocomplete' | 'restore'): void {\n formCallbackRegistry.get(this)?.onStateRestore?.(state, mode);\n }\n\n private _handleError(err: unknown): void {\n if (this._runtime.errorHandlers.length > 0) {\n for (const fn of this._runtime.errorHandlers) fn(err);\n } else {\n console.error(`[craftit:E3] <${this.localName}>`, err);\n\n throw err instanceof Error ? err : new Error(String(err));\n }\n }\n\n private _runSetup(): void {\n this._setupDone = true;\n runtimeStack.push(this._runtime as any);\n\n try {\n const options = (this.constructor as typeof BaseElement)._options;\n const { host: hostOptions } = options ?? {};\n\n if (hostOptions) {\n for (const [name, value] of Object.entries(hostOptions)) {\n if (typeof value === 'boolean') {\n if (value) {\n this.setAttribute(name, '');\n } else {\n this.removeAttribute(name);\n }\n } else {\n this.setAttribute(name, String(value));\n }\n }\n }\n\n const result = (this.constructor as typeof BaseElement)._setup();\n\n if (typeof result === 'string' || (typeof result === 'object' && result !== null && '__html' in result)) {\n this._template = result as ComponentSetupResult;\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n }\n }\n\n private _init(): void {\n const { styles } = this._runtime;\n\n if (styles?.length) this.shadow.adoptedStyleSheets = styles.map(loadStylesheet);\n\n if (this._template) {\n const result: HTMLResult = typeof this._template === 'string' ? htmlResult(this._template) : this._template;\n\n if (!this._rendered) {\n this.shadow.replaceChildren(parseHTML(result.__html));\n this._rendered = true;\n }\n\n if (result.__bindings.length) {\n const registerCleanup: RegisterCleanup = (fn) => this._runtime.cleanups.push(fn);\n\n applyBindingsInContainer(this.shadow, result.__bindings, registerCleanup, {\n onHtml: (binding) => {\n if (!this._appliedHtmlBindings.has(binding.uid)) {\n this._appliedHtmlBindings.add(binding.uid);\n applyHtmlBinding(this.shadow, binding, registerCleanup, this._keyedStates);\n }\n },\n });\n }\n }\n\n queueMicrotask(() => {\n runtimeStack.push(this._runtime as any);\n\n try {\n const mountFns = this._runtime.onMount;\n\n this._mountFns = mountFns.slice();\n\n for (const mountFn of mountFns) {\n const cleanup = mountFn();\n\n if (typeof cleanup === 'function') this._runtime.cleanups.push(cleanup);\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n this._runtime.onMount = [];\n }\n });\n }\n}\n\n/** @internal — use define() instead. */\nexport function registerComponent(\n tag: string,\n setup: () => ComponentSetupResult,\n options: ComponentRegistrationOptions = {},\n): string {\n if (!tag) throw new Error('[craftit:E4] registerComponent(tag, ...) requires a tag name');\n\n if (customElements.get(tag)) {\n return tag;\n }\n\n class Element extends BaseElement {\n static override _options = options;\n static override _setup = setup;\n static override formAssociated = options.formAssociated ?? false;\n static override observedAttributes = options.observedAttrs ?? [];\n }\n\n customElements.define(tag, Element);\n\n return tag;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"registration.js","names":[],"sources":["../src/registration.ts"],"sourcesContent":["import { onCleanup as _onCleanup, scope as _scope, type Scope, untrack } from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { createHost, createSlots, type ComponentHost, type ComponentSlots } from './host';\nimport {\n createEmitFn,\n type CSSResult,\n type EmitFn,\n extractResult,\n type HTMLResult,\n loadStylesheet,\n toKebab,\n} from './internal';\nimport {\n createProps,\n isReflecting,\n normalizePropDefinition,\n prop,\n propRegistry,\n type InferPropsFromDefs,\n type InferPropsSignals,\n type PropDef,\n type PropInputDefs,\n type PropOptions,\n type PropsDef,\n} from './props';\nimport { type OnMountedCallback, type RuntimeScope, withCurrentElement, withRuntimeScope } from './runtime';\nimport { applyBindingsInContainer, applyHtmlBinding, parseHTML } from './template-bindings';\n\nexport type ComponentRegistrationOptions = {\n /** Indicates if this should be a form-associated element */\n formAssociated?: boolean;\n /** @internal — list of attribute names to observe via attributeChangedCallback */\n observedAttrs?: string[];\n /** Shadow root init options (mode is always 'open') — use e.g. `{ delegatesFocus: true }` for form controls */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles applied to the shadow root. Static — set at definition time, not per-render. */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\nexport type ComponentTemplate = () => HTMLResult;\n\ntype ComponentState = {\n mountCallbacks: OnMountedCallback[];\n mountedCallbacksRan: boolean;\n mountToken: number;\n scope: Scope;\n setupDone: boolean;\n styles?: (string | CSSStyleSheet | CSSResult)[];\n templateMounted: boolean;\n templateResult: HTMLResult | null;\n};\n\nclass BaseElement extends HTMLElement {\n // Lifecycle: setup() runs on first connect (initializes scope + calls user setup).\n // _init() runs on every connect (applies initial attributes to reset prop state).\n // disconnectedCallback() disposes scope to run effect cleanups, then recreates it.\n // This means setup() re-runs on reconnect. Future optimization: track \"mounted\" state\n // separately to avoid re-running setup() on reconnect while still running cleanups.\n // On disconnect: cleanups run; on reconnect, styles and bindings are re-applied.\n static _options?: ComponentRegistrationOptions;\n static _setup: () => ComponentTemplate;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n shadow: ShadowRoot;\n private _component: ComponentState;\n\n constructor() {\n super();\n\n const options = (this.constructor as typeof BaseElement)._options;\n\n this.shadow = this.attachShadow({ mode: 'open', ...options?.shadow });\n this._component = {\n mountCallbacks: [],\n mountedCallbacksRan: false,\n mountToken: 0,\n scope: _scope(),\n setupDone: false,\n styles: options?.styles,\n templateMounted: false,\n templateResult: null,\n };\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (!this._component.setupDone) this._runSetup();\n\n this._init();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (isReflecting(this, name)) return;\n\n const propMeta = propRegistry.get(this)?.get(name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n ) {\n propMeta.signal.value = parsed as never;\n }\n }\n\n disconnectedCallback(): void {\n this._component.mountToken++;\n // Dispose and recreate scope to run all effect cleanups\n this._component.scope.dispose();\n this._component.scope = _scope();\n // Reset mount state for fresh mount callbacks on reconnect\n this._component.mountCallbacks = [];\n this._component.mountedCallbacksRan = false;\n this._component.templateMounted = false;\n this._component.templateResult = null;\n // Reset setupDone to re-run setup() on reconnect, ensuring effects are re-registered\n this._component.setupDone = false;\n }\n\n private _handleError(err: unknown): void {\n console.error(CRAFTIT_ERRORS.unhandledComponentError(this.localName), err);\n\n throw err instanceof Error ? err : new Error(String(err));\n }\n\n private _runSetup(): void {\n const setupScope: RuntimeScope = {\n element: this,\n mountCallbacks: [],\n };\n\n try {\n this._component.scope.run(() => {\n const template = withRuntimeScope(setupScope, () =>\n withCurrentElement(this, () => (this.constructor as typeof BaseElement)._setup()),\n );\n\n this._component.templateResult = withRuntimeScope(setupScope, () => withCurrentElement(this, () => template()));\n });\n\n this._component.mountCallbacks.push(...setupScope.mountCallbacks);\n this._component.setupDone = true;\n } catch (err) {\n this._handleError(err);\n }\n }\n\n private _init(): void {\n const { styles } = this._component;\n\n if (styles?.length) this.shadow.adoptedStyleSheets = styles.map(loadStylesheet);\n\n if (!this._component.templateMounted && this._component.templateResult != null) {\n const { bindings, html: htmlString } = extractResult(this._component.templateResult);\n\n this.shadow.replaceChildren(parseHTML(htmlString));\n this._component.templateMounted = true;\n\n if (bindings.length) {\n this._component.scope.run(() => {\n applyBindingsInContainer(this.shadow, bindings, _onCleanup, {\n onHtml: (binding) => applyHtmlBinding(this.shadow, binding, _onCleanup),\n });\n });\n }\n }\n\n if (!this._component.mountedCallbacksRan && this._component.mountCallbacks.length > 0) {\n this._component.mountedCallbacksRan = true;\n\n const token = ++this._component.mountToken;\n\n queueMicrotask(() => {\n if (!this.isConnected || token !== this._component.mountToken) return;\n\n try {\n for (const callback of this._component.mountCallbacks) {\n this._component.scope.run(() => {\n withRuntimeScope(\n {\n element: this,\n mountCallbacks: [],\n },\n () =>\n withCurrentElement(this, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') _onCleanup(cleanup);\n }),\n );\n });\n }\n } catch (err) {\n this._handleError(err);\n }\n });\n }\n }\n}\n\nconst defineComponent = (\n tag: string,\n setup: () => ComponentTemplate,\n options: ComponentRegistrationOptions = {},\n): string => {\n if (!tag) throw new Error(CRAFTIT_ERRORS.defineRequiresTag);\n\n if (customElements.get(tag)) {\n throw new Error(CRAFTIT_ERRORS.defineDuplicate(tag));\n }\n\n class Element extends BaseElement {\n static override _options = options;\n static override _setup = setup;\n static override formAssociated = options.formAssociated ?? false;\n static override observedAttributes = options.observedAttrs ?? [];\n }\n\n customElements.define(tag, Element);\n\n return tag;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// PUBLIC COMPONENT AUTHORING API (absorbed from component.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport { prop };\nexport type { InferPropsFromDefs, InferPropsSignals, PropDef, PropInputDefs, PropOptions, PropsDef };\n\n/**\n * Setup context passed as the second argument to the component setup function.\n */\nexport type SetupContextBag<Emits extends Record<string, unknown> = Record<string, unknown>> = {\n emit: EmitFn<Emits>;\n host: ComponentHost;\n slots: ComponentSlots;\n};\n\nexport type ComponentDefinition<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Enable form association for the custom element */\n formAssociated?: boolean;\n /** Component properties and their metadata */\n props?: PropsDef<Props>;\n /** Main setup function. Props are the first positional parameter, context bag is second. Returns a template function. */\n setup: (props: InferPropsSignals<Props>, ctx: SetupContextBag<Emits>) => ComponentTemplate;\n /** Shadow DOM configuration (mode is always 'open') */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component-specific styles */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\nconst createSetupProps = <Props extends Record<string, unknown>>(\n defs: PropsDef<Props> | undefined,\n): InferPropsSignals<Props> => {\n if (!defs) return {} as InferPropsSignals<Props>;\n\n return createProps(defs) as InferPropsSignals<Props>;\n};\n\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n>(tag: string, definition: ComponentDefinition<Props, Emits>): string {\n const { formAssociated, props: propDefs, setup, shadow: shadowOptions, styles } = definition;\n\n // Normalize props at define-time for early error feedback\n const normalizedPropDefs: PropsDef<Props> | undefined = (() => {\n if (!propDefs) return undefined;\n\n const normalized: PropInputDefs = {};\n\n for (const [key, def] of Object.entries(propDefs)) {\n normalized[key] = normalizePropDefinition(def);\n }\n\n return normalized as PropsDef<Props>;\n })();\n\n const observedAttrs = normalizedPropDefs ? Object.keys(normalizedPropDefs).map(toKebab) : [];\n\n return defineComponent(\n tag,\n () => {\n const props = createSetupProps(normalizedPropDefs);\n const host = createHost();\n const emit = createEmitFn<Emits>();\n const slots = createSlots();\n\n return setup(props, { emit, host, slots });\n },\n { formAssociated, observedAttrs, shadow: shadowOptions, styles },\n );\n}\n"],"mappings":"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"}
|
package/dist/runtime.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`./
|
|
1
|
+
const e=require(`./errors.cjs`),t=require(`./internal.cjs`);let n=require(`@vielzeug/stateit`);var r=null,i=null,a=(e,t)=>{let n=r;r=e;try{return t()}finally{r=n}},o=()=>{if(r)return r;throw Error(e.CRAFTIT_ERRORS.lifecycleOutsideSetup)},s=(e,t)=>{let n=i;i=e;try{return t()}finally{i=n}},c=e=>i?((0,n.onCleanup)(e),!0):!1,l=n.onCleanup,u=t=>{if(!i)throw Error(e.CRAFTIT_ERRORS.lifecycleOutsideSetup);i.mountCallbacks.push(t)},d=e=>{let t=(0,n.effect)(()=>e());return c(t),t};function f(n,r,a,o){if(!i)throw Error(e.CRAFTIT_ERRORS.lifecycleOutsideSetup);n&&c(t.listen(n,r,a,o))}function p(e,n,r,i){return t.listen(e,n,r,i)}var m=(e,t)=>d(()=>{let n=e.value;if(n)return t(n)});exports.currentElementOrThrow=o,exports.effect=d,exports.listen=p,exports.on=f,exports.onCleanup=l,exports.onElement=m,exports.onMounted=u,exports.tryRegisterCleanup=c,exports.withCurrentElement=a,exports.withRuntimeScope=s;
|
|
2
2
|
//# sourceMappingURL=runtime.cjs.map
|
package/dist/runtime.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.cjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"runtime.cjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n effect as _effect,\n onCleanup as _onCleanup,\n type CleanupFn,\n type EffectCallback,\n type ReadonlySignal,\n type Subscription,\n} from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { fire, listen as listenInternal } from './internal';\n\nexport { fire };\n\nlet currentElement: HTMLElement | null = null;\nlet currentScope: RuntimeScope | null = null;\n\nexport type OnMountedCallback = () => CleanupFn | void;\n\nexport type RuntimeScope = {\n element: HTMLElement;\n mountCallbacks: OnMountedCallback[];\n};\n\nexport const withCurrentElement = <T>(el: HTMLElement, fn: () => T): T => {\n const previous = currentElement;\n\n currentElement = el;\n\n try {\n return fn();\n } finally {\n currentElement = previous;\n }\n};\n\nexport const currentElementOrThrow = (): HTMLElement => {\n if (currentElement) return currentElement;\n\n throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n};\n\n/** @internal */\nexport const withRuntimeScope = <T>(runtimeScope: RuntimeScope, fn: () => T): T => {\n const prev = currentScope;\n\n currentScope = runtimeScope;\n\n try {\n return fn();\n } finally {\n currentScope = prev;\n }\n};\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentScope) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to be called on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts.\n * Multiple callbacks are supported and run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n currentScope.mountCallbacks.push(fn);\n};\n\nexport const effect = (fn: EffectCallback): Subscription => {\n const dispose = _effect(() => {\n return fn();\n });\n\n tryRegisterCleanup(dispose);\n\n return dispose;\n};\n\nexport function on<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function on(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n tryRegisterCleanup(cleanup);\n}\n\n/**\n * Attaches an event listener and returns a disposal function.\n * Unlike `on()`, this does not require a runtime scope and cleanup must be\n * managed manually by calling the returned function.\n */\nexport function listen<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): () => void;\nexport function listen(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): () => void {\n return listenInternal(target, event, listener, options);\n}\n\nexport const onElement = <T extends HTMLElement>(\n ref: ReadonlySignal<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): Subscription => {\n return effect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"+FAcA,IAAI,EAAqC,KACrC,EAAoC,KAS3B,GAAyB,EAAiB,IAAmB,CACxE,IAAM,EAAW,EAEjB,EAAiB,EAEjB,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAiB,CACnB,CACF,EAEa,MAA2C,CACtD,GAAI,EAAgB,OAAO,EAE3B,MAAU,MAAM,EAAA,eAAe,qBAAqB,CACtD,EAGa,GAAuB,EAA4B,IAAmB,CACjF,IAAM,EAAO,EAEb,EAAe,EAEf,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAe,CACjB,CACF,EAEa,EAAsB,GAC5B,IAEL,EAAA,EAAA,WAAW,CAAE,EAEN,IAJmB,GAWf,EAAY,EAAA,UAMZ,EAAa,GAAgC,CACxD,GAAI,CAAC,EAAc,MAAU,MAAM,EAAA,eAAe,qBAAqB,EAEvE,EAAa,eAAe,KAAK,CAAE,CACrC,EAEa,EAAU,GAAqC,CAC1D,IAAM,GAAA,EAAA,EAAA,YACG,EAAG,CACX,EAID,OAFA,EAAmB,CAAO,EAEnB,CACT,EAQA,SAAgB,EACd,EACA,EACA,EACA,EACM,CACN,GAAI,CAAC,EAAc,MAAU,MAAM,EAAA,eAAe,qBAAqB,EAElE,GAIL,EAFgB,EAAA,OAAe,EAAQ,EAAO,EAAU,CAErC,CAAO,CAC5B,CAaA,SAAgB,EACd,EACA,EACA,EACA,EACY,CACZ,OAAO,EAAA,OAAe,EAAQ,EAAO,EAAU,CAAO,CACxD,CAEA,IAAa,GACX,EACA,IAEO,MAAa,CAClB,IAAM,EAAK,EAAI,MAEf,GAAI,EAAI,OAAO,EAAS,CAAE,CAC5B,CAAC"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,21 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
mouse(target: EventTarget, type: string, options?: MouseEventInit): boolean;
|
|
9
|
-
touch(target: EventTarget, type: string, options?: TouchEventInit): boolean;
|
|
1
|
+
import { type CleanupFn, type EffectCallback, type ReadonlySignal, type Subscription } from '@vielzeug/stateit';
|
|
2
|
+
import { fire } from './internal';
|
|
3
|
+
export { fire };
|
|
4
|
+
export type OnMountedCallback = () => CleanupFn | void;
|
|
5
|
+
export type RuntimeScope = {
|
|
6
|
+
element: HTMLElement;
|
|
7
|
+
mountCallbacks: OnMountedCallback[];
|
|
10
8
|
};
|
|
9
|
+
export declare const withCurrentElement: <T>(el: HTMLElement, fn: () => T) => T;
|
|
10
|
+
export declare const currentElementOrThrow: () => HTMLElement;
|
|
11
|
+
/** @internal */
|
|
12
|
+
export declare const withRuntimeScope: <T>(runtimeScope: RuntimeScope, fn: () => T) => T;
|
|
13
|
+
export declare const tryRegisterCleanup: (fn: CleanupFn) => boolean;
|
|
11
14
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* fire.mouse(el, 'click');
|
|
16
|
-
* fire.keyboard(el, 'keydown', { key: 'Enter' });
|
|
17
|
-
* fire.custom(el, 'change', { detail: { value: 42 } });
|
|
18
|
-
* fire.event(el, new PointerEvent('pointerdown'));
|
|
15
|
+
* Register a cleanup function to be called on component disconnect.
|
|
16
|
+
* Must be called synchronously during component setup or inside scope.run().
|
|
19
17
|
*/
|
|
20
|
-
export declare const
|
|
18
|
+
export declare const onCleanup: (fn: CleanupFn) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Register work to run after the component template mounts.
|
|
21
|
+
* Multiple callbacks are supported and run in registration order.
|
|
22
|
+
*/
|
|
23
|
+
export declare const onMounted: (fn: OnMountedCallback) => void;
|
|
24
|
+
export declare const effect: (fn: EffectCallback) => Subscription;
|
|
25
|
+
export declare function on<K extends keyof HTMLElementEventMap>(target: EventTarget | null | undefined, event: K, listener: (e: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): void;
|
|
26
|
+
/**
|
|
27
|
+
* Attaches an event listener and returns a disposal function.
|
|
28
|
+
* Unlike `on()`, this does not require a runtime scope and cleanup must be
|
|
29
|
+
* managed manually by calling the returned function.
|
|
30
|
+
*/
|
|
31
|
+
export declare function listen<K extends keyof HTMLElementEventMap>(target: EventTarget | null | undefined, event: K, listener: (e: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
|
|
32
|
+
export declare const onElement: <T extends HTMLElement>(ref: ReadonlySignal<T | null>, callback: (el: T) => CleanupFn | undefined | void) => Subscription;
|
|
21
33
|
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,IAAI,EAA4B,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,IAAI,EAAE,CAAC;AAKhB,MAAM,MAAM,iBAAiB,GAAG,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,WAAW,CAAC;IACrB,cAAc,EAAE,iBAAiB,EAAE,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAAE,IAAI,WAAW,EAAE,IAAI,MAAM,CAAC,KAAG,CAUpE,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,WAIxC,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,cAAc,YAAY,EAAE,IAAI,MAAM,CAAC,KAAG,CAU7E,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,IAAI,SAAS,KAAG,OAMlD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,yBAAa,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,IAAI,iBAAiB,KAAG,IAIjD,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,IAAI,cAAc,KAAG,YAQ3C,CAAC;AAEF,wBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,mBAAmB,EACpD,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,CAAC,EAAE,uBAAuB,GAChC,IAAI,CAAC;AAgBR;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,mBAAmB,EACxD,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,CAAC,EAAE,uBAAuB,GAChC,MAAM,IAAI,CAAC;AAUd,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,EAC7C,KAAK,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC,EAC7B,UAAU,CAAC,EAAE,EAAE,CAAC,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI,KAChD,YAMF,CAAC"}
|
package/dist/runtime.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"./
|
|
1
|
+
import{CRAFTIT_ERRORS as e}from"./errors.js";import{listen as t}from"./internal.js";import{effect as n,onCleanup as r}from"@vielzeug/stateit";var i=null,a=null,o=(e,t)=>{let n=i;i=e;try{return t()}finally{i=n}},s=()=>{if(i)return i;throw Error(e.lifecycleOutsideSetup)},c=(e,t)=>{let n=a;a=e;try{return t()}finally{a=n}},l=e=>a?(r(e),!0):!1,u=r,d=t=>{if(!a)throw Error(e.lifecycleOutsideSetup);a.mountCallbacks.push(t)},f=e=>{let t=n(()=>e());return l(t),t};function p(n,r,i,o){if(!a)throw Error(e.lifecycleOutsideSetup);n&&l(t(n,r,i,o))}function m(e,n,r,i){return t(e,n,r,i)}var h=(e,t)=>f(()=>{let n=e.value;if(n)return t(n)});export{s as currentElementOrThrow,f as effect,m as listen,p as on,u as onCleanup,h as onElement,d as onMounted,l as tryRegisterCleanup,o as withCurrentElement,c as withRuntimeScope};
|
|
2
2
|
//# sourceMappingURL=runtime.js.map
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n effect as _effect,\n onCleanup as _onCleanup,\n type CleanupFn,\n type EffectCallback,\n type ReadonlySignal,\n type Subscription,\n} from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { fire, listen as listenInternal } from './internal';\n\nexport { fire };\n\nlet currentElement: HTMLElement | null = null;\nlet currentScope: RuntimeScope | null = null;\n\nexport type OnMountedCallback = () => CleanupFn | void;\n\nexport type RuntimeScope = {\n element: HTMLElement;\n mountCallbacks: OnMountedCallback[];\n};\n\nexport const withCurrentElement = <T>(el: HTMLElement, fn: () => T): T => {\n const previous = currentElement;\n\n currentElement = el;\n\n try {\n return fn();\n } finally {\n currentElement = previous;\n }\n};\n\nexport const currentElementOrThrow = (): HTMLElement => {\n if (currentElement) return currentElement;\n\n throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n};\n\n/** @internal */\nexport const withRuntimeScope = <T>(runtimeScope: RuntimeScope, fn: () => T): T => {\n const prev = currentScope;\n\n currentScope = runtimeScope;\n\n try {\n return fn();\n } finally {\n currentScope = prev;\n }\n};\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentScope) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to be called on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts.\n * Multiple callbacks are supported and run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n currentScope.mountCallbacks.push(fn);\n};\n\nexport const effect = (fn: EffectCallback): Subscription => {\n const dispose = _effect(() => {\n return fn();\n });\n\n tryRegisterCleanup(dispose);\n\n return dispose;\n};\n\nexport function on<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function on(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n tryRegisterCleanup(cleanup);\n}\n\n/**\n * Attaches an event listener and returns a disposal function.\n * Unlike `on()`, this does not require a runtime scope and cleanup must be\n * managed manually by calling the returned function.\n */\nexport function listen<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): () => void;\nexport function listen(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): () => void {\n return listenInternal(target, event, listener, options);\n}\n\nexport const onElement = <T extends HTMLElement>(\n ref: ReadonlySignal<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): Subscription => {\n return effect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"8IAcA,IAAI,EAAqC,KACrC,EAAoC,KAS3B,GAAyB,EAAiB,IAAmB,CACxE,IAAM,EAAW,EAEjB,EAAiB,EAEjB,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAiB,CACnB,CACF,EAEa,MAA2C,CACtD,GAAI,EAAgB,OAAO,EAE3B,MAAU,MAAM,EAAe,qBAAqB,CACtD,EAGa,GAAuB,EAA4B,IAAmB,CACjF,IAAM,EAAO,EAEb,EAAe,EAEf,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAe,CACjB,CACF,EAEa,EAAsB,GAC5B,GAEL,EAAW,CAAE,EAEN,IAJmB,GAWf,EAAY,EAMZ,EAAa,GAAgC,CACxD,GAAI,CAAC,EAAc,MAAU,MAAM,EAAe,qBAAqB,EAEvE,EAAa,eAAe,KAAK,CAAE,CACrC,EAEa,EAAU,GAAqC,CAC1D,IAAM,EAAU,MACP,EAAG,CACX,EAID,OAFA,EAAmB,CAAO,EAEnB,CACT,EAQA,SAAgB,EACd,EACA,EACA,EACA,EACM,CACN,GAAI,CAAC,EAAc,MAAU,MAAM,EAAe,qBAAqB,EAElE,GAIL,EAFgB,EAAe,EAAQ,EAAO,EAAU,CAErC,CAAO,CAC5B,CAaA,SAAgB,EACd,EACA,EACA,EACA,EACY,CACZ,OAAO,EAAe,EAAQ,EAAO,EAAU,CAAO,CACxD,CAEA,IAAa,GACX,EACA,IAEO,MAAa,CAClB,IAAM,EAAK,EAAI,MAEf,GAAI,EAAI,OAAO,EAAS,CAAE,CAC5B,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`./internal.cjs`),t=require(`./
|
|
1
|
+
const e=require(`./internal.cjs`),t=require(`./props.cjs`),n=require(`./directives/live.cjs`);let r=require(`@vielzeug/stateit`);var i=e=>{let t=document.createElement(`template`);return t.innerHTML=e,t.content.cloneNode(!0)},a=(e,t)=>{if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue;n&&t.comments.set(n,e);return}if(e.nodeType!==Node.ELEMENT_NODE)return;let n=e.getAttribute(`u`);n&&t.elements.set(n,e)},o=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_ELEMENT);for(t(e);n.nextNode();)t(n.currentNode)},s=e=>{let t={comments:new Map,elements:new Map};for(let n of e)o(n,e=>a(e,t));return t},c=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT);for(;n.nextNode();){let e=n.currentNode;if(e.nodeValue===t)return e}return null},l=e=>Array.isArray(e)||typeof e==`object`&&!!e,u=e=>e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement,d=(e,t,n,r)=>{let i=t==null?``:String(t);n&&r.last!==void 0&&!Object.is(e.value,r.last)&&!Object.is(e.value,i)||(e.value=i,n&&(r.last=i))},f=(e,t,n,r)=>{let i=!!t;n&&r.last!==void 0&&e.checked!==!!r.last&&e.checked!==i||(e.checked=i,n&&(r.last=i))},p=(t,n,i,a)=>{let o=l(a)?a:n.parse(i.mode===`bool`?a?``:null:a==null||a===!1?null:String(a));if(Object.is((0,r.untrack)(()=>n.signal.value),o)||(n.signal.value=o),!n.reflect){if(l(a))return;i.mode===`bool`?t.toggleAttribute(i.name,!!a):e.setAttr(t,i.name,a)}},m=(e,t,n)=>{n((0,r.effect)(()=>t(e.value)))},h=(n,r,i)=>{let a=t.propRegistry.get(n)?.get(r.name),o={last:void 0},s=t=>{if(!a&&l(t)){n[r.name]=t;return}if(!a&&r.name===`value`&&u(n)){d(n,t,r.live,o);return}if(!a&&r.name===`checked`&&n instanceof HTMLInputElement){f(n,t,r.live,o);return}if(!a){r.mode===`bool`?n.toggleAttribute(r.name,!!t):e.setAttr(n,r.name,t);return}p(n,a,r,t)};r.signal?m(r.signal,s,i):s(r.value)},g=(t,n,r)=>{r(e.listen(t,n.name,n.handler,n.options))},_=(e,t,n)=>{let{ref:r}=t;if(typeof r==`function`){r(e),n(()=>r(null));return}if(Array.isArray(r)){r.push(e),n(()=>{let t=r.indexOf(e);t!==-1&&r.splice(t,1)});return}r.value=e,n(()=>{r.value=null})},v=(e,t,n,r)=>{let i=new Map;for(let a of e){let e=a.uid;if(a.type===`text`){let r=n.comments.get(e);if(r){let i=document.createTextNode(``);r.replaceWith(i),n.comments.delete(e),m(a.signal,e=>{i.textContent=String(e)},t)}}else if(a.type===`directive`){let r=n.comments.get(e);r&&(a.directive.mount(r,t),n.comments.delete(e))}else if(a.type===`html`)r?.onHtml?.(a);else{let t=i.get(e);t?t.push(a):i.set(e,[a])}}for(let[e,r]of i){let i=n.elements.get(e);if(i){i.removeAttribute(`u`),n.elements.delete(e);for(let e of r)e.type===`attr`?h(i,e,t):e.type===`event`?g(i,e,t):e.type===`ref`&&_(i,e,t)}}},y=(e,t,n,r)=>{v(t,n,s([e]),r)},b=(e,t,i,a)=>n.isLiveSignal(a)?{live:!0,mode:e,name:t,signal:a,type:`attr`,uid:i}:typeof a==`function`?{mode:e,name:t,signal:(0,r.computed)(a),type:`attr`,uid:i}:(0,r.isSignal)(a)?{mode:e,name:t,signal:a,type:`attr`,uid:i}:{mode:e,name:t,type:`attr`,uid:i,value:a},x=(t,n,a)=>{let o=c(t,n.uid);if(!o)return;let s=document.createComment(`html-binding`);o.replaceWith(s);let l=[],u=e=>l.push(e),d=()=>{e.runAll(l),l=[]},f=null,p=[];a((0,r.effect)(()=>{(0,r.batch)(()=>{let a;try{a=n.signal.value}catch(e){if(e instanceof Error&&e.message.includes(`[stateit] Cannot read disposed computed signal`))return;throw e}if(a.html===f)return;f=a.html,d();let{bindings:o,html:c}=a,l=s.parentElement||t;(0,r.untrack)(()=>{(0,r.batch)(()=>{e.removeNodes(p);let t=i(c);p=Array.from(t.childNodes),s.after(t)}),y(l,o,u,{onHtml:e=>x(l,e,u)})})})})),a(d)};exports.applyBindingsInContainer=y,exports.applyBindingsWithTargets=v,exports.applyHtmlBinding=x,exports.createAttrBinding=b,exports.indexBindingTargets=s,exports.parseHTML=i;
|
|
2
2
|
//# sourceMappingURL=template-bindings.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-bindings.cjs","names":[],"sources":["../src/template-bindings.ts"],"sourcesContent":["import { effect as rawEffect, type CleanupFn, type ReadonlySignal, untrack } from '@vielzeug/stateit';\n\nimport {\n type AttrBinding,\n type EventBinding,\n type PropBinding,\n type RefBinding,\n type Binding,\n type HtmlBinding,\n CF_ID_ATTR,\n} from './internal';\nimport { listen, setAttr } from './internal';\nimport { propRegistry } from './props';\nimport { bindPropertyModel } from './runtime-bindings';\nimport { indexBindings, type BindingTargets } from './template-dom';\n\nexport type RegisterCleanup = (fn: CleanupFn) => void;\n\n// ─── Helper utilities ────────────────────────────────────────────────────────\n\n/** Check if a value is a structured type (object or array), not a primitive. */\nconst isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n\n/**\n * Register a reactive effect that updates when a signal changes.\n * Common pattern: `if (signal) registerCleanup(effect(() => update(signal.value)))`\n */\nconst signalEffect = (\n signal: ReadonlySignal<unknown>,\n update: (v: unknown) => void,\n registerCleanup: RegisterCleanup,\n): void => {\n registerCleanup(rawEffect(() => update(signal.value)));\n};\n\n// ─── Individual binding application functions ─────────────────────────────────\n\n/**\n * Apply an attribute binding to an element.\n * Handles bool/attr modes, prop pre-upgrade, and reactive updates.\n */\nexport const applyAttrBinding = (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup) => {\n const update = (value: unknown) => {\n const meta = propRegistry.get(el)?.get(binding.name);\n\n // Preserve structured values as pre-upgrade properties\n if (!meta && isStructuredValue(value)) {\n (el as any)[binding.name] = value;\n\n return;\n }\n\n if (!meta || meta.reflect) {\n if (binding.mode === 'bool') {\n el.toggleAttribute(binding.name, Boolean(value));\n } else {\n setAttr(el, binding.name, value);\n }\n }\n\n if (!meta) return;\n\n const parsedValue = isStructuredValue(value)\n ? value\n : meta.parse(\n binding.mode === 'bool' ? (value ? '' : null) : value == null || value === false ? null : String(value),\n );\n\n if (\n !Object.is(\n untrack(() => meta.signal.value),\n parsedValue,\n )\n ) {\n meta.signal.value = parsedValue as never;\n }\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n};\n\n/**\n * Apply a property binding to an element.\n * Handles reactive updates and two-way binding via property models.\n */\nexport const applyPropBinding = (el: HTMLElement, binding: PropBinding, registerCleanup: RegisterCleanup) => {\n const update = (value: unknown) => {\n (el as any)[binding.name] = value;\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n\n bindPropertyModel(el, binding.name, binding.model, registerCleanup);\n};\n\n/**\n * Apply an event listener binding to an element.\n * Handles event modifiers (stop, prevent, self, capture, once, passive).\n */\nexport const applyEventBinding = (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => {\n const { modifiers } = binding;\n const listenerOptions = modifiers\n ? { capture: !!modifiers.capture, once: !!modifiers.once, passive: !!modifiers.passive }\n : undefined;\n\n const wrappedHandler = (event: Event) => {\n if (modifiers?.self && event.target !== event.currentTarget) return;\n\n if (modifiers?.stop) event.stopPropagation();\n\n if (modifiers?.prevent && !modifiers?.passive) event.preventDefault();\n\n binding.handler(event);\n };\n\n registerCleanup(listen(el, binding.name, wrappedHandler, listenerOptions));\n};\n\n/**\n * Apply a ref binding to an element.\n * Supports function refs, ref arrays, and signal refs with cleanup.\n */\nexport const applyRefBinding = (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => {\n const { ref } = binding;\n\n if (typeof ref === 'function') {\n ref(el as never);\n registerCleanup(() => ref(null));\n\n return;\n }\n\n if (Array.isArray(ref)) {\n ref.push(el);\n registerCleanup(() => {\n const idx = ref.indexOf(el);\n\n if (idx !== -1) ref.splice(idx, 1);\n });\n\n return;\n }\n\n ref.value = el as never;\n registerCleanup(() => {\n ref.value = null;\n });\n};\n\n// ─── Binding orchestration ────────────────────────────────────────────────────\n\n/**\n * Apply all bindings to target elements.\n *\n * - Text bindings: Create text nodes, register reactive effects\n * - HTML bindings: Notify caller for keyed reconciliation\n * - Element bindings: Group by ID, apply attr/prop/event/ref in one pass per element\n *\n * @param bindings Array of compiled bindings to apply\n * @param registerCleanup Function to register cleanup callbacks\n * @param targets Indexed comment/element targets from DOM\n * @param opts Optional callbacks (e.g., onHtml for keyed reconciliation)\n */\nexport const applyBindingsWithTargets = (\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n targets: BindingTargets,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n const bindingMap = new Map<string, Binding[]>();\n\n for (const b of bindings) {\n const id = b.uid;\n\n if (b.type === 'text') {\n const found = targets.comments.get(id);\n\n if (found) {\n const textNode = document.createTextNode('');\n\n found.replaceWith(textNode);\n targets.comments.delete(id);\n signalEffect(\n b.signal,\n (v) => {\n textNode.textContent = String(v);\n },\n registerCleanup,\n );\n }\n } else if (b.type === 'html') {\n opts?.onHtml?.(b);\n } else {\n if (!bindingMap.has(id)) bindingMap.set(id, []);\n\n bindingMap.get(id)!.push(b);\n }\n }\n\n for (const [id, elBindings] of bindingMap) {\n const el = targets.elements.get(id);\n\n if (!el) continue;\n\n el.removeAttribute(CF_ID_ATTR);\n targets.elements.delete(id);\n\n for (const b of elBindings) {\n switch (b.type) {\n case 'attr':\n applyAttrBinding(el, b, registerCleanup);\n break;\n case 'callback':\n b.apply(el, registerCleanup);\n break;\n case 'event':\n applyEventBinding(el, b, registerCleanup);\n break;\n case 'prop':\n applyPropBinding(el, b, registerCleanup);\n break;\n case 'ref':\n applyRefBinding(el, b, registerCleanup);\n break;\n }\n }\n }\n};\n\nexport const applyBindingsInContainer = (\n container: ParentNode,\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n applyBindingsWithTargets(bindings, registerCleanup, indexBindings(container), opts);\n};\n\n// ─── Binding factories ────────────────────────────────────────────────────────\n\nimport { type Signal } from '@vielzeug/stateit';\n\nimport { hasWritableValueSetter, toReactiveBindingSource } from './runtime-bindings';\n\n/**\n * Create an attribute binding descriptor.\n * Called during template compilation for each attribute interpolation.\n *\n * @param mode 'bool' for boolean attributes (presence = true), 'attr' for string values\n * @param name Attribute name (e.g., 'disabled', 'aria-label')\n * @param uid Unique binding ID\n * @param value Attribute value (signal or static)\n */\nexport const createAttrBinding = (mode: 'bool' | 'attr', name: string, uid: string, value: unknown): AttrBinding => {\n const source = toReactiveBindingSource(value);\n\n return source ? { mode, name, signal: source, type: 'attr', uid } : { mode, name, type: 'attr', uid, value };\n};\n\n/**\n * Create a property binding descriptor.\n * Called during template compilation for each `.property` interpolation.\n *\n * @param name Property name (e.g., 'value', 'checked')\n * @param uid Unique binding ID\n * @param value Property value (signal, function, or static)\n */\nexport const createPropBinding = (name: string, uid: string, value: unknown): PropBinding => {\n const source = toReactiveBindingSource(value);\n\n if (source) {\n return {\n model: hasWritableValueSetter(value) ? (value as Signal<unknown>) : undefined,\n name,\n signal: source,\n type: 'prop',\n uid,\n };\n }\n\n return { name, type: 'prop', uid, value };\n};\n"],"mappings":"kKAqBA,IAAM,EAAqB,GACzB,MAAM,QAAQ,EAAM,EAAK,OAAO,GAAU,YAAY,EAMlD,GACJ,EACA,EACA,IACS,CACT,GAAA,EAAA,EAAA,YAAgC,EAAO,EAAO,MAAM,CAAC,CAAC,EAS3C,GAAoB,EAAiB,EAAsB,IAAqC,CAC3G,IAAM,EAAU,GAAmB,CACjC,IAAM,EAAO,EAAA,aAAa,IAAI,EAAG,EAAE,IAAI,EAAQ,KAAK,CAGpD,GAAI,CAAC,GAAQ,EAAkB,EAAM,CAAE,CACpC,EAAW,EAAQ,MAAQ,EAE5B,OAWF,IARI,CAAC,GAAQ,EAAK,WACZ,EAAQ,OAAS,OACnB,EAAG,gBAAgB,EAAQ,KAAM,EAAQ,EAAO,CAEhD,EAAA,QAAQ,EAAI,EAAQ,KAAM,EAAM,EAIhC,CAAC,EAAM,OAEX,IAAM,EAAc,EAAkB,EAAM,CACxC,EACA,EAAK,MACH,EAAQ,OAAS,OAAU,EAAQ,GAAK,KAAQ,GAAS,MAAQ,IAAU,GAAQ,KAAO,OAAO,EAAM,CACxG,CAGF,OAAO,IAAA,EAAA,EAAA,aACQ,EAAK,OAAO,MAAM,CAChC,EACD,GAED,EAAK,OAAO,MAAQ,IAIpB,EAAQ,OACV,EAAa,EAAQ,OAAQ,EAAQ,EAAgB,CAErD,EAAO,EAAQ,MAAO,EAQb,GAAoB,EAAiB,EAAsB,IAAqC,CAC3G,IAAM,EAAU,GAAmB,CAChC,EAAW,EAAQ,MAAQ,GAG1B,EAAQ,OACV,EAAa,EAAQ,OAAQ,EAAQ,EAAgB,CAErD,EAAO,EAAQ,MAAO,CAGxB,EAAA,kBAAkB,EAAI,EAAQ,KAAM,EAAQ,MAAO,EAAgB,EAOxD,GAAqB,EAAiB,EAAuB,IAAqC,CAC7G,GAAM,CAAE,aAAc,EAChB,EAAkB,EACpB,CAAE,QAAS,CAAC,CAAC,EAAU,QAAS,KAAM,CAAC,CAAC,EAAU,KAAM,QAAS,CAAC,CAAC,EAAU,QAAS,CACtF,IAAA,GAYJ,EAAgB,EAAA,OAAO,EAAI,EAAQ,KAVX,GAAiB,CACnC,GAAW,MAAQ,EAAM,SAAW,EAAM,gBAE1C,GAAW,MAAM,EAAM,iBAAiB,CAExC,GAAW,SAAW,CAAC,GAAW,SAAS,EAAM,gBAAgB,CAErE,EAAQ,QAAQ,EAAM,GAGiC,EAAgB,CAAC,EAO/D,GAAmB,EAAiB,EAAqB,IAAqC,CACzG,GAAM,CAAE,OAAQ,EAEhB,GAAI,OAAO,GAAQ,WAAY,CAC7B,EAAI,EAAY,CAChB,MAAsB,EAAI,KAAK,CAAC,CAEhC,OAGF,GAAI,MAAM,QAAQ,EAAI,CAAE,CACtB,EAAI,KAAK,EAAG,CACZ,MAAsB,CACpB,IAAM,EAAM,EAAI,QAAQ,EAAG,CAEvB,IAAQ,IAAI,EAAI,OAAO,EAAK,EAAE,EAClC,CAEF,OAGF,EAAI,MAAQ,EACZ,MAAsB,CACpB,EAAI,MAAQ,MACZ,EAiBS,GACX,EACA,EACA,EACA,IACG,CACH,IAAM,EAAa,IAAI,IAEvB,IAAK,IAAM,KAAK,EAAU,CACxB,IAAM,EAAK,EAAE,IAEb,GAAI,EAAE,OAAS,OAAQ,CACrB,IAAM,EAAQ,EAAQ,SAAS,IAAI,EAAG,CAEtC,GAAI,EAAO,CACT,IAAM,EAAW,SAAS,eAAe,GAAG,CAE5C,EAAM,YAAY,EAAS,CAC3B,EAAQ,SAAS,OAAO,EAAG,CAC3B,EACE,EAAE,OACD,GAAM,CACL,EAAS,YAAc,OAAO,EAAE,EAElC,EACD,OAEM,EAAE,OAAS,OACpB,GAAM,SAAS,EAAE,EAEZ,EAAW,IAAI,EAAG,EAAE,EAAW,IAAI,EAAI,EAAE,CAAC,CAE/C,EAAW,IAAI,EAAG,CAAE,KAAK,EAAE,EAI/B,IAAK,GAAM,CAAC,EAAI,KAAe,EAAY,CACzC,IAAM,EAAK,EAAQ,SAAS,IAAI,EAAG,CAE9B,KAGL,CADA,EAAG,gBAAA,IAA2B,CAC9B,EAAQ,SAAS,OAAO,EAAG,CAE3B,IAAK,IAAM,KAAK,EACd,OAAQ,EAAE,KAAV,CACE,IAAK,OACH,EAAiB,EAAI,EAAG,EAAgB,CACxC,MACF,IAAK,WACH,EAAE,MAAM,EAAI,EAAgB,CAC5B,MACF,IAAK,QACH,EAAkB,EAAI,EAAG,EAAgB,CACzC,MACF,IAAK,OACH,EAAiB,EAAI,EAAG,EAAgB,CACxC,MACF,IAAK,MACH,EAAgB,EAAI,EAAG,EAAgB,CACvC,UAMG,GACX,EACA,EACA,EACA,IACG,CACH,EAAyB,EAAU,EAAiB,EAAA,cAAc,EAAU,CAAE,EAAK,EAkBxE,GAAqB,EAAuB,EAAc,EAAa,IAAgC,CAClH,IAAM,EAAS,EAAA,wBAAwB,EAAM,CAE7C,OAAO,EAAS,CAAE,OAAM,OAAM,OAAQ,EAAQ,KAAM,OAAQ,MAAK,CAAG,CAAE,OAAM,OAAM,KAAM,OAAQ,MAAK,QAAO,EAWjG,GAAqB,EAAc,EAAa,IAAgC,CAC3F,IAAM,EAAS,EAAA,wBAAwB,EAAM,CAY7C,OAVI,EACK,CACL,MAAO,EAAA,uBAAuB,EAAM,CAAI,EAA4B,IAAA,GACpE,OACA,OAAQ,EACR,KAAM,OACN,MACD,CAGI,CAAE,OAAM,KAAM,OAAQ,MAAK,QAAO"}
|
|
1
|
+
{"version":3,"file":"template-bindings.cjs","names":[],"sources":["../src/template-bindings.ts"],"sourcesContent":["import {\n batch,\n computed,\n effect as rawEffect,\n isSignal,\n type CleanupFn,\n type ReadonlySignal,\n untrack,\n} from '@vielzeug/stateit';\n\nimport { isLiveSignal } from './directives/live';\nimport {\n CF_ID_ATTR,\n type AttrBinding,\n type Binding,\n type EventBinding,\n type HtmlBinding,\n type RefBinding,\n listen,\n removeNodes,\n runAll,\n setAttr,\n} from './internal';\nimport { propRegistry } from './props';\n\nexport type RegisterCleanup = (fn: CleanupFn) => void;\n\nexport type BindingTargets = {\n comments: Map<string, Comment>;\n elements: Map<string, HTMLElement>;\n};\n\nexport const parseHTML = (html: string): DocumentFragment => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n return tpl.content.cloneNode(true) as DocumentFragment;\n};\n\nconst collectBindingTarget = (node: Node, targets: BindingTargets): void => {\n if (node.nodeType === Node.COMMENT_NODE) {\n const marker = (node as Comment).nodeValue;\n\n if (marker) targets.comments.set(marker, node as Comment);\n\n return;\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n\n const id = (node as Element).getAttribute(CF_ID_ATTR);\n\n if (id) targets.elements.set(id, node as HTMLElement);\n};\n\nconst walkBindingTargets = (root: Node, visit: (node: Node) => void): void => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_ELEMENT);\n\n visit(root);\n\n while (walker.nextNode()) visit(walker.currentNode);\n};\n\nexport const indexBindingTargets = (nodes: Iterable<Node>): BindingTargets => {\n const targets: BindingTargets = { comments: new Map(), elements: new Map() };\n\n for (const node of nodes) walkBindingTargets(node, (current) => collectBindingTarget(current, targets));\n\n return targets;\n};\n\nexport const findCommentMarker = (root: Node, marker: string): Comment | null => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n\n if (comment.nodeValue === marker) return comment;\n }\n\n return null;\n};\n\nconst isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n\nconst isNativeFormInput = (el: HTMLElement): el is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement =>\n el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement;\n\ntype LiveWriteState = { last: unknown };\n\nconst applyFormValue = (\n el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = value == null ? '' : String(value);\n\n if (isLive && state.last !== undefined && !Object.is(el.value, state.last) && !Object.is(el.value, next)) return;\n\n el.value = next;\n\n if (isLive) state.last = next;\n};\n\nconst applyCheckedValue = (\n el: HTMLInputElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = Boolean(value);\n\n if (isLive && state.last !== undefined && el.checked !== Boolean(state.last) && el.checked !== next) return;\n\n el.checked = next;\n\n if (isLive) state.last = next;\n};\n\ntype PropMetaLike = { parse: (v: string | null) => unknown; reflect: boolean; signal: { value: unknown } };\n\nconst syncRegisteredProp = (el: HTMLElement, meta: PropMetaLike, binding: AttrBinding, value: unknown): void => {\n const parsed = isStructuredValue(value)\n ? value\n : meta.parse(\n binding.mode === 'bool' ? (value ? '' : null) : value == null || value === false ? null : String(value),\n );\n\n if (\n !Object.is(\n untrack(() => meta.signal.value),\n parsed,\n )\n ) {\n meta.signal.value = parsed as never;\n }\n\n // When reflect:false the prop signal has no reflect-effect; write the attribute\n // directly so the DOM stays in sync with template bindings.\n if (!meta.reflect) {\n if (isStructuredValue(value)) return;\n\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n }\n};\n\nconst signalEffect = (\n signal: ReadonlySignal<unknown>,\n update: (v: unknown) => void,\n registerCleanup: RegisterCleanup,\n): void => {\n registerCleanup(rawEffect(() => update(signal.value)));\n};\n\nexport const applyAttrBinding = (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup): void => {\n const meta = propRegistry.get(el)?.get(binding.name) as PropMetaLike | undefined;\n const liveState: LiveWriteState = { last: undefined };\n\n const update = (value: unknown): void => {\n if (!meta && isStructuredValue(value)) {\n (el as unknown as Record<string, unknown>)[binding.name] = value;\n\n return;\n }\n\n if (!meta && binding.name === 'value' && isNativeFormInput(el)) {\n applyFormValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta && binding.name === 'checked' && el instanceof HTMLInputElement) {\n applyCheckedValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta) {\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n\n return;\n }\n\n syncRegisteredProp(el, meta, binding, value);\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n};\n\nexport const applyEventBinding = (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => {\n registerCleanup(listen(el, binding.name, binding.handler, binding.options));\n};\n\nexport const applyRefBinding = (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => {\n const { ref } = binding;\n\n if (typeof ref === 'function') {\n ref(el as never);\n registerCleanup(() => ref(null as never));\n\n return;\n }\n\n if (Array.isArray(ref)) {\n ref.push(el);\n registerCleanup(() => {\n const i = ref.indexOf(el);\n\n if (i !== -1) ref.splice(i, 1);\n });\n\n return;\n }\n\n ref.value = el as never;\n registerCleanup(() => {\n ref.value = null as never;\n });\n};\n\ntype ElementBinding = AttrBinding | EventBinding | RefBinding;\n\nexport const applyBindingsWithTargets = (\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n targets: BindingTargets,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n const bindingMap = new Map<string, ElementBinding[]>();\n\n for (const b of bindings) {\n const id = b.uid;\n\n if (b.type === 'text') {\n const found = targets.comments.get(id);\n\n if (found) {\n const textNode = document.createTextNode('');\n\n found.replaceWith(textNode);\n targets.comments.delete(id);\n signalEffect(\n b.signal,\n (v) => {\n textNode.textContent = String(v);\n },\n registerCleanup,\n );\n }\n } else if (b.type === 'directive') {\n const found = targets.comments.get(id);\n\n if (found) {\n b.directive.mount(found, registerCleanup);\n targets.comments.delete(id);\n }\n } else if (b.type === 'html') {\n opts?.onHtml?.(b);\n } else {\n const grouped = bindingMap.get(id);\n\n if (grouped) grouped.push(b);\n else bindingMap.set(id, [b]);\n }\n }\n\n for (const [id, elBindings] of bindingMap) {\n const el = targets.elements.get(id);\n\n if (!el) continue;\n\n el.removeAttribute(CF_ID_ATTR);\n targets.elements.delete(id);\n\n // Inline element binding dispatch\n for (const b of elBindings) {\n if (b.type === 'attr') {\n applyAttrBinding(el, b, registerCleanup);\n } else if (b.type === 'event') {\n applyEventBinding(el, b, registerCleanup);\n } else if (b.type === 'ref') {\n applyRefBinding(el, b, registerCleanup);\n }\n }\n }\n};\n\nexport const applyBindingsInContainer = (\n container: ParentNode,\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n applyBindingsWithTargets(bindings, registerCleanup, indexBindingTargets([container]), opts);\n};\n\nexport const createAttrBinding = (mode: 'bool' | 'attr', name: string, uid: string, value: unknown): AttrBinding => {\n if (isLiveSignal(value)) {\n return { live: true, mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n if (typeof value === 'function') {\n return { mode, name, signal: computed(value as () => unknown), type: 'attr', uid };\n }\n\n if (isSignal(value)) {\n return { mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n return { mode, name, type: 'attr', uid, value };\n};\n\n/**\n * Sets up the reactive effect for an html-binding marker using full fragment replacement.\n */\nexport const applyHtmlBinding = (root: Node, b: HtmlBinding, registerCleanup: RegisterCleanup): void => {\n const found = findCommentMarker(root, b.uid);\n\n if (!found) return;\n\n const marker = document.createComment('html-binding');\n\n found.replaceWith(marker);\n\n let currentCleanups: CleanupFn[] = [];\n const registerInnerCleanup: RegisterCleanup = (fn) => currentCleanups.push(fn);\n const runCurrentCleanups = () => {\n runAll(currentCleanups);\n currentCleanups = [];\n };\n let lastHtml: string | null = null;\n let lastInsertedNodes: Node[] = [];\n\n const stop = rawEffect(() => {\n batch(() => {\n let data: HtmlBinding['signal']['value'];\n\n try {\n data = b.signal.value;\n } catch (error) {\n if (error instanceof Error && error.message.includes('[stateit] Cannot read disposed computed signal')) return;\n\n throw error;\n }\n\n if (data.html === lastHtml) {\n return;\n }\n\n lastHtml = data.html;\n runCurrentCleanups();\n\n const { bindings, html } = data;\n const container = (marker.parentElement || root) as ParentNode;\n\n untrack(() => {\n batch(() => {\n removeNodes(lastInsertedNodes);\n\n const parsed = parseHTML(html);\n\n lastInsertedNodes = Array.from(parsed.childNodes);\n marker.after(parsed);\n });\n\n applyBindingsInContainer(container, bindings, registerInnerCleanup, {\n onHtml: (binding) => applyHtmlBinding(container as unknown as Node, binding, registerInnerCleanup),\n });\n });\n });\n });\n\n registerCleanup(stop);\n registerCleanup(runCurrentCleanups);\n};\n"],"mappings":"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"}
|
|
@@ -1,62 +1,25 @@
|
|
|
1
1
|
import { type CleanupFn } from '@vielzeug/stateit';
|
|
2
|
-
import { type AttrBinding, type
|
|
3
|
-
import { type BindingTargets } from './template-dom';
|
|
2
|
+
import { type AttrBinding, type Binding, type EventBinding, type HtmlBinding, type RefBinding } from './internal';
|
|
4
3
|
export type RegisterCleanup = (fn: CleanupFn) => void;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export type BindingTargets = {
|
|
5
|
+
comments: Map<string, Comment>;
|
|
6
|
+
elements: Map<string, HTMLElement>;
|
|
7
|
+
};
|
|
8
|
+
export declare const parseHTML: (html: string) => DocumentFragment;
|
|
9
|
+
export declare const indexBindingTargets: (nodes: Iterable<Node>) => BindingTargets;
|
|
10
|
+
export declare const findCommentMarker: (root: Node, marker: string) => Comment | null;
|
|
9
11
|
export declare const applyAttrBinding: (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup) => void;
|
|
10
|
-
/**
|
|
11
|
-
* Apply a property binding to an element.
|
|
12
|
-
* Handles reactive updates and two-way binding via property models.
|
|
13
|
-
*/
|
|
14
|
-
export declare const applyPropBinding: (el: HTMLElement, binding: PropBinding, registerCleanup: RegisterCleanup) => void;
|
|
15
|
-
/**
|
|
16
|
-
* Apply an event listener binding to an element.
|
|
17
|
-
* Handles event modifiers (stop, prevent, self, capture, once, passive).
|
|
18
|
-
*/
|
|
19
12
|
export declare const applyEventBinding: (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => void;
|
|
20
|
-
/**
|
|
21
|
-
* Apply a ref binding to an element.
|
|
22
|
-
* Supports function refs, ref arrays, and signal refs with cleanup.
|
|
23
|
-
*/
|
|
24
13
|
export declare const applyRefBinding: (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => void;
|
|
25
|
-
/**
|
|
26
|
-
* Apply all bindings to target elements.
|
|
27
|
-
*
|
|
28
|
-
* - Text bindings: Create text nodes, register reactive effects
|
|
29
|
-
* - HTML bindings: Notify caller for keyed reconciliation
|
|
30
|
-
* - Element bindings: Group by ID, apply attr/prop/event/ref in one pass per element
|
|
31
|
-
*
|
|
32
|
-
* @param bindings Array of compiled bindings to apply
|
|
33
|
-
* @param registerCleanup Function to register cleanup callbacks
|
|
34
|
-
* @param targets Indexed comment/element targets from DOM
|
|
35
|
-
* @param opts Optional callbacks (e.g., onHtml for keyed reconciliation)
|
|
36
|
-
*/
|
|
37
14
|
export declare const applyBindingsWithTargets: (bindings: Binding[], registerCleanup: RegisterCleanup, targets: BindingTargets, opts?: {
|
|
38
15
|
onHtml?: (b: HtmlBinding) => void;
|
|
39
16
|
}) => void;
|
|
40
17
|
export declare const applyBindingsInContainer: (container: ParentNode, bindings: Binding[], registerCleanup: RegisterCleanup, opts?: {
|
|
41
18
|
onHtml?: (b: HtmlBinding) => void;
|
|
42
19
|
}) => void;
|
|
43
|
-
/**
|
|
44
|
-
* Create an attribute binding descriptor.
|
|
45
|
-
* Called during template compilation for each attribute interpolation.
|
|
46
|
-
*
|
|
47
|
-
* @param mode 'bool' for boolean attributes (presence = true), 'attr' for string values
|
|
48
|
-
* @param name Attribute name (e.g., 'disabled', 'aria-label')
|
|
49
|
-
* @param uid Unique binding ID
|
|
50
|
-
* @param value Attribute value (signal or static)
|
|
51
|
-
*/
|
|
52
20
|
export declare const createAttrBinding: (mode: "bool" | "attr", name: string, uid: string, value: unknown) => AttrBinding;
|
|
53
21
|
/**
|
|
54
|
-
*
|
|
55
|
-
* Called during template compilation for each `.property` interpolation.
|
|
56
|
-
*
|
|
57
|
-
* @param name Property name (e.g., 'value', 'checked')
|
|
58
|
-
* @param uid Unique binding ID
|
|
59
|
-
* @param value Property value (signal, function, or static)
|
|
22
|
+
* Sets up the reactive effect for an html-binding marker using full fragment replacement.
|
|
60
23
|
*/
|
|
61
|
-
export declare const
|
|
24
|
+
export declare const applyHtmlBinding: (root: Node, b: HtmlBinding, registerCleanup: RegisterCleanup) => void;
|
|
62
25
|
//# sourceMappingURL=template-bindings.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-bindings.d.ts","sourceRoot":"","sources":["../src/template-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"template-bindings.d.ts","sourceRoot":"","sources":["../src/template-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,EAKhB,MAAM,YAAY,CAAC;AAGpB,MAAM,MAAM,eAAe,GAAG,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACpC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,gBAMxC,CAAC;AA0BF,eAAO,MAAM,mBAAmB,GAAI,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAG,cAM3D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,IAAI,EAAE,QAAQ,MAAM,KAAG,OAAO,GAAG,IAUxE,CAAC;AA4EF,eAAO,MAAM,gBAAgB,GAAI,IAAI,WAAW,EAAE,SAAS,WAAW,EAAE,iBAAiB,eAAe,KAAG,IAsC1G,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,IAAI,WAAW,EAAE,SAAS,YAAY,EAAE,iBAAiB,eAAe,SAEzG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,IAAI,WAAW,EAAE,SAAS,UAAU,EAAE,iBAAiB,eAAe,SAyBrG,CAAC;AAIF,eAAO,MAAM,wBAAwB,GACnC,UAAU,OAAO,EAAE,EACnB,iBAAiB,eAAe,EAChC,SAAS,cAAc,EACvB,OAAO;IAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;CAAE,SA2D7C,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,WAAW,UAAU,EACrB,UAAU,OAAO,EAAE,EACnB,iBAAiB,eAAe,EAChC,OAAO;IAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;CAAE,SAG7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,MAAM,EAAE,OAAO,OAAO,KAAG,WAcpG,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,IAAI,EAAE,GAAG,WAAW,EAAE,iBAAiB,eAAe,KAAG,IA2D/F,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{listen as e,
|
|
1
|
+
import{listen as e,removeNodes as t,runAll as n,setAttr as r}from"./internal.js";import{propRegistry as i}from"./props.js";import{isLiveSignal as a}from"./directives/live.js";import{batch as o,computed as s,effect as c,isSignal as l,untrack as u}from"@vielzeug/stateit";var d=e=>{let t=document.createElement(`template`);return t.innerHTML=e,t.content.cloneNode(!0)},f=(e,t)=>{if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue;n&&t.comments.set(n,e);return}if(e.nodeType!==Node.ELEMENT_NODE)return;let n=e.getAttribute(`u`);n&&t.elements.set(n,e)},p=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_ELEMENT);for(t(e);n.nextNode();)t(n.currentNode)},m=e=>{let t={comments:new Map,elements:new Map};for(let n of e)p(n,e=>f(e,t));return t},h=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT);for(;n.nextNode();){let e=n.currentNode;if(e.nodeValue===t)return e}return null},g=e=>Array.isArray(e)||typeof e==`object`&&!!e,_=e=>e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement,v=(e,t,n,r)=>{let i=t==null?``:String(t);n&&r.last!==void 0&&!Object.is(e.value,r.last)&&!Object.is(e.value,i)||(e.value=i,n&&(r.last=i))},y=(e,t,n,r)=>{let i=!!t;n&&r.last!==void 0&&e.checked!==!!r.last&&e.checked!==i||(e.checked=i,n&&(r.last=i))},b=(e,t,n,i)=>{let a=g(i)?i:t.parse(n.mode===`bool`?i?``:null:i==null||i===!1?null:String(i));if(Object.is(u(()=>t.signal.value),a)||(t.signal.value=a),!t.reflect){if(g(i))return;n.mode===`bool`?e.toggleAttribute(n.name,!!i):r(e,n.name,i)}},x=(e,t,n)=>{n(c(()=>t(e.value)))},S=(e,t,n)=>{let a=i.get(e)?.get(t.name),o={last:void 0},s=n=>{if(!a&&g(n)){e[t.name]=n;return}if(!a&&t.name===`value`&&_(e)){v(e,n,t.live,o);return}if(!a&&t.name===`checked`&&e instanceof HTMLInputElement){y(e,n,t.live,o);return}if(!a){t.mode===`bool`?e.toggleAttribute(t.name,!!n):r(e,t.name,n);return}b(e,a,t,n)};t.signal?x(t.signal,s,n):s(t.value)},C=(t,n,r)=>{r(e(t,n.name,n.handler,n.options))},w=(e,t,n)=>{let{ref:r}=t;if(typeof r==`function`){r(e),n(()=>r(null));return}if(Array.isArray(r)){r.push(e),n(()=>{let t=r.indexOf(e);t!==-1&&r.splice(t,1)});return}r.value=e,n(()=>{r.value=null})},T=(e,t,n,r)=>{let i=new Map;for(let a of e){let e=a.uid;if(a.type===`text`){let r=n.comments.get(e);if(r){let i=document.createTextNode(``);r.replaceWith(i),n.comments.delete(e),x(a.signal,e=>{i.textContent=String(e)},t)}}else if(a.type===`directive`){let r=n.comments.get(e);r&&(a.directive.mount(r,t),n.comments.delete(e))}else if(a.type===`html`)r?.onHtml?.(a);else{let t=i.get(e);t?t.push(a):i.set(e,[a])}}for(let[e,r]of i){let i=n.elements.get(e);if(i){i.removeAttribute(`u`),n.elements.delete(e);for(let e of r)e.type===`attr`?S(i,e,t):e.type===`event`?C(i,e,t):e.type===`ref`&&w(i,e,t)}}},E=(e,t,n,r)=>{T(t,n,m([e]),r)},D=(e,t,n,r)=>a(r)?{live:!0,mode:e,name:t,signal:r,type:`attr`,uid:n}:typeof r==`function`?{mode:e,name:t,signal:s(r),type:`attr`,uid:n}:l(r)?{mode:e,name:t,signal:r,type:`attr`,uid:n}:{mode:e,name:t,type:`attr`,uid:n,value:r},O=(e,r,i)=>{let a=h(e,r.uid);if(!a)return;let s=document.createComment(`html-binding`);a.replaceWith(s);let l=[],f=e=>l.push(e),p=()=>{n(l),l=[]},m=null,g=[];i(c(()=>{o(()=>{let n;try{n=r.signal.value}catch(e){if(e instanceof Error&&e.message.includes(`[stateit] Cannot read disposed computed signal`))return;throw e}if(n.html===m)return;m=n.html,p();let{bindings:i,html:a}=n,c=s.parentElement||e;u(()=>{o(()=>{t(g);let e=d(a);g=Array.from(e.childNodes),s.after(e)}),E(c,i,f,{onHtml:e=>O(c,e,f)})})})})),i(p)};export{E as applyBindingsInContainer,T as applyBindingsWithTargets,O as applyHtmlBinding,D as createAttrBinding,m as indexBindingTargets,d as parseHTML};
|
|
2
2
|
//# sourceMappingURL=template-bindings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-bindings.js","names":[],"sources":["../src/template-bindings.ts"],"sourcesContent":["import { effect as rawEffect, type CleanupFn, type ReadonlySignal, untrack } from '@vielzeug/stateit';\n\nimport {\n type AttrBinding,\n type EventBinding,\n type PropBinding,\n type RefBinding,\n type Binding,\n type HtmlBinding,\n CF_ID_ATTR,\n} from './internal';\nimport { listen, setAttr } from './internal';\nimport { propRegistry } from './props';\nimport { bindPropertyModel } from './runtime-bindings';\nimport { indexBindings, type BindingTargets } from './template-dom';\n\nexport type RegisterCleanup = (fn: CleanupFn) => void;\n\n// ─── Helper utilities ────────────────────────────────────────────────────────\n\n/** Check if a value is a structured type (object or array), not a primitive. */\nconst isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n\n/**\n * Register a reactive effect that updates when a signal changes.\n * Common pattern: `if (signal) registerCleanup(effect(() => update(signal.value)))`\n */\nconst signalEffect = (\n signal: ReadonlySignal<unknown>,\n update: (v: unknown) => void,\n registerCleanup: RegisterCleanup,\n): void => {\n registerCleanup(rawEffect(() => update(signal.value)));\n};\n\n// ─── Individual binding application functions ─────────────────────────────────\n\n/**\n * Apply an attribute binding to an element.\n * Handles bool/attr modes, prop pre-upgrade, and reactive updates.\n */\nexport const applyAttrBinding = (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup) => {\n const update = (value: unknown) => {\n const meta = propRegistry.get(el)?.get(binding.name);\n\n // Preserve structured values as pre-upgrade properties\n if (!meta && isStructuredValue(value)) {\n (el as any)[binding.name] = value;\n\n return;\n }\n\n if (!meta || meta.reflect) {\n if (binding.mode === 'bool') {\n el.toggleAttribute(binding.name, Boolean(value));\n } else {\n setAttr(el, binding.name, value);\n }\n }\n\n if (!meta) return;\n\n const parsedValue = isStructuredValue(value)\n ? value\n : meta.parse(\n binding.mode === 'bool' ? (value ? '' : null) : value == null || value === false ? null : String(value),\n );\n\n if (\n !Object.is(\n untrack(() => meta.signal.value),\n parsedValue,\n )\n ) {\n meta.signal.value = parsedValue as never;\n }\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n};\n\n/**\n * Apply a property binding to an element.\n * Handles reactive updates and two-way binding via property models.\n */\nexport const applyPropBinding = (el: HTMLElement, binding: PropBinding, registerCleanup: RegisterCleanup) => {\n const update = (value: unknown) => {\n (el as any)[binding.name] = value;\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n\n bindPropertyModel(el, binding.name, binding.model, registerCleanup);\n};\n\n/**\n * Apply an event listener binding to an element.\n * Handles event modifiers (stop, prevent, self, capture, once, passive).\n */\nexport const applyEventBinding = (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => {\n const { modifiers } = binding;\n const listenerOptions = modifiers\n ? { capture: !!modifiers.capture, once: !!modifiers.once, passive: !!modifiers.passive }\n : undefined;\n\n const wrappedHandler = (event: Event) => {\n if (modifiers?.self && event.target !== event.currentTarget) return;\n\n if (modifiers?.stop) event.stopPropagation();\n\n if (modifiers?.prevent && !modifiers?.passive) event.preventDefault();\n\n binding.handler(event);\n };\n\n registerCleanup(listen(el, binding.name, wrappedHandler, listenerOptions));\n};\n\n/**\n * Apply a ref binding to an element.\n * Supports function refs, ref arrays, and signal refs with cleanup.\n */\nexport const applyRefBinding = (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => {\n const { ref } = binding;\n\n if (typeof ref === 'function') {\n ref(el as never);\n registerCleanup(() => ref(null));\n\n return;\n }\n\n if (Array.isArray(ref)) {\n ref.push(el);\n registerCleanup(() => {\n const idx = ref.indexOf(el);\n\n if (idx !== -1) ref.splice(idx, 1);\n });\n\n return;\n }\n\n ref.value = el as never;\n registerCleanup(() => {\n ref.value = null;\n });\n};\n\n// ─── Binding orchestration ────────────────────────────────────────────────────\n\n/**\n * Apply all bindings to target elements.\n *\n * - Text bindings: Create text nodes, register reactive effects\n * - HTML bindings: Notify caller for keyed reconciliation\n * - Element bindings: Group by ID, apply attr/prop/event/ref in one pass per element\n *\n * @param bindings Array of compiled bindings to apply\n * @param registerCleanup Function to register cleanup callbacks\n * @param targets Indexed comment/element targets from DOM\n * @param opts Optional callbacks (e.g., onHtml for keyed reconciliation)\n */\nexport const applyBindingsWithTargets = (\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n targets: BindingTargets,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n const bindingMap = new Map<string, Binding[]>();\n\n for (const b of bindings) {\n const id = b.uid;\n\n if (b.type === 'text') {\n const found = targets.comments.get(id);\n\n if (found) {\n const textNode = document.createTextNode('');\n\n found.replaceWith(textNode);\n targets.comments.delete(id);\n signalEffect(\n b.signal,\n (v) => {\n textNode.textContent = String(v);\n },\n registerCleanup,\n );\n }\n } else if (b.type === 'html') {\n opts?.onHtml?.(b);\n } else {\n if (!bindingMap.has(id)) bindingMap.set(id, []);\n\n bindingMap.get(id)!.push(b);\n }\n }\n\n for (const [id, elBindings] of bindingMap) {\n const el = targets.elements.get(id);\n\n if (!el) continue;\n\n el.removeAttribute(CF_ID_ATTR);\n targets.elements.delete(id);\n\n for (const b of elBindings) {\n switch (b.type) {\n case 'attr':\n applyAttrBinding(el, b, registerCleanup);\n break;\n case 'callback':\n b.apply(el, registerCleanup);\n break;\n case 'event':\n applyEventBinding(el, b, registerCleanup);\n break;\n case 'prop':\n applyPropBinding(el, b, registerCleanup);\n break;\n case 'ref':\n applyRefBinding(el, b, registerCleanup);\n break;\n }\n }\n }\n};\n\nexport const applyBindingsInContainer = (\n container: ParentNode,\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n applyBindingsWithTargets(bindings, registerCleanup, indexBindings(container), opts);\n};\n\n// ─── Binding factories ────────────────────────────────────────────────────────\n\nimport { type Signal } from '@vielzeug/stateit';\n\nimport { hasWritableValueSetter, toReactiveBindingSource } from './runtime-bindings';\n\n/**\n * Create an attribute binding descriptor.\n * Called during template compilation for each attribute interpolation.\n *\n * @param mode 'bool' for boolean attributes (presence = true), 'attr' for string values\n * @param name Attribute name (e.g., 'disabled', 'aria-label')\n * @param uid Unique binding ID\n * @param value Attribute value (signal or static)\n */\nexport const createAttrBinding = (mode: 'bool' | 'attr', name: string, uid: string, value: unknown): AttrBinding => {\n const source = toReactiveBindingSource(value);\n\n return source ? { mode, name, signal: source, type: 'attr', uid } : { mode, name, type: 'attr', uid, value };\n};\n\n/**\n * Create a property binding descriptor.\n * Called during template compilation for each `.property` interpolation.\n *\n * @param name Property name (e.g., 'value', 'checked')\n * @param uid Unique binding ID\n * @param value Property value (signal, function, or static)\n */\nexport const createPropBinding = (name: string, uid: string, value: unknown): PropBinding => {\n const source = toReactiveBindingSource(value);\n\n if (source) {\n return {\n model: hasWritableValueSetter(value) ? (value as Signal<unknown>) : undefined,\n name,\n signal: source,\n type: 'prop',\n uid,\n };\n }\n\n return { name, type: 'prop', uid, value };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"template-bindings.js","names":[],"sources":["../src/template-bindings.ts"],"sourcesContent":["import {\n batch,\n computed,\n effect as rawEffect,\n isSignal,\n type CleanupFn,\n type ReadonlySignal,\n untrack,\n} from '@vielzeug/stateit';\n\nimport { isLiveSignal } from './directives/live';\nimport {\n CF_ID_ATTR,\n type AttrBinding,\n type Binding,\n type EventBinding,\n type HtmlBinding,\n type RefBinding,\n listen,\n removeNodes,\n runAll,\n setAttr,\n} from './internal';\nimport { propRegistry } from './props';\n\nexport type RegisterCleanup = (fn: CleanupFn) => void;\n\nexport type BindingTargets = {\n comments: Map<string, Comment>;\n elements: Map<string, HTMLElement>;\n};\n\nexport const parseHTML = (html: string): DocumentFragment => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n return tpl.content.cloneNode(true) as DocumentFragment;\n};\n\nconst collectBindingTarget = (node: Node, targets: BindingTargets): void => {\n if (node.nodeType === Node.COMMENT_NODE) {\n const marker = (node as Comment).nodeValue;\n\n if (marker) targets.comments.set(marker, node as Comment);\n\n return;\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n\n const id = (node as Element).getAttribute(CF_ID_ATTR);\n\n if (id) targets.elements.set(id, node as HTMLElement);\n};\n\nconst walkBindingTargets = (root: Node, visit: (node: Node) => void): void => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_ELEMENT);\n\n visit(root);\n\n while (walker.nextNode()) visit(walker.currentNode);\n};\n\nexport const indexBindingTargets = (nodes: Iterable<Node>): BindingTargets => {\n const targets: BindingTargets = { comments: new Map(), elements: new Map() };\n\n for (const node of nodes) walkBindingTargets(node, (current) => collectBindingTarget(current, targets));\n\n return targets;\n};\n\nexport const findCommentMarker = (root: Node, marker: string): Comment | null => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n\n if (comment.nodeValue === marker) return comment;\n }\n\n return null;\n};\n\nconst isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n\nconst isNativeFormInput = (el: HTMLElement): el is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement =>\n el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement;\n\ntype LiveWriteState = { last: unknown };\n\nconst applyFormValue = (\n el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = value == null ? '' : String(value);\n\n if (isLive && state.last !== undefined && !Object.is(el.value, state.last) && !Object.is(el.value, next)) return;\n\n el.value = next;\n\n if (isLive) state.last = next;\n};\n\nconst applyCheckedValue = (\n el: HTMLInputElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = Boolean(value);\n\n if (isLive && state.last !== undefined && el.checked !== Boolean(state.last) && el.checked !== next) return;\n\n el.checked = next;\n\n if (isLive) state.last = next;\n};\n\ntype PropMetaLike = { parse: (v: string | null) => unknown; reflect: boolean; signal: { value: unknown } };\n\nconst syncRegisteredProp = (el: HTMLElement, meta: PropMetaLike, binding: AttrBinding, value: unknown): void => {\n const parsed = isStructuredValue(value)\n ? value\n : meta.parse(\n binding.mode === 'bool' ? (value ? '' : null) : value == null || value === false ? null : String(value),\n );\n\n if (\n !Object.is(\n untrack(() => meta.signal.value),\n parsed,\n )\n ) {\n meta.signal.value = parsed as never;\n }\n\n // When reflect:false the prop signal has no reflect-effect; write the attribute\n // directly so the DOM stays in sync with template bindings.\n if (!meta.reflect) {\n if (isStructuredValue(value)) return;\n\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n }\n};\n\nconst signalEffect = (\n signal: ReadonlySignal<unknown>,\n update: (v: unknown) => void,\n registerCleanup: RegisterCleanup,\n): void => {\n registerCleanup(rawEffect(() => update(signal.value)));\n};\n\nexport const applyAttrBinding = (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup): void => {\n const meta = propRegistry.get(el)?.get(binding.name) as PropMetaLike | undefined;\n const liveState: LiveWriteState = { last: undefined };\n\n const update = (value: unknown): void => {\n if (!meta && isStructuredValue(value)) {\n (el as unknown as Record<string, unknown>)[binding.name] = value;\n\n return;\n }\n\n if (!meta && binding.name === 'value' && isNativeFormInput(el)) {\n applyFormValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta && binding.name === 'checked' && el instanceof HTMLInputElement) {\n applyCheckedValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta) {\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n\n return;\n }\n\n syncRegisteredProp(el, meta, binding, value);\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n};\n\nexport const applyEventBinding = (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => {\n registerCleanup(listen(el, binding.name, binding.handler, binding.options));\n};\n\nexport const applyRefBinding = (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => {\n const { ref } = binding;\n\n if (typeof ref === 'function') {\n ref(el as never);\n registerCleanup(() => ref(null as never));\n\n return;\n }\n\n if (Array.isArray(ref)) {\n ref.push(el);\n registerCleanup(() => {\n const i = ref.indexOf(el);\n\n if (i !== -1) ref.splice(i, 1);\n });\n\n return;\n }\n\n ref.value = el as never;\n registerCleanup(() => {\n ref.value = null as never;\n });\n};\n\ntype ElementBinding = AttrBinding | EventBinding | RefBinding;\n\nexport const applyBindingsWithTargets = (\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n targets: BindingTargets,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n const bindingMap = new Map<string, ElementBinding[]>();\n\n for (const b of bindings) {\n const id = b.uid;\n\n if (b.type === 'text') {\n const found = targets.comments.get(id);\n\n if (found) {\n const textNode = document.createTextNode('');\n\n found.replaceWith(textNode);\n targets.comments.delete(id);\n signalEffect(\n b.signal,\n (v) => {\n textNode.textContent = String(v);\n },\n registerCleanup,\n );\n }\n } else if (b.type === 'directive') {\n const found = targets.comments.get(id);\n\n if (found) {\n b.directive.mount(found, registerCleanup);\n targets.comments.delete(id);\n }\n } else if (b.type === 'html') {\n opts?.onHtml?.(b);\n } else {\n const grouped = bindingMap.get(id);\n\n if (grouped) grouped.push(b);\n else bindingMap.set(id, [b]);\n }\n }\n\n for (const [id, elBindings] of bindingMap) {\n const el = targets.elements.get(id);\n\n if (!el) continue;\n\n el.removeAttribute(CF_ID_ATTR);\n targets.elements.delete(id);\n\n // Inline element binding dispatch\n for (const b of elBindings) {\n if (b.type === 'attr') {\n applyAttrBinding(el, b, registerCleanup);\n } else if (b.type === 'event') {\n applyEventBinding(el, b, registerCleanup);\n } else if (b.type === 'ref') {\n applyRefBinding(el, b, registerCleanup);\n }\n }\n }\n};\n\nexport const applyBindingsInContainer = (\n container: ParentNode,\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n applyBindingsWithTargets(bindings, registerCleanup, indexBindingTargets([container]), opts);\n};\n\nexport const createAttrBinding = (mode: 'bool' | 'attr', name: string, uid: string, value: unknown): AttrBinding => {\n if (isLiveSignal(value)) {\n return { live: true, mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n if (typeof value === 'function') {\n return { mode, name, signal: computed(value as () => unknown), type: 'attr', uid };\n }\n\n if (isSignal(value)) {\n return { mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n return { mode, name, type: 'attr', uid, value };\n};\n\n/**\n * Sets up the reactive effect for an html-binding marker using full fragment replacement.\n */\nexport const applyHtmlBinding = (root: Node, b: HtmlBinding, registerCleanup: RegisterCleanup): void => {\n const found = findCommentMarker(root, b.uid);\n\n if (!found) return;\n\n const marker = document.createComment('html-binding');\n\n found.replaceWith(marker);\n\n let currentCleanups: CleanupFn[] = [];\n const registerInnerCleanup: RegisterCleanup = (fn) => currentCleanups.push(fn);\n const runCurrentCleanups = () => {\n runAll(currentCleanups);\n currentCleanups = [];\n };\n let lastHtml: string | null = null;\n let lastInsertedNodes: Node[] = [];\n\n const stop = rawEffect(() => {\n batch(() => {\n let data: HtmlBinding['signal']['value'];\n\n try {\n data = b.signal.value;\n } catch (error) {\n if (error instanceof Error && error.message.includes('[stateit] Cannot read disposed computed signal')) return;\n\n throw error;\n }\n\n if (data.html === lastHtml) {\n return;\n }\n\n lastHtml = data.html;\n runCurrentCleanups();\n\n const { bindings, html } = data;\n const container = (marker.parentElement || root) as ParentNode;\n\n untrack(() => {\n batch(() => {\n removeNodes(lastInsertedNodes);\n\n const parsed = parseHTML(html);\n\n lastInsertedNodes = Array.from(parsed.childNodes);\n marker.after(parsed);\n });\n\n applyBindingsInContainer(container, bindings, registerInnerCleanup, {\n onHtml: (binding) => applyHtmlBinding(container as unknown as Node, binding, registerInnerCleanup),\n });\n });\n });\n });\n\n registerCleanup(stop);\n registerCleanup(runCurrentCleanups);\n};\n"],"mappings":"8QAgCA,IAAa,EAAa,GAAmC,CAC3D,IAAM,EAAM,SAAS,cAAc,UAAU,EAI7C,MAFA,GAAI,UAAY,EAET,EAAI,QAAQ,UAAU,EAAI,CACnC,EAEM,GAAwB,EAAY,IAAkC,CAC1E,GAAI,EAAK,WAAa,KAAK,aAAc,CACvC,IAAM,EAAU,EAAiB,UAE7B,GAAQ,EAAQ,SAAS,IAAI,EAAQ,CAAe,EAExD,MACF,CAEA,GAAI,EAAK,WAAa,KAAK,aAAc,OAEzC,IAAM,EAAM,EAAiB,aAAA,GAAuB,EAEhD,GAAI,EAAQ,SAAS,IAAI,EAAI,CAAmB,CACtD,EAEM,GAAsB,EAAY,IAAsC,CAC5E,IAAM,EAAS,SAAS,iBAAiB,EAAM,WAAW,aAAe,WAAW,YAAY,EAIhG,IAFA,EAAM,CAAI,EAEH,EAAO,SAAS,GAAG,EAAM,EAAO,WAAW,CACpD,EAEa,EAAuB,GAA0C,CAC5E,IAAM,EAA0B,CAAE,SAAU,IAAI,IAAO,SAAU,IAAI,GAAM,EAE3E,IAAK,IAAM,KAAQ,EAAO,EAAmB,EAAO,GAAY,EAAqB,EAAS,CAAO,CAAC,EAEtG,OAAO,CACT,EAEa,GAAqB,EAAY,IAAmC,CAC/E,IAAM,EAAS,SAAS,iBAAiB,EAAM,WAAW,YAAY,EAEtE,KAAO,EAAO,SAAS,GAAG,CACxB,IAAM,EAAU,EAAO,YAEvB,GAAI,EAAQ,YAAc,EAAQ,OAAO,CAC3C,CAEA,OAAO,IACT,EAEM,EAAqB,GACzB,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY,EAElD,EAAqB,GACzB,aAAc,kBAAoB,aAAc,qBAAuB,aAAc,kBAIjF,GACJ,EACA,EACA,EACA,IACS,CACT,IAAM,EAAO,GAAS,KAAO,GAAK,OAAO,CAAK,EAE1C,GAAU,EAAM,OAAS,IAAA,IAAa,CAAC,OAAO,GAAG,EAAG,MAAO,EAAM,IAAI,GAAK,CAAC,OAAO,GAAG,EAAG,MAAO,CAAI,IAEvG,EAAG,MAAQ,EAEP,IAAQ,EAAM,KAAO,GAC3B,EAEM,GACJ,EACA,EACA,EACA,IACS,CACT,IAAM,EAAO,EAAQ,EAEjB,GAAU,EAAM,OAAS,IAAA,IAAa,EAAG,UAAY,EAAQ,EAAM,MAAS,EAAG,UAAY,IAE/F,EAAG,QAAU,EAET,IAAQ,EAAM,KAAO,GAC3B,EAIM,GAAsB,EAAiB,EAAoB,EAAsB,IAAyB,CAC9G,IAAM,EAAS,EAAkB,CAAK,EAClC,EACA,EAAK,MACH,EAAQ,OAAS,OAAU,EAAQ,GAAK,KAAQ,GAAS,MAAQ,IAAU,GAAQ,KAAO,OAAO,CAAK,CACxG,EAaJ,GAVG,OAAO,GACN,MAAc,EAAK,OAAO,KAAK,EAC/B,CACF,IAEA,EAAK,OAAO,MAAQ,GAKlB,CAAC,EAAK,QAAS,CACjB,GAAI,EAAkB,CAAK,EAAG,OAE1B,EAAQ,OAAS,OAAQ,EAAG,gBAAgB,EAAQ,KAAM,EAAQ,CAAM,EACvE,EAAQ,EAAI,EAAQ,KAAM,CAAK,CACtC,CACF,EAEM,GACJ,EACA,EACA,IACS,CACT,EAAgB,MAAgB,EAAO,EAAO,KAAK,CAAC,CAAC,CACvD,EAEa,GAAoB,EAAiB,EAAsB,IAA2C,CACjH,IAAM,EAAO,EAAa,IAAI,CAAE,GAAG,IAAI,EAAQ,IAAI,EAC7C,EAA4B,CAAE,KAAM,IAAA,EAAU,EAE9C,EAAU,GAAyB,CACvC,GAAI,CAAC,GAAQ,EAAkB,CAAK,EAAG,CACrC,EAA2C,EAAQ,MAAQ,EAE3D,MACF,CAEA,GAAI,CAAC,GAAQ,EAAQ,OAAS,SAAW,EAAkB,CAAE,EAAG,CAC9D,EAAe,EAAI,EAAO,EAAQ,KAAM,CAAS,EAEjD,MACF,CAEA,GAAI,CAAC,GAAQ,EAAQ,OAAS,WAAa,aAAc,iBAAkB,CACzE,EAAkB,EAAI,EAAO,EAAQ,KAAM,CAAS,EAEpD,MACF,CAEA,GAAI,CAAC,EAAM,CACL,EAAQ,OAAS,OAAQ,EAAG,gBAAgB,EAAQ,KAAM,EAAQ,CAAM,EACvE,EAAQ,EAAI,EAAQ,KAAM,CAAK,EAEpC,MACF,CAEA,EAAmB,EAAI,EAAM,EAAS,CAAK,CAC7C,EAEI,EAAQ,OACV,EAAa,EAAQ,OAAQ,EAAQ,CAAe,EAEpD,EAAO,EAAQ,KAAM,CAEzB,EAEa,GAAqB,EAAiB,EAAuB,IAAqC,CAC7G,EAAgB,EAAO,EAAI,EAAQ,KAAM,EAAQ,QAAS,EAAQ,OAAO,CAAC,CAC5E,EAEa,GAAmB,EAAiB,EAAqB,IAAqC,CACzG,GAAM,CAAE,OAAQ,EAEhB,GAAI,OAAO,GAAQ,WAAY,CAC7B,EAAI,CAAW,EACf,MAAsB,EAAI,IAAa,CAAC,EAExC,MACF,CAEA,GAAI,MAAM,QAAQ,CAAG,EAAG,CACtB,EAAI,KAAK,CAAE,EACX,MAAsB,CACpB,IAAM,EAAI,EAAI,QAAQ,CAAE,EAEpB,IAAM,IAAI,EAAI,OAAO,EAAG,CAAC,CAC/B,CAAC,EAED,MACF,CAEA,EAAI,MAAQ,EACZ,MAAsB,CACpB,EAAI,MAAQ,IACd,CAAC,CACH,EAIa,GACX,EACA,EACA,EACA,IACG,CACH,IAAM,EAAa,IAAI,IAEvB,IAAK,IAAM,KAAK,EAAU,CACxB,IAAM,EAAK,EAAE,IAEb,GAAI,EAAE,OAAS,OAAQ,CACrB,IAAM,EAAQ,EAAQ,SAAS,IAAI,CAAE,EAErC,GAAI,EAAO,CACT,IAAM,EAAW,SAAS,eAAe,EAAE,EAE3C,EAAM,YAAY,CAAQ,EAC1B,EAAQ,SAAS,OAAO,CAAE,EAC1B,EACE,EAAE,OACD,GAAM,CACL,EAAS,YAAc,OAAO,CAAC,CACjC,EACA,CACF,CACF,CACF,MAAO,GAAI,EAAE,OAAS,YAAa,CACjC,IAAM,EAAQ,EAAQ,SAAS,IAAI,CAAE,EAEjC,IACF,EAAE,UAAU,MAAM,EAAO,CAAe,EACxC,EAAQ,SAAS,OAAO,CAAE,EAE9B,MAAO,GAAI,EAAE,OAAS,OACpB,GAAM,SAAS,CAAC,MACX,CACL,IAAM,EAAU,EAAW,IAAI,CAAE,EAE7B,EAAS,EAAQ,KAAK,CAAC,EACtB,EAAW,IAAI,EAAI,CAAC,CAAC,CAAC,CAC7B,CACF,CAEA,IAAK,GAAM,CAAC,EAAI,KAAe,EAAY,CACzC,IAAM,EAAK,EAAQ,SAAS,IAAI,CAAE,EAE7B,KAGL,CADA,EAAG,gBAAA,GAA0B,EAC7B,EAAQ,SAAS,OAAO,CAAE,EAG1B,IAAK,IAAM,KAAK,EACV,EAAE,OAAS,OACb,EAAiB,EAAI,EAAG,CAAe,EAC9B,EAAE,OAAS,QACpB,EAAkB,EAAI,EAAG,CAAe,EAC/B,EAAE,OAAS,OACpB,EAAgB,EAAI,EAAG,CAAe,CAThB,CAY5B,CACF,EAEa,GACX,EACA,EACA,EACA,IACG,CACH,EAAyB,EAAU,EAAiB,EAAoB,CAAC,CAAS,CAAC,EAAG,CAAI,CAC5F,EAEa,GAAqB,EAAuB,EAAc,EAAa,IAC9E,EAAa,CAAK,EACb,CAAE,KAAM,GAAM,OAAM,OAAM,OAAQ,EAAkC,KAAM,OAAQ,KAAI,EAG3F,OAAO,GAAU,WACZ,CAAE,OAAM,OAAM,OAAQ,EAAS,CAAsB,EAAG,KAAM,OAAQ,KAAI,EAG/E,EAAS,CAAK,EACT,CAAE,OAAM,OAAM,OAAQ,EAAkC,KAAM,OAAQ,KAAI,EAG5E,CAAE,OAAM,OAAM,KAAM,OAAQ,MAAK,OAAM,EAMnC,GAAoB,EAAY,EAAgB,IAA2C,CACtG,IAAM,EAAQ,EAAkB,EAAM,EAAE,GAAG,EAE3C,GAAI,CAAC,EAAO,OAEZ,IAAM,EAAS,SAAS,cAAc,cAAc,EAEpD,EAAM,YAAY,CAAM,EAExB,IAAI,EAA+B,CAAC,EAC9B,EAAyC,GAAO,EAAgB,KAAK,CAAE,EACvE,MAA2B,CAC/B,EAAO,CAAe,EACtB,EAAkB,CAAC,CACrB,EACI,EAA0B,KAC1B,EAA4B,CAAC,EAyCjC,EAvCa,MAAgB,CAC3B,MAAY,CACV,IAAI,EAEJ,GAAI,CACF,EAAO,EAAE,OAAO,KAClB,OAAS,EAAO,CACd,GAAI,aAAiB,OAAS,EAAM,QAAQ,SAAS,gDAAgD,EAAG,OAExG,MAAM,CACR,CAEA,GAAI,EAAK,OAAS,EAChB,OAGF,EAAW,EAAK,KAChB,EAAmB,EAEnB,GAAM,CAAE,WAAU,QAAS,EACrB,EAAa,EAAO,eAAiB,EAE3C,MAAc,CACZ,MAAY,CACV,EAAY,CAAiB,EAE7B,IAAM,EAAS,EAAU,CAAI,EAE7B,EAAoB,MAAM,KAAK,EAAO,UAAU,EAChD,EAAO,MAAM,CAAM,CACrB,CAAC,EAED,EAAyB,EAAW,EAAU,EAAsB,CAClE,OAAS,GAAY,EAAiB,EAA8B,EAAS,CAAoB,CACnG,CAAC,CACH,CAAC,CACH,CAAC,CACH,CAEgB,CAAI,EACpB,EAAgB,CAAkB,CACpC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`./internal.cjs`),t=require(`./template-bindings.cjs`);let n=require(`@vielzeug/stateit`);var r=
|
|
1
|
+
const e=require(`./internal.cjs`),t=require(`./template-bindings.cjs`);let n=require(`@vielzeug/stateit`);var r=[{kind:`event`,regex:/\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\s*=\s*["']?$/},{kind:`ref`,regex:/\s+ref\s*=\s*["']?$/},{kind:`boolAttr`,regex:/\s+\?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/},{kind:`attr`,regex:/\s+:?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/}],i=new WeakMap,a=new WeakMap,o=new WeakMap,s={prevent:e=>t=>{t.preventDefault(),e(t)},self:e=>t=>{t.target===t.currentTarget&&e(t)},stop:e=>t=>{t.stopPropagation(),e(t)}},c=(e,t)=>{let n=t.reduce((e,t)=>s[t]?.(e)??e,e),r={};return t.includes(`capture`)&&(r.capture=!0),t.includes(`once`)&&(r.once=!0),t.includes(`passive`)&&(r.passive=!0),{handler:n,...Object.keys(r).length?{options:r}:{}}},l=t=>typeof t==`string`?e.escapeHtml(t):t==null?``:e.isHtmlResult(t)?t.__html:e.escapeHtml(String(t)),u=t=>{let r={bindings:[],html:``};return{bindings:[],signal:(0,n.computed)(()=>{let n=t(),i=Array.isArray(n)?n:[n],a=e.createMarkerIdFactory(),o=``,s=[];for(let t of i)if(e.isHtmlResult(t)){let n=e.rekeyHtmlResult(t,a);o+=n.html,s.push(...n.bindings)}else o+=l(t);let c=s.length!==r.bindings.length||s.some((e,t)=>e!==r.bindings[t]);return(o!==r.html||c)&&(r={bindings:s,html:o}),r})}},d=t=>{if(typeof t==`function`){let e=t,n=a.get(e);if(n)return{signal:n};let{signal:r}=u(e);return a.set(e,r),{signal:r}}if((0,n.isSignal)(t)&&e.isHtmlResult(t.value)){let r=t,i=o.get(r);if(i)return{signal:i};let a=(0,n.computed)(()=>{let t=r.value;if(!e.isHtmlResult(t))return{bindings:[],html:l(t)};let n=e.rekeyHtmlResult(t,e.createMarkerIdFactory());return{bindings:n.bindings,html:n.html}});return o.set(r,a),{signal:a}}return null},f=e=>{let t=[];for(let n=0;n<e.length-1;n++){let i=e[n],a=!1;for(let e of r){let n=e.regex.exec(i);if(!n)continue;let r=i.slice(0,-n[0].length);if(a=!0,e.kind===`event`){let e=n[1].split(`.`),a=e[0],o=e.slice(1);t.push({kind:`event`,modifiers:o,name:a,prefix:r,raw:i})}else e.kind===`ref`?t.push({kind:`ref`,prefix:r,raw:i}):e.kind===`boolAttr`?t.push({kind:`boolAttr`,mode:`bool`,name:n[1],prefix:r,raw:i}):e.kind===`attr`&&t.push({kind:`attr`,mode:`attr`,name:n[1],prefix:r,raw:i});break}a||t.push({kind:`node`,prefix:i,raw:i})}return{slots:t,tail:e[e.length-1]??``}},p=e=>{let t=i.get(e);return t||(t=f(e),i.set(e,t)),t},m=(r,i)=>{let a=p(r),o=``,s=[],u=null,f=e.createMarkerIdFactory(),m=e=>e.lastIndexOf(`<`)>e.lastIndexOf(`>`),h=e=>((!u||m(e))&&(u=f()),u),g=()=>{u=null};for(let r=0;r<a.slots.length;r++){let u=a.slots[r],p=i[r];if(u.kind===`event`){if(typeof p==`function`){let e=h(u.prefix),{handler:t,options:n}=c(p,u.modifiers??[]);o+=`${u.prefix} u="${e}"`,s.push({handler:t,name:u.name,options:n,type:`event`,uid:e})}else if((0,n.isSignal)(p)){let e=h(u.prefix),{handler:t,options:n}=c(e=>{let t=p.value;typeof t==`function`&&t(e)},u.modifiers??[]);o+=`${u.prefix} u="${e}"`,s.push({handler:t,name:u.name,options:n,type:`event`,uid:e})}else o+=u.raw;continue}if(u.kind===`ref`){if(p){let e=h(u.prefix);o+=`${u.prefix} u="${e}"`,s.push({ref:p,type:`ref`,uid:e})}else o+=u.raw;continue}if(u.kind===`boolAttr`||u.kind===`attr`){let e=h(u.prefix);o+=`${u.prefix} u="${e}"`,s.push(t.createAttrBinding(u.mode,u.name,e,p));continue}if(u.kind===`node`){if(g(),e.isDirectiveResult(p)){let e=f();o+=`${u.raw}<!--${e}-->`,s.push({directive:p,type:`directive`,uid:e});continue}let t=d(p);if(t){let e=f();o+=`${u.raw}<!--${e}-->`,s.push({signal:t.signal,type:`html`,uid:e});continue}if(Array.isArray(p)){let t=``;for(let n of p)if(e.isHtmlResult(n)){let r=e.rekeyHtmlResult(n,f);t+=r.html,s.push(...r.bindings)}else t+=l(n);o+=u.raw+t;continue}if((0,n.isSignal)(p)){let e=f();o+=`${u.raw}<!--${e}-->`,s.push({signal:p,type:`text`,uid:e})}else if(e.isHtmlResult(p)){let t=e.rekeyHtmlResult(p,f);o+=u.raw+t.html,s.push(...t.bindings)}else o+=u.raw+l(p);continue}}return o+=a.tail,e.htmlResult(o,s)},h=(e,...t)=>m(e,t);exports.html=h;
|
|
2
2
|
//# sourceMappingURL=template-compiler.cjs.map
|