@vielzeug/craftit 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -53
- package/dist/component.cjs +2 -0
- package/dist/component.cjs.map +1 -0
- package/dist/component.d.ts +39 -0
- package/dist/component.d.ts.map +1 -0
- package/dist/component.js +2 -0
- package/dist/component.js.map +1 -0
- package/dist/controls/a11y-control.cjs +2 -0
- package/dist/controls/a11y-control.cjs.map +1 -0
- package/dist/controls/a11y-control.d.ts +16 -0
- package/dist/controls/a11y-control.d.ts.map +1 -0
- package/dist/controls/a11y-control.js +2 -0
- package/dist/controls/a11y-control.js.map +1 -0
- package/dist/controls/checkable-control.cjs +2 -0
- package/dist/controls/checkable-control.cjs.map +1 -0
- package/dist/controls/checkable-control.d.ts +15 -0
- package/dist/controls/checkable-control.d.ts.map +1 -0
- package/dist/controls/checkable-control.js +2 -0
- package/dist/controls/checkable-control.js.map +1 -0
- package/dist/controls/field-control.cjs +2 -0
- package/dist/controls/field-control.cjs.map +1 -0
- package/dist/controls/field-control.d.ts +156 -0
- package/dist/controls/field-control.d.ts.map +1 -0
- package/dist/controls/field-control.js +2 -0
- package/dist/controls/field-control.js.map +1 -0
- package/dist/controls/index.d.ts +10 -0
- package/dist/controls/index.d.ts.map +1 -0
- package/dist/controls/internal/control-state.cjs +2 -0
- package/dist/controls/internal/control-state.cjs.map +1 -0
- package/dist/controls/internal/control-state.d.ts +19 -0
- package/dist/controls/internal/control-state.d.ts.map +1 -0
- package/dist/controls/internal/control-state.js +2 -0
- package/dist/controls/internal/control-state.js.map +1 -0
- package/dist/controls/internal/keyboard-utils.cjs +2 -0
- package/dist/controls/internal/keyboard-utils.cjs.map +1 -0
- package/dist/controls/internal/keyboard-utils.d.ts +7 -0
- package/dist/controls/internal/keyboard-utils.d.ts.map +1 -0
- package/dist/controls/internal/keyboard-utils.js +2 -0
- package/dist/controls/internal/keyboard-utils.js.map +1 -0
- package/dist/controls/internal/number-utils.cjs +2 -0
- package/dist/controls/internal/number-utils.cjs.map +1 -0
- package/dist/controls/internal/number-utils.d.ts +6 -0
- package/dist/controls/internal/number-utils.d.ts.map +1 -0
- package/dist/controls/internal/number-utils.js +2 -0
- package/dist/controls/internal/number-utils.js.map +1 -0
- package/dist/controls/internal/validation-utils.cjs +2 -0
- package/dist/controls/internal/validation-utils.cjs.map +1 -0
- package/dist/controls/internal/validation-utils.d.ts +13 -0
- package/dist/controls/internal/validation-utils.d.ts.map +1 -0
- package/dist/controls/internal/validation-utils.js +2 -0
- package/dist/controls/internal/validation-utils.js.map +1 -0
- package/dist/controls/list-control.cjs +2 -0
- package/dist/controls/list-control.cjs.map +1 -0
- package/dist/controls/list-control.d.ts +21 -0
- package/dist/controls/list-control.d.ts.map +1 -0
- package/dist/controls/list-control.js +2 -0
- package/dist/controls/list-control.js.map +1 -0
- package/dist/controls/list-key-control.cjs +2 -0
- package/dist/controls/list-key-control.cjs.map +1 -0
- package/dist/controls/list-key-control.d.ts +14 -0
- package/dist/controls/list-key-control.d.ts.map +1 -0
- package/dist/controls/list-key-control.js +2 -0
- package/dist/controls/list-key-control.js.map +1 -0
- package/dist/controls/overlay-control.cjs +2 -0
- package/dist/controls/overlay-control.cjs.map +1 -0
- package/dist/controls/overlay-control.d.ts +37 -0
- package/dist/controls/overlay-control.d.ts.map +1 -0
- package/dist/controls/overlay-control.js +2 -0
- package/dist/controls/overlay-control.js.map +1 -0
- package/dist/controls/press-control.cjs +2 -0
- package/dist/controls/press-control.cjs.map +1 -0
- package/dist/controls/press-control.d.ts +12 -0
- package/dist/controls/press-control.d.ts.map +1 -0
- package/dist/controls/press-control.js +2 -0
- package/dist/controls/press-control.js.map +1 -0
- package/dist/controls/slider-control.cjs +2 -0
- package/dist/controls/slider-control.cjs.map +1 -0
- package/dist/controls/slider-control.d.ts +19 -0
- package/dist/controls/slider-control.d.ts.map +1 -0
- package/dist/controls/slider-control.js +2 -0
- package/dist/controls/slider-control.js.map +1 -0
- package/dist/controls/spinner-control.cjs +2 -0
- package/dist/controls/spinner-control.cjs.map +1 -0
- package/dist/controls/spinner-control.d.ts +18 -0
- package/dist/controls/spinner-control.d.ts.map +1 -0
- package/dist/controls/spinner-control.js +2 -0
- package/dist/controls/spinner-control.js.map +1 -0
- package/dist/controls.cjs +1 -0
- package/dist/controls.js +1 -0
- 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/attr.cjs +1 -1
- package/dist/directives/attr.cjs.map +1 -1
- package/dist/directives/attr.d.ts +4 -6
- package/dist/directives/attr.d.ts.map +1 -1
- package/dist/directives/attr.js +1 -1
- package/dist/directives/attr.js.map +1 -1
- package/dist/directives/bind.cjs +1 -1
- package/dist/directives/bind.cjs.map +1 -1
- package/dist/directives/bind.d.ts +20 -12
- package/dist/directives/bind.d.ts.map +1 -1
- package/dist/directives/bind.js +1 -1
- package/dist/directives/bind.js.map +1 -1
- package/dist/directives/choose.cjs +1 -1
- package/dist/directives/choose.cjs.map +1 -1
- package/dist/directives/choose.d.ts +17 -12
- package/dist/directives/choose.d.ts.map +1 -1
- package/dist/directives/choose.js +1 -1
- package/dist/directives/choose.js.map +1 -1
- package/dist/directives/each.cjs +1 -1
- package/dist/directives/each.cjs.map +1 -1
- package/dist/directives/each.d.ts +19 -31
- 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/index.d.ts +1 -2
- package/dist/directives/index.d.ts.map +1 -1
- package/dist/directives/memo.cjs +1 -1
- package/dist/directives/memo.cjs.map +1 -1
- package/dist/directives/memo.d.ts +8 -4
- package/dist/directives/memo.d.ts.map +1 -1
- package/dist/directives/memo.js +1 -1
- package/dist/directives/memo.js.map +1 -1
- package/dist/directives/on.cjs +1 -1
- package/dist/directives/on.cjs.map +1 -1
- package/dist/directives/on.d.ts +1 -1
- package/dist/directives/on.d.ts.map +1 -1
- package/dist/directives/on.js +1 -1
- package/dist/directives/on.js.map +1 -1
- package/dist/directives/raw.cjs +1 -1
- package/dist/directives/raw.cjs.map +1 -1
- package/dist/directives/raw.d.ts +1 -1
- 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/spread.cjs +1 -1
- package/dist/directives/spread.cjs.map +1 -1
- package/dist/directives/spread.d.ts +1 -1
- package/dist/directives/spread.d.ts.map +1 -1
- package/dist/directives/spread.js +1 -1
- package/dist/directives/spread.js.map +1 -1
- package/dist/directives/style.cjs +1 -1
- package/dist/directives/style.cjs.map +1 -1
- package/dist/directives/style.js +1 -1
- package/dist/directives/style.js.map +1 -1
- package/dist/directives/until.cjs.map +1 -1
- package/dist/directives/until.d.ts +1 -1
- package/dist/directives/until.d.ts.map +1 -1
- package/dist/directives/until.js.map +1 -1
- package/dist/directives/when.cjs +1 -1
- package/dist/directives/when.cjs.map +1 -1
- package/dist/directives/when.d.ts +11 -5
- 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/directives.cjs +1 -0
- package/dist/directives.js +1 -0
- package/dist/form.cjs +2 -0
- package/dist/form.cjs.map +1 -0
- package/dist/form.d.ts +29 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +2 -0
- package/dist/form.js.map +1 -0
- package/dist/host.cjs +2 -0
- package/dist/host.cjs.map +1 -0
- package/dist/host.d.ts +75 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +2 -0
- package/dist/host.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +8 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.cjs +2 -0
- package/dist/internal.cjs.map +1 -0
- package/dist/internal.d.ts +171 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +2 -0
- package/dist/internal.js.map +1 -0
- package/dist/observers/index.d.ts +4 -0
- package/dist/observers/index.d.ts.map +1 -0
- package/dist/observers/intersection-observe.cjs +2 -0
- package/dist/observers/intersection-observe.cjs.map +1 -0
- package/dist/observers/intersection-observe.d.ts +9 -0
- package/dist/observers/intersection-observe.d.ts.map +1 -0
- package/dist/observers/intersection-observe.js +2 -0
- package/dist/observers/intersection-observe.js.map +1 -0
- package/dist/observers/media-observe.cjs +2 -0
- package/dist/observers/media-observe.cjs.map +1 -0
- package/dist/observers/media-observe.d.ts +8 -0
- package/dist/observers/media-observe.d.ts.map +1 -0
- package/dist/observers/media-observe.js +2 -0
- package/dist/observers/media-observe.js.map +1 -0
- package/dist/observers/resize-observe.cjs +2 -0
- package/dist/observers/resize-observe.cjs.map +1 -0
- package/dist/observers/resize-observe.d.ts +11 -0
- package/dist/observers/resize-observe.d.ts.map +1 -0
- package/dist/observers/resize-observe.js +2 -0
- package/dist/observers/resize-observe.js.map +1 -0
- package/dist/observers.cjs +1 -0
- package/dist/observers.js +1 -0
- package/dist/props.cjs +2 -0
- package/dist/props.cjs.map +1 -0
- package/dist/props.d.ts +52 -0
- package/dist/props.d.ts.map +1 -0
- package/dist/props.js +2 -0
- package/dist/props.js.map +1 -0
- package/dist/registration.cjs +2 -0
- package/dist/registration.cjs.map +1 -0
- package/dist/registration.d.ts +18 -0
- package/dist/registration.d.ts.map +1 -0
- package/dist/registration.js +2 -0
- package/dist/registration.js.map +1 -0
- package/dist/runtime-bindings.cjs +2 -0
- package/dist/runtime-bindings.cjs.map +1 -0
- package/dist/runtime-bindings.d.ts.map +1 -0
- package/dist/runtime-bindings.js +2 -0
- package/dist/runtime-bindings.js.map +1 -0
- package/dist/runtime-core.cjs +2 -0
- package/dist/runtime-core.cjs.map +1 -0
- package/dist/runtime-core.d.ts +21 -0
- package/dist/runtime-core.d.ts.map +1 -0
- package/dist/runtime-core.js +2 -0
- package/dist/runtime-core.js.map +1 -0
- package/dist/runtime-lifecycle.cjs +2 -0
- package/dist/runtime-lifecycle.cjs.map +1 -0
- package/dist/runtime-lifecycle.d.ts +24 -0
- package/dist/runtime-lifecycle.d.ts.map +1 -0
- package/dist/runtime-lifecycle.js +2 -0
- package/dist/runtime-lifecycle.js.map +1 -0
- package/dist/runtime.cjs +2 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.ts +21 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +1 -0
- package/dist/template-bindings.cjs +2 -0
- package/dist/template-bindings.cjs.map +1 -0
- package/dist/{core/template-bindings.d.ts → template-bindings.d.ts} +4 -1
- package/dist/template-bindings.d.ts.map +1 -0
- package/dist/template-bindings.js +2 -0
- package/dist/template-bindings.js.map +1 -0
- package/dist/template-compiler.cjs +2 -0
- package/dist/template-compiler.cjs.map +1 -0
- package/dist/{core/template-compiler.d.ts → template-compiler.d.ts} +1 -2
- package/dist/template-compiler.d.ts.map +1 -0
- package/dist/template-compiler.js +2 -0
- package/dist/template-compiler.js.map +1 -0
- package/dist/template-dom.cjs +2 -0
- package/dist/{core/template-dom.js.map → template-dom.cjs.map} +1 -1
- package/dist/template-dom.d.ts.map +1 -0
- package/dist/template-dom.js +2 -0
- package/dist/template-dom.js.map +1 -0
- package/dist/template-html.cjs +2 -0
- package/dist/template-html.cjs.map +1 -0
- package/dist/{core/template-html.d.ts → template-html.d.ts} +1 -4
- package/dist/template-html.d.ts.map +1 -0
- package/dist/template-html.js +2 -0
- package/dist/template-html.js.map +1 -0
- package/dist/template.cjs +2 -0
- package/dist/template.cjs.map +1 -0
- package/dist/{core/template.d.ts → template.d.ts} +2 -3
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +2 -0
- package/dist/template.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/testing.cjs +2 -0
- package/dist/testing/testing.cjs.map +1 -0
- package/dist/{test/test.d.ts → testing/testing.d.ts} +8 -8
- package/dist/testing/testing.d.ts.map +1 -0
- package/dist/testing/testing.js +2 -0
- package/dist/testing/testing.js.map +1 -0
- package/dist/testing.cjs +1 -0
- package/dist/testing.js +1 -0
- package/package.json +19 -14
- package/dist/core/component.cjs +0 -2
- package/dist/core/component.cjs.map +0 -1
- package/dist/core/component.d.ts +0 -172
- package/dist/core/component.d.ts.map +0 -1
- package/dist/core/component.js +0 -2
- package/dist/core/component.js.map +0 -1
- package/dist/core/host.cjs +0 -2
- package/dist/core/host.cjs.map +0 -1
- package/dist/core/host.d.ts +0 -77
- package/dist/core/host.d.ts.map +0 -1
- package/dist/core/host.js +0 -2
- package/dist/core/host.js.map +0 -1
- package/dist/core/internal.cjs +0 -2
- package/dist/core/internal.cjs.map +0 -1
- package/dist/core/internal.d.ts +0 -107
- package/dist/core/internal.d.ts.map +0 -1
- package/dist/core/internal.js +0 -2
- package/dist/core/internal.js.map +0 -1
- package/dist/core/runtime-bindings.cjs +0 -2
- package/dist/core/runtime-bindings.cjs.map +0 -1
- package/dist/core/runtime-bindings.d.ts.map +0 -1
- package/dist/core/runtime-bindings.js +0 -2
- package/dist/core/runtime-bindings.js.map +0 -1
- package/dist/core/runtime-lifecycle.cjs +0 -2
- package/dist/core/runtime-lifecycle.cjs.map +0 -1
- package/dist/core/runtime-lifecycle.d.ts +0 -116
- package/dist/core/runtime-lifecycle.d.ts.map +0 -1
- package/dist/core/runtime-lifecycle.js +0 -2
- package/dist/core/runtime-lifecycle.js.map +0 -1
- package/dist/core/runtime.cjs +0 -1
- package/dist/core/runtime.d.ts +0 -3
- package/dist/core/runtime.d.ts.map +0 -1
- package/dist/core/runtime.js +0 -1
- package/dist/core/template-bindings.cjs +0 -2
- package/dist/core/template-bindings.cjs.map +0 -1
- package/dist/core/template-bindings.d.ts.map +0 -1
- package/dist/core/template-bindings.js +0 -2
- package/dist/core/template-bindings.js.map +0 -1
- package/dist/core/template-compiler.cjs +0 -2
- package/dist/core/template-compiler.cjs.map +0 -1
- package/dist/core/template-compiler.d.ts.map +0 -1
- package/dist/core/template-compiler.js +0 -2
- package/dist/core/template-compiler.js.map +0 -1
- package/dist/core/template-dom.cjs +0 -2
- package/dist/core/template-dom.cjs.map +0 -1
- package/dist/core/template-dom.d.ts.map +0 -1
- package/dist/core/template-dom.js +0 -2
- package/dist/core/template-html.cjs +0 -2
- package/dist/core/template-html.cjs.map +0 -1
- package/dist/core/template-html.d.ts.map +0 -1
- package/dist/core/template-html.js +0 -2
- package/dist/core/template-html.js.map +0 -1
- package/dist/core/template.cjs +0 -2
- package/dist/core/template.cjs.map +0 -1
- package/dist/core/template.d.ts.map +0 -1
- package/dist/core/template.js +0 -2
- package/dist/core/template.js.map +0 -1
- package/dist/core/utilities.cjs +0 -2
- package/dist/core/utilities.cjs.map +0 -1
- package/dist/core/utilities.d.ts +0 -68
- package/dist/core/utilities.d.ts.map +0 -1
- package/dist/core/utilities.js +0 -2
- package/dist/core/utilities.js.map +0 -1
- package/dist/directives/index.cjs +0 -1
- package/dist/directives/index.js +0 -1
- package/dist/directives/match.cjs +0 -2
- package/dist/directives/match.cjs.map +0 -1
- package/dist/directives/match.d.ts +0 -31
- package/dist/directives/match.d.ts.map +0 -1
- package/dist/directives/match.js +0 -2
- package/dist/directives/match.js.map +0 -1
- package/dist/labs/a11y.cjs +0 -2
- package/dist/labs/a11y.cjs.map +0 -1
- package/dist/labs/a11y.d.ts +0 -61
- package/dist/labs/a11y.d.ts.map +0 -1
- package/dist/labs/a11y.js +0 -2
- package/dist/labs/a11y.js.map +0 -1
- package/dist/labs/index.d.ts +0 -8
- package/dist/labs/index.d.ts.map +0 -1
- package/dist/labs/list.cjs +0 -2
- package/dist/labs/list.cjs.map +0 -1
- package/dist/labs/list.d.ts +0 -26
- package/dist/labs/list.d.ts.map +0 -1
- package/dist/labs/list.js +0 -2
- package/dist/labs/list.js.map +0 -1
- package/dist/labs/observers.cjs +0 -2
- package/dist/labs/observers.cjs.map +0 -1
- package/dist/labs/observers.d.ts +0 -42
- package/dist/labs/observers.d.ts.map +0 -1
- package/dist/labs/observers.js +0 -2
- package/dist/labs/observers.js.map +0 -1
- package/dist/labs/overlay.cjs +0 -2
- package/dist/labs/overlay.cjs.map +0 -1
- package/dist/labs/overlay.d.ts +0 -35
- package/dist/labs/overlay.d.ts.map +0 -1
- package/dist/labs/overlay.js +0 -2
- package/dist/labs/overlay.js.map +0 -1
- package/dist/labs/selectable.cjs +0 -2
- package/dist/labs/selectable.cjs.map +0 -1
- package/dist/labs/selectable.d.ts +0 -70
- package/dist/labs/selectable.d.ts.map +0 -1
- package/dist/labs/selectable.js +0 -2
- package/dist/labs/selectable.js.map +0 -1
- package/dist/labs/selection.cjs +0 -2
- package/dist/labs/selection.cjs.map +0 -1
- package/dist/labs/selection.d.ts +0 -68
- package/dist/labs/selection.d.ts.map +0 -1
- package/dist/labs/selection.js +0 -2
- package/dist/labs/selection.js.map +0 -1
- package/dist/labs.cjs +0 -1
- package/dist/labs.js +0 -1
- package/dist/test/index.d.ts +0 -2
- package/dist/test/index.d.ts.map +0 -1
- package/dist/test/test.cjs +0 -2
- package/dist/test/test.cjs.map +0 -1
- package/dist/test/test.d.ts.map +0 -1
- package/dist/test/test.js +0 -2
- package/dist/test/test.js.map +0 -1
- package/dist/test.cjs +0 -1
- package/dist/test.js +0 -1
- /package/dist/{core/runtime-bindings.d.ts → runtime-bindings.d.ts} +0 -0
- /package/dist/{core/template-dom.d.ts → template-dom.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.cjs","names":[],"sources":["../src/host.ts"],"sourcesContent":["/**\n * Host utilities — component context injection, slot observation, and attribute/class reflection.\n *\n * - Context API (provide, inject, createContext, syncContextProps)\n * - Slot observation and detection (setup slots)\n * - Host element binding (reflect) for attributes, classes, and host listeners\n */\n\nimport { type ReadonlySignal, type Signal, signal } from '@vielzeug/stateit';\n\nimport { listen, setAttr } from './internal';\nimport { currentRuntime } from './runtime-core';\nimport { effect, onCleanup, onMount, type HostEventListeners } from './runtime-lifecycle';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// CONTEXT API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown> | string | symbol, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __craftit_injection_key?: T;\n};\n\nexport const provide = <T>(key: InjectionKey<T> | string | symbol, value: T): void => {\n const el = currentRuntime().el;\n\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(key, value);\n};\n\nexport function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, ...rest: [T?]): T | undefined {\n let node: Node | null = currentRuntime().el;\n\n while (node) {\n if (node instanceof HTMLElement) {\n const v = contextRegistry.get(node)?.get(key);\n\n if (v !== undefined) return v as T;\n }\n\n const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return rest.length > 0 ? rest[0] : undefined;\n}\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n\n/**\n * Reactively inherits prop values from a context object provided by an ancestor component.\n * For each key, when the context value is not `undefined`, it is written into the matching prop signal.\n * The effect is automatically cleaned up when the component unmounts.\n *\n * Deferred to `onMount` so context values win over HTML attribute values set on the child.\n *\n * @example\n * syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);\n */\nexport const syncContextProps = <\n K extends string,\n Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>,\n Props extends Record<K, Signal<unknown>>,\n>(\n ctx: Ctx | undefined,\n props: Props,\n keys: K[],\n): void => {\n if (!ctx) return;\n\n onMount(() => {\n effect(() => {\n const target = props as Record<K, Signal<unknown>>;\n\n for (const k of keys) {\n const v = ctx[k]?.value;\n\n if (v !== undefined) target[k].value = v;\n }\n });\n });\n};\n\nexport type HostContextAttributeBridge = {\n contextDisabled?: ReadonlySignal<boolean | undefined>;\n contextSize?: ReadonlySignal<string | undefined>;\n contextVariant?: ReadonlySignal<string | undefined>;\n ownDisabled?: ReadonlySignal<boolean | undefined>;\n ownSize?: ReadonlySignal<string | undefined>;\n ownVariant?: ReadonlySignal<string | undefined>;\n};\n\nexport const bridgeContextAttributes = (host: HTMLElement, options: HostContextAttributeBridge): void => {\n let contextDisabledActive = false;\n\n effect(() => {\n const contextDisabled = Boolean(options.contextDisabled?.value);\n\n if (contextDisabled && !contextDisabledActive) {\n host.setAttribute('disabled', '');\n contextDisabledActive = true;\n } else if (!contextDisabled && contextDisabledActive && !options.ownDisabled?.value) {\n host.removeAttribute('disabled');\n contextDisabledActive = false;\n }\n\n const contextSize = options.contextSize?.value;\n const hasOwnSize = Boolean(options.ownSize?.value);\n\n if (contextSize && !hasOwnSize) host.setAttribute('size', contextSize);\n else if (!hasOwnSize) host.removeAttribute('size');\n\n const contextVariant = options.contextVariant?.value;\n const hasOwnVariant = Boolean(options.ownVariant?.value);\n\n if (contextVariant && !hasOwnVariant) host.setAttribute('variant', contextVariant);\n else if (!hasOwnVariant) host.removeAttribute('variant');\n });\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SLOTS API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SLOT_DEFAULT = 'default';\nconst normalizeSlotName = (slotName: string | null | undefined): string => {\n if (!slotName || slotName === SLOT_DEFAULT) return SLOT_DEFAULT;\n\n return slotName;\n};\n\nconst slotsRegistry = new WeakMap<HTMLElement, ComponentSlots>();\n\nexport type ComponentSlots = {\n elements: (name?: string) => ReadonlySignal<Element[]>;\n has: (name?: string) => ReadonlySignal<boolean>;\n};\n\n/**\n * Creates first-class slot signals for setup context.\n *\n * - `slots.has(name?)`: whether a slot has assigned elements\n * - `slots.elements(name?)`: assigned elements for a slot (flattened)\n */\nexport const createSlots = (): ComponentSlots => {\n const host = currentRuntime().el;\n const cached = slotsRegistry.get(host);\n\n if (cached) return cached;\n\n const presenceSignals = new Map<string, Signal<boolean>>();\n const elementSignals = new Map<string, Signal<Element[]>>();\n const slotNodesByName = new Map<string, Set<HTMLSlotElement>>();\n const slotCleanupMap = new Map<HTMLSlotElement, () => void>();\n let isDisposing = false;\n\n const ensurePresenceSignal = (name: string): Signal<boolean> => {\n const normalized = normalizeSlotName(name);\n let s = presenceSignals.get(normalized);\n\n if (!s) {\n s = signal(false);\n presenceSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const ensureElementSignal = (name: string): Signal<Element[]> => {\n const normalized = normalizeSlotName(name);\n let s = elementSignals.get(normalized);\n\n if (!s) {\n s = signal<Element[]>([]);\n elementSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const recomputeSlot = (name: string): void => {\n const normalized = normalizeSlotName(name);\n const slotsForName = slotNodesByName.get(normalized);\n const assigned: Element[] = [];\n\n if (slotsForName) {\n for (const slotEl of slotsForName) {\n assigned.push(...slotEl.assignedElements({ flatten: true }));\n }\n }\n\n ensureElementSignal(normalized).value = assigned;\n ensurePresenceSignal(normalized).value = assigned.length > 0;\n };\n\n const bindSlot = (slotEl: HTMLSlotElement): void => {\n if (slotCleanupMap.has(slotEl)) return;\n\n const name = normalizeSlotName(slotEl.getAttribute('name'));\n const setForName = slotNodesByName.get(name) ?? new Set<HTMLSlotElement>();\n\n setForName.add(slotEl);\n slotNodesByName.set(name, setForName);\n\n const onChange = () => recomputeSlot(name);\n\n slotEl.addEventListener('slotchange', onChange);\n\n const cleanup = () => {\n slotEl.removeEventListener('slotchange', onChange);\n slotCleanupMap.delete(slotEl);\n\n if (isDisposing) return;\n\n const currentSet = slotNodesByName.get(name);\n\n if (!currentSet) return;\n\n currentSet.delete(slotEl);\n\n if (currentSet.size === 0) {\n slotNodesByName.delete(name);\n }\n\n recomputeSlot(name);\n };\n\n slotCleanupMap.set(slotEl, cleanup);\n\n recomputeSlot(name);\n };\n\n const unbindSlot = (slotEl: HTMLSlotElement): void => {\n slotCleanupMap.get(slotEl)?.();\n };\n\n const bindAllSlots = (): void => {\n host.shadowRoot?.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n };\n\n ensurePresenceSignal(SLOT_DEFAULT);\n ensureElementSignal(SLOT_DEFAULT);\n\n bindAllSlots();\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n mutation.addedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n bindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n }\n });\n\n mutation.removedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n unbindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => unbindSlot(slotEl));\n }\n });\n }\n });\n\n if (host.shadowRoot) {\n observer.observe(host.shadowRoot, { childList: true, subtree: true });\n }\n\n onCleanup(() => {\n isDisposing = true;\n observer.disconnect();\n\n for (const cleanup of [...slotCleanupMap.values()]) cleanup();\n\n slotCleanupMap.clear();\n slotNodesByName.clear();\n });\n\n const slots: ComponentSlots = {\n elements: (name?: string) => ensureElementSignal(normalizeSlotName(name)),\n has: (name?: string) => ensurePresenceSignal(normalizeSlotName(name)),\n };\n\n slotsRegistry.set(host, slots);\n\n return slots;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REFLECT API (HOST ATTRIBUTE/EVENT/CLASS BINDING)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => Record<string, boolean>)\n | (() => string | number | boolean | null | undefined)\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\nexport type HostBindConfig<CustomEvents extends Record<string, unknown> = Record<string, never>> =\n | { attr: ReflectConfig }\n | { class: () => Record<string, boolean> }\n | { on: HostEventListeners<CustomEvents> };\n\nexport type HostBindTarget = 'attr' | 'class' | 'on';\n\nexport type ComponentHost = {\n bind: {\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n config: HostBindConfig<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'attr',\n config: ReflectConfig,\n ): () => void;\n (target: 'class', getter: () => Record<string, boolean>): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'on',\n hostEvents: HostEventListeners<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n };\n el: HTMLElement;\n shadowRoot: ShadowRoot;\n};\n\nexport const createHost = (): ComponentHost => {\n const el = currentRuntime().el;\n\n return {\n bind: (\n targetOrConfig: HostBindTarget | HostBindConfig,\n configOrOptions?: ReflectConfig | (() => Record<string, boolean>) | HostEventListeners | AddEventListenerOptions,\n maybeOptions?: AddEventListenerOptions,\n ) => {\n const disposers: Array<() => void> = [];\n\n const config =\n typeof targetOrConfig === 'string'\n ? ({ [targetOrConfig]: configOrOptions } as HostBindConfig)\n : (targetOrConfig as HostBindConfig);\n const options =\n typeof targetOrConfig === 'string' && targetOrConfig === 'on'\n ? (maybeOptions as AddEventListenerOptions | undefined)\n : (configOrOptions as AddEventListenerOptions | undefined);\n\n if ('attr' in config) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name =\n key.startsWith('aria-') || key === 'role'\n ? key\n : key.startsWith('aria')\n ? `aria-${key.slice(4).toLowerCase()}`\n : key;\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if ('class' in config) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if ('on' in config) {\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, options));\n }\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n onCleanup(cleanup);\n\n return cleanup;\n },\n el,\n shadowRoot: el.shadowRoot as ShadowRoot,\n };\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n if (typeof value === 'function') {\n return effect(() => setAttr(host, name, (value as () => HostBindingValue)()));\n } else {\n setAttr(host, name, value);\n }\n}\n\nfunction applyClassMap(host: HTMLElement, getter: () => Record<string, boolean>): () => void {\n let prev = new Set<string>();\n\n return effect(() => {\n const next = new Set(\n Object.entries(getter())\n .filter(([, active]) => active)\n .map(([cls]) => cls),\n );\n\n for (const cls of prev) if (!next.has(cls)) host.classList.remove(cls);\n for (const cls of next) if (!prev.has(cls)) host.classList.add(cls);\n\n prev = next;\n });\n}\n"],"mappings":"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"}
|
package/dist/host.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host utilities — component context injection, slot observation, and attribute/class reflection.
|
|
3
|
+
*
|
|
4
|
+
* - Context API (provide, inject, createContext, syncContextProps)
|
|
5
|
+
* - Slot observation and detection (setup slots)
|
|
6
|
+
* - Host element binding (reflect) for attributes, classes, and host listeners
|
|
7
|
+
*/
|
|
8
|
+
import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
|
|
9
|
+
import { type HostEventListeners } from './runtime-lifecycle';
|
|
10
|
+
export type InjectionKey<T> = symbol & {
|
|
11
|
+
readonly __craftit_injection_key?: T;
|
|
12
|
+
};
|
|
13
|
+
export declare const provide: <T>(key: InjectionKey<T> | string | symbol, value: T) => void;
|
|
14
|
+
export declare function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;
|
|
15
|
+
export declare function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;
|
|
16
|
+
export declare function createContext<T>(description?: string): InjectionKey<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Reactively inherits prop values from a context object provided by an ancestor component.
|
|
19
|
+
* For each key, when the context value is not `undefined`, it is written into the matching prop signal.
|
|
20
|
+
* The effect is automatically cleaned up when the component unmounts.
|
|
21
|
+
*
|
|
22
|
+
* Deferred to `onMount` so context values win over HTML attribute values set on the child.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);
|
|
26
|
+
*/
|
|
27
|
+
export declare const syncContextProps: <K extends string, Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>, Props extends Record<K, Signal<unknown>>>(ctx: Ctx | undefined, props: Props, keys: K[]) => void;
|
|
28
|
+
export type HostContextAttributeBridge = {
|
|
29
|
+
contextDisabled?: ReadonlySignal<boolean | undefined>;
|
|
30
|
+
contextSize?: ReadonlySignal<string | undefined>;
|
|
31
|
+
contextVariant?: ReadonlySignal<string | undefined>;
|
|
32
|
+
ownDisabled?: ReadonlySignal<boolean | undefined>;
|
|
33
|
+
ownSize?: ReadonlySignal<string | undefined>;
|
|
34
|
+
ownVariant?: ReadonlySignal<string | undefined>;
|
|
35
|
+
};
|
|
36
|
+
export declare const bridgeContextAttributes: (host: HTMLElement, options: HostContextAttributeBridge) => void;
|
|
37
|
+
export type ComponentSlots = {
|
|
38
|
+
elements: (name?: string) => ReadonlySignal<Element[]>;
|
|
39
|
+
has: (name?: string) => ReadonlySignal<boolean>;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Creates first-class slot signals for setup context.
|
|
43
|
+
*
|
|
44
|
+
* - `slots.has(name?)`: whether a slot has assigned elements
|
|
45
|
+
* - `slots.elements(name?)`: assigned elements for a slot (flattened)
|
|
46
|
+
*/
|
|
47
|
+
export declare const createSlots: () => ComponentSlots;
|
|
48
|
+
/**
|
|
49
|
+
* Describes a reactive or static host binding value.
|
|
50
|
+
*/
|
|
51
|
+
export type HostBindingValue = (() => Record<string, boolean>) | (() => string | number | boolean | null | undefined) | string | number | boolean | null | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Configuration for host attribute bindings.
|
|
54
|
+
*/
|
|
55
|
+
export type ReflectConfig = Record<string, HostBindingValue>;
|
|
56
|
+
export type HostBindConfig<CustomEvents extends Record<string, unknown> = Record<string, never>> = {
|
|
57
|
+
attr: ReflectConfig;
|
|
58
|
+
} | {
|
|
59
|
+
class: () => Record<string, boolean>;
|
|
60
|
+
} | {
|
|
61
|
+
on: HostEventListeners<CustomEvents>;
|
|
62
|
+
};
|
|
63
|
+
export type HostBindTarget = 'attr' | 'class' | 'on';
|
|
64
|
+
export type ComponentHost = {
|
|
65
|
+
bind: {
|
|
66
|
+
<CustomEvents extends Record<string, unknown> = Record<string, never>>(config: HostBindConfig<CustomEvents>, options?: AddEventListenerOptions): () => void;
|
|
67
|
+
<CustomEvents extends Record<string, unknown> = Record<string, never>>(target: 'attr', config: ReflectConfig): () => void;
|
|
68
|
+
(target: 'class', getter: () => Record<string, boolean>): () => void;
|
|
69
|
+
<CustomEvents extends Record<string, unknown> = Record<string, never>>(target: 'on', hostEvents: HostEventListeners<CustomEvents>, options?: AddEventListenerOptions): () => void;
|
|
70
|
+
};
|
|
71
|
+
el: HTMLElement;
|
|
72
|
+
shadowRoot: ShadowRoot;
|
|
73
|
+
};
|
|
74
|
+
export declare const createHost: () => ComponentHost;
|
|
75
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
|
package/dist/host.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{currentRuntime as e}from"./runtime-core.js";import{effect as t,onCleanup as n,onMount as r}from"./runtime-lifecycle.js";import{listen as i,setAttr as a}from"./internal.js";import{signal as o}from"@vielzeug/stateit";var s=new WeakMap,c=(t,n)=>{let r=e().el;s.has(r)||s.set(r,new Map),s.get(r).set(t,n)};function l(t,...n){let r=e().el;for(;r;){if(r instanceof HTMLElement){let e=s.get(r)?.get(t);if(e!==void 0)return e}let e=r.getRootNode();r=r.parentElement??(e instanceof ShadowRoot?e.host:null)}return n.length>0?n[0]:void 0}function u(e){return Symbol(e)}var d=(e,n,i)=>{e&&r(()=>{t(()=>{let t=n;for(let n of i){let r=e[n]?.value;r!==void 0&&(t[n].value=r)}})})},f=(e,n)=>{let r=!1;t(()=>{let t=!!n.contextDisabled?.value;t&&!r?(e.setAttribute(`disabled`,``),r=!0):!t&&r&&!n.ownDisabled?.value&&(e.removeAttribute(`disabled`),r=!1);let i=n.contextSize?.value,a=!!n.ownSize?.value;i&&!a?e.setAttribute(`size`,i):a||e.removeAttribute(`size`);let o=n.contextVariant?.value,s=!!n.ownVariant?.value;o&&!s?e.setAttribute(`variant`,o):s||e.removeAttribute(`variant`)})},p=`default`,m=e=>!e||e===p?p:e,h=new WeakMap,g=()=>{let t=e().el,r=h.get(t);if(r)return r;let i=new Map,a=new Map,s=new Map,c=new Map,l=!1,u=e=>{let t=m(e),n=i.get(t);return n||(n=o(!1),i.set(t,n)),n},d=e=>{let t=m(e),n=a.get(t);return n||(n=o([]),a.set(t,n)),n},f=e=>{let t=m(e),n=s.get(t),r=[];if(n)for(let e of n)r.push(...e.assignedElements({flatten:!0}));d(t).value=r,u(t).value=r.length>0},g=e=>{if(c.has(e))return;let t=m(e.getAttribute(`name`)),n=s.get(t)??new Set;n.add(e),s.set(t,n);let r=()=>f(t);e.addEventListener(`slotchange`,r),c.set(e,()=>{if(e.removeEventListener(`slotchange`,r),c.delete(e),l)return;let n=s.get(t);n&&(n.delete(e),n.size===0&&s.delete(t),f(t))}),f(t)},_=e=>{c.get(e)?.()};u(p),d(p),t.shadowRoot?.querySelectorAll(`slot`).forEach(e=>g(e));let v=new MutationObserver(e=>{for(let t of e)t.addedNodes.forEach(e=>{if(e instanceof HTMLSlotElement){g(e);return}e instanceof Element&&e.querySelectorAll(`slot`).forEach(e=>g(e))}),t.removedNodes.forEach(e=>{if(e instanceof HTMLSlotElement){_(e);return}e instanceof Element&&e.querySelectorAll(`slot`).forEach(e=>_(e))})});t.shadowRoot&&v.observe(t.shadowRoot,{childList:!0,subtree:!0}),n(()=>{l=!0,v.disconnect();for(let e of[...c.values()])e();c.clear(),s.clear()});let y={elements:e=>d(m(e)),has:e=>u(m(e))};return h.set(t,y),y},_=()=>{let t=e().el;return{bind:(e,r,a)=>{let o=[],s=typeof e==`string`?{[e]:r}:e,c=typeof e==`string`&&e===`on`?a:r;if(`attr`in s)for(let[e,n]of Object.entries(s.attr)){let r=v(t,e.startsWith(`aria-`)||e===`role`?e:e.startsWith(`aria`)?`aria-${e.slice(4).toLowerCase()}`:e,n);r&&o.push(r)}if(`class`in s&&o.push(y(t,s.class)),`on`in s)for(let e of Object.keys(s.on)){let n=s.on[e];n&&o.push(i(t,e,n,c))}let l=()=>{for(;o.length>0;)o.pop()?.()};return n(l),l},el:t,shadowRoot:t.shadowRoot}};function v(e,n,r){if(typeof r==`function`)return t(()=>a(e,n,r()));a(e,n,r)}function y(e,n){let r=new Set;return t(()=>{let t=new Set(Object.entries(n()).filter(([,e])=>e).map(([e])=>e));for(let n of r)t.has(n)||e.classList.remove(n);for(let n of t)r.has(n)||e.classList.add(n);r=t})}export{f as bridgeContextAttributes,u as createContext,_ as createHost,g as createSlots,l as inject,c as provide,d as syncContextProps};
|
|
2
|
+
//# sourceMappingURL=host.js.map
|
package/dist/host.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","names":[],"sources":["../src/host.ts"],"sourcesContent":["/**\n * Host utilities — component context injection, slot observation, and attribute/class reflection.\n *\n * - Context API (provide, inject, createContext, syncContextProps)\n * - Slot observation and detection (setup slots)\n * - Host element binding (reflect) for attributes, classes, and host listeners\n */\n\nimport { type ReadonlySignal, type Signal, signal } from '@vielzeug/stateit';\n\nimport { listen, setAttr } from './internal';\nimport { currentRuntime } from './runtime-core';\nimport { effect, onCleanup, onMount, type HostEventListeners } from './runtime-lifecycle';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// CONTEXT API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown> | string | symbol, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __craftit_injection_key?: T;\n};\n\nexport const provide = <T>(key: InjectionKey<T> | string | symbol, value: T): void => {\n const el = currentRuntime().el;\n\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(key, value);\n};\n\nexport function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, ...rest: [T?]): T | undefined {\n let node: Node | null = currentRuntime().el;\n\n while (node) {\n if (node instanceof HTMLElement) {\n const v = contextRegistry.get(node)?.get(key);\n\n if (v !== undefined) return v as T;\n }\n\n const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return rest.length > 0 ? rest[0] : undefined;\n}\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n\n/**\n * Reactively inherits prop values from a context object provided by an ancestor component.\n * For each key, when the context value is not `undefined`, it is written into the matching prop signal.\n * The effect is automatically cleaned up when the component unmounts.\n *\n * Deferred to `onMount` so context values win over HTML attribute values set on the child.\n *\n * @example\n * syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);\n */\nexport const syncContextProps = <\n K extends string,\n Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>,\n Props extends Record<K, Signal<unknown>>,\n>(\n ctx: Ctx | undefined,\n props: Props,\n keys: K[],\n): void => {\n if (!ctx) return;\n\n onMount(() => {\n effect(() => {\n const target = props as Record<K, Signal<unknown>>;\n\n for (const k of keys) {\n const v = ctx[k]?.value;\n\n if (v !== undefined) target[k].value = v;\n }\n });\n });\n};\n\nexport type HostContextAttributeBridge = {\n contextDisabled?: ReadonlySignal<boolean | undefined>;\n contextSize?: ReadonlySignal<string | undefined>;\n contextVariant?: ReadonlySignal<string | undefined>;\n ownDisabled?: ReadonlySignal<boolean | undefined>;\n ownSize?: ReadonlySignal<string | undefined>;\n ownVariant?: ReadonlySignal<string | undefined>;\n};\n\nexport const bridgeContextAttributes = (host: HTMLElement, options: HostContextAttributeBridge): void => {\n let contextDisabledActive = false;\n\n effect(() => {\n const contextDisabled = Boolean(options.contextDisabled?.value);\n\n if (contextDisabled && !contextDisabledActive) {\n host.setAttribute('disabled', '');\n contextDisabledActive = true;\n } else if (!contextDisabled && contextDisabledActive && !options.ownDisabled?.value) {\n host.removeAttribute('disabled');\n contextDisabledActive = false;\n }\n\n const contextSize = options.contextSize?.value;\n const hasOwnSize = Boolean(options.ownSize?.value);\n\n if (contextSize && !hasOwnSize) host.setAttribute('size', contextSize);\n else if (!hasOwnSize) host.removeAttribute('size');\n\n const contextVariant = options.contextVariant?.value;\n const hasOwnVariant = Boolean(options.ownVariant?.value);\n\n if (contextVariant && !hasOwnVariant) host.setAttribute('variant', contextVariant);\n else if (!hasOwnVariant) host.removeAttribute('variant');\n });\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SLOTS API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SLOT_DEFAULT = 'default';\nconst normalizeSlotName = (slotName: string | null | undefined): string => {\n if (!slotName || slotName === SLOT_DEFAULT) return SLOT_DEFAULT;\n\n return slotName;\n};\n\nconst slotsRegistry = new WeakMap<HTMLElement, ComponentSlots>();\n\nexport type ComponentSlots = {\n elements: (name?: string) => ReadonlySignal<Element[]>;\n has: (name?: string) => ReadonlySignal<boolean>;\n};\n\n/**\n * Creates first-class slot signals for setup context.\n *\n * - `slots.has(name?)`: whether a slot has assigned elements\n * - `slots.elements(name?)`: assigned elements for a slot (flattened)\n */\nexport const createSlots = (): ComponentSlots => {\n const host = currentRuntime().el;\n const cached = slotsRegistry.get(host);\n\n if (cached) return cached;\n\n const presenceSignals = new Map<string, Signal<boolean>>();\n const elementSignals = new Map<string, Signal<Element[]>>();\n const slotNodesByName = new Map<string, Set<HTMLSlotElement>>();\n const slotCleanupMap = new Map<HTMLSlotElement, () => void>();\n let isDisposing = false;\n\n const ensurePresenceSignal = (name: string): Signal<boolean> => {\n const normalized = normalizeSlotName(name);\n let s = presenceSignals.get(normalized);\n\n if (!s) {\n s = signal(false);\n presenceSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const ensureElementSignal = (name: string): Signal<Element[]> => {\n const normalized = normalizeSlotName(name);\n let s = elementSignals.get(normalized);\n\n if (!s) {\n s = signal<Element[]>([]);\n elementSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const recomputeSlot = (name: string): void => {\n const normalized = normalizeSlotName(name);\n const slotsForName = slotNodesByName.get(normalized);\n const assigned: Element[] = [];\n\n if (slotsForName) {\n for (const slotEl of slotsForName) {\n assigned.push(...slotEl.assignedElements({ flatten: true }));\n }\n }\n\n ensureElementSignal(normalized).value = assigned;\n ensurePresenceSignal(normalized).value = assigned.length > 0;\n };\n\n const bindSlot = (slotEl: HTMLSlotElement): void => {\n if (slotCleanupMap.has(slotEl)) return;\n\n const name = normalizeSlotName(slotEl.getAttribute('name'));\n const setForName = slotNodesByName.get(name) ?? new Set<HTMLSlotElement>();\n\n setForName.add(slotEl);\n slotNodesByName.set(name, setForName);\n\n const onChange = () => recomputeSlot(name);\n\n slotEl.addEventListener('slotchange', onChange);\n\n const cleanup = () => {\n slotEl.removeEventListener('slotchange', onChange);\n slotCleanupMap.delete(slotEl);\n\n if (isDisposing) return;\n\n const currentSet = slotNodesByName.get(name);\n\n if (!currentSet) return;\n\n currentSet.delete(slotEl);\n\n if (currentSet.size === 0) {\n slotNodesByName.delete(name);\n }\n\n recomputeSlot(name);\n };\n\n slotCleanupMap.set(slotEl, cleanup);\n\n recomputeSlot(name);\n };\n\n const unbindSlot = (slotEl: HTMLSlotElement): void => {\n slotCleanupMap.get(slotEl)?.();\n };\n\n const bindAllSlots = (): void => {\n host.shadowRoot?.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n };\n\n ensurePresenceSignal(SLOT_DEFAULT);\n ensureElementSignal(SLOT_DEFAULT);\n\n bindAllSlots();\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n mutation.addedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n bindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n }\n });\n\n mutation.removedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n unbindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => unbindSlot(slotEl));\n }\n });\n }\n });\n\n if (host.shadowRoot) {\n observer.observe(host.shadowRoot, { childList: true, subtree: true });\n }\n\n onCleanup(() => {\n isDisposing = true;\n observer.disconnect();\n\n for (const cleanup of [...slotCleanupMap.values()]) cleanup();\n\n slotCleanupMap.clear();\n slotNodesByName.clear();\n });\n\n const slots: ComponentSlots = {\n elements: (name?: string) => ensureElementSignal(normalizeSlotName(name)),\n has: (name?: string) => ensurePresenceSignal(normalizeSlotName(name)),\n };\n\n slotsRegistry.set(host, slots);\n\n return slots;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REFLECT API (HOST ATTRIBUTE/EVENT/CLASS BINDING)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => Record<string, boolean>)\n | (() => string | number | boolean | null | undefined)\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\nexport type HostBindConfig<CustomEvents extends Record<string, unknown> = Record<string, never>> =\n | { attr: ReflectConfig }\n | { class: () => Record<string, boolean> }\n | { on: HostEventListeners<CustomEvents> };\n\nexport type HostBindTarget = 'attr' | 'class' | 'on';\n\nexport type ComponentHost = {\n bind: {\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n config: HostBindConfig<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'attr',\n config: ReflectConfig,\n ): () => void;\n (target: 'class', getter: () => Record<string, boolean>): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'on',\n hostEvents: HostEventListeners<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n };\n el: HTMLElement;\n shadowRoot: ShadowRoot;\n};\n\nexport const createHost = (): ComponentHost => {\n const el = currentRuntime().el;\n\n return {\n bind: (\n targetOrConfig: HostBindTarget | HostBindConfig,\n configOrOptions?: ReflectConfig | (() => Record<string, boolean>) | HostEventListeners | AddEventListenerOptions,\n maybeOptions?: AddEventListenerOptions,\n ) => {\n const disposers: Array<() => void> = [];\n\n const config =\n typeof targetOrConfig === 'string'\n ? ({ [targetOrConfig]: configOrOptions } as HostBindConfig)\n : (targetOrConfig as HostBindConfig);\n const options =\n typeof targetOrConfig === 'string' && targetOrConfig === 'on'\n ? (maybeOptions as AddEventListenerOptions | undefined)\n : (configOrOptions as AddEventListenerOptions | undefined);\n\n if ('attr' in config) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name =\n key.startsWith('aria-') || key === 'role'\n ? key\n : key.startsWith('aria')\n ? `aria-${key.slice(4).toLowerCase()}`\n : key;\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if ('class' in config) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if ('on' in config) {\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, options));\n }\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n onCleanup(cleanup);\n\n return cleanup;\n },\n el,\n shadowRoot: el.shadowRoot as ShadowRoot,\n };\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n if (typeof value === 'function') {\n return effect(() => setAttr(host, name, (value as () => HostBindingValue)()));\n } else {\n setAttr(host, name, value);\n }\n}\n\nfunction applyClassMap(host: HTMLElement, getter: () => Record<string, boolean>): () => void {\n let prev = new Set<string>();\n\n return effect(() => {\n const next = new Set(\n Object.entries(getter())\n .filter(([, active]) => active)\n .map(([cls]) => cls),\n );\n\n for (const cls of prev) if (!next.has(cls)) host.classList.remove(cls);\n for (const cls of next) if (!prev.has(cls)) host.classList.add(cls);\n\n prev = next;\n });\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./core
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./runtime-core.cjs`),t=require(`./runtime-lifecycle.cjs`),n=require(`./runtime.cjs`),r=require(`./internal.cjs`),i=require(`./form.cjs`),a=require(`./host.cjs`),o=require(`./template.cjs`),s=require(`./component.cjs`);let c=require(`@vielzeug/stateit`);Object.defineProperty(exports,`batch`,{enumerable:!0,get:function(){return c.batch}}),exports.bridgeContextAttributes=a.bridgeContextAttributes,Object.defineProperty(exports,`computed`,{enumerable:!0,get:function(){return c.computed}}),exports.createCleanupSignal=t.createCleanupSignal,exports.createContext=a.createContext,exports.createId=r.createId,exports.css=r.css,exports.currentRuntime=e.currentRuntime,exports.define=s.define,exports.defineField=i.defineField,exports.effect=t.effect,exports.fire=n.fire,exports.handle=t.handle,exports.html=o.html,exports.inject=a.inject,Object.defineProperty(exports,`isSignal`,{enumerable:!0,get:function(){return c.isSignal}}),exports.onCleanup=t.onCleanup,exports.onElement=t.onElement,exports.onError=t.onError,exports.onMount=t.onMount,Object.defineProperty(exports,`peekValue`,{enumerable:!0,get:function(){return c.peekValue}}),exports.provide=a.provide,Object.defineProperty(exports,`readonly`,{enumerable:!0,get:function(){return c.readonly}}),exports.ref=r.ref,exports.refs=r.refs,Object.defineProperty(exports,`signal`,{enumerable:!0,get:function(){return c.signal}}),exports.syncContextProps=a.syncContextProps,Object.defineProperty(exports,`toValue`,{enumerable:!0,get:function(){return c.toValue}}),Object.defineProperty(exports,`untrack`,{enumerable:!0,get:function(){return c.untrack}}),exports.watch=t.watch,Object.defineProperty(exports,`writable`,{enumerable:!0,get:function(){return c.writable}});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
export
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export { observeResize } from './labs/observers';
|
|
1
|
+
export { batch, computed, isSignal, peekValue, readonly, signal, toValue, untrack, writable, type ReadonlySignal, type Signal, type WatchOptions, } from '@vielzeug/stateit';
|
|
2
|
+
export { createCleanupSignal, effect, fire, handle, onCleanup, onElement, onError, onMount, watch, type HostEventListeners, type HostEventMap, } from './runtime';
|
|
3
|
+
export { currentRuntime, type ComponentRuntime } from './runtime-core';
|
|
4
|
+
export { define, type ComponentDefinition, type ComponentOptions, type ComponentSetupContext, type InferPropsSignals, type PropDef, type PropsInput, type PropOptions, } from './component';
|
|
5
|
+
export { defineField, type FormFieldCallbacks, type FormFieldHandle, type FormFieldOptions } from './form';
|
|
6
|
+
export { createContext, inject, provide, bridgeContextAttributes, syncContextProps, type ComponentHost, type ComponentSlots, type HostBindingValue, type InjectionKey, type ReflectConfig, type HostContextAttributeBridge, } from './host';
|
|
7
|
+
export { html, type KeyedNode } from './template';
|
|
8
|
+
export { css, createId, ref, refs, type CSSResult, type Directive, type EmitFn, type HTMLResult, type Ref, type RefCallback, type Refs, } from './internal';
|
|
10
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,MAAM,EACN,OAAO,EACP,OAAO,EACP,QAAQ,EACR,KAAK,cAAc,EACnB,KAAK,MAAM,EACX,KAAK,YAAY,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,mBAAmB,EACnB,MAAM,EACN,IAAI,EACJ,MAAM,EACN,SAAS,EACT,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,EACL,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EACL,MAAM,EACN,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAE3G,OAAO,EACL,aAAa,EACb,MAAM,EACN,OAAO,EACP,uBAAuB,EACvB,gBAAgB,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,0BAA0B,GAChC,MAAM,QAAQ,CAAC;AAEhB,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EACL,GAAG,EACH,QAAQ,EACR,GAAG,EACH,IAAI,EACJ,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,GAAG,EACR,KAAK,WAAW,EAChB,KAAK,IAAI,GACV,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{currentRuntime as e}from"./runtime-core.js";import{createCleanupSignal as t,effect as n,handle as r,onCleanup as i,onElement as a,onError as o,onMount as s,watch as c}from"./runtime-lifecycle.js";import{fire as l}from"./runtime.js";import{createId as u,css as d,ref as f,refs as p}from"./internal.js";import{defineField as m}from"./form.js";import{bridgeContextAttributes as h,createContext as g,inject as _,provide as v,syncContextProps as y}from"./host.js";import{html as b}from"./template.js";import{define as x}from"./component.js";import{batch as S,computed as C,isSignal as w,peekValue as T,readonly as E,signal as D,toValue as O,untrack as k,writable as A}from"@vielzeug/stateit";export{S as batch,h as bridgeContextAttributes,C as computed,t as createCleanupSignal,g as createContext,u as createId,d as css,e as currentRuntime,x as define,m as defineField,n as effect,l as fire,r as handle,b as html,_ as inject,w as isSignal,i as onCleanup,a as onElement,o as onError,s as onMount,T as peekValue,v as provide,E as readonly,f as ref,p as refs,D as signal,y as syncContextProps,O as toValue,k as untrack,c as watch,A as writable};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`./runtime-core.cjs`),t=require(`./runtime.cjs`);let n=require(`@vielzeug/stateit`);var r=Symbol(`craftit.htmlResultBrand`),i=0,a=()=>{i=0},o=e=>`${e?`${e}-`:`cft-`}${++i}`;function s(){return(0,n.signal)(null)}function c(){return[]}function l(e,t=[]){let n={__bindings:t,__html:e,toString(){return e}};return Object.defineProperty(n,r,{configurable:!1,enumerable:!1,value:!0,writable:!1}),n}var u=e=>typeof e==`object`&&!!e&&e[r]===!0;function d(e){return typeof e==`string`?{bindings:[],html:e}:{bindings:e.__bindings,html:e.__html}}var f=Symbol(`craftit.eachSignal`),p=e=>{let t=[...e];for(let e=t.length-1;e>=0;e--)t[e]?.()},m=(e,t,n)=>{if(/^on/i.test(t)){e.removeAttribute(t);return}n==null||n===!1?e.removeAttribute(t):n===!0?e.setAttribute(t,t.startsWith(`aria-`)?`true`:``):e.setAttribute(t,String(n))},h=(e,t,n,r)=>{let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},g=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),_={"'":`'`,'"':`"`,"&":`&`,"<":`<`,">":`>`},v=e=>String(e).replace(/[&<>"']/g,e=>_[e]),y=()=>{let n=e.currentRuntime().el;return((e,...r)=>{t.fire.custom(n,String(e),r.length>0?{detail:r[0]}:void 0)})},b=function(){return this.content},x=(e,...t)=>{let n=``;for(let r=0;r<e.length;r++)if(n+=e[r],r<t.length){let e=t[r];n+=e&&typeof e==`object`&&`content`in e?e.content:e??``}return{content:n.trim(),toString:b}},S=new Map,C=e=>{if(e instanceof CSSStyleSheet)return e;let t=typeof e==`string`?e:e.content,n=S.get(t);if(n)return n;let r=new CSSStyleSheet;try{r.replaceSync(t),S.set(t,r)}catch(e){console.error(`[craftit:E2] style replace failed`,e)}return r};exports.EACH_SIGNAL=f,exports._resetIdCounter=a,exports.createEmitFn=y,exports.createId=o,exports.css=x,exports.escapeHtml=v,exports.extractResult=d,exports.htmlResult=l,exports.isHtmlResult=u,exports.listen=h,exports.loadStylesheet=C,exports.ref=s,exports.refs=c,exports.runAll=p,exports.setAttr=m,exports.toKebab=g;
|
|
2
|
+
//# sourceMappingURL=internal.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.cjs","names":[],"sources":["../src/internal.ts"],"sourcesContent":["/**\n * @internal — Binding type system, compiler/runtime helpers, and engine internals.\n *\n * These types and helpers define the contract between the template compiler, binding engine,\n * and component runtime.\n * They are NOT part of the public API and importing directly is an unstable contract.\n *\n * Selected author-facing exports (such as css(), CSSResult, EmitFn, HTMLResult, Directive,\n * ref(), and refs()) are re-exported from the main entry point.\n */\n\nimport { signal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { fire } from './runtime';\nimport { currentRuntime } from './runtime-core';\n\nconst HTML_RESULT_BRAND: unique symbol = Symbol('craftit.htmlResultBrand');\n\nlet _idCounter = 0;\n\n/** @internal — resets the ID counter. Used by _resetCounters in test/test.ts. */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n};\n\n/**\n * Creates a unique, stable ID string — suitable for `aria-labelledby`, `aria-describedby`,\n * and similar accessibility linkages. Call once per component instance (at setup time or inside `onMount`).\n */\nexport const createId = (prefix?: string): string => `${prefix ? `${prefix}-` : 'cft-'}${++_idCounter}`;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REF TYPES\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * A reactive reference to a DOM element.\n *\n * Backed by a Signal — reactivity is built-in. Use with onElement()\n * for first-class element lifecycle management.\n *\n * @example\n * const inputRef = ref<HTMLInputElement>();\n *\n * onElement(inputRef, (input) => {\n * input.focus();\n * return () => { }; // cleanup\n * });\n *\n * // In template\n * <input ref=${inputRef} />\n */\nexport type Ref<T extends Element> = Signal<T | null>;\n\n/**\n * Create a reactive element reference.\n *\n * Returns a Signal that tracks the mounted/unmounted state of a DOM element.\n * Automatically reactive — use directly in effects or with onElement().\n *\n * @see onElement for element lifecycle integration\n *\n * @example\n * const ref = ref<HTMLInputElement>();\n * // Type: Signal<HTMLInputElement | null>\n * // Automatically updates when element mounts/unmounts\n */\nexport function ref<T extends Element>(): Ref<T> {\n return signal<T | null>(null);\n}\n\nexport type Refs<T extends Element> = T[];\n\nexport function refs<T extends Element>(): Refs<T> {\n return [];\n}\n\nexport type RefCallback<T extends Element> = (el: T | null) => void;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// HTML RESULT\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface HTMLResult {\n __bindings: Binding[];\n __html: string;\n toString(): string;\n}\n\n/** @internal — construct an HTMLResult from a pre-built html string and bindings. */\nexport function htmlResult(html: string, bindings: Binding[] = []): HTMLResult {\n const result = {\n __bindings: bindings,\n __html: html,\n toString() {\n return html;\n },\n };\n\n Object.defineProperty(result, HTML_RESULT_BRAND, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n\n return result as HTMLResult;\n}\n\n/** @internal — strict HTMLResult runtime type guard. */\nexport const isHtmlResult = (value: unknown): value is HTMLResult =>\n typeof value === 'object' && !!value && (value as Record<symbol, unknown>)[HTML_RESULT_BRAND] === true;\n\n/** @internal — extract html and bindings from a string or HTMLResult. */\nexport function extractResult(v: string | HTMLResult): { bindings: Binding[]; html: string } {\n return typeof v === 'string' ? { bindings: [], html: v } : { bindings: v.__bindings, html: v.__html };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DIRECTIVES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface DirectiveContext {\n /** The cleanup registration function for the component. */\n registerCleanup: (fn: () => void) => void;\n}\n\nexport interface Directive {\n /** Invoked when the element is mounted in the DOM. */\n mount?(el: HTMLElement, context: DirectiveContext): void;\n /** Invoked by the template engine to render content (interpolation directives). */\n render?(): HTMLResult | string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// BINDING TYPES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type TextBinding = {\n signal: ReadonlySignal<unknown>;\n type: 'text';\n uid: string;\n};\n\nexport type AttrBinding = {\n mode: 'bool' | 'attr';\n name: string;\n signal?: ReadonlySignal<unknown>;\n type: 'attr';\n uid: string;\n value?: unknown;\n};\n\nexport type PropBinding = {\n /** Optional writable source used for native two-way bridge (.value/.checked). */\n model?: Signal<unknown>;\n name: string;\n signal?: ReadonlySignal<unknown>;\n type: 'prop';\n uid: string;\n value?: unknown;\n};\n\nexport type EventBinding = {\n handler: (e: Event) => void;\n modifiers?: {\n capture?: boolean;\n once?: boolean;\n passive?: boolean;\n prevent?: boolean;\n self?: boolean;\n stop?: boolean;\n };\n name: string;\n type: 'event';\n uid: string;\n};\n\nexport type RefBinding = {\n ref: Ref<Element> | Refs<Element> | RefCallback<Element>;\n type: 'ref';\n uid: string;\n};\n\nexport type CallbackBinding = {\n apply: (el: HTMLElement, registerCleanup: (fn: () => void) => void) => void;\n type: 'callback';\n uid: string;\n};\n\nexport type HtmlBinding = {\n keyed?: boolean;\n signal: ReadonlySignal<{\n bindings: Binding[];\n html: string;\n items?: Array<{ bindings: Binding[]; html: string }>;\n keys?: (string | number)[];\n }>;\n type: 'html';\n uid: string;\n};\n\nexport type Binding =\n | TextBinding\n | AttrBinding\n | PropBinding\n | EventBinding\n | RefBinding\n | CallbackBinding\n | HtmlBinding;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL MARKERS & CONSTANTS\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @internal — opaque marker for each() reactive results. */\nexport const EACH_SIGNAL: unique symbol = Symbol('craftit.eachSignal');\n\n/** @internal — binding element identifier attribute. */\nexport const CF_ID_ATTR = 'u';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL DOM & EVENT UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @internal — Iterate an iterable and call every function in it. */\nexport const runAll = (fns: Iterable<() => void>): void => {\n const callbacks = [...fns];\n\n for (let index = callbacks.length - 1; index >= 0; index--) {\n callbacks[index]?.();\n }\n};\n\n/** @internal — Set an attribute on an element, handling boolean and null values. */\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n // Avoid inline event-handler attributes (onclick, onerror, ...) to reduce injection risk.\n if (/^on/i.test(name)) {\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n } else if (val === true) {\n el.setAttribute(name, name.startsWith('aria-') ? 'true' : '');\n } else {\n el.setAttribute(name, String(val));\n }\n};\n\n/** @internal — Attach an event listener with automatic cleanup. */\nexport const listen = (\n el: EventTarget,\n name: string,\n handler: (e: any) => void,\n options?: AddEventListenerOptions,\n): (() => void) => {\n const listener: EventListener = handler as EventListener;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL STRING UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nconst ESC: Record<string, string> = { \"'\": ''', '\"': '"', '&': '&', '<': '<', '>': '>' };\n\n/** @internal — Escape untrusted text for HTML text/attribute contexts. */\nexport const escapeHtml = (value: unknown): string => String(value).replace(/[&<>\"']/g, (c) => ESC[c]);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL EMIT TYPES & HELPERS\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\nexport type EmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): void;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): void;\n};\n\n/** @internal — Create a type-safe custom event emitter for the current runtime host. */\nexport const createEmitFn = <T extends Record<string, unknown>>(): EmitFn<T> => {\n const el = currentRuntime().el;\n\n return ((event: keyof T, ...rest: unknown[]) => {\n fire.custom(el, String(event), rest.length > 0 ? { detail: rest[0] } : undefined);\n }) as EmitFn<T>;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL CSS & STYLESHEET UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type CSSResult = {\n content: string;\n toString(): string;\n};\n\nconst cssResultToString = function (this: CSSResult): string {\n return this.content;\n};\n\n/** @internal — Compile CSS template strings into a CSSResult. */\nexport const css = (strings: TemplateStringsArray, ...values: unknown[]): CSSResult => {\n let content = '';\n\n for (let i = 0; i < strings.length; i++) {\n content += strings[i];\n\n if (i < values.length) {\n const v = values[i];\n\n content += v && typeof v === 'object' && 'content' in v ? (v as CSSResult).content : (v ?? '');\n }\n }\n\n return { content: content.trim(), toString: cssResultToString };\n};\n\nconst stylesheetStringCache = new Map<string, CSSStyleSheet>();\n\n/** @internal — Load a stylesheet string or CSSResult into an adoptedStyleSheet. */\nexport const loadStylesheet = (style: string | CSSStyleSheet | CSSResult): CSSStyleSheet => {\n if (style instanceof CSSStyleSheet) return style;\n\n const cssText = typeof style === 'string' ? style : style.content;\n const cached = stylesheetStringCache.get(cssText);\n\n if (cached) return cached;\n\n const sheet = new CSSStyleSheet();\n\n try {\n sheet.replaceSync(cssText);\n stylesheetStringCache.set(cssText, sheet);\n } catch (err) {\n console.error(`[craftit:E2] style replace failed`, err);\n }\n\n return sheet;\n};\n"],"mappings":"oGAgBA,IAAM,EAAmC,OAAO,0BAA0B,CAEtE,EAAa,EAGJ,MAA8B,CACzC,EAAa,GAOF,EAAY,GAA4B,GAAG,EAAS,GAAG,EAAO,GAAK,SAAS,EAAE,IAsC3F,SAAgB,GAAiC,CAC/C,OAAA,EAAA,EAAA,QAAwB,KAAK,CAK/B,SAAgB,GAAmC,CACjD,MAAO,EAAE,CAgBX,SAAgB,EAAW,EAAc,EAAsB,EAAE,CAAc,CAC7E,IAAM,EAAS,CACb,WAAY,EACZ,OAAQ,EACR,UAAW,CACT,OAAO,GAEV,CASD,OAPA,OAAO,eAAe,EAAQ,EAAmB,CAC/C,aAAc,GACd,WAAY,GACZ,MAAO,GACP,SAAU,GACX,CAAC,CAEK,EAIT,IAAa,EAAgB,GAC3B,OAAO,GAAU,UAAY,CAAC,CAAC,GAAU,EAAkC,KAAuB,GAGpG,SAAgB,EAAc,EAA+D,CAC3F,OAAO,OAAO,GAAM,SAAW,CAAE,SAAU,EAAE,CAAE,KAAM,EAAG,CAAG,CAAE,SAAU,EAAE,WAAY,KAAM,EAAE,OAAQ,CAqGvG,IAAa,EAA6B,OAAO,qBAAqB,CAUzD,EAAU,GAAoC,CACzD,IAAM,EAAY,CAAC,GAAG,EAAI,CAE1B,IAAK,IAAI,EAAQ,EAAU,OAAS,EAAG,GAAS,EAAG,IACjD,EAAU,MAAU,EAKX,GAAW,EAAa,EAAc,IAAuB,CAExE,GAAI,OAAO,KAAK,EAAK,CAAE,CACrB,EAAG,gBAAgB,EAAK,CAExB,OAGE,GAAO,MAAQ,IAAQ,GACzB,EAAG,gBAAgB,EAAK,CACf,IAAQ,GACjB,EAAG,aAAa,EAAM,EAAK,WAAW,QAAQ,CAAG,OAAS,GAAG,CAE7D,EAAG,aAAa,EAAM,OAAO,EAAI,CAAC,EAKzB,GACX,EACA,EACA,EACA,IACiB,CACjB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,EAAQ,KAE/B,EAAG,oBAAoB,EAAM,EAAU,EAAQ,EAOjD,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,aAAa,GAAG,CAE7F,EAA8B,CAAE,IAAK,QAAS,IAAK,SAAU,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,CAG9F,EAAc,GAA2B,OAAO,EAAM,CAAC,QAAQ,WAAa,GAAM,EAAI,GAAG,CAiBzF,MAAmE,CAC9E,IAAM,EAAK,EAAA,gBAAgB,CAAC,GAE5B,QAAS,EAAgB,GAAG,IAAoB,CAC9C,EAAA,KAAK,OAAO,EAAI,OAAO,EAAM,CAAE,EAAK,OAAS,EAAI,CAAE,OAAQ,EAAK,GAAI,CAAG,IAAA,GAAU,IAa/E,EAAoB,UAAmC,CAC3D,OAAO,KAAK,SAID,GAAO,EAA+B,GAAG,IAAiC,CACrF,IAAI,EAAU,GAEd,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAGlC,GAFA,GAAW,EAAQ,GAEf,EAAI,EAAO,OAAQ,CACrB,IAAM,EAAI,EAAO,GAEjB,GAAW,GAAK,OAAO,GAAM,UAAY,YAAa,EAAK,EAAgB,QAAW,GAAK,GAI/F,MAAO,CAAE,QAAS,EAAQ,MAAM,CAAE,SAAU,EAAmB,EAG3D,EAAwB,IAAI,IAGrB,EAAkB,GAA6D,CAC1F,GAAI,aAAiB,cAAe,OAAO,EAE3C,IAAM,EAAU,OAAO,GAAU,SAAW,EAAQ,EAAM,QACpD,EAAS,EAAsB,IAAI,EAAQ,CAEjD,GAAI,EAAQ,OAAO,EAEnB,IAAM,EAAQ,IAAI,cAElB,GAAI,CACF,EAAM,YAAY,EAAQ,CAC1B,EAAsB,IAAI,EAAS,EAAM,OAClC,EAAK,CACZ,QAAQ,MAAM,oCAAqC,EAAI,CAGzD,OAAO"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal — Binding type system, compiler/runtime helpers, and engine internals.
|
|
3
|
+
*
|
|
4
|
+
* These types and helpers define the contract between the template compiler, binding engine,
|
|
5
|
+
* and component runtime.
|
|
6
|
+
* They are NOT part of the public API and importing directly is an unstable contract.
|
|
7
|
+
*
|
|
8
|
+
* Selected author-facing exports (such as css(), CSSResult, EmitFn, HTMLResult, Directive,
|
|
9
|
+
* ref(), and refs()) are re-exported from the main entry point.
|
|
10
|
+
*/
|
|
11
|
+
import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
|
|
12
|
+
/** @internal — resets the ID counter. Used by _resetCounters in test/test.ts. */
|
|
13
|
+
export declare const _resetIdCounter: () => void;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a unique, stable ID string — suitable for `aria-labelledby`, `aria-describedby`,
|
|
16
|
+
* and similar accessibility linkages. Call once per component instance (at setup time or inside `onMount`).
|
|
17
|
+
*/
|
|
18
|
+
export declare const createId: (prefix?: string) => string;
|
|
19
|
+
/**
|
|
20
|
+
* A reactive reference to a DOM element.
|
|
21
|
+
*
|
|
22
|
+
* Backed by a Signal — reactivity is built-in. Use with onElement()
|
|
23
|
+
* for first-class element lifecycle management.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const inputRef = ref<HTMLInputElement>();
|
|
27
|
+
*
|
|
28
|
+
* onElement(inputRef, (input) => {
|
|
29
|
+
* input.focus();
|
|
30
|
+
* return () => { }; // cleanup
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // In template
|
|
34
|
+
* <input ref=${inputRef} />
|
|
35
|
+
*/
|
|
36
|
+
export type Ref<T extends Element> = Signal<T | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Create a reactive element reference.
|
|
39
|
+
*
|
|
40
|
+
* Returns a Signal that tracks the mounted/unmounted state of a DOM element.
|
|
41
|
+
* Automatically reactive — use directly in effects or with onElement().
|
|
42
|
+
*
|
|
43
|
+
* @see onElement for element lifecycle integration
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const ref = ref<HTMLInputElement>();
|
|
47
|
+
* // Type: Signal<HTMLInputElement | null>
|
|
48
|
+
* // Automatically updates when element mounts/unmounts
|
|
49
|
+
*/
|
|
50
|
+
export declare function ref<T extends Element>(): Ref<T>;
|
|
51
|
+
export type Refs<T extends Element> = T[];
|
|
52
|
+
export declare function refs<T extends Element>(): Refs<T>;
|
|
53
|
+
export type RefCallback<T extends Element> = (el: T | null) => void;
|
|
54
|
+
export interface HTMLResult {
|
|
55
|
+
__bindings: Binding[];
|
|
56
|
+
__html: string;
|
|
57
|
+
toString(): string;
|
|
58
|
+
}
|
|
59
|
+
/** @internal — construct an HTMLResult from a pre-built html string and bindings. */
|
|
60
|
+
export declare function htmlResult(html: string, bindings?: Binding[]): HTMLResult;
|
|
61
|
+
/** @internal — strict HTMLResult runtime type guard. */
|
|
62
|
+
export declare const isHtmlResult: (value: unknown) => value is HTMLResult;
|
|
63
|
+
/** @internal — extract html and bindings from a string or HTMLResult. */
|
|
64
|
+
export declare function extractResult(v: string | HTMLResult): {
|
|
65
|
+
bindings: Binding[];
|
|
66
|
+
html: string;
|
|
67
|
+
};
|
|
68
|
+
export interface DirectiveContext {
|
|
69
|
+
/** The cleanup registration function for the component. */
|
|
70
|
+
registerCleanup: (fn: () => void) => void;
|
|
71
|
+
}
|
|
72
|
+
export interface Directive {
|
|
73
|
+
/** Invoked when the element is mounted in the DOM. */
|
|
74
|
+
mount?(el: HTMLElement, context: DirectiveContext): void;
|
|
75
|
+
/** Invoked by the template engine to render content (interpolation directives). */
|
|
76
|
+
render?(): HTMLResult | string;
|
|
77
|
+
}
|
|
78
|
+
export type TextBinding = {
|
|
79
|
+
signal: ReadonlySignal<unknown>;
|
|
80
|
+
type: 'text';
|
|
81
|
+
uid: string;
|
|
82
|
+
};
|
|
83
|
+
export type AttrBinding = {
|
|
84
|
+
mode: 'bool' | 'attr';
|
|
85
|
+
name: string;
|
|
86
|
+
signal?: ReadonlySignal<unknown>;
|
|
87
|
+
type: 'attr';
|
|
88
|
+
uid: string;
|
|
89
|
+
value?: unknown;
|
|
90
|
+
};
|
|
91
|
+
export type PropBinding = {
|
|
92
|
+
/** Optional writable source used for native two-way bridge (.value/.checked). */
|
|
93
|
+
model?: Signal<unknown>;
|
|
94
|
+
name: string;
|
|
95
|
+
signal?: ReadonlySignal<unknown>;
|
|
96
|
+
type: 'prop';
|
|
97
|
+
uid: string;
|
|
98
|
+
value?: unknown;
|
|
99
|
+
};
|
|
100
|
+
export type EventBinding = {
|
|
101
|
+
handler: (e: Event) => void;
|
|
102
|
+
modifiers?: {
|
|
103
|
+
capture?: boolean;
|
|
104
|
+
once?: boolean;
|
|
105
|
+
passive?: boolean;
|
|
106
|
+
prevent?: boolean;
|
|
107
|
+
self?: boolean;
|
|
108
|
+
stop?: boolean;
|
|
109
|
+
};
|
|
110
|
+
name: string;
|
|
111
|
+
type: 'event';
|
|
112
|
+
uid: string;
|
|
113
|
+
};
|
|
114
|
+
export type RefBinding = {
|
|
115
|
+
ref: Ref<Element> | Refs<Element> | RefCallback<Element>;
|
|
116
|
+
type: 'ref';
|
|
117
|
+
uid: string;
|
|
118
|
+
};
|
|
119
|
+
export type CallbackBinding = {
|
|
120
|
+
apply: (el: HTMLElement, registerCleanup: (fn: () => void) => void) => void;
|
|
121
|
+
type: 'callback';
|
|
122
|
+
uid: string;
|
|
123
|
+
};
|
|
124
|
+
export type HtmlBinding = {
|
|
125
|
+
keyed?: boolean;
|
|
126
|
+
signal: ReadonlySignal<{
|
|
127
|
+
bindings: Binding[];
|
|
128
|
+
html: string;
|
|
129
|
+
items?: Array<{
|
|
130
|
+
bindings: Binding[];
|
|
131
|
+
html: string;
|
|
132
|
+
}>;
|
|
133
|
+
keys?: (string | number)[];
|
|
134
|
+
}>;
|
|
135
|
+
type: 'html';
|
|
136
|
+
uid: string;
|
|
137
|
+
};
|
|
138
|
+
export type Binding = TextBinding | AttrBinding | PropBinding | EventBinding | RefBinding | CallbackBinding | HtmlBinding;
|
|
139
|
+
/** @internal — opaque marker for each() reactive results. */
|
|
140
|
+
export declare const EACH_SIGNAL: unique symbol;
|
|
141
|
+
/** @internal — binding element identifier attribute. */
|
|
142
|
+
export declare const CF_ID_ATTR = "u";
|
|
143
|
+
/** @internal — Iterate an iterable and call every function in it. */
|
|
144
|
+
export declare const runAll: (fns: Iterable<() => void>) => void;
|
|
145
|
+
/** @internal — Set an attribute on an element, handling boolean and null values. */
|
|
146
|
+
export declare const setAttr: (el: Element, name: string, val: unknown) => void;
|
|
147
|
+
/** @internal — Attach an event listener with automatic cleanup. */
|
|
148
|
+
export declare const listen: (el: EventTarget, name: string, handler: (e: any) => void, options?: AddEventListenerOptions) => (() => void);
|
|
149
|
+
export declare const toKebab: (str: string) => string;
|
|
150
|
+
/** @internal — Escape untrusted text for HTML text/attribute contexts. */
|
|
151
|
+
export declare const escapeHtml: (value: unknown) => string;
|
|
152
|
+
type NoDetail = void | undefined | never;
|
|
153
|
+
type KeysWithoutDetail<T extends Record<string, unknown>> = {
|
|
154
|
+
[P in keyof T]: [T[P]] extends [NoDetail] ? P : never;
|
|
155
|
+
}[keyof T];
|
|
156
|
+
export type EmitFn<T extends Record<string, unknown>> = {
|
|
157
|
+
<K extends KeysWithoutDetail<T>>(event: K): void;
|
|
158
|
+
<K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): void;
|
|
159
|
+
};
|
|
160
|
+
/** @internal — Create a type-safe custom event emitter for the current runtime host. */
|
|
161
|
+
export declare const createEmitFn: <T extends Record<string, unknown>>() => EmitFn<T>;
|
|
162
|
+
export type CSSResult = {
|
|
163
|
+
content: string;
|
|
164
|
+
toString(): string;
|
|
165
|
+
};
|
|
166
|
+
/** @internal — Compile CSS template strings into a CSSResult. */
|
|
167
|
+
export declare const css: (strings: TemplateStringsArray, ...values: unknown[]) => CSSResult;
|
|
168
|
+
/** @internal — Load a stylesheet string or CSSResult into an adoptedStyleSheet. */
|
|
169
|
+
export declare const loadStylesheet: (style: string | CSSStyleSheet | CSSResult) => CSSStyleSheet;
|
|
170
|
+
export {};
|
|
171
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAU,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAS7E,iFAAiF;AACjF,eAAO,MAAM,eAAe,QAAO,IAElC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,KAAG,MAA4D,CAAC;AAMxG;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,OAAO,IAAI,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,CAAC,SAAS,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAE/C;AAED,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC,EAAE,CAAC;AAE1C,wBAAgB,IAAI,CAAC,CAAC,SAAS,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAEjD;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;AAMpE,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,OAAO,EAAO,GAAG,UAAU,CAiB7E;AAED,wDAAwD;AACxD,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,UACiD,CAAC;AAEzG,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAE3F;AAMD,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,KAAK,CAAC,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACzD,mFAAmF;IACnF,MAAM,CAAC,IAAI,UAAU,GAAG,MAAM,CAAC;CAChC;AAMD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACzD,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,CAAC,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC;IAC5E,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,cAAc,CAAC;QACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACrD,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,OAAO,GACf,WAAW,GACX,WAAW,GACX,WAAW,GACX,YAAY,GACZ,UAAU,GACV,eAAe,GACf,WAAW,CAAC;AAMhB,6DAA6D;AAC7D,eAAO,MAAM,WAAW,EAAE,OAAO,MAAqC,CAAC;AAEvE,wDAAwD;AACxD,eAAO,MAAM,UAAU,MAAM,CAAC;AAM9B,qEAAqE;AACrE,eAAO,MAAM,MAAM,GAAI,KAAK,QAAQ,CAAC,MAAM,IAAI,CAAC,KAAG,IAMlD,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,OAAO,GAAI,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,OAAO,KAAG,IAejE,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,MAAM,GACjB,IAAI,WAAW,EACf,MAAM,MAAM,EACZ,SAAS,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,EACzB,UAAU,uBAAuB,KAChC,CAAC,MAAM,IAAI,CAMb,CAAC;AAMF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAA6D,CAAC;AAIpG,0EAA0E;AAC1E,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,MAA0D,CAAC;AAMvG,KAAK,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AACzC,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;KACzD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK;CACtD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACtD,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACjD,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAClF,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAK,MAAM,CAAC,CAAC,CAM1E,CAAC;AAMF,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,IAAI,MAAM,CAAC;CACpB,CAAC;AAMF,iEAAiE;AACjE,eAAO,MAAM,GAAG,GAAI,SAAS,oBAAoB,EAAE,GAAG,QAAQ,OAAO,EAAE,KAAG,SAczE,CAAC;AAIF,mFAAmF;AACnF,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,GAAG,aAAa,GAAG,SAAS,KAAG,aAkB1E,CAAC"}
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{currentRuntime as e}from"./runtime-core.js";import{fire as t}from"./runtime.js";import{signal as n}from"@vielzeug/stateit";var r=Symbol(`craftit.htmlResultBrand`),i=0,a=()=>{i=0},o=e=>`${e?`${e}-`:`cft-`}${++i}`;function s(){return n(null)}function c(){return[]}function l(e,t=[]){let n={__bindings:t,__html:e,toString(){return e}};return Object.defineProperty(n,r,{configurable:!1,enumerable:!1,value:!0,writable:!1}),n}var u=e=>typeof e==`object`&&!!e&&e[r]===!0;function d(e){return typeof e==`string`?{bindings:[],html:e}:{bindings:e.__bindings,html:e.__html}}var f=Symbol(`craftit.eachSignal`),p=e=>{let t=[...e];for(let e=t.length-1;e>=0;e--)t[e]?.()},m=(e,t,n)=>{if(/^on/i.test(t)){e.removeAttribute(t);return}n==null||n===!1?e.removeAttribute(t):n===!0?e.setAttribute(t,t.startsWith(`aria-`)?`true`:``):e.setAttribute(t,String(n))},h=(e,t,n,r)=>{let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},g=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),_={"'":`'`,'"':`"`,"&":`&`,"<":`<`,">":`>`},v=e=>String(e).replace(/[&<>"']/g,e=>_[e]),y=()=>{let n=e().el;return((e,...r)=>{t.custom(n,String(e),r.length>0?{detail:r[0]}:void 0)})},b=function(){return this.content},x=(e,...t)=>{let n=``;for(let r=0;r<e.length;r++)if(n+=e[r],r<t.length){let e=t[r];n+=e&&typeof e==`object`&&`content`in e?e.content:e??``}return{content:n.trim(),toString:b}},S=new Map,C=e=>{if(e instanceof CSSStyleSheet)return e;let t=typeof e==`string`?e:e.content,n=S.get(t);if(n)return n;let r=new CSSStyleSheet;try{r.replaceSync(t),S.set(t,r)}catch(e){console.error(`[craftit:E2] style replace failed`,e)}return r};export{f as EACH_SIGNAL,a as _resetIdCounter,y as createEmitFn,o as createId,x as css,v as escapeHtml,d as extractResult,l as htmlResult,u as isHtmlResult,h as listen,C as loadStylesheet,s as ref,c as refs,p as runAll,m as setAttr,g as toKebab};
|
|
2
|
+
//# sourceMappingURL=internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.js","names":[],"sources":["../src/internal.ts"],"sourcesContent":["/**\n * @internal — Binding type system, compiler/runtime helpers, and engine internals.\n *\n * These types and helpers define the contract between the template compiler, binding engine,\n * and component runtime.\n * They are NOT part of the public API and importing directly is an unstable contract.\n *\n * Selected author-facing exports (such as css(), CSSResult, EmitFn, HTMLResult, Directive,\n * ref(), and refs()) are re-exported from the main entry point.\n */\n\nimport { signal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { fire } from './runtime';\nimport { currentRuntime } from './runtime-core';\n\nconst HTML_RESULT_BRAND: unique symbol = Symbol('craftit.htmlResultBrand');\n\nlet _idCounter = 0;\n\n/** @internal — resets the ID counter. Used by _resetCounters in test/test.ts. */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n};\n\n/**\n * Creates a unique, stable ID string — suitable for `aria-labelledby`, `aria-describedby`,\n * and similar accessibility linkages. Call once per component instance (at setup time or inside `onMount`).\n */\nexport const createId = (prefix?: string): string => `${prefix ? `${prefix}-` : 'cft-'}${++_idCounter}`;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REF TYPES\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * A reactive reference to a DOM element.\n *\n * Backed by a Signal — reactivity is built-in. Use with onElement()\n * for first-class element lifecycle management.\n *\n * @example\n * const inputRef = ref<HTMLInputElement>();\n *\n * onElement(inputRef, (input) => {\n * input.focus();\n * return () => { }; // cleanup\n * });\n *\n * // In template\n * <input ref=${inputRef} />\n */\nexport type Ref<T extends Element> = Signal<T | null>;\n\n/**\n * Create a reactive element reference.\n *\n * Returns a Signal that tracks the mounted/unmounted state of a DOM element.\n * Automatically reactive — use directly in effects or with onElement().\n *\n * @see onElement for element lifecycle integration\n *\n * @example\n * const ref = ref<HTMLInputElement>();\n * // Type: Signal<HTMLInputElement | null>\n * // Automatically updates when element mounts/unmounts\n */\nexport function ref<T extends Element>(): Ref<T> {\n return signal<T | null>(null);\n}\n\nexport type Refs<T extends Element> = T[];\n\nexport function refs<T extends Element>(): Refs<T> {\n return [];\n}\n\nexport type RefCallback<T extends Element> = (el: T | null) => void;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// HTML RESULT\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface HTMLResult {\n __bindings: Binding[];\n __html: string;\n toString(): string;\n}\n\n/** @internal — construct an HTMLResult from a pre-built html string and bindings. */\nexport function htmlResult(html: string, bindings: Binding[] = []): HTMLResult {\n const result = {\n __bindings: bindings,\n __html: html,\n toString() {\n return html;\n },\n };\n\n Object.defineProperty(result, HTML_RESULT_BRAND, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n\n return result as HTMLResult;\n}\n\n/** @internal — strict HTMLResult runtime type guard. */\nexport const isHtmlResult = (value: unknown): value is HTMLResult =>\n typeof value === 'object' && !!value && (value as Record<symbol, unknown>)[HTML_RESULT_BRAND] === true;\n\n/** @internal — extract html and bindings from a string or HTMLResult. */\nexport function extractResult(v: string | HTMLResult): { bindings: Binding[]; html: string } {\n return typeof v === 'string' ? { bindings: [], html: v } : { bindings: v.__bindings, html: v.__html };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DIRECTIVES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface DirectiveContext {\n /** The cleanup registration function for the component. */\n registerCleanup: (fn: () => void) => void;\n}\n\nexport interface Directive {\n /** Invoked when the element is mounted in the DOM. */\n mount?(el: HTMLElement, context: DirectiveContext): void;\n /** Invoked by the template engine to render content (interpolation directives). */\n render?(): HTMLResult | string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// BINDING TYPES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type TextBinding = {\n signal: ReadonlySignal<unknown>;\n type: 'text';\n uid: string;\n};\n\nexport type AttrBinding = {\n mode: 'bool' | 'attr';\n name: string;\n signal?: ReadonlySignal<unknown>;\n type: 'attr';\n uid: string;\n value?: unknown;\n};\n\nexport type PropBinding = {\n /** Optional writable source used for native two-way bridge (.value/.checked). */\n model?: Signal<unknown>;\n name: string;\n signal?: ReadonlySignal<unknown>;\n type: 'prop';\n uid: string;\n value?: unknown;\n};\n\nexport type EventBinding = {\n handler: (e: Event) => void;\n modifiers?: {\n capture?: boolean;\n once?: boolean;\n passive?: boolean;\n prevent?: boolean;\n self?: boolean;\n stop?: boolean;\n };\n name: string;\n type: 'event';\n uid: string;\n};\n\nexport type RefBinding = {\n ref: Ref<Element> | Refs<Element> | RefCallback<Element>;\n type: 'ref';\n uid: string;\n};\n\nexport type CallbackBinding = {\n apply: (el: HTMLElement, registerCleanup: (fn: () => void) => void) => void;\n type: 'callback';\n uid: string;\n};\n\nexport type HtmlBinding = {\n keyed?: boolean;\n signal: ReadonlySignal<{\n bindings: Binding[];\n html: string;\n items?: Array<{ bindings: Binding[]; html: string }>;\n keys?: (string | number)[];\n }>;\n type: 'html';\n uid: string;\n};\n\nexport type Binding =\n | TextBinding\n | AttrBinding\n | PropBinding\n | EventBinding\n | RefBinding\n | CallbackBinding\n | HtmlBinding;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL MARKERS & CONSTANTS\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @internal — opaque marker for each() reactive results. */\nexport const EACH_SIGNAL: unique symbol = Symbol('craftit.eachSignal');\n\n/** @internal — binding element identifier attribute. */\nexport const CF_ID_ATTR = 'u';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL DOM & EVENT UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** @internal — Iterate an iterable and call every function in it. */\nexport const runAll = (fns: Iterable<() => void>): void => {\n const callbacks = [...fns];\n\n for (let index = callbacks.length - 1; index >= 0; index--) {\n callbacks[index]?.();\n }\n};\n\n/** @internal — Set an attribute on an element, handling boolean and null values. */\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n // Avoid inline event-handler attributes (onclick, onerror, ...) to reduce injection risk.\n if (/^on/i.test(name)) {\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n } else if (val === true) {\n el.setAttribute(name, name.startsWith('aria-') ? 'true' : '');\n } else {\n el.setAttribute(name, String(val));\n }\n};\n\n/** @internal — Attach an event listener with automatic cleanup. */\nexport const listen = (\n el: EventTarget,\n name: string,\n handler: (e: any) => void,\n options?: AddEventListenerOptions,\n): (() => void) => {\n const listener: EventListener = handler as EventListener;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL STRING UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nconst ESC: Record<string, string> = { \"'\": ''', '\"': '"', '&': '&', '<': '<', '>': '>' };\n\n/** @internal — Escape untrusted text for HTML text/attribute contexts. */\nexport const escapeHtml = (value: unknown): string => String(value).replace(/[&<>\"']/g, (c) => ESC[c]);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL EMIT TYPES & HELPERS\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\nexport type EmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): void;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): void;\n};\n\n/** @internal — Create a type-safe custom event emitter for the current runtime host. */\nexport const createEmitFn = <T extends Record<string, unknown>>(): EmitFn<T> => {\n const el = currentRuntime().el;\n\n return ((event: keyof T, ...rest: unknown[]) => {\n fire.custom(el, String(event), rest.length > 0 ? { detail: rest[0] } : undefined);\n }) as EmitFn<T>;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// INTERNAL CSS & STYLESHEET UTILITIES\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type CSSResult = {\n content: string;\n toString(): string;\n};\n\nconst cssResultToString = function (this: CSSResult): string {\n return this.content;\n};\n\n/** @internal — Compile CSS template strings into a CSSResult. */\nexport const css = (strings: TemplateStringsArray, ...values: unknown[]): CSSResult => {\n let content = '';\n\n for (let i = 0; i < strings.length; i++) {\n content += strings[i];\n\n if (i < values.length) {\n const v = values[i];\n\n content += v && typeof v === 'object' && 'content' in v ? (v as CSSResult).content : (v ?? '');\n }\n }\n\n return { content: content.trim(), toString: cssResultToString };\n};\n\nconst stylesheetStringCache = new Map<string, CSSStyleSheet>();\n\n/** @internal — Load a stylesheet string or CSSResult into an adoptedStyleSheet. */\nexport const loadStylesheet = (style: string | CSSStyleSheet | CSSResult): CSSStyleSheet => {\n if (style instanceof CSSStyleSheet) return style;\n\n const cssText = typeof style === 'string' ? style : style.content;\n const cached = stylesheetStringCache.get(cssText);\n\n if (cached) return cached;\n\n const sheet = new CSSStyleSheet();\n\n try {\n sheet.replaceSync(cssText);\n stylesheetStringCache.set(cssText, sheet);\n } catch (err) {\n console.error(`[craftit:E2] style replace failed`, err);\n }\n\n return sheet;\n};\n"],"mappings":"kIAgBA,IAAM,EAAmC,OAAO,0BAA0B,CAEtE,EAAa,EAGJ,MAA8B,CACzC,EAAa,GAOF,EAAY,GAA4B,GAAG,EAAS,GAAG,EAAO,GAAK,SAAS,EAAE,IAsC3F,SAAgB,GAAiC,CAC/C,OAAO,EAAiB,KAAK,CAK/B,SAAgB,GAAmC,CACjD,MAAO,EAAE,CAgBX,SAAgB,EAAW,EAAc,EAAsB,EAAE,CAAc,CAC7E,IAAM,EAAS,CACb,WAAY,EACZ,OAAQ,EACR,UAAW,CACT,OAAO,GAEV,CASD,OAPA,OAAO,eAAe,EAAQ,EAAmB,CAC/C,aAAc,GACd,WAAY,GACZ,MAAO,GACP,SAAU,GACX,CAAC,CAEK,EAIT,IAAa,EAAgB,GAC3B,OAAO,GAAU,UAAY,CAAC,CAAC,GAAU,EAAkC,KAAuB,GAGpG,SAAgB,EAAc,EAA+D,CAC3F,OAAO,OAAO,GAAM,SAAW,CAAE,SAAU,EAAE,CAAE,KAAM,EAAG,CAAG,CAAE,SAAU,EAAE,WAAY,KAAM,EAAE,OAAQ,CAqGvG,IAAa,EAA6B,OAAO,qBAAqB,CAUzD,EAAU,GAAoC,CACzD,IAAM,EAAY,CAAC,GAAG,EAAI,CAE1B,IAAK,IAAI,EAAQ,EAAU,OAAS,EAAG,GAAS,EAAG,IACjD,EAAU,MAAU,EAKX,GAAW,EAAa,EAAc,IAAuB,CAExE,GAAI,OAAO,KAAK,EAAK,CAAE,CACrB,EAAG,gBAAgB,EAAK,CAExB,OAGE,GAAO,MAAQ,IAAQ,GACzB,EAAG,gBAAgB,EAAK,CACf,IAAQ,GACjB,EAAG,aAAa,EAAM,EAAK,WAAW,QAAQ,CAAG,OAAS,GAAG,CAE7D,EAAG,aAAa,EAAM,OAAO,EAAI,CAAC,EAKzB,GACX,EACA,EACA,EACA,IACiB,CACjB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,EAAQ,KAE/B,EAAG,oBAAoB,EAAM,EAAU,EAAQ,EAOjD,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,aAAa,GAAG,CAE7F,EAA8B,CAAE,IAAK,QAAS,IAAK,SAAU,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,CAG9F,EAAc,GAA2B,OAAO,EAAM,CAAC,QAAQ,WAAa,GAAM,EAAI,GAAG,CAiBzF,MAAmE,CAC9E,IAAM,EAAK,GAAgB,CAAC,GAE5B,QAAS,EAAgB,GAAG,IAAoB,CAC9C,EAAK,OAAO,EAAI,OAAO,EAAM,CAAE,EAAK,OAAS,EAAI,CAAE,OAAQ,EAAK,GAAI,CAAG,IAAA,GAAU,IAa/E,EAAoB,UAAmC,CAC3D,OAAO,KAAK,SAID,GAAO,EAA+B,GAAG,IAAiC,CACrF,IAAI,EAAU,GAEd,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAGlC,GAFA,GAAW,EAAQ,GAEf,EAAI,EAAO,OAAQ,CACrB,IAAM,EAAI,EAAO,GAEjB,GAAW,GAAK,OAAO,GAAM,UAAY,YAAa,EAAK,EAAgB,QAAW,GAAK,GAI/F,MAAO,CAAE,QAAS,EAAQ,MAAM,CAAE,SAAU,EAAmB,EAG3D,EAAwB,IAAI,IAGrB,EAAkB,GAA6D,CAC1F,GAAI,aAAiB,cAAe,OAAO,EAE3C,IAAM,EAAU,OAAO,GAAU,SAAW,EAAQ,EAAM,QACpD,EAAS,EAAsB,IAAI,EAAQ,CAEjD,GAAI,EAAQ,OAAO,EAEnB,IAAM,EAAQ,IAAI,cAElB,GAAI,CACF,EAAM,YAAY,EAAQ,CAC1B,EAAsB,IAAI,EAAS,EAAM,OAClC,EAAK,CACZ,QAAQ,MAAM,oCAAqC,EAAI,CAGzD,OAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`../runtime-lifecycle.cjs`);let t=require(`@vielzeug/stateit`);var n=(n,r)=>{let i=(0,t.signal)(null),a=new IntersectionObserver(([e])=>{e&&(i.value=e)},r);return a.observe(n),e.onCleanup(()=>a.disconnect()),i};exports.intersectionObserver=n;
|
|
2
|
+
//# sourceMappingURL=intersection-observe.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intersection-observe.cjs","names":[],"sources":["../../src/observers/intersection-observe.ts"],"sourcesContent":["import { signal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { onCleanup } from '../runtime-lifecycle';\n\n/**\n * Observes an element's intersection with the viewport (or a given root) via\n * `IntersectionObserver`. Returns a `ReadonlySignal` that updates whenever the\n * intersection ratio changes.\n * Must be called inside an {@link onMount} callback.\n */\nexport const intersectionObserver = (\n el: Element,\n options?: IntersectionObserverInit,\n): ReadonlySignal<IntersectionObserverEntry | null> => {\n const entry = signal<IntersectionObserverEntry | null>(null);\n const io = new IntersectionObserver(([nextEntry]) => {\n if (nextEntry) entry.value = nextEntry;\n }, options);\n\n io.observe(el);\n onCleanup(() => io.disconnect());\n\n return entry;\n};\n"],"mappings":"+EAUA,IAAa,GACX,EACA,IACqD,CACrD,IAAM,GAAA,EAAA,EAAA,QAAiD,KAAK,CACtD,EAAK,IAAI,sBAAsB,CAAC,KAAe,CAC/C,IAAW,EAAM,MAAQ,IAC5B,EAAQ,CAKX,OAHA,EAAG,QAAQ,EAAG,CACd,EAAA,cAAgB,EAAG,YAAY,CAAC,CAEzB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReadonlySignal } from '@vielzeug/stateit';
|
|
2
|
+
/**
|
|
3
|
+
* Observes an element's intersection with the viewport (or a given root) via
|
|
4
|
+
* `IntersectionObserver`. Returns a `ReadonlySignal` that updates whenever the
|
|
5
|
+
* intersection ratio changes.
|
|
6
|
+
* Must be called inside an {@link onMount} callback.
|
|
7
|
+
*/
|
|
8
|
+
export declare const intersectionObserver: (el: Element, options?: IntersectionObserverInit) => ReadonlySignal<IntersectionObserverEntry | null>;
|
|
9
|
+
//# sourceMappingURL=intersection-observe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intersection-observe.d.ts","sourceRoot":"","sources":["../../src/observers/intersection-observe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIhE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,IAAI,OAAO,EACX,UAAU,wBAAwB,KACjC,cAAc,CAAC,yBAAyB,GAAG,IAAI,CAUjD,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{onCleanup as e}from"../runtime-lifecycle.js";import{signal as t}from"@vielzeug/stateit";var n=(n,r)=>{let i=t(null),a=new IntersectionObserver(([e])=>{e&&(i.value=e)},r);return a.observe(n),e(()=>a.disconnect()),i};export{n as intersectionObserver};
|
|
2
|
+
//# sourceMappingURL=intersection-observe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intersection-observe.js","names":[],"sources":["../../src/observers/intersection-observe.ts"],"sourcesContent":["import { signal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { onCleanup } from '../runtime-lifecycle';\n\n/**\n * Observes an element's intersection with the viewport (or a given root) via\n * `IntersectionObserver`. Returns a `ReadonlySignal` that updates whenever the\n * intersection ratio changes.\n * Must be called inside an {@link onMount} callback.\n */\nexport const intersectionObserver = (\n el: Element,\n options?: IntersectionObserverInit,\n): ReadonlySignal<IntersectionObserverEntry | null> => {\n const entry = signal<IntersectionObserverEntry | null>(null);\n const io = new IntersectionObserver(([nextEntry]) => {\n if (nextEntry) entry.value = nextEntry;\n }, options);\n\n io.observe(el);\n onCleanup(() => io.disconnect());\n\n return entry;\n};\n"],"mappings":"+FAUA,IAAa,GACX,EACA,IACqD,CACrD,IAAM,EAAQ,EAAyC,KAAK,CACtD,EAAK,IAAI,sBAAsB,CAAC,KAAe,CAC/C,IAAW,EAAM,MAAQ,IAC5B,EAAQ,CAKX,OAHA,EAAG,QAAQ,EAAG,CACd,MAAgB,EAAG,YAAY,CAAC,CAEzB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`../runtime-lifecycle.cjs`);let t=require(`@vielzeug/stateit`);var n=n=>{let r=window.matchMedia(n),i=(0,t.signal)(r.matches),a=e=>{i.value=e.matches};return r.addEventListener(`change`,a),e.onCleanup(()=>r.removeEventListener(`change`,a)),i};exports.mediaObserver=n;
|
|
2
|
+
//# sourceMappingURL=media-observe.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-observe.cjs","names":[],"sources":["../../src/observers/media-observe.ts"],"sourcesContent":["import { signal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { onCleanup } from '../runtime-lifecycle';\n\n/**\n * Observes a CSS media query via `window.matchMedia`. Returns a `ReadonlySignal`\n * that is `true` when the query matches and `false` when it does not.\n * Must be called inside an {@link onMount} callback.\n */\nexport const mediaObserver = (query: string): ReadonlySignal<boolean> => {\n const mql = window.matchMedia(query);\n const matches = signal(mql.matches);\n const handler = (e: MediaQueryListEvent) => {\n matches.value = e.matches;\n };\n\n mql.addEventListener('change', handler);\n onCleanup(() => mql.removeEventListener('change', handler));\n\n return matches;\n};\n"],"mappings":"+EASA,IAAa,EAAiB,GAA2C,CACvE,IAAM,EAAM,OAAO,WAAW,EAAM,CAC9B,GAAA,EAAA,EAAA,QAAiB,EAAI,QAAQ,CAC7B,EAAW,GAA2B,CAC1C,EAAQ,MAAQ,EAAE,SAMpB,OAHA,EAAI,iBAAiB,SAAU,EAAQ,CACvC,EAAA,cAAgB,EAAI,oBAAoB,SAAU,EAAQ,CAAC,CAEpD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReadonlySignal } from '@vielzeug/stateit';
|
|
2
|
+
/**
|
|
3
|
+
* Observes a CSS media query via `window.matchMedia`. Returns a `ReadonlySignal`
|
|
4
|
+
* that is `true` when the query matches and `false` when it does not.
|
|
5
|
+
* Must be called inside an {@link onMount} callback.
|
|
6
|
+
*/
|
|
7
|
+
export declare const mediaObserver: (query: string) => ReadonlySignal<boolean>;
|
|
8
|
+
//# sourceMappingURL=media-observe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-observe.d.ts","sourceRoot":"","sources":["../../src/observers/media-observe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIhE;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,cAAc,CAAC,OAAO,CAWnE,CAAC"}
|