@vielzeug/craftit 2.1.0 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -124
- package/dist/controls/a11y-control.cjs +1 -1
- package/dist/controls/a11y-control.cjs.map +1 -1
- package/dist/controls/a11y-control.d.ts +1 -1
- package/dist/controls/a11y-control.d.ts.map +1 -1
- package/dist/controls/a11y-control.js +1 -1
- package/dist/controls/a11y-control.js.map +1 -1
- package/dist/controls/checkable-control.cjs +1 -1
- package/dist/controls/checkable-control.cjs.map +1 -1
- package/dist/controls/checkable-control.d.ts +7 -7
- package/dist/controls/checkable-control.d.ts.map +1 -1
- package/dist/controls/checkable-control.js +1 -1
- package/dist/controls/checkable-control.js.map +1 -1
- package/dist/controls/choice-field-control.cjs +2 -0
- package/dist/controls/choice-field-control.cjs.map +1 -0
- package/dist/controls/choice-field-control.d.ts +3 -0
- package/dist/controls/choice-field-control.d.ts.map +1 -0
- package/dist/controls/choice-field-control.js +2 -0
- package/dist/controls/choice-field-control.js.map +1 -0
- package/dist/controls/field-control.cjs +1 -1
- package/dist/controls/field-control.cjs.map +1 -1
- package/dist/controls/field-control.d.ts +28 -73
- package/dist/controls/field-control.d.ts.map +1 -1
- package/dist/controls/field-control.js +1 -1
- package/dist/controls/field-control.js.map +1 -1
- package/dist/controls/index.d.ts +11 -9
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/internal/control-state.cjs +1 -1
- package/dist/controls/internal/control-state.cjs.map +1 -1
- package/dist/controls/internal/control-state.d.ts +6 -4
- package/dist/controls/internal/control-state.d.ts.map +1 -1
- package/dist/controls/internal/control-state.js +1 -1
- package/dist/controls/internal/control-state.js.map +1 -1
- package/dist/controls/internal/keyboard-utils.cjs.map +1 -1
- package/dist/controls/internal/keyboard-utils.js.map +1 -1
- package/dist/controls/internal/number-utils.cjs.map +1 -1
- package/dist/controls/internal/number-utils.js.map +1 -1
- package/dist/controls/internal/validation-utils.cjs.map +1 -1
- package/dist/controls/internal/validation-utils.js.map +1 -1
- package/dist/controls/list-control.cjs +1 -1
- package/dist/controls/list-control.cjs.map +1 -1
- package/dist/controls/list-control.d.ts +10 -8
- package/dist/controls/list-control.d.ts.map +1 -1
- package/dist/controls/list-control.js +1 -1
- package/dist/controls/list-control.js.map +1 -1
- package/dist/controls/overlay-control.cjs +1 -1
- package/dist/controls/overlay-control.cjs.map +1 -1
- package/dist/controls/overlay-control.d.ts +17 -14
- package/dist/controls/overlay-control.d.ts.map +1 -1
- package/dist/controls/overlay-control.js +1 -1
- package/dist/controls/overlay-control.js.map +1 -1
- package/dist/controls/popup-list-control.cjs +2 -0
- package/dist/controls/popup-list-control.cjs.map +1 -0
- package/dist/controls/popup-list-control.d.ts +160 -0
- package/dist/controls/popup-list-control.d.ts.map +1 -0
- package/dist/controls/popup-list-control.js +2 -0
- package/dist/controls/popup-list-control.js.map +1 -0
- package/dist/controls/press-control.cjs.map +1 -1
- package/dist/controls/press-control.js.map +1 -1
- package/dist/controls/slider-control.cjs.map +1 -1
- package/dist/controls/slider-control.js.map +1 -1
- package/dist/controls/spinner-control.cjs.map +1 -1
- package/dist/controls/spinner-control.js.map +1 -1
- package/dist/controls/swipe-control.cjs +2 -0
- package/dist/controls/swipe-control.cjs.map +1 -0
- package/dist/controls/swipe-control.d.ts +32 -0
- package/dist/controls/swipe-control.d.ts.map +1 -0
- package/dist/controls/swipe-control.js +2 -0
- package/dist/controls/swipe-control.js.map +1 -0
- package/dist/controls/text-field-control.cjs +2 -0
- package/dist/controls/text-field-control.cjs.map +1 -0
- package/dist/controls/text-field-control.d.ts +3 -0
- package/dist/controls/text-field-control.d.ts.map +1 -0
- package/dist/controls/text-field-control.js +2 -0
- package/dist/controls/text-field-control.js.map +1 -0
- package/dist/controls.cjs +1 -1
- package/dist/controls.js +1 -1
- package/dist/craftit.cjs +1 -1
- package/dist/craftit.cjs.map +1 -1
- package/dist/craftit.js +1 -1
- package/dist/craftit.js.map +1 -1
- package/dist/directives/classMap.cjs +2 -0
- package/dist/directives/classMap.cjs.map +1 -0
- package/dist/directives/classMap.d.ts +19 -0
- package/dist/directives/classMap.d.ts.map +1 -0
- package/dist/directives/classMap.js +2 -0
- package/dist/directives/classMap.js.map +1 -0
- package/dist/directives/each.cjs +1 -1
- package/dist/directives/each.cjs.map +1 -1
- package/dist/directives/each.d.ts +5 -30
- package/dist/directives/each.d.ts.map +1 -1
- package/dist/directives/each.js +1 -1
- package/dist/directives/each.js.map +1 -1
- package/dist/directives/guard.cjs +2 -0
- package/dist/directives/guard.cjs.map +1 -0
- package/dist/directives/guard.d.ts +10 -0
- package/dist/directives/guard.d.ts.map +1 -0
- package/dist/directives/guard.js +2 -0
- package/dist/directives/guard.js.map +1 -0
- package/dist/directives/live.cjs +2 -0
- package/dist/directives/live.cjs.map +1 -0
- package/dist/directives/live.d.ts +23 -0
- package/dist/directives/live.d.ts.map +1 -0
- package/dist/directives/live.js +2 -0
- package/dist/directives/live.js.map +1 -0
- package/dist/directives/raw.cjs +1 -1
- package/dist/directives/raw.cjs.map +1 -1
- package/dist/directives/raw.d.ts +3 -5
- package/dist/directives/raw.d.ts.map +1 -1
- package/dist/directives/raw.js +1 -1
- package/dist/directives/raw.js.map +1 -1
- package/dist/directives/resource.cjs +2 -0
- package/dist/directives/resource.cjs.map +1 -0
- package/dist/directives/resource.d.ts +32 -0
- package/dist/directives/resource.d.ts.map +1 -0
- package/dist/directives/resource.js +2 -0
- package/dist/directives/resource.js.map +1 -0
- package/dist/directives/styleMap.cjs +2 -0
- package/dist/directives/styleMap.cjs.map +1 -0
- package/dist/directives/styleMap.d.ts +11 -0
- package/dist/directives/styleMap.d.ts.map +1 -0
- package/dist/directives/styleMap.js +2 -0
- package/dist/directives/styleMap.js.map +1 -0
- package/dist/directives/when.cjs +1 -1
- package/dist/directives/when.cjs.map +1 -1
- package/dist/directives/when.d.ts +6 -19
- package/dist/directives/when.d.ts.map +1 -1
- package/dist/directives/when.js +1 -1
- package/dist/directives/when.js.map +1 -1
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -0
- package/dist/form.cjs +1 -1
- package/dist/form.cjs.map +1 -1
- package/dist/form.d.ts +3 -17
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +1 -1
- package/dist/form.js.map +1 -1
- package/dist/host.cjs +1 -1
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.ts +40 -37
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +1 -1
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +16 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal.cjs +1 -1
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.ts +60 -120
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/observers/index.d.ts +1 -0
- package/dist/observers/index.d.ts.map +1 -1
- package/dist/observers/intersection-observe.cjs +1 -1
- package/dist/observers/intersection-observe.cjs.map +1 -1
- package/dist/observers/intersection-observe.d.ts +1 -1
- package/dist/observers/intersection-observe.js +1 -1
- package/dist/observers/intersection-observe.js.map +1 -1
- package/dist/observers/media-observe.cjs +1 -1
- package/dist/observers/media-observe.cjs.map +1 -1
- package/dist/observers/media-observe.d.ts +1 -1
- package/dist/observers/media-observe.js +1 -1
- package/dist/observers/media-observe.js.map +1 -1
- package/dist/observers/mutation-observe.cjs +2 -0
- package/dist/observers/mutation-observe.cjs.map +1 -0
- package/dist/observers/mutation-observe.d.ts +10 -0
- package/dist/observers/mutation-observe.d.ts.map +1 -0
- package/dist/observers/mutation-observe.js +2 -0
- package/dist/observers/mutation-observe.js.map +1 -0
- package/dist/observers/resize-observe.cjs +1 -1
- package/dist/observers/resize-observe.cjs.map +1 -1
- package/dist/observers/resize-observe.d.ts +1 -1
- package/dist/observers/resize-observe.js +1 -1
- package/dist/observers/resize-observe.js.map +1 -1
- package/dist/observers.cjs +1 -1
- package/dist/observers.js +1 -1
- package/dist/props.cjs +1 -1
- package/dist/props.cjs.map +1 -1
- package/dist/props.d.ts +18 -31
- package/dist/props.d.ts.map +1 -1
- package/dist/props.js +1 -1
- package/dist/props.js.map +1 -1
- package/dist/registration.cjs +1 -1
- package/dist/registration.cjs.map +1 -1
- package/dist/registration.d.ts +27 -7
- package/dist/registration.d.ts.map +1 -1
- package/dist/registration.js +1 -1
- package/dist/registration.js.map +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.ts +29 -17
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/template-bindings.cjs +1 -1
- package/dist/template-bindings.cjs.map +1 -1
- package/dist/template-bindings.d.ts +10 -47
- package/dist/template-bindings.d.ts.map +1 -1
- package/dist/template-bindings.js +1 -1
- package/dist/template-bindings.js.map +1 -1
- package/dist/template-compiler.cjs +1 -1
- package/dist/template-compiler.cjs.map +1 -1
- package/dist/template-compiler.d.ts +1 -21
- package/dist/template-compiler.d.ts.map +1 -1
- package/dist/template-compiler.js +1 -1
- package/dist/template-compiler.js.map +1 -1
- package/dist/testing/testing.cjs +1 -1
- package/dist/testing/testing.cjs.map +1 -1
- package/dist/testing/testing.d.ts +12 -5
- package/dist/testing/testing.d.ts.map +1 -1
- package/dist/testing/testing.js +1 -1
- package/dist/testing/testing.js.map +1 -1
- package/package.json +6 -12
- package/dist/component.cjs +0 -2
- package/dist/component.cjs.map +0 -1
- package/dist/component.d.ts +0 -39
- package/dist/component.d.ts.map +0 -1
- package/dist/component.js +0 -2
- package/dist/component.js.map +0 -1
- package/dist/controls/list-key-control.cjs +0 -2
- package/dist/controls/list-key-control.cjs.map +0 -1
- package/dist/controls/list-key-control.d.ts +0 -14
- package/dist/controls/list-key-control.d.ts.map +0 -1
- package/dist/controls/list-key-control.js +0 -2
- package/dist/controls/list-key-control.js.map +0 -1
- package/dist/directives/attr.cjs +0 -2
- package/dist/directives/attr.cjs.map +0 -1
- package/dist/directives/attr.d.ts +0 -12
- package/dist/directives/attr.d.ts.map +0 -1
- package/dist/directives/attr.js +0 -2
- package/dist/directives/attr.js.map +0 -1
- package/dist/directives/bind.cjs +0 -2
- package/dist/directives/bind.cjs.map +0 -1
- package/dist/directives/bind.d.ts +0 -38
- package/dist/directives/bind.d.ts.map +0 -1
- package/dist/directives/bind.js +0 -2
- package/dist/directives/bind.js.map +0 -1
- package/dist/directives/choose.cjs +0 -2
- package/dist/directives/choose.cjs.map +0 -1
- package/dist/directives/choose.d.ts +0 -39
- package/dist/directives/choose.d.ts.map +0 -1
- package/dist/directives/choose.js +0 -2
- package/dist/directives/choose.js.map +0 -1
- package/dist/directives/classes.cjs +0 -2
- package/dist/directives/classes.cjs.map +0 -1
- package/dist/directives/classes.d.ts +0 -20
- package/dist/directives/classes.d.ts.map +0 -1
- package/dist/directives/classes.js +0 -2
- package/dist/directives/classes.js.map +0 -1
- package/dist/directives/index.d.ts +0 -13
- package/dist/directives/index.d.ts.map +0 -1
- package/dist/directives/memo.cjs +0 -2
- package/dist/directives/memo.cjs.map +0 -1
- package/dist/directives/memo.d.ts +0 -27
- package/dist/directives/memo.d.ts.map +0 -1
- package/dist/directives/memo.js +0 -2
- package/dist/directives/memo.js.map +0 -1
- package/dist/directives/on.cjs +0 -2
- package/dist/directives/on.cjs.map +0 -1
- package/dist/directives/on.d.ts +0 -25
- package/dist/directives/on.d.ts.map +0 -1
- package/dist/directives/on.js +0 -2
- package/dist/directives/on.js.map +0 -1
- package/dist/directives/spread.cjs +0 -2
- package/dist/directives/spread.cjs.map +0 -1
- package/dist/directives/spread.d.ts +0 -14
- package/dist/directives/spread.d.ts.map +0 -1
- package/dist/directives/spread.js +0 -2
- package/dist/directives/spread.js.map +0 -1
- package/dist/directives/style.cjs +0 -2
- package/dist/directives/style.cjs.map +0 -1
- package/dist/directives/style.d.ts +0 -22
- package/dist/directives/style.d.ts.map +0 -1
- package/dist/directives/style.js +0 -2
- package/dist/directives/style.js.map +0 -1
- package/dist/directives/until.cjs +0 -2
- package/dist/directives/until.cjs.map +0 -1
- package/dist/directives/until.d.ts +0 -26
- package/dist/directives/until.d.ts.map +0 -1
- package/dist/directives/until.js +0 -2
- package/dist/directives/until.js.map +0 -1
- package/dist/directives.cjs +0 -1
- package/dist/directives.js +0 -1
- package/dist/runtime-bindings.cjs +0 -2
- package/dist/runtime-bindings.cjs.map +0 -1
- package/dist/runtime-bindings.d.ts +0 -6
- package/dist/runtime-bindings.d.ts.map +0 -1
- package/dist/runtime-bindings.js +0 -2
- package/dist/runtime-bindings.js.map +0 -1
- package/dist/runtime-core.cjs +0 -2
- package/dist/runtime-core.cjs.map +0 -1
- package/dist/runtime-core.d.ts +0 -21
- package/dist/runtime-core.d.ts.map +0 -1
- package/dist/runtime-core.js +0 -2
- package/dist/runtime-core.js.map +0 -1
- package/dist/runtime-lifecycle.cjs +0 -2
- package/dist/runtime-lifecycle.cjs.map +0 -1
- package/dist/runtime-lifecycle.d.ts +0 -24
- package/dist/runtime-lifecycle.d.ts.map +0 -1
- package/dist/runtime-lifecycle.js +0 -2
- package/dist/runtime-lifecycle.js.map +0 -1
- package/dist/template-dom.cjs +0 -2
- package/dist/template-dom.cjs.map +0 -1
- package/dist/template-dom.d.ts +0 -13
- package/dist/template-dom.d.ts.map +0 -1
- package/dist/template-dom.js +0 -2
- package/dist/template-dom.js.map +0 -1
- package/dist/template-html.cjs +0 -2
- package/dist/template-html.cjs.map +0 -1
- package/dist/template-html.d.ts +0 -23
- package/dist/template-html.d.ts.map +0 -1
- package/dist/template-html.js +0 -2
- package/dist/template-html.js.map +0 -1
- package/dist/template.cjs +0 -2
- package/dist/template.cjs.map +0 -1
- package/dist/template.d.ts +0 -10
- package/dist/template.d.ts.map +0 -1
- package/dist/template.js +0 -2
- package/dist/template.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for Craftit components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n */\n\nimport { define, type ComponentDefinition } from '../component';\nimport { _resetIdCounter } from '../internal';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface Fixture<T extends HTMLElement = HTMLElement> {\n /** The component element */\n element: T;\n /** The component's shadow root */\n readonly shadow: ShadowRoot;\n /** Query a single element within shadow root */\n query<E extends Element = Element>(selector: string): E | null;\n /** Query all elements within shadow root */\n queryAll<E extends Element = Element>(selector: string): E[];\n /** Query the first element whose trimmed text content matches */\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n /** Query all elements whose trimmed text content matches */\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n /** Query a single element by its `data-testid` attribute */\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n /** Query all elements by their `data-testid` attribute */\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n /** Set an attribute (boolean `false` removes it) then flush */\n attr(name: string, value: string | number | boolean): Promise<void>;\n /** Set multiple attributes then flush */\n attrs(record: Record<string, string | number | boolean>): Promise<void>;\n /** Wait for all reactive updates and animation frames */\n flush(): Promise<void>;\n /** Run a callback then flush — the standard way to trigger and assert a reactive update */\n act(fn: () => unknown): Promise<void>;\n /** Remove the component from the DOM */\n destroy(): void;\n}\n\n/** Scoped query helpers for any DOM element — see {@link within} */\nexport interface QueryScope {\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n}\n\nexport interface MountOptions {\n /** Properties assigned directly onto the element */\n props?: Record<string, unknown>;\n /** HTML attributes to set on the element */\n attrs?: Record<string, string | number | boolean>;\n /** Inner HTML for slot content */\n html?: string;\n /** Parent container (default: document.body) */\n container?: HTMLElement;\n /** Extra component options when passing an inline setup function */\n componentOptions?: Omit<ComponentDefinition<any, any>, 'setup'>;\n}\n\ntype TestComponentOptions<\n Props extends Record<string, unknown> = Record<string, never>,\n Events extends Record<string, unknown> = Record<string, unknown>,\n> = Omit<ComponentDefinition<Props, Events>, 'setup'> & Pick<ComponentDefinition<Props, Events>, 'setup'>;\n\nexport interface WaitOptions {\n /** Maximum wait time in ms (default: 1000) */\n timeout?: number;\n /** Polling interval in ms (default: 50) */\n interval?: number;\n /** Message included in timeout error */\n message?: string;\n}\n\n// ─── Test environment state ───────────────────────────────────────────────────\n\nconst _mountedElements: HTMLElement[] = [];\nlet _componentTagCounter = 0;\n\n/**\n * Resets global test counters used for deterministic IDs/markers.\n * @internal\n */\nexport const _resetCounters = (): void => {\n _resetIdCounter();\n};\n\n// ─── Core ────────────────────────────────────────────────────────────────────\n\n/**\n * Flush pending reactive updates.\n * Drains several microtask turns, then yields one animation frame and\n * one final microtask pass for rAF-scheduled work.\n */\nexport async function flush(): Promise<void> {\n const drainMicrotasks = async (turns: number): Promise<void> => {\n for (let i = 0; i < turns; i++) {\n await Promise.resolve();\n await new Promise<void>((resolve) => queueMicrotask(resolve));\n }\n };\n\n await drainMicrotasks(12);\n\n await new Promise<void>((resolve) =>\n typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(() => resolve()) : resolve(),\n );\n\n await drainMicrotasks(2);\n}\n\n/**\n * Register auto-cleanup after each test. Call once in your test setup file.\n *\n * @example\n * // vitest.setup.ts\n * import { afterEach } from 'vitest';\n * import { install } from '@vielzeug/craftit/testing';\n * install(afterEach);\n */\nexport function install(afterEachHook: (fn: () => void) => void): void {\n afterEachHook(cleanup);\n}\n\nfunction applyAttr(element: Element, name: string, value: string | number | boolean): void {\n if (value === false) element.removeAttribute(name);\n else element.setAttribute(name, value === true ? '' : String(value));\n}\n\nconst toError = (value: unknown): Error => {\n return value instanceof Error ? value : new Error(String(value));\n};\n\nconst withWindowErrorCapture = async <T>(action: () => Promise<T>): Promise<T> => {\n if (typeof window === 'undefined') return action();\n\n let captured: Error | null = null;\n const onError = (event: ErrorEvent) => {\n captured = toError(event.error ?? event.message);\n event.preventDefault();\n };\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n captured = toError(event.reason);\n event.preventDefault();\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n\n try {\n const result = await action();\n\n if (captured) throw captured;\n\n return result;\n } finally {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n }\n};\n\n/**\n * Mount a component into the DOM and return a test fixture.\n *\n * Accepts a registered tag name, an inline setup function, or a component\n * options object. Setup functions are auto-registered with generated tag names.\n *\n * @example — inline setup function\n * const { query } = await mount(() => {\n * const count = signal(0);\n * return html`<button @click=${() => count.value++}>${count}</button>`;\n * });\n *\n * @example — registered tag name\n * const { query } = await mount('my-counter');\n */\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: string,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: TestComponentOptions['setup'],\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: TestComponentOptions<any, any>,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: string | TestComponentOptions['setup'] | TestComponentOptions<any, any>,\n options: MountOptions = {},\n): Promise<Fixture<T>> {\n const { attrs = {}, componentOptions, container = document.body, html, props = {} } = options;\n\n let tagName: string;\n let inlineDefinition: TestComponentOptions<any, any> | undefined;\n\n if (typeof tagOrSetupOrOptions === 'string') {\n tagName = tagOrSetupOrOptions;\n } else if (typeof tagOrSetupOrOptions === 'function') {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = {\n ...(componentOptions ?? {}),\n setup: tagOrSetupOrOptions as TestComponentOptions<any, any>['setup'],\n };\n } else {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = tagOrSetupOrOptions;\n }\n\n if (inlineDefinition) {\n define(tagName, inlineDefinition as TestComponentOptions<any, any>);\n }\n\n const element = document.createElement(tagName) as T;\n\n if (html) element.innerHTML = html;\n\n if (Object.keys(props).length) Object.assign(element, props);\n\n for (const [name, value] of Object.entries(attrs)) applyAttr(element, name, value);\n\n await withWindowErrorCapture(async () => {\n container.appendChild(element);\n _mountedElements.push(element);\n await flush();\n });\n\n return {\n async act(fn) {\n await fn();\n await flush();\n },\n\n async attr(name, value) {\n applyAttr(element, name, value);\n await flush();\n },\n\n async attrs(record) {\n for (const [name, value] of Object.entries(record)) applyAttr(element, name, value);\n await flush();\n },\n\n destroy() {\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n },\n element,\n\n flush,\n\n query<E extends Element = Element>(selector: string): E | null {\n return element.shadowRoot?.querySelector<E>(selector) ?? null;\n },\n\n queryAll<E extends Element = Element>(selector: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(selector) ?? []);\n },\n\n queryAllByTestId<E extends Element = Element>(testId: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(`[data-testid=\"${testId}\"]`) ?? []);\n },\n\n queryAllByText<E extends Element = Element>(text: string, selector = '*'): E[] {\n return queryAllByText<E>(element.shadowRoot!, text, selector);\n },\n\n queryByTestId<E extends Element = Element>(testId: string): E | null {\n return element.shadowRoot?.querySelector<E>(`[data-testid=\"${testId}\"]`) ?? null;\n },\n\n queryByText<E extends Element = Element>(text: string, selector = '*'): E | null {\n return queryByText<E>(element.shadowRoot!, text, selector);\n },\n\n get shadow(): ShadowRoot {\n return element.shadowRoot!;\n },\n };\n}\n\n// ─── Scoped queries ───────────────────────────────────────────────────────────\n\nfunction queryByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E | null {\n for (const el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n}\n\nfunction queryAllByText<E extends Element = Element>(root: Element | ShadowRoot, text: string, selector: string): E[] {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n}\n\n/**\n * Create query helpers scoped to any element — useful for slotted/light DOM content.\n *\n * @example\n * const panel = fixture.query('.panel')!;\n * const { query } = within(panel);\n * expect(query('.title')?.textContent).toBe('Hello');\n */\nexport function within(element: Element): QueryScope {\n return {\n query: <E extends Element = Element>(selector: string) => element.querySelector<E>(selector),\n queryAll: <E extends Element = Element>(selector: string) => Array.from(element.querySelectorAll<E>(selector)),\n queryAllByTestId: <E extends Element = Element>(testId: string) =>\n Array.from(element.querySelectorAll<E>(`[data-testid=\"${testId}\"]`)),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(element, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) =>\n element.querySelector<E>(`[data-testid=\"${testId}\"]`),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(element, text, selector),\n };\n}\n\n// ─── Events ──────────────────────────────────────────────────────────────────\n\nconst createPointerEvent = (type: string, init: PointerEventInit = {}): Event => {\n if (typeof PointerEvent !== 'undefined') {\n return new PointerEvent(type, init);\n }\n\n return new MouseEvent(type, init);\n};\n\n/**\n * Fire low-level DOM events synchronously.\n *\n * @example\n * fire.click(button);\n * fire.keyDown(input, { key: 'Enter' });\n * fire.custom(el, 'value-change', 42);\n */\nexport const fire = {\n blur: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('blur', { bubbles: true, ...opts })),\n change: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('change', { bubbles: true, ...opts })),\n click: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, ...opts })),\n custom<D = unknown>(el: Element, name: string, detail?: D, opts?: Omit<CustomEventInit<D>, 'detail'>): void {\n el.dispatchEvent(new CustomEvent<D>(name, { bubbles: true, cancelable: true, detail, ...opts }));\n },\n focus: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('focus', { bubbles: true, ...opts })),\n input: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('input', { bubbles: true, ...opts })),\n keyDown: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...opts })),\n keyUp: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...opts })),\n pointerDown: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerdown', { bubbles: true, cancelable: true, ...opts })),\n pointerEnter: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerenter', { bubbles: false, ...opts })),\n pointerLeave: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerleave', { bubbles: false, ...opts })),\n pointerUp: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerup', { bubbles: true, cancelable: true, ...opts })),\n submit: (el: Element, opts?: EventInit) =>\n el.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true, ...opts })),\n} as const;\n\n// ─── User interactions ────────────────────────────────────────────────────────\n\nconst tick = (): Promise<void> => flush();\n\n/**\n * Higher-level async user interactions that mirror real browser behavior.\n *\n * @example\n * await user.type(input, 'hello');\n * await user.fill(input, 'replacement'); // clear then type\n * await user.click(button);\n * await user.press(input, 'Enter');\n */\nexport const user = {\n async clear(el: HTMLInputElement | HTMLTextAreaElement): Promise<void> {\n el.focus();\n el.value = '';\n fire.input(el);\n fire.change(el);\n await tick();\n },\n async click(el: Element, opts?: PointerEventInit): Promise<void> {\n fire.pointerEnter(el, opts);\n fire.click(el, opts);\n await tick();\n },\n\n async dblClick(el: Element): Promise<void> {\n for (let i = 0; i < 2; i++) {\n fire.pointerDown(el);\n fire.pointerUp(el);\n fire.click(el);\n }\n el.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }));\n await tick();\n },\n\n /** Clear existing value and type new text (select-all-and-replace semantics) */\n async fill(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n el.value = '';\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async hover(el: Element): Promise<void> {\n fire.pointerEnter(el);\n await tick();\n },\n\n /** Dispatch keydown + keyup for a single key */\n async press(el: Element, key: string, opts?: KeyboardEventInit): Promise<void> {\n fire.keyDown(el, { key, ...opts });\n fire.keyUp(el, { key, ...opts });\n await tick();\n },\n\n async select(el: HTMLSelectElement, value: string | string[]): Promise<void> {\n const values = Array.isArray(value) ? value : [value];\n\n for (const opt of el.options) opt.selected = values.includes(opt.value);\n fire.change(el);\n await tick();\n },\n\n /** Type text character-by-character, appending to any existing value */\n async type(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async unhover(el: Element): Promise<void> {\n fire.pointerLeave(el);\n await tick();\n },\n} as const;\n\n// ─── Waiting ─────────────────────────────────────────────────────────────────\n\n/**\n * Poll until a callback returns truthy (or void) without throwing.\n * Supports both boolean conditions and `expect()` assertions.\n *\n * - Returns truthy → success\n * - Returns `undefined` (e.g. bare `expect()` call) → success\n * - Returns falsy value → retry\n * - Throws → retry, re-throw original error on timeout\n *\n * @example\n * await waitFor(() => query('.status')?.textContent === 'loaded');\n * await waitFor(() => expect(count).toBe(3));\n */\nexport async function waitFor(\n fn: () => unknown,\n { interval = 50, message, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n const attempt = async (): Promise<boolean> => {\n try {\n const result = await fn();\n\n return result === undefined || !!result;\n } catch (e) {\n lastError = e;\n\n return false;\n }\n };\n\n while (Date.now() < deadline) {\n if (await attempt()) return;\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n if (await attempt()) return;\n\n const base = message ?? `waitFor timed out after ${timeout}ms`;\n\n if (lastError instanceof Error) {\n lastError.message = `${base}\\n${lastError.message}`;\n throw lastError;\n }\n\n throw new Error(lastError != null ? `${base}\\nCause: ${lastError}` : base);\n}\n\n/**\n * Resolve when the target element emits the given event.\n *\n * @example\n * const promise = waitForEvent(el, 'change');\n * fire.click(trigger);\n * const event = await promise;\n */\nexport function waitForEvent<T extends Event = Event>(element: Element, name: string, timeout = 1000): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`waitForEvent: \"${name}\" timed out after ${timeout}ms`)), timeout);\n\n element.addEventListener(\n name,\n (e) => {\n clearTimeout(timer);\n resolve(e as T);\n },\n { once: true },\n );\n });\n}\n\n// ─── Stubs & cleanup ─────────────────────────────────────────────────────────\n\n/**\n * Register a stub custom element (no-op if already defined).\n *\n * @example\n * mock('child-button', '<slot></slot>');\n */\nexport function mock(tagName: string, template = ''): void {\n if (!customElements.get(tagName)) {\n customElements.define(\n tagName,\n class extends HTMLElement {\n connectedCallback() {\n this.innerHTML = template;\n }\n },\n );\n }\n}\n\n/**\n * Remove all elements mounted via `mount()`.\n * Call in `afterEach` to keep tests isolated.\n *\n * @example\n * afterEach(() => cleanup());\n */\nexport function cleanup(): void {\n for (const el of _mountedElements) el.remove();\n _mountedElements.length = 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testing.js","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for Craftit components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n */\n\nimport type { Signal } from '@vielzeug/stateit';\n\nimport type { ComponentTemplate } from '../registration';\n\nimport { _resetIdCounter, type HTMLResult } from '../internal';\nimport { define, type ComponentDefinition, type SetupContextBag } from '../registration';\nimport { fire as runtimeFire } from '../runtime';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface Fixture<T extends HTMLElement = HTMLElement> {\n /** The component element */\n element: T;\n /** The component's shadow root */\n readonly shadow: ShadowRoot;\n /** Query a single element within shadow root */\n query<E extends Element = Element>(selector: string): E | null;\n /** Query all elements within shadow root */\n queryAll<E extends Element = Element>(selector: string): E[];\n /** Query the first element whose trimmed text content matches */\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n /** Query all elements whose trimmed text content matches */\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n /** Query a single element by its `data-testid` attribute */\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n /** Query all elements by their `data-testid` attribute */\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n /** Set an attribute (boolean `false` removes it) then flush */\n attr(name: string, value: string | number | boolean): Promise<void>;\n /** Set multiple attributes then flush */\n attrs(record: Record<string, string | number | boolean>): Promise<void>;\n /** Wait for all reactive updates and animation frames */\n flush(): Promise<void>;\n /** Run a callback then flush — the standard way to trigger and assert a reactive update */\n act(fn: () => unknown): Promise<void>;\n /** Remove the component from the DOM */\n destroy(): void;\n}\n\n/** Scoped query helpers for any DOM element — see {@link within} */\nexport interface QueryScope {\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n}\n\nexport interface MountOptions {\n /** Properties assigned directly onto the element */\n props?: Record<string, unknown>;\n /** HTML attributes to set on the element */\n attrs?: Record<string, string | number | boolean>;\n /** Inner HTML for slot content */\n html?: string;\n /** Parent container (default: document.body) */\n container?: HTMLElement;\n /** Extra component options when passing an inline setup function */\n componentOptions?: Omit<ComponentDefinition<any, any>, 'setup'>;\n}\n\ntype TestSetup<\n Props extends Record<string, unknown> = Record<string, never>,\n Events extends Record<string, unknown> = Record<string, unknown>,\n> = (...args: Parameters<ComponentDefinition<Props, Events>['setup']>) => ComponentTemplate | HTMLResult;\n\ntype MountProps = { readonly [x: string]: Signal<unknown> };\n\n// Bivariant callback type keeps inline test callbacks ergonomic across varying setup context specializations.\nexport type MountSetup = {\n bivarianceHack: (props: MountProps, ctx: SetupContextBag<any>) => ComponentTemplate | HTMLResult;\n}['bivarianceHack'];\n\nexport interface WaitOptions {\n /** Maximum wait time in ms (default: 1000) */\n timeout?: number;\n /** Polling interval in ms (default: 50) */\n interval?: number;\n /** Message included in timeout error */\n message?: string;\n}\n\n// ─── Test environment state ───────────────────────────────────────────────────\n\nconst _mountedElements: HTMLElement[] = [];\nlet _componentTagCounter = 0;\n\n/**\n * Resets global test counters used for deterministic IDs/markers.\n * @internal\n */\nexport const _resetCounters = (): void => {\n _resetIdCounter();\n _componentTagCounter = 0;\n};\n\n// ─── Core ────────────────────────────────────────────────────────────────────\n\n/**\n * Flush pending reactive updates.\n * Drains several microtask turns, then yields one animation frame and\n * one final microtask pass for rAF-scheduled work.\n */\nexport async function flush(): Promise<void> {\n const drainMicrotasks = async (turns: number): Promise<void> => {\n for (let i = 0; i < turns; i++) {\n await Promise.resolve();\n await new Promise<void>((resolve) => queueMicrotask(resolve));\n }\n };\n\n await drainMicrotasks(12);\n\n await new Promise<void>((resolve) =>\n typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(() => resolve()) : resolve(),\n );\n\n await drainMicrotasks(2);\n}\n\n/**\n * Register auto-cleanup after each test. Call once in your test setup file.\n *\n * @example\n * // vitest.setup.ts\n * import { afterEach } from 'vitest';\n * import { install } from '@vielzeug/craftit/testing';\n * install(afterEach);\n */\nexport function install(afterEachHook: (fn: () => void) => void): void {\n afterEachHook(cleanup);\n}\n\nfunction applyAttr(element: Element, name: string, value: string | number | boolean): void {\n if (value === false) element.removeAttribute(name);\n else element.setAttribute(name, value === true ? '' : String(value));\n}\n\nconst toError = (value: unknown): Error => {\n return value instanceof Error ? value : new Error(String(value));\n};\n\nconst withWindowErrorCapture = async <T>(action: () => Promise<T>): Promise<T> => {\n if (typeof window === 'undefined') return action();\n\n let captured: Error | null = null;\n const onError = (event: ErrorEvent) => {\n captured = toError(event.error ?? event.message);\n event.preventDefault();\n };\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n captured = toError(event.reason);\n event.preventDefault();\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n\n try {\n const result = await action();\n\n if (captured) throw captured;\n\n return result;\n } finally {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n }\n};\n\n/**\n * Mount a component into the DOM and return a test fixture.\n *\n * Accepts a registered tag name, an inline setup function, or a component\n * options object. Setup functions are auto-registered with generated tag names.\n *\n * @example — inline setup function\n * const { query } = await mount(() => {\n * const count = signal(0);\n * return html`<button @click=${() => count.value++}>${count}</button>`;\n * });\n *\n * @example — registered tag name\n * const { query } = await mount('my-counter');\n */\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetup: string,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetup: MountSetup,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetup: string | MountSetup,\n options: MountOptions = {},\n): Promise<Fixture<T>> {\n const { attrs = {}, componentOptions, container = document.body, html, props = {} } = options;\n\n const normalizeSetup = <P extends Record<string, unknown>, E extends Record<string, unknown>>(\n setup: TestSetup<P, E>,\n ): ComponentDefinition<P, E>['setup'] => {\n return (setupProps, setupCtx) => {\n const result = setup(setupProps, setupCtx);\n\n if (typeof result === 'function') {\n return result;\n }\n\n return () => result;\n };\n };\n\n let tagName: string;\n let inlineDefinition: ComponentDefinition<any, any> | undefined;\n\n if (typeof tagOrSetup === 'string') {\n tagName = tagOrSetup;\n } else {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = {\n ...(componentOptions ?? {}),\n setup: normalizeSetup(tagOrSetup as TestSetup<any, any>),\n };\n }\n\n if (inlineDefinition) {\n define(tagName, inlineDefinition);\n }\n\n const element = document.createElement(tagName) as T;\n\n if (html) element.innerHTML = html;\n\n if (Object.keys(props).length) Object.assign(element, props);\n\n for (const [name, value] of Object.entries(attrs)) applyAttr(element, name, value);\n\n await withWindowErrorCapture(async () => {\n container.appendChild(element);\n _mountedElements.push(element);\n await flush();\n });\n\n return {\n async act(fn) {\n await fn();\n await flush();\n },\n\n async attr(name, value) {\n applyAttr(element, name, value);\n await flush();\n },\n\n async attrs(record) {\n for (const [name, value] of Object.entries(record)) applyAttr(element, name, value);\n await flush();\n },\n\n destroy() {\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n },\n element,\n\n flush,\n\n query<E extends Element = Element>(selector: string): E | null {\n return element.shadowRoot?.querySelector<E>(selector) ?? null;\n },\n\n queryAll<E extends Element = Element>(selector: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(selector) ?? []);\n },\n\n queryAllByTestId<E extends Element = Element>(testId: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(`[data-testid=\"${testId}\"]`) ?? []);\n },\n\n queryAllByText<E extends Element = Element>(text: string, selector = '*'): E[] {\n return queryAllByText<E>(element.shadowRoot!, text, selector);\n },\n\n queryByTestId<E extends Element = Element>(testId: string): E | null {\n return element.shadowRoot?.querySelector<E>(`[data-testid=\"${testId}\"]`) ?? null;\n },\n\n queryByText<E extends Element = Element>(text: string, selector = '*'): E | null {\n return queryByText<E>(element.shadowRoot!, text, selector);\n },\n\n get shadow(): ShadowRoot {\n return element.shadowRoot!;\n },\n };\n}\n\n// ─── Scoped queries ───────────────────────────────────────────────────────────\n\nfunction queryByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E | null {\n for (const el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n}\n\nfunction queryAllByText<E extends Element = Element>(root: Element | ShadowRoot, text: string, selector: string): E[] {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n}\n\n/**\n * Create query helpers scoped to any element — useful for slotted/light DOM content.\n *\n * @example\n * const panel = fixture.query('.panel')!;\n * const { query } = within(panel);\n * expect(query('.title')?.textContent).toBe('Hello');\n */\nexport function within(element: Element): QueryScope {\n return {\n query: <E extends Element = Element>(selector: string) => element.querySelector<E>(selector),\n queryAll: <E extends Element = Element>(selector: string) => Array.from(element.querySelectorAll<E>(selector)),\n queryAllByTestId: <E extends Element = Element>(testId: string) =>\n Array.from(element.querySelectorAll<E>(`[data-testid=\"${testId}\"]`)),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(element, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) =>\n element.querySelector<E>(`[data-testid=\"${testId}\"]`),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(element, text, selector),\n };\n}\n\n// ─── Events ──────────────────────────────────────────────────────────────────\n\nconst createPointerEvent = (type: string, init: PointerEventInit = {}): Event => {\n if (typeof PointerEvent !== 'undefined') {\n return new PointerEvent(type, init);\n }\n\n return new MouseEvent(type, init);\n};\n\n/**\n * Fire low-level DOM events synchronously.\n *\n * @example\n * fire.click(button);\n * fire.keyDown(input, { key: 'Enter' });\n * fire.custom(el, 'value-change', 42);\n */\nexport const fire = {\n blur: (el: Element, opts?: FocusEventInit) =>\n runtimeFire.event(el, new FocusEvent('blur', { bubbles: true, ...opts })),\n change: (el: Element, opts?: EventInit) => runtimeFire.event(el, new Event('change', { bubbles: true, ...opts })),\n click: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, new MouseEvent('click', { bubbles: true, cancelable: true, ...opts })),\n custom<D = unknown>(el: Element, name: string, detail?: D, opts?: Omit<CustomEventInit<D>, 'detail'>): void {\n runtimeFire.event(el, new CustomEvent<D>(name, { bubbles: true, cancelable: true, detail, ...opts }));\n },\n focus: (el: Element, opts?: FocusEventInit) =>\n runtimeFire.event(el, new FocusEvent('focus', { bubbles: true, ...opts })),\n input: (el: Element, opts?: EventInit) => runtimeFire.event(el, new Event('input', { bubbles: true, ...opts })),\n keyDown: (el: Element, opts?: KeyboardEventInit) =>\n runtimeFire.event(el, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...opts })),\n keyUp: (el: Element, opts?: KeyboardEventInit) =>\n runtimeFire.event(el, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...opts })),\n pointerDown: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerdown', { bubbles: true, cancelable: true, ...opts })),\n pointerEnter: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerenter', { bubbles: false, ...opts })),\n pointerLeave: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerleave', { bubbles: false, ...opts })),\n pointerUp: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerup', { bubbles: true, cancelable: true, ...opts })),\n submit: (el: Element, opts?: EventInit) =>\n runtimeFire.event(el, new Event('submit', { bubbles: true, cancelable: true, ...opts })),\n} as const;\n\n// ─── User interactions ────────────────────────────────────────────────────────\n\nconst tick = (): Promise<void> => flush();\n\n/**\n * Higher-level async user interactions that mirror real browser behavior.\n *\n * @example\n * await user.type(input, 'hello');\n * await user.fill(input, 'replacement'); // clear then type\n * await user.click(button);\n * await user.press(input, 'Enter');\n */\nexport const user = {\n async clear(el: HTMLInputElement | HTMLTextAreaElement): Promise<void> {\n el.focus();\n el.value = '';\n fire.input(el);\n fire.change(el);\n await tick();\n },\n async click(el: Element, opts?: PointerEventInit): Promise<void> {\n fire.pointerEnter(el, opts);\n fire.click(el, opts);\n await tick();\n },\n\n async dblClick(el: Element): Promise<void> {\n for (let i = 0; i < 2; i++) {\n fire.pointerDown(el);\n fire.pointerUp(el);\n fire.click(el);\n }\n el.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }));\n await tick();\n },\n\n /** Clear existing value and type new text (select-all-and-replace semantics) */\n async fill(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n el.value = '';\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async hover(el: Element): Promise<void> {\n fire.pointerEnter(el);\n await tick();\n },\n\n /** Dispatch keydown + keyup for a single key */\n async press(el: Element, key: string, opts?: KeyboardEventInit): Promise<void> {\n fire.keyDown(el, { key, ...opts });\n fire.keyUp(el, { key, ...opts });\n await tick();\n },\n\n async select(el: HTMLSelectElement, value: string | string[]): Promise<void> {\n const values = Array.isArray(value) ? value : [value];\n\n for (const opt of el.options) opt.selected = values.includes(opt.value);\n fire.change(el);\n await tick();\n },\n\n /** Type text character-by-character, appending to any existing value */\n async type(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async unhover(el: Element): Promise<void> {\n fire.pointerLeave(el);\n await tick();\n },\n} as const;\n\n// ─── Waiting ─────────────────────────────────────────────────────────────────\n\n/**\n * Poll until a callback returns truthy (or void) without throwing.\n * Supports both boolean conditions and `expect()` assertions.\n *\n * - Returns truthy → success\n * - Returns `undefined` (e.g. bare `expect()` call) → success\n * - Returns falsy value → retry\n * - Throws → retry, re-throw original error on timeout\n *\n * @example\n * await waitFor(() => query('.status')?.textContent === 'loaded');\n * await waitFor(() => expect(count).toBe(3));\n */\nexport async function waitFor(\n fn: () => unknown,\n { interval = 50, message, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n const attempt = async (): Promise<boolean> => {\n try {\n const result = await fn();\n\n return result === undefined || !!result;\n } catch (e) {\n lastError = e;\n\n return false;\n }\n };\n\n while (Date.now() < deadline) {\n if (await attempt()) return;\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n if (await attempt()) return;\n\n const base = message ?? `waitFor timed out after ${timeout}ms`;\n\n if (lastError instanceof Error) {\n lastError.message = `${base}\\n${lastError.message}`;\n throw lastError;\n }\n\n throw new Error(lastError != null ? `${base}\\nCause: ${lastError}` : base);\n}\n\n/**\n * Resolve when the target element emits the given event.\n *\n * @example\n * const promise = waitForEvent(el, 'change');\n * fire.click(trigger);\n * const event = await promise;\n */\nexport function waitForEvent<T extends Event = Event>(element: Element, name: string, timeout = 1000): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`waitForEvent: \"${name}\" timed out after ${timeout}ms`)), timeout);\n\n element.addEventListener(\n name,\n (e) => {\n clearTimeout(timer);\n resolve(e as T);\n },\n { once: true },\n );\n });\n}\n\n// ─── Stubs & cleanup ─────────────────────────────────────────────────────────\n\n/**\n * Register a stub custom element (no-op if already defined).\n *\n * @example\n * mock('child-button', '<slot></slot>');\n */\nexport function mock(tagName: string, template = ''): void {\n if (!customElements.get(tagName)) {\n customElements.define(\n tagName,\n class extends HTMLElement {\n connectedCallback() {\n this.innerHTML = template;\n }\n },\n );\n }\n}\n\n/**\n * Remove all elements mounted via `mount()`.\n * Call in `afterEach` to keep tests isolated.\n *\n * @example\n * afterEach(() => cleanup());\n */\nexport function cleanup(): void {\n for (const el of _mountedElements) el.remove();\n _mountedElements.length = 0;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/craftit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -27,12 +27,6 @@
|
|
|
27
27
|
"import": "./dist/observers.js",
|
|
28
28
|
"require": "./dist/observers.cjs"
|
|
29
29
|
},
|
|
30
|
-
"./directives": {
|
|
31
|
-
"source": "./src/directives/index.ts",
|
|
32
|
-
"types": "./dist/directives/index.d.ts",
|
|
33
|
-
"import": "./dist/directives/index.js",
|
|
34
|
-
"require": "./dist/directives/index.cjs"
|
|
35
|
-
},
|
|
36
30
|
"./testing": {
|
|
37
31
|
"source": "./src/testing/index.ts",
|
|
38
32
|
"types": "./dist/testing/index.d.ts",
|
|
@@ -59,10 +53,10 @@
|
|
|
59
53
|
"@vielzeug/stateit": "workspace:*"
|
|
60
54
|
},
|
|
61
55
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^25.
|
|
63
|
-
"jsdom": "^29.
|
|
64
|
-
"typescript": "~6.0.
|
|
65
|
-
"vite": "^8.0.
|
|
66
|
-
"vitest": "^4.1.
|
|
56
|
+
"@types/node": "^25.8.0",
|
|
57
|
+
"jsdom": "^29.1.1",
|
|
58
|
+
"typescript": "~6.0.3",
|
|
59
|
+
"vite": "^8.0.13",
|
|
60
|
+
"vitest": "^4.1.6"
|
|
67
61
|
}
|
|
68
62
|
}
|
package/dist/component.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./internal.cjs`),t=require(`./host.cjs`),n=require(`./props.cjs`),r=require(`./registration.cjs`);var i=(i,a)=>{let{formAssociated:o,host:s,props:c,setup:l,shadow:u,styles:d}=a;return r.registerComponent(i,()=>{let r=c?n.createProps(c):{},i=e.createEmitFn(),a=t.createHost(),o;return l({emit:i,host:a,props:r,shadowRoot:a.shadowRoot,slots:{elements:e=>(o||=t.createSlots(),o.elements(e)),has:e=>(o||=t.createSlots(),o.has(e))}})},{formAssociated:o,host:s,observedAttrs:c?Object.keys(c).map(e.toKebab):[],shadow:u,styles:d})};function a(e,t){return i(e,t)}exports.define=a;
|
|
2
|
-
//# sourceMappingURL=component.cjs.map
|
package/dist/component.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"component.cjs","names":[],"sources":["../src/component.ts"],"sourcesContent":["/**\n * Component authoring API — define custom elements, props, and registration.\n */\n\nimport { type ComponentHost, type ComponentSlots, createHost, createSlots } from './host';\nimport { type EmitFn, type HTMLResult, createEmitFn, toKebab } from './internal';\nimport {\n createProps,\n type ComponentProps,\n type InferPropsFromDefs,\n type InferPropsSignals,\n type PropDef,\n type PropInputDefs,\n type PropOptions,\n type PropsInput,\n type ResolveComponentProps,\n} from './props';\nimport { type ComponentRegistrationOptions, registerComponent } from './registration';\n\nexport { createProps, type PropsInput };\nexport type {\n InferPropsFromDefs,\n InferPropsSignals,\n ComponentProps,\n PropDef,\n PropInputDefs,\n PropOptions,\n ResolveComponentProps,\n};\nexport { registerComponent, type ComponentRegistrationOptions };\n\n/**\n * Unified setup context passed to component setup functions.\n */\nexport type ComponentSetupContext<\n P extends Record<string, unknown> = Record<never, never>,\n E extends Record<string, unknown> = Record<string, never>,\n D extends PropInputDefs = PropsInput<P>,\n> = {\n emit: EmitFn<E>;\n host: ComponentHost;\n props: ComponentProps<ResolveComponentProps<P, D>>;\n shadowRoot: ShadowRoot;\n slots: ComponentSlots;\n};\n\n/**\n * Configuration object for define().\n */\nexport type ComponentOptions<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n> = {\n formAssociated?: boolean;\n host?: Record<string, string | boolean | number>;\n props?: PropDefs;\n setup: (ctx: ComponentSetupContext<ResolveComponentProps<Props, PropDefs>, Emits, PropDefs>) => string | HTMLResult;\n shadow?: Omit<ShadowRootInit, 'mode'>;\n styles?: (string | CSSStyleSheet | import('./internal').CSSResult)[];\n};\n\nexport type ComponentDefinition<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n> = ComponentOptions<Props, Emits, PropDefs>;\n\nconst defineInternal = <\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n>(\n tag: string,\n definition: ComponentDefinition<Props, EventsType, PropDefs> & { props?: PropDefs },\n): string => {\n const { formAssociated, host: hostOptions, props: propDefs, setup, shadow: shadowOptions, styles } = definition;\n\n const observedAttrs = propDefs ? Object.keys(propDefs).map(toKebab) : [];\n\n return registerComponent(\n tag,\n () => {\n const props = propDefs ? createProps(propDefs) : ({} as ComponentProps<ResolveComponentProps<Props, PropDefs>>);\n const emit = createEmitFn<EventsType>();\n const host = createHost();\n let slotsApi: ComponentSlots | undefined;\n const slots: ComponentSlots = {\n elements: (name?: string) => {\n if (!slotsApi) slotsApi = createSlots();\n\n return slotsApi.elements(name);\n },\n has: (name?: string) => {\n if (!slotsApi) slotsApi = createSlots();\n\n return slotsApi.has(name);\n },\n };\n\n return setup({\n emit: emit as EmitFn<EventsType>,\n host,\n props: props as ComponentProps<ResolveComponentProps<Props, PropDefs>>,\n shadowRoot: host.shadowRoot,\n slots,\n } as ComponentSetupContext<ResolveComponentProps<Props, PropDefs>, EventsType, PropDefs>);\n },\n {\n formAssociated,\n host: hostOptions,\n observedAttrs,\n shadow: shadowOptions,\n styles,\n } satisfies ComponentRegistrationOptions,\n );\n};\n\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n const PropDefs extends PropInputDefs = PropsInput<Props>,\n>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & { props: PropDefs }): string;\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & { props?: PropDefs }): string;\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & { props?: PropDefs }): string {\n return defineInternal(tag, definition);\n}\n"],"mappings":"mHAoEA,IAAM,GAKJ,EACA,IACW,CACX,GAAM,CAAE,iBAAgB,KAAM,EAAa,MAAO,EAAU,QAAO,OAAQ,EAAe,UAAW,EAIrG,OAAO,EAAA,kBACL,MACM,CACJ,IAAM,EAAQ,EAAW,EAAA,YAAY,EAAS,CAAI,EAAE,CAC9C,EAAO,EAAA,cAA0B,CACjC,EAAO,EAAA,YAAY,CACrB,EAcJ,OAAO,EAAM,CACL,OACN,OACO,QACP,WAAY,EAAK,WACjB,MAlB4B,CAC5B,SAAW,IACT,AAAe,IAAW,EAAA,aAAa,CAEhC,EAAS,SAAS,EAAK,EAEhC,IAAM,IACJ,AAAe,IAAW,EAAA,aAAa,CAEhC,EAAS,IAAI,EAAK,EAE5B,CAQA,CAAwF,EAE3F,CACE,iBACA,KAAM,EACN,cAjCkB,EAAW,OAAO,KAAK,EAAS,CAAC,IAAI,EAAA,QAAQ,CAAG,EAAE,CAkCpE,OAAQ,EACR,SACD,CACF,EAaH,SAAgB,EAId,EAAa,EAA6F,CAC1G,OAAO,EAAe,EAAK,EAAW"}
|
package/dist/component.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Component authoring API — define custom elements, props, and registration.
|
|
3
|
-
*/
|
|
4
|
-
import { type ComponentHost, type ComponentSlots } from './host';
|
|
5
|
-
import { type EmitFn, type HTMLResult } from './internal';
|
|
6
|
-
import { createProps, type ComponentProps, type InferPropsFromDefs, type InferPropsSignals, type PropDef, type PropInputDefs, type PropOptions, type PropsInput, type ResolveComponentProps } from './props';
|
|
7
|
-
import { type ComponentRegistrationOptions, registerComponent } from './registration';
|
|
8
|
-
export { createProps, type PropsInput };
|
|
9
|
-
export type { InferPropsFromDefs, InferPropsSignals, ComponentProps, PropDef, PropInputDefs, PropOptions, ResolveComponentProps, };
|
|
10
|
-
export { registerComponent, type ComponentRegistrationOptions };
|
|
11
|
-
/**
|
|
12
|
-
* Unified setup context passed to component setup functions.
|
|
13
|
-
*/
|
|
14
|
-
export type ComponentSetupContext<P extends Record<string, unknown> = Record<never, never>, E extends Record<string, unknown> = Record<string, never>, D extends PropInputDefs = PropsInput<P>> = {
|
|
15
|
-
emit: EmitFn<E>;
|
|
16
|
-
host: ComponentHost;
|
|
17
|
-
props: ComponentProps<ResolveComponentProps<P, D>>;
|
|
18
|
-
shadowRoot: ShadowRoot;
|
|
19
|
-
slots: ComponentSlots;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Configuration object for define().
|
|
23
|
-
*/
|
|
24
|
-
export type ComponentOptions<Props extends Record<string, unknown> = Record<never, never>, Emits extends Record<string, unknown> = Record<string, never>, PropDefs extends PropInputDefs = PropsInput<Props>> = {
|
|
25
|
-
formAssociated?: boolean;
|
|
26
|
-
host?: Record<string, string | boolean | number>;
|
|
27
|
-
props?: PropDefs;
|
|
28
|
-
setup: (ctx: ComponentSetupContext<ResolveComponentProps<Props, PropDefs>, Emits, PropDefs>) => string | HTMLResult;
|
|
29
|
-
shadow?: Omit<ShadowRootInit, 'mode'>;
|
|
30
|
-
styles?: (string | CSSStyleSheet | import('./internal').CSSResult)[];
|
|
31
|
-
};
|
|
32
|
-
export type ComponentDefinition<Props extends Record<string, unknown> = Record<never, never>, Emits extends Record<string, unknown> = Record<string, never>, PropDefs extends PropInputDefs = PropsInput<Props>> = ComponentOptions<Props, Emits, PropDefs>;
|
|
33
|
-
export declare function define<Props extends Record<string, unknown> = Record<never, never>, EventsType extends Record<string, unknown> = Record<string, never>, const PropDefs extends PropInputDefs = PropsInput<Props>>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & {
|
|
34
|
-
props: PropDefs;
|
|
35
|
-
}): string;
|
|
36
|
-
export declare function define<Props extends Record<string, unknown> = Record<never, never>, EventsType extends Record<string, unknown> = Record<string, never>, PropDefs extends PropInputDefs = PropsInput<Props>>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & {
|
|
37
|
-
props?: PropDefs;
|
|
38
|
-
}): string;
|
|
39
|
-
//# sourceMappingURL=component.d.ts.map
|
package/dist/component.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAA2B,MAAM,QAAQ,CAAC;AAC1F,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,EAAyB,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC3B,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,KAAK,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAE,WAAW,EAAE,KAAK,UAAU,EAAE,CAAC;AACxC,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,OAAO,EACP,aAAa,EACb,WAAW,EACX,qBAAqB,GACtB,CAAC;AACF,OAAO,EAAE,iBAAiB,EAAE,KAAK,4BAA4B,EAAE,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAC/B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACxD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACzD,CAAC,SAAS,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,IACrC;IACF,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,cAAc,CAAC,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,cAAc,CAAC;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAC1B,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC5D,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC7D,QAAQ,SAAS,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,IAChD;IACF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,CAAC,GAAG,EAAE,qBAAqB,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,MAAM,GAAG,UAAU,CAAC;IACpH,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,aAAa,GAAG,OAAO,YAAY,EAAE,SAAS,CAAC,EAAE,CAAC;CACtE,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAC7B,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC5D,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC7D,QAAQ,SAAS,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,IAChD,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AAoD7C,wBAAgB,MAAM,CACpB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC5D,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAClE,KAAK,CAAC,QAAQ,SAAS,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,EACxD,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GAAG,MAAM,CAAC;AAC3G,wBAAgB,MAAM,CACpB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAC5D,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAClE,QAAQ,SAAS,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,EAClD,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAAG,MAAM,CAAC"}
|
package/dist/component.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{createEmitFn as e,toKebab as t}from"./internal.js";import{createHost as n,createSlots as r}from"./host.js";import{createProps as i}from"./props.js";import{registerComponent as a}from"./registration.js";var o=(o,s)=>{let{formAssociated:c,host:l,props:u,setup:d,shadow:f,styles:p}=s;return a(o,()=>{let t=u?i(u):{},a=e(),o=n(),s;return d({emit:a,host:o,props:t,shadowRoot:o.shadowRoot,slots:{elements:e=>(s||=r(),s.elements(e)),has:e=>(s||=r(),s.has(e))}})},{formAssociated:c,host:l,observedAttrs:u?Object.keys(u).map(t):[],shadow:f,styles:p})};function s(e,t){return o(e,t)}export{s as define};
|
|
2
|
-
//# sourceMappingURL=component.js.map
|
package/dist/component.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","names":[],"sources":["../src/component.ts"],"sourcesContent":["/**\n * Component authoring API — define custom elements, props, and registration.\n */\n\nimport { type ComponentHost, type ComponentSlots, createHost, createSlots } from './host';\nimport { type EmitFn, type HTMLResult, createEmitFn, toKebab } from './internal';\nimport {\n createProps,\n type ComponentProps,\n type InferPropsFromDefs,\n type InferPropsSignals,\n type PropDef,\n type PropInputDefs,\n type PropOptions,\n type PropsInput,\n type ResolveComponentProps,\n} from './props';\nimport { type ComponentRegistrationOptions, registerComponent } from './registration';\n\nexport { createProps, type PropsInput };\nexport type {\n InferPropsFromDefs,\n InferPropsSignals,\n ComponentProps,\n PropDef,\n PropInputDefs,\n PropOptions,\n ResolveComponentProps,\n};\nexport { registerComponent, type ComponentRegistrationOptions };\n\n/**\n * Unified setup context passed to component setup functions.\n */\nexport type ComponentSetupContext<\n P extends Record<string, unknown> = Record<never, never>,\n E extends Record<string, unknown> = Record<string, never>,\n D extends PropInputDefs = PropsInput<P>,\n> = {\n emit: EmitFn<E>;\n host: ComponentHost;\n props: ComponentProps<ResolveComponentProps<P, D>>;\n shadowRoot: ShadowRoot;\n slots: ComponentSlots;\n};\n\n/**\n * Configuration object for define().\n */\nexport type ComponentOptions<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n> = {\n formAssociated?: boolean;\n host?: Record<string, string | boolean | number>;\n props?: PropDefs;\n setup: (ctx: ComponentSetupContext<ResolveComponentProps<Props, PropDefs>, Emits, PropDefs>) => string | HTMLResult;\n shadow?: Omit<ShadowRootInit, 'mode'>;\n styles?: (string | CSSStyleSheet | import('./internal').CSSResult)[];\n};\n\nexport type ComponentDefinition<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n> = ComponentOptions<Props, Emits, PropDefs>;\n\nconst defineInternal = <\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n>(\n tag: string,\n definition: ComponentDefinition<Props, EventsType, PropDefs> & { props?: PropDefs },\n): string => {\n const { formAssociated, host: hostOptions, props: propDefs, setup, shadow: shadowOptions, styles } = definition;\n\n const observedAttrs = propDefs ? Object.keys(propDefs).map(toKebab) : [];\n\n return registerComponent(\n tag,\n () => {\n const props = propDefs ? createProps(propDefs) : ({} as ComponentProps<ResolveComponentProps<Props, PropDefs>>);\n const emit = createEmitFn<EventsType>();\n const host = createHost();\n let slotsApi: ComponentSlots | undefined;\n const slots: ComponentSlots = {\n elements: (name?: string) => {\n if (!slotsApi) slotsApi = createSlots();\n\n return slotsApi.elements(name);\n },\n has: (name?: string) => {\n if (!slotsApi) slotsApi = createSlots();\n\n return slotsApi.has(name);\n },\n };\n\n return setup({\n emit: emit as EmitFn<EventsType>,\n host,\n props: props as ComponentProps<ResolveComponentProps<Props, PropDefs>>,\n shadowRoot: host.shadowRoot,\n slots,\n } as ComponentSetupContext<ResolveComponentProps<Props, PropDefs>, EventsType, PropDefs>);\n },\n {\n formAssociated,\n host: hostOptions,\n observedAttrs,\n shadow: shadowOptions,\n styles,\n } satisfies ComponentRegistrationOptions,\n );\n};\n\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n const PropDefs extends PropInputDefs = PropsInput<Props>,\n>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & { props: PropDefs }): string;\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & { props?: PropDefs }): string;\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n PropDefs extends PropInputDefs = PropsInput<Props>,\n>(tag: string, definition: ComponentDefinition<Props, EventsType, PropDefs> & { props?: PropDefs }): string {\n return defineInternal(tag, definition);\n}\n"],"mappings":"iNAoEA,IAAM,GAKJ,EACA,IACW,CACX,GAAM,CAAE,iBAAgB,KAAM,EAAa,MAAO,EAAU,QAAO,OAAQ,EAAe,UAAW,EAIrG,OAAO,EACL,MACM,CACJ,IAAM,EAAQ,EAAW,EAAY,EAAS,CAAI,EAAE,CAC9C,EAAO,GAA0B,CACjC,EAAO,GAAY,CACrB,EAcJ,OAAO,EAAM,CACL,OACN,OACO,QACP,WAAY,EAAK,WACjB,MAlB4B,CAC5B,SAAW,IACT,AAAe,IAAW,GAAa,CAEhC,EAAS,SAAS,EAAK,EAEhC,IAAM,IACJ,AAAe,IAAW,GAAa,CAEhC,EAAS,IAAI,EAAK,EAE5B,CAQA,CAAwF,EAE3F,CACE,iBACA,KAAM,EACN,cAjCkB,EAAW,OAAO,KAAK,EAAS,CAAC,IAAI,EAAQ,CAAG,EAAE,CAkCpE,OAAQ,EACR,SACD,CACF,EAaH,SAAgB,EAId,EAAa,EAA6F,CAC1G,OAAO,EAAe,EAAK,EAAW"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./internal/keyboard-utils.cjs`);var t={first:[`Home`],last:[`End`],next:[`ArrowDown`],prev:[`ArrowUp`]},n=n=>{let r=()=>!!n.disabled?.(),i=()=>{let e=typeof n.keys==`function`?n.keys():n.keys;return{first:e?.first??t.first,last:e?.last??t.last,next:e?.next??t.next,prev:e?.prev??t.prev}};return{handleKeydown:t=>{let a=i(),o={},s=e=>{for(let t of a[e])o[t]=t=>{let r=n.control[e]();n.onInvoke?.(e,r,t)}};return s(`next`),s(`prev`),s(`first`),s(`last`),e.dispatchKeyboardAction(t,{disabled:r,keymap:o})}}};exports.createListKeyControl=n;
|
|
2
|
-
//# sourceMappingURL=list-key-control.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list-key-control.cjs","names":[],"sources":["../../src/controls/list-key-control.ts"],"sourcesContent":["import type { ListControl } from './list-control';\n\nimport { dispatchKeyboardAction } from './internal/keyboard-utils';\n\ntype ListKeyAction = 'first' | 'last' | 'next' | 'prev';\n\nexport type ListKeyControlOptions = {\n control: Pick<ListControl<unknown>, ListKeyAction>;\n disabled?: () => boolean;\n keys?: Partial<Record<ListKeyAction, string[]>> | (() => Partial<Record<ListKeyAction, string[]>>);\n onInvoke?: (action: ListKeyAction, result: unknown, event: KeyboardEvent) => void;\n};\n\nexport type ListKeyControl = {\n handleKeydown: (event: KeyboardEvent) => boolean;\n};\n\nconst DEFAULT_KEYS: Record<ListKeyAction, string[]> = {\n first: ['Home'],\n last: ['End'],\n next: ['ArrowDown'],\n prev: ['ArrowUp'],\n};\n\nexport const createListKeyControl = (options: ListKeyControlOptions): ListKeyControl => {\n const isDisabled = (): boolean => Boolean(options.disabled?.());\n const resolveKeys = (): Record<ListKeyAction, string[]> => {\n const keys = typeof options.keys === 'function' ? options.keys() : options.keys;\n\n return {\n first: keys?.first ?? DEFAULT_KEYS.first,\n last: keys?.last ?? DEFAULT_KEYS.last,\n next: keys?.next ?? DEFAULT_KEYS.next,\n prev: keys?.prev ?? DEFAULT_KEYS.prev,\n };\n };\n\n const handleKeydown = (event: KeyboardEvent): boolean => {\n const keys = resolveKeys();\n const keymap: Record<string, (keyboardEvent: KeyboardEvent) => void> = {};\n\n const bindAction = (action: ListKeyAction) => {\n for (const key of keys[action]) {\n keymap[key] = (keyboardEvent: KeyboardEvent) => {\n const result = options.control[action]();\n\n options.onInvoke?.(action, result, keyboardEvent);\n };\n }\n };\n\n bindAction('next');\n bindAction('prev');\n bindAction('first');\n bindAction('last');\n\n return dispatchKeyboardAction(event, {\n disabled: isDisabled,\n keymap,\n });\n };\n\n return {\n handleKeydown,\n };\n};\n"],"mappings":"iDAiBA,IAAM,EAAgD,CACpD,MAAO,CAAC,OAAO,CACf,KAAM,CAAC,MAAM,CACb,KAAM,CAAC,YAAY,CACnB,KAAM,CAAC,UAAU,CAClB,CAEY,EAAwB,GAAmD,CACtF,IAAM,MAA4B,EAAQ,EAAQ,YAAY,CACxD,MAAqD,CACzD,IAAM,EAAO,OAAO,EAAQ,MAAS,WAAa,EAAQ,MAAM,CAAG,EAAQ,KAE3E,MAAO,CACL,MAAO,GAAM,OAAS,EAAa,MACnC,KAAM,GAAM,MAAQ,EAAa,KACjC,KAAM,GAAM,MAAQ,EAAa,KACjC,KAAM,GAAM,MAAQ,EAAa,KAClC,EA4BH,MAAO,CACL,cA1BqB,GAAkC,CACvD,IAAM,EAAO,GAAa,CACpB,EAAiE,EAAE,CAEnE,EAAc,GAA0B,CAC5C,IAAK,IAAM,KAAO,EAAK,GACrB,EAAO,GAAQ,GAAiC,CAC9C,IAAM,EAAS,EAAQ,QAAQ,IAAS,CAExC,EAAQ,WAAW,EAAQ,EAAQ,EAAc,GAUvD,OALA,EAAW,OAAO,CAClB,EAAW,OAAO,CAClB,EAAW,QAAQ,CACnB,EAAW,OAAO,CAEX,EAAA,uBAAuB,EAAO,CACnC,SAAU,EACV,SACD,CAAC,EAKH"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ListControl } from './list-control';
|
|
2
|
-
type ListKeyAction = 'first' | 'last' | 'next' | 'prev';
|
|
3
|
-
export type ListKeyControlOptions = {
|
|
4
|
-
control: Pick<ListControl<unknown>, ListKeyAction>;
|
|
5
|
-
disabled?: () => boolean;
|
|
6
|
-
keys?: Partial<Record<ListKeyAction, string[]>> | (() => Partial<Record<ListKeyAction, string[]>>);
|
|
7
|
-
onInvoke?: (action: ListKeyAction, result: unknown, event: KeyboardEvent) => void;
|
|
8
|
-
};
|
|
9
|
-
export type ListKeyControl = {
|
|
10
|
-
handleKeydown: (event: KeyboardEvent) => boolean;
|
|
11
|
-
};
|
|
12
|
-
export declare const createListKeyControl: (options: ListKeyControlOptions) => ListKeyControl;
|
|
13
|
-
export {};
|
|
14
|
-
//# sourceMappingURL=list-key-control.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list-key-control.d.ts","sourceRoot":"","sources":["../../src/controls/list-key-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD,KAAK,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAExD,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC;IACnD,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IACnG,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CACnF,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC;CAClD,CAAC;AASF,eAAO,MAAM,oBAAoB,GAAI,SAAS,qBAAqB,KAAG,cAyCrE,CAAC"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{dispatchKeyboardAction as e}from"./internal/keyboard-utils.js";var t={first:[`Home`],last:[`End`],next:[`ArrowDown`],prev:[`ArrowUp`]},n=n=>{let r=()=>!!n.disabled?.(),i=()=>{let e=typeof n.keys==`function`?n.keys():n.keys;return{first:e?.first??t.first,last:e?.last??t.last,next:e?.next??t.next,prev:e?.prev??t.prev}};return{handleKeydown:t=>{let a=i(),o={},s=e=>{for(let t of a[e])o[t]=t=>{let r=n.control[e]();n.onInvoke?.(e,r,t)}};return s(`next`),s(`prev`),s(`first`),s(`last`),e(t,{disabled:r,keymap:o})}}};export{n as createListKeyControl};
|
|
2
|
-
//# sourceMappingURL=list-key-control.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list-key-control.js","names":[],"sources":["../../src/controls/list-key-control.ts"],"sourcesContent":["import type { ListControl } from './list-control';\n\nimport { dispatchKeyboardAction } from './internal/keyboard-utils';\n\ntype ListKeyAction = 'first' | 'last' | 'next' | 'prev';\n\nexport type ListKeyControlOptions = {\n control: Pick<ListControl<unknown>, ListKeyAction>;\n disabled?: () => boolean;\n keys?: Partial<Record<ListKeyAction, string[]>> | (() => Partial<Record<ListKeyAction, string[]>>);\n onInvoke?: (action: ListKeyAction, result: unknown, event: KeyboardEvent) => void;\n};\n\nexport type ListKeyControl = {\n handleKeydown: (event: KeyboardEvent) => boolean;\n};\n\nconst DEFAULT_KEYS: Record<ListKeyAction, string[]> = {\n first: ['Home'],\n last: ['End'],\n next: ['ArrowDown'],\n prev: ['ArrowUp'],\n};\n\nexport const createListKeyControl = (options: ListKeyControlOptions): ListKeyControl => {\n const isDisabled = (): boolean => Boolean(options.disabled?.());\n const resolveKeys = (): Record<ListKeyAction, string[]> => {\n const keys = typeof options.keys === 'function' ? options.keys() : options.keys;\n\n return {\n first: keys?.first ?? DEFAULT_KEYS.first,\n last: keys?.last ?? DEFAULT_KEYS.last,\n next: keys?.next ?? DEFAULT_KEYS.next,\n prev: keys?.prev ?? DEFAULT_KEYS.prev,\n };\n };\n\n const handleKeydown = (event: KeyboardEvent): boolean => {\n const keys = resolveKeys();\n const keymap: Record<string, (keyboardEvent: KeyboardEvent) => void> = {};\n\n const bindAction = (action: ListKeyAction) => {\n for (const key of keys[action]) {\n keymap[key] = (keyboardEvent: KeyboardEvent) => {\n const result = options.control[action]();\n\n options.onInvoke?.(action, result, keyboardEvent);\n };\n }\n };\n\n bindAction('next');\n bindAction('prev');\n bindAction('first');\n bindAction('last');\n\n return dispatchKeyboardAction(event, {\n disabled: isDisabled,\n keymap,\n });\n };\n\n return {\n handleKeydown,\n };\n};\n"],"mappings":"sEAiBA,IAAM,EAAgD,CACpD,MAAO,CAAC,OAAO,CACf,KAAM,CAAC,MAAM,CACb,KAAM,CAAC,YAAY,CACnB,KAAM,CAAC,UAAU,CAClB,CAEY,EAAwB,GAAmD,CACtF,IAAM,MAA4B,EAAQ,EAAQ,YAAY,CACxD,MAAqD,CACzD,IAAM,EAAO,OAAO,EAAQ,MAAS,WAAa,EAAQ,MAAM,CAAG,EAAQ,KAE3E,MAAO,CACL,MAAO,GAAM,OAAS,EAAa,MACnC,KAAM,GAAM,MAAQ,EAAa,KACjC,KAAM,GAAM,MAAQ,EAAa,KACjC,KAAM,GAAM,MAAQ,EAAa,KAClC,EA4BH,MAAO,CACL,cA1BqB,GAAkC,CACvD,IAAM,EAAO,GAAa,CACpB,EAAiE,EAAE,CAEnE,EAAc,GAA0B,CAC5C,IAAK,IAAM,KAAO,EAAK,GACrB,EAAO,GAAQ,GAAiC,CAC9C,IAAM,EAAS,EAAQ,QAAQ,IAAS,CAExC,EAAQ,WAAW,EAAQ,EAAQ,EAAc,GAUvD,OALA,EAAW,OAAO,CAClB,EAAW,OAAO,CAClB,EAAW,QAAQ,CACnB,EAAW,OAAO,CAEX,EAAuB,EAAO,CACnC,SAAU,EACV,SACD,CAAC,EAKH"}
|
package/dist/directives/attr.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"attr.cjs","names":[],"sources":["../../src/directives/attr.ts"],"sourcesContent":["import { type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { type Directive } from '../internal';\nimport { spread } from './spread';\n\nexport type AttrValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ReadonlySignal<string | number | boolean | null | undefined>\n | (() => string | number | boolean | null | undefined);\n\n/**\n * Batch DOM property-binding helper.\n * Applied as `.property` bindings under the hood.\n *\n * @example\n * html`<input ${attrs({ value, disabled, readOnly: readonly })} />`\n */\nexport function attrs(map: Record<string, AttrValue>): Directive {\n const mapped: Record<string, AttrValue> = {};\n\n for (const [key, value] of Object.entries(map)) {\n mapped[`.${key}`] = value;\n }\n\n return spread(mapped);\n}\n"],"mappings":"wFAqBA,SAAgB,EAAM,EAA2C,CAC/D,IAAM,EAAoC,EAAE,CAE5C,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAI,CAC5C,EAAO,IAAI,KAAS,EAGtB,OAAO,EAAA,OAAO,EAAO"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type ReadonlySignal } from '@vielzeug/stateit';
|
|
2
|
-
import { type Directive } from '../internal';
|
|
3
|
-
export type AttrValue = string | number | boolean | null | undefined | ReadonlySignal<string | number | boolean | null | undefined> | (() => string | number | boolean | null | undefined);
|
|
4
|
-
/**
|
|
5
|
-
* Batch DOM property-binding helper.
|
|
6
|
-
* Applied as `.property` bindings under the hood.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* html`<input ${attrs({ value, disabled, readOnly: readonly })} />`
|
|
10
|
-
*/
|
|
11
|
-
export declare function attrs(map: Record<string, AttrValue>): Directive;
|
|
12
|
-
//# sourceMappingURL=attr.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"attr.d.ts","sourceRoot":"","sources":["../../src/directives/attr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,cAAc,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GAC5D,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,SAAS,CAQ/D"}
|
package/dist/directives/attr.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"attr.js","names":[],"sources":["../../src/directives/attr.ts"],"sourcesContent":["import { type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { type Directive } from '../internal';\nimport { spread } from './spread';\n\nexport type AttrValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ReadonlySignal<string | number | boolean | null | undefined>\n | (() => string | number | boolean | null | undefined);\n\n/**\n * Batch DOM property-binding helper.\n * Applied as `.property` bindings under the hood.\n *\n * @example\n * html`<input ${attrs({ value, disabled, readOnly: readonly })} />`\n */\nexport function attrs(map: Record<string, AttrValue>): Directive {\n const mapped: Record<string, AttrValue> = {};\n\n for (const [key, value] of Object.entries(map)) {\n mapped[`.${key}`] = value;\n }\n\n return spread(mapped);\n}\n"],"mappings":"sFAqBA,SAAgB,EAAM,EAA2C,CAC/D,IAAM,EAAoC,EAAE,CAE5C,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAI,CAC5C,EAAO,IAAI,KAAS,EAGtB,OAAO,EAAO,EAAO"}
|
package/dist/directives/bind.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`../internal.cjs`),t=require(`./attr.cjs`);require(`@vielzeug/stateit`);var n=e=>{if(typeof e!=`object`||!e||!(`value`in e))return!1;let t=e.value;return typeof t==`object`&&!!t&&`value`in t},r=(e,t)=>t||(e instanceof HTMLInputElement&&(e.type===`checkbox`||e.type===`radio`)?`checked`:`value`),i=(e,t,n)=>n||(t===`checked`||e instanceof HTMLSelectElement?`change`:`input`),a=(e,t)=>{if(t===`checked`){if(!(e instanceof HTMLInputElement)||e.type!==`checkbox`&&e.type!==`radio`)throw Error(`[craftit:bind] mode "checked" requires <input type="checkbox|radio">.`);return}if(!(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement))throw Error(`[craftit:bind] value binding requires <input>, <textarea>, or <select>.`)},o=e=>{if(e.event!==void 0&&e.event.trim()===``)throw Error(`[craftit:bind] options.event must be a non-empty event name.`);if(e.parse!==void 0&&typeof e.parse!=`function`)throw Error(`[craftit:bind] options.parse must be a function when provided.`)},s=(e,t,n,r)=>{let i=t===`checked`?e.checked:e.value;return n.parse?n.parse(i,e,r):t===`checked`?i:typeof n.value.value==`number`?Number(i):i};function c(c){return{mount(l,u){let d=n(c)?c:{value:c};o(d);let f=r(l,d.as);a(l,f);let p=i(l,f,d.event);t.attrs(f===`checked`?{checked:d.value}:{value:d.value}).mount(l,u),u.registerCleanup(e.listen(l,p,e=>{let t=s(l,f,d,e);Object.is(d.value.value,t)||(d.value.value=t)}))}}}exports.bind=c;
|
|
2
|
-
//# sourceMappingURL=bind.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bind.cjs","names":[],"sources":["../../src/directives/bind.ts"],"sourcesContent":["import { type Signal } from '@vielzeug/stateit';\n\nimport { type Directive, listen } from '../internal';\nimport { attrs } from './attr';\n\nexport type BindMode = 'checked' | 'value';\n\nexport type BindOptions<T extends boolean | number | string> = {\n as?: BindMode;\n event?: string;\n parse?: (value: boolean | string, element: HTMLElement, event: Event) => T;\n value: Signal<T>;\n};\n\nconst isBindOptions = <T extends boolean | number | string>(\n input: Signal<T> | BindOptions<T>,\n): input is BindOptions<T> => {\n if (typeof input !== 'object' || input === null || !('value' in input)) return false;\n\n const candidate = (input as BindOptions<T>).value as unknown;\n\n return typeof candidate === 'object' && candidate !== null && 'value' in (candidate as object);\n};\n\nconst resolveMode = (element: HTMLElement, explicitMode?: BindMode): BindMode => {\n if (explicitMode) return explicitMode;\n\n if (element instanceof HTMLInputElement && (element.type === 'checkbox' || element.type === 'radio')) {\n return 'checked';\n }\n\n return 'value';\n};\n\nconst resolveEventName = (element: HTMLElement, mode: BindMode, explicitEvent?: string): string => {\n if (explicitEvent) return explicitEvent;\n\n if (mode === 'checked' || element instanceof HTMLSelectElement) return 'change';\n\n return 'input';\n};\n\nconst assertBindableTarget = (element: HTMLElement, mode: BindMode): void => {\n if (mode === 'checked') {\n if (!(element instanceof HTMLInputElement) || (element.type !== 'checkbox' && element.type !== 'radio')) {\n throw new Error('[craftit:bind] mode \"checked\" requires <input type=\"checkbox|radio\">.');\n }\n\n return;\n }\n\n if (\n !(\n element instanceof HTMLInputElement ||\n element instanceof HTMLTextAreaElement ||\n element instanceof HTMLSelectElement\n )\n ) {\n throw new Error('[craftit:bind] value binding requires <input>, <textarea>, or <select>.');\n }\n};\n\nconst validateBindOptions = <T extends boolean | number | string>(options: BindOptions<T>): void => {\n if (options.event !== undefined && options.event.trim() === '') {\n throw new Error('[craftit:bind] options.event must be a non-empty event name.');\n }\n\n if (options.parse !== undefined && typeof options.parse !== 'function') {\n throw new Error('[craftit:bind] options.parse must be a function when provided.');\n }\n};\n\nconst readBoundValue = <T extends boolean | number | string>(\n element: HTMLElement,\n mode: BindMode,\n options: BindOptions<T>,\n event: Event,\n): T => {\n const raw = mode === 'checked' ? (element as HTMLInputElement).checked : (element as HTMLInputElement).value;\n\n if (options.parse) return options.parse(raw, element, event);\n\n if (mode === 'checked') return raw as T;\n\n if (typeof options.value.value === 'number') return Number(raw) as T;\n\n return raw as T;\n};\n\n/**\n * Creates a two-way binding between a writable Signal and a form element.\n *\n * Defaults:\n * - Checkbox/radio elements bind `.checked` via `change`\n * - Other form elements bind `.value` via `input`\n * - Select elements bind `.value` via `change`\n * - Number signals default to `Number(el.value)` unless you provide `parse`\n *\n * Internally this reuses craftit's shared property-binding path, so `.value`,\n * `.checked`, `attrs(...)`, and `spread({ '.value': ... })` stay in sync.\n *\n * Use in spread position on any form element.\n *\n * @example\n * import { bind } from '@vielzeug/craftit/directives';\n *\n * const name = signal('');\n * html`<input ${bind({ value: name })} />`\n *\n * const accepted = signal(false);\n * html`<input type=\"checkbox\" ${bind({ value: accepted })} />`\n *\n * const amount = signal(1);\n * html`<input type=\"number\" ${bind({ value: amount })} />`\n */\nexport function bind<T extends boolean | number | string>(value: Signal<T>): Directive;\nexport function bind<T extends boolean | number | string>(options: BindOptions<T>): Directive;\nexport function bind<T extends boolean | number | string>(input: Signal<T> | BindOptions<T>): Directive {\n return {\n mount(el, context) {\n const options = isBindOptions(input) ? input : ({ value: input } as BindOptions<T>);\n\n validateBindOptions(options);\n\n const mode = resolveMode(el, options.as);\n\n assertBindableTarget(el, mode);\n\n const eventName = resolveEventName(el, mode, options.event);\n\n attrs(mode === 'checked' ? { checked: options.value } : { value: options.value }).mount!(el, context);\n\n context.registerCleanup(\n listen(el, eventName, (event: Event) => {\n const next = readBoundValue(el, mode, options, event);\n\n if (!Object.is(options.value.value, next)) options.value.value = next;\n }),\n );\n },\n };\n}\n"],"mappings":"wFAcA,IAAM,EACJ,GAC4B,CAC5B,GAAI,OAAO,GAAU,WAAY,GAAkB,EAAE,UAAW,GAAQ,MAAO,GAE/E,IAAM,EAAa,EAAyB,MAE5C,OAAO,OAAO,GAAc,YAAY,GAAsB,UAAY,GAGtE,GAAe,EAAsB,IACrC,IAEA,aAAmB,mBAAqB,EAAQ,OAAS,YAAc,EAAQ,OAAS,SACnF,UAGF,SAGH,GAAoB,EAAsB,EAAgB,IAC1D,IAEA,IAAS,WAAa,aAAmB,kBAA0B,SAEhE,SAGH,GAAwB,EAAsB,IAAyB,CAC3E,GAAI,IAAS,UAAW,CACtB,GAAI,EAAE,aAAmB,mBAAsB,EAAQ,OAAS,YAAc,EAAQ,OAAS,QAC7F,MAAU,MAAM,wEAAwE,CAG1F,OAGF,GACE,EACE,aAAmB,kBACnB,aAAmB,qBACnB,aAAmB,mBAGrB,MAAU,MAAM,0EAA0E,EAIxF,EAA4D,GAAkC,CAClG,GAAI,EAAQ,QAAU,IAAA,IAAa,EAAQ,MAAM,MAAM,GAAK,GAC1D,MAAU,MAAM,+DAA+D,CAGjF,GAAI,EAAQ,QAAU,IAAA,IAAa,OAAO,EAAQ,OAAU,WAC1D,MAAU,MAAM,iEAAiE,EAI/E,GACJ,EACA,EACA,EACA,IACM,CACN,IAAM,EAAM,IAAS,UAAa,EAA6B,QAAW,EAA6B,MAQvG,OANI,EAAQ,MAAc,EAAQ,MAAM,EAAK,EAAS,EAAM,CAExD,IAAS,UAAkB,EAE3B,OAAO,EAAQ,MAAM,OAAU,SAAiB,OAAO,EAAI,CAExD,GA+BT,SAAgB,EAA0C,EAA8C,CACtG,MAAO,CACL,MAAM,EAAI,EAAS,CACjB,IAAM,EAAU,EAAc,EAAM,CAAG,EAAS,CAAE,MAAO,EAAO,CAEhE,EAAoB,EAAQ,CAE5B,IAAM,EAAO,EAAY,EAAI,EAAQ,GAAG,CAExC,EAAqB,EAAI,EAAK,CAE9B,IAAM,EAAY,EAAiB,EAAI,EAAM,EAAQ,MAAM,CAE3D,EAAA,MAAM,IAAS,UAAY,CAAE,QAAS,EAAQ,MAAO,CAAG,CAAE,MAAO,EAAQ,MAAO,CAAC,CAAC,MAAO,EAAI,EAAQ,CAErG,EAAQ,gBACN,EAAA,OAAO,EAAI,EAAY,GAAiB,CACtC,IAAM,EAAO,EAAe,EAAI,EAAM,EAAS,EAAM,CAEhD,OAAO,GAAG,EAAQ,MAAM,MAAO,EAAK,GAAE,EAAQ,MAAM,MAAQ,IACjE,CACH,EAEJ"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { type Signal } from '@vielzeug/stateit';
|
|
2
|
-
import { type Directive } from '../internal';
|
|
3
|
-
export type BindMode = 'checked' | 'value';
|
|
4
|
-
export type BindOptions<T extends boolean | number | string> = {
|
|
5
|
-
as?: BindMode;
|
|
6
|
-
event?: string;
|
|
7
|
-
parse?: (value: boolean | string, element: HTMLElement, event: Event) => T;
|
|
8
|
-
value: Signal<T>;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Creates a two-way binding between a writable Signal and a form element.
|
|
12
|
-
*
|
|
13
|
-
* Defaults:
|
|
14
|
-
* - Checkbox/radio elements bind `.checked` via `change`
|
|
15
|
-
* - Other form elements bind `.value` via `input`
|
|
16
|
-
* - Select elements bind `.value` via `change`
|
|
17
|
-
* - Number signals default to `Number(el.value)` unless you provide `parse`
|
|
18
|
-
*
|
|
19
|
-
* Internally this reuses craftit's shared property-binding path, so `.value`,
|
|
20
|
-
* `.checked`, `attrs(...)`, and `spread({ '.value': ... })` stay in sync.
|
|
21
|
-
*
|
|
22
|
-
* Use in spread position on any form element.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* import { bind } from '@vielzeug/craftit/directives';
|
|
26
|
-
*
|
|
27
|
-
* const name = signal('');
|
|
28
|
-
* html`<input ${bind({ value: name })} />`
|
|
29
|
-
*
|
|
30
|
-
* const accepted = signal(false);
|
|
31
|
-
* html`<input type="checkbox" ${bind({ value: accepted })} />`
|
|
32
|
-
*
|
|
33
|
-
* const amount = signal(1);
|
|
34
|
-
* html`<input type="number" ${bind({ value: amount })} />`
|
|
35
|
-
*/
|
|
36
|
-
export declare function bind<T extends boolean | number | string>(value: Signal<T>): Directive;
|
|
37
|
-
export declare function bind<T extends boolean | number | string>(options: BindOptions<T>): Directive;
|
|
38
|
-
//# sourceMappingURL=bind.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../../src/directives/bind.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,aAAa,CAAC;AAGrD,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3C,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,GAAG,MAAM,GAAG,MAAM,IAAI;IAC7D,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,KAAK,CAAC,CAAC;IAC3E,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CAClB,CAAC;AA6EF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,OAAO,GAAG,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AACvF,wBAAgB,IAAI,CAAC,CAAC,SAAS,OAAO,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC"}
|
package/dist/directives/bind.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{listen as e}from"../internal.js";import{attrs as t}from"./attr.js";import"@vielzeug/stateit";var n=e=>{if(typeof e!=`object`||!e||!(`value`in e))return!1;let t=e.value;return typeof t==`object`&&!!t&&`value`in t},r=(e,t)=>t||(e instanceof HTMLInputElement&&(e.type===`checkbox`||e.type===`radio`)?`checked`:`value`),i=(e,t,n)=>n||(t===`checked`||e instanceof HTMLSelectElement?`change`:`input`),a=(e,t)=>{if(t===`checked`){if(!(e instanceof HTMLInputElement)||e.type!==`checkbox`&&e.type!==`radio`)throw Error(`[craftit:bind] mode "checked" requires <input type="checkbox|radio">.`);return}if(!(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement))throw Error(`[craftit:bind] value binding requires <input>, <textarea>, or <select>.`)},o=e=>{if(e.event!==void 0&&e.event.trim()===``)throw Error(`[craftit:bind] options.event must be a non-empty event name.`);if(e.parse!==void 0&&typeof e.parse!=`function`)throw Error(`[craftit:bind] options.parse must be a function when provided.`)},s=(e,t,n,r)=>{let i=t===`checked`?e.checked:e.value;return n.parse?n.parse(i,e,r):t===`checked`?i:typeof n.value.value==`number`?Number(i):i};function c(c){return{mount(l,u){let d=n(c)?c:{value:c};o(d);let f=r(l,d.as);a(l,f);let p=i(l,f,d.event);t(f===`checked`?{checked:d.value}:{value:d.value}).mount(l,u),u.registerCleanup(e(l,p,e=>{let t=s(l,f,d,e);Object.is(d.value.value,t)||(d.value.value=t)}))}}}export{c as bind};
|
|
2
|
-
//# sourceMappingURL=bind.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bind.js","names":[],"sources":["../../src/directives/bind.ts"],"sourcesContent":["import { type Signal } from '@vielzeug/stateit';\n\nimport { type Directive, listen } from '../internal';\nimport { attrs } from './attr';\n\nexport type BindMode = 'checked' | 'value';\n\nexport type BindOptions<T extends boolean | number | string> = {\n as?: BindMode;\n event?: string;\n parse?: (value: boolean | string, element: HTMLElement, event: Event) => T;\n value: Signal<T>;\n};\n\nconst isBindOptions = <T extends boolean | number | string>(\n input: Signal<T> | BindOptions<T>,\n): input is BindOptions<T> => {\n if (typeof input !== 'object' || input === null || !('value' in input)) return false;\n\n const candidate = (input as BindOptions<T>).value as unknown;\n\n return typeof candidate === 'object' && candidate !== null && 'value' in (candidate as object);\n};\n\nconst resolveMode = (element: HTMLElement, explicitMode?: BindMode): BindMode => {\n if (explicitMode) return explicitMode;\n\n if (element instanceof HTMLInputElement && (element.type === 'checkbox' || element.type === 'radio')) {\n return 'checked';\n }\n\n return 'value';\n};\n\nconst resolveEventName = (element: HTMLElement, mode: BindMode, explicitEvent?: string): string => {\n if (explicitEvent) return explicitEvent;\n\n if (mode === 'checked' || element instanceof HTMLSelectElement) return 'change';\n\n return 'input';\n};\n\nconst assertBindableTarget = (element: HTMLElement, mode: BindMode): void => {\n if (mode === 'checked') {\n if (!(element instanceof HTMLInputElement) || (element.type !== 'checkbox' && element.type !== 'radio')) {\n throw new Error('[craftit:bind] mode \"checked\" requires <input type=\"checkbox|radio\">.');\n }\n\n return;\n }\n\n if (\n !(\n element instanceof HTMLInputElement ||\n element instanceof HTMLTextAreaElement ||\n element instanceof HTMLSelectElement\n )\n ) {\n throw new Error('[craftit:bind] value binding requires <input>, <textarea>, or <select>.');\n }\n};\n\nconst validateBindOptions = <T extends boolean | number | string>(options: BindOptions<T>): void => {\n if (options.event !== undefined && options.event.trim() === '') {\n throw new Error('[craftit:bind] options.event must be a non-empty event name.');\n }\n\n if (options.parse !== undefined && typeof options.parse !== 'function') {\n throw new Error('[craftit:bind] options.parse must be a function when provided.');\n }\n};\n\nconst readBoundValue = <T extends boolean | number | string>(\n element: HTMLElement,\n mode: BindMode,\n options: BindOptions<T>,\n event: Event,\n): T => {\n const raw = mode === 'checked' ? (element as HTMLInputElement).checked : (element as HTMLInputElement).value;\n\n if (options.parse) return options.parse(raw, element, event);\n\n if (mode === 'checked') return raw as T;\n\n if (typeof options.value.value === 'number') return Number(raw) as T;\n\n return raw as T;\n};\n\n/**\n * Creates a two-way binding between a writable Signal and a form element.\n *\n * Defaults:\n * - Checkbox/radio elements bind `.checked` via `change`\n * - Other form elements bind `.value` via `input`\n * - Select elements bind `.value` via `change`\n * - Number signals default to `Number(el.value)` unless you provide `parse`\n *\n * Internally this reuses craftit's shared property-binding path, so `.value`,\n * `.checked`, `attrs(...)`, and `spread({ '.value': ... })` stay in sync.\n *\n * Use in spread position on any form element.\n *\n * @example\n * import { bind } from '@vielzeug/craftit/directives';\n *\n * const name = signal('');\n * html`<input ${bind({ value: name })} />`\n *\n * const accepted = signal(false);\n * html`<input type=\"checkbox\" ${bind({ value: accepted })} />`\n *\n * const amount = signal(1);\n * html`<input type=\"number\" ${bind({ value: amount })} />`\n */\nexport function bind<T extends boolean | number | string>(value: Signal<T>): Directive;\nexport function bind<T extends boolean | number | string>(options: BindOptions<T>): Directive;\nexport function bind<T extends boolean | number | string>(input: Signal<T> | BindOptions<T>): Directive {\n return {\n mount(el, context) {\n const options = isBindOptions(input) ? input : ({ value: input } as BindOptions<T>);\n\n validateBindOptions(options);\n\n const mode = resolveMode(el, options.as);\n\n assertBindableTarget(el, mode);\n\n const eventName = resolveEventName(el, mode, options.event);\n\n attrs(mode === 'checked' ? { checked: options.value } : { value: options.value }).mount!(el, context);\n\n context.registerCleanup(\n listen(el, eventName, (event: Event) => {\n const next = readBoundValue(el, mode, options, event);\n\n if (!Object.is(options.value.value, next)) options.value.value = next;\n }),\n );\n },\n };\n}\n"],"mappings":"oGAcA,IAAM,EACJ,GAC4B,CAC5B,GAAI,OAAO,GAAU,WAAY,GAAkB,EAAE,UAAW,GAAQ,MAAO,GAE/E,IAAM,EAAa,EAAyB,MAE5C,OAAO,OAAO,GAAc,YAAY,GAAsB,UAAY,GAGtE,GAAe,EAAsB,IACrC,IAEA,aAAmB,mBAAqB,EAAQ,OAAS,YAAc,EAAQ,OAAS,SACnF,UAGF,SAGH,GAAoB,EAAsB,EAAgB,IAC1D,IAEA,IAAS,WAAa,aAAmB,kBAA0B,SAEhE,SAGH,GAAwB,EAAsB,IAAyB,CAC3E,GAAI,IAAS,UAAW,CACtB,GAAI,EAAE,aAAmB,mBAAsB,EAAQ,OAAS,YAAc,EAAQ,OAAS,QAC7F,MAAU,MAAM,wEAAwE,CAG1F,OAGF,GACE,EACE,aAAmB,kBACnB,aAAmB,qBACnB,aAAmB,mBAGrB,MAAU,MAAM,0EAA0E,EAIxF,EAA4D,GAAkC,CAClG,GAAI,EAAQ,QAAU,IAAA,IAAa,EAAQ,MAAM,MAAM,GAAK,GAC1D,MAAU,MAAM,+DAA+D,CAGjF,GAAI,EAAQ,QAAU,IAAA,IAAa,OAAO,EAAQ,OAAU,WAC1D,MAAU,MAAM,iEAAiE,EAI/E,GACJ,EACA,EACA,EACA,IACM,CACN,IAAM,EAAM,IAAS,UAAa,EAA6B,QAAW,EAA6B,MAQvG,OANI,EAAQ,MAAc,EAAQ,MAAM,EAAK,EAAS,EAAM,CAExD,IAAS,UAAkB,EAE3B,OAAO,EAAQ,MAAM,OAAU,SAAiB,OAAO,EAAI,CAExD,GA+BT,SAAgB,EAA0C,EAA8C,CACtG,MAAO,CACL,MAAM,EAAI,EAAS,CACjB,IAAM,EAAU,EAAc,EAAM,CAAG,EAAS,CAAE,MAAO,EAAO,CAEhE,EAAoB,EAAQ,CAE5B,IAAM,EAAO,EAAY,EAAI,EAAQ,GAAG,CAExC,EAAqB,EAAI,EAAK,CAE9B,IAAM,EAAY,EAAiB,EAAI,EAAM,EAAQ,MAAM,CAE3D,EAAM,IAAS,UAAY,CAAE,QAAS,EAAQ,MAAO,CAAG,CAAE,MAAO,EAAQ,MAAO,CAAC,CAAC,MAAO,EAAI,EAAQ,CAErG,EAAQ,gBACN,EAAO,EAAI,EAAY,GAAiB,CACtC,IAAM,EAAO,EAAe,EAAI,EAAM,EAAS,EAAM,CAEhD,OAAO,GAAG,EAAQ,MAAM,MAAO,EAAK,GAAE,EAAQ,MAAM,MAAQ,IACjE,CACH,EAEJ"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
let e=require(`@vielzeug/stateit`);var t=e=>{if(!Array.isArray(e.cases))throw Error(`[craftit:choose] options.cases must be an array of [key, templateFn] entries.`);for(let t=0;t<e.cases.length;t++){let n=e.cases[t];if(!Array.isArray(n)||n.length!==2||typeof n[1]!=`function`)throw Error(`[craftit:choose] Invalid case at index ${t}. Expected [key, templateFn].`)}if(e.fallback!==void 0&&typeof e.fallback!=`function`)throw Error(`[craftit:choose] options.fallback must be a function when provided.`)};function n(n){t(n);let i=new Map(n.cases),a=e=>(i.get(e)??n.fallback??r)(),{value:o}=n;return(0,e.isSignal)(o)?()=>a(o.value):typeof o==`function`?()=>a(o()):a(o)}var r=()=>``;exports.choose=n;
|
|
2
|
-
//# sourceMappingURL=choose.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"choose.cjs","names":[],"sources":["../../src/directives/choose.ts"],"sourcesContent":["import { isSignal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../internal';\n\ntype TemplateFn = () => string | HTMLResult;\ntype CaseEntry<T> = readonly [T, TemplateFn];\n\nexport type ChooseOptions<T extends PropertyKey> = {\n cases: ReadonlyArray<CaseEntry<T>>;\n fallback?: TemplateFn;\n value: T | ReadonlySignal<T> | (() => T);\n};\n\nconst validateChooseOptions = <T extends PropertyKey>(options: ChooseOptions<T>): void => {\n if (!Array.isArray(options.cases)) {\n throw new Error('[craftit:choose] options.cases must be an array of [key, templateFn] entries.');\n }\n\n for (let i = 0; i < options.cases.length; i++) {\n const entry = options.cases[i] as unknown;\n\n if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[1] !== 'function') {\n throw new Error(`[craftit:choose] Invalid case at index ${i}. Expected [key, templateFn].`);\n }\n }\n\n if (options.fallback !== undefined && typeof options.fallback !== 'function') {\n throw new Error('[craftit:choose] options.fallback must be a function when provided.');\n }\n};\n\n/**\n * Renders the template matching the current value — like a type-safe `switch`.\n * Cases are `[value, templateFn]` pairs evaluated with strict equality (`===`).\n *\n * The discriminant can be a static value, a reactive Signal, or a getter function.\n * When reactive, the rendered output updates automatically when the value changes.\n *\n * @example\n * import { choose } from '@vielzeug/craftit/directives';\n *\n * // Static\n * html`${choose({\n * value: section,\n * cases: [\n * ['home', () => html`<h1>Home</h1>`],\n * ['about', () => html`<h1>About</h1>`],\n * ],\n * fallback: () => html`<h1>Not found</h1>`,\n * })}`\n *\n * // Reactive signal — updates on change\n * const tab = signal('home');\n * html`${choose({ value: tab, cases: [['home', () => html`<home-panel>`], ['about', () => html`<about-panel>`]] })}`\n *\n * // Reactive getter\n * html`${choose({ value: () => props.view.value, cases })}`\n */\nexport function choose<T extends PropertyKey>(options: ChooseOptions<T>): string | HTMLResult | TemplateFn {\n validateChooseOptions(options);\n\n const caseMap = new Map(options.cases);\n const pick = (value: T): string | HTMLResult => (caseMap.get(value) ?? options.fallback ?? emptyTemplate)();\n const { value } = options;\n\n if (isSignal(value)) {\n return () => pick((value as ReadonlySignal<T>).value);\n }\n\n if (typeof value === 'function') {\n return () => pick((value as () => T)());\n }\n\n return pick(value as T);\n}\n\nconst emptyTemplate = (): string => '';\n"],"mappings":"mCAaA,IAAM,EAAgD,GAAoC,CACxF,GAAI,CAAC,MAAM,QAAQ,EAAQ,MAAM,CAC/B,MAAU,MAAM,gFAAgF,CAGlG,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,MAAM,OAAQ,IAAK,CAC7C,IAAM,EAAQ,EAAQ,MAAM,GAE5B,GAAI,CAAC,MAAM,QAAQ,EAAM,EAAI,EAAM,SAAW,GAAK,OAAO,EAAM,IAAO,WACrE,MAAU,MAAM,0CAA0C,EAAE,+BAA+B,CAI/F,GAAI,EAAQ,WAAa,IAAA,IAAa,OAAO,EAAQ,UAAa,WAChE,MAAU,MAAM,sEAAsE,EA+B1F,SAAgB,EAA8B,EAA6D,CACzG,EAAsB,EAAQ,CAE9B,IAAM,EAAU,IAAI,IAAI,EAAQ,MAAM,CAChC,EAAQ,IAAmC,EAAQ,IAAI,EAAM,EAAI,EAAQ,UAAY,IAAgB,CACrG,CAAE,SAAU,EAUlB,OARA,EAAA,EAAA,UAAa,EAAM,KACJ,EAAM,EAA4B,MAAM,CAGnD,OAAO,GAAU,eACN,EAAM,GAAmB,CAAC,CAGlC,EAAK,EAAW,CAGzB,IAAM,MAA8B"}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { type ReadonlySignal } from '@vielzeug/stateit';
|
|
2
|
-
import type { HTMLResult } from '../internal';
|
|
3
|
-
type TemplateFn = () => string | HTMLResult;
|
|
4
|
-
type CaseEntry<T> = readonly [T, TemplateFn];
|
|
5
|
-
export type ChooseOptions<T extends PropertyKey> = {
|
|
6
|
-
cases: ReadonlyArray<CaseEntry<T>>;
|
|
7
|
-
fallback?: TemplateFn;
|
|
8
|
-
value: T | ReadonlySignal<T> | (() => T);
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Renders the template matching the current value — like a type-safe `switch`.
|
|
12
|
-
* Cases are `[value, templateFn]` pairs evaluated with strict equality (`===`).
|
|
13
|
-
*
|
|
14
|
-
* The discriminant can be a static value, a reactive Signal, or a getter function.
|
|
15
|
-
* When reactive, the rendered output updates automatically when the value changes.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* import { choose } from '@vielzeug/craftit/directives';
|
|
19
|
-
*
|
|
20
|
-
* // Static
|
|
21
|
-
* html`${choose({
|
|
22
|
-
* value: section,
|
|
23
|
-
* cases: [
|
|
24
|
-
* ['home', () => html`<h1>Home</h1>`],
|
|
25
|
-
* ['about', () => html`<h1>About</h1>`],
|
|
26
|
-
* ],
|
|
27
|
-
* fallback: () => html`<h1>Not found</h1>`,
|
|
28
|
-
* })}`
|
|
29
|
-
*
|
|
30
|
-
* // Reactive signal — updates on change
|
|
31
|
-
* const tab = signal('home');
|
|
32
|
-
* html`${choose({ value: tab, cases: [['home', () => html`<home-panel>`], ['about', () => html`<about-panel>`]] })}`
|
|
33
|
-
*
|
|
34
|
-
* // Reactive getter
|
|
35
|
-
* html`${choose({ value: () => props.view.value, cases })}`
|
|
36
|
-
*/
|
|
37
|
-
export declare function choose<T extends PropertyKey>(options: ChooseOptions<T>): string | HTMLResult | TemplateFn;
|
|
38
|
-
export {};
|
|
39
|
-
//# sourceMappingURL=choose.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"choose.d.ts","sourceRoot":"","sources":["../../src/directives/choose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,KAAK,UAAU,GAAG,MAAM,MAAM,GAAG,UAAU,CAAC;AAC5C,KAAK,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AAE7C,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,WAAW,IAAI;IACjD,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,KAAK,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CAC1C,CAAC;AAoBF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAgBzG"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{isSignal as e}from"@vielzeug/stateit";var t=e=>{if(!Array.isArray(e.cases))throw Error(`[craftit:choose] options.cases must be an array of [key, templateFn] entries.`);for(let t=0;t<e.cases.length;t++){let n=e.cases[t];if(!Array.isArray(n)||n.length!==2||typeof n[1]!=`function`)throw Error(`[craftit:choose] Invalid case at index ${t}. Expected [key, templateFn].`)}if(e.fallback!==void 0&&typeof e.fallback!=`function`)throw Error(`[craftit:choose] options.fallback must be a function when provided.`)};function n(n){t(n);let i=new Map(n.cases),a=e=>(i.get(e)??n.fallback??r)(),{value:o}=n;return e(o)?()=>a(o.value):typeof o==`function`?()=>a(o()):a(o)}var r=()=>``;export{n as choose};
|
|
2
|
-
//# sourceMappingURL=choose.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"choose.js","names":[],"sources":["../../src/directives/choose.ts"],"sourcesContent":["import { isSignal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../internal';\n\ntype TemplateFn = () => string | HTMLResult;\ntype CaseEntry<T> = readonly [T, TemplateFn];\n\nexport type ChooseOptions<T extends PropertyKey> = {\n cases: ReadonlyArray<CaseEntry<T>>;\n fallback?: TemplateFn;\n value: T | ReadonlySignal<T> | (() => T);\n};\n\nconst validateChooseOptions = <T extends PropertyKey>(options: ChooseOptions<T>): void => {\n if (!Array.isArray(options.cases)) {\n throw new Error('[craftit:choose] options.cases must be an array of [key, templateFn] entries.');\n }\n\n for (let i = 0; i < options.cases.length; i++) {\n const entry = options.cases[i] as unknown;\n\n if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[1] !== 'function') {\n throw new Error(`[craftit:choose] Invalid case at index ${i}. Expected [key, templateFn].`);\n }\n }\n\n if (options.fallback !== undefined && typeof options.fallback !== 'function') {\n throw new Error('[craftit:choose] options.fallback must be a function when provided.');\n }\n};\n\n/**\n * Renders the template matching the current value — like a type-safe `switch`.\n * Cases are `[value, templateFn]` pairs evaluated with strict equality (`===`).\n *\n * The discriminant can be a static value, a reactive Signal, or a getter function.\n * When reactive, the rendered output updates automatically when the value changes.\n *\n * @example\n * import { choose } from '@vielzeug/craftit/directives';\n *\n * // Static\n * html`${choose({\n * value: section,\n * cases: [\n * ['home', () => html`<h1>Home</h1>`],\n * ['about', () => html`<h1>About</h1>`],\n * ],\n * fallback: () => html`<h1>Not found</h1>`,\n * })}`\n *\n * // Reactive signal — updates on change\n * const tab = signal('home');\n * html`${choose({ value: tab, cases: [['home', () => html`<home-panel>`], ['about', () => html`<about-panel>`]] })}`\n *\n * // Reactive getter\n * html`${choose({ value: () => props.view.value, cases })}`\n */\nexport function choose<T extends PropertyKey>(options: ChooseOptions<T>): string | HTMLResult | TemplateFn {\n validateChooseOptions(options);\n\n const caseMap = new Map(options.cases);\n const pick = (value: T): string | HTMLResult => (caseMap.get(value) ?? options.fallback ?? emptyTemplate)();\n const { value } = options;\n\n if (isSignal(value)) {\n return () => pick((value as ReadonlySignal<T>).value);\n }\n\n if (typeof value === 'function') {\n return () => pick((value as () => T)());\n }\n\n return pick(value as T);\n}\n\nconst emptyTemplate = (): string => '';\n"],"mappings":"6CAaA,IAAM,EAAgD,GAAoC,CACxF,GAAI,CAAC,MAAM,QAAQ,EAAQ,MAAM,CAC/B,MAAU,MAAM,gFAAgF,CAGlG,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,MAAM,OAAQ,IAAK,CAC7C,IAAM,EAAQ,EAAQ,MAAM,GAE5B,GAAI,CAAC,MAAM,QAAQ,EAAM,EAAI,EAAM,SAAW,GAAK,OAAO,EAAM,IAAO,WACrE,MAAU,MAAM,0CAA0C,EAAE,+BAA+B,CAI/F,GAAI,EAAQ,WAAa,IAAA,IAAa,OAAO,EAAQ,UAAa,WAChE,MAAU,MAAM,sEAAsE,EA+B1F,SAAgB,EAA8B,EAA6D,CACzG,EAAsB,EAAQ,CAE9B,IAAM,EAAU,IAAI,IAAI,EAAQ,MAAM,CAChC,EAAQ,IAAmC,EAAQ,IAAI,EAAM,EAAI,EAAQ,UAAY,IAAgB,CACrG,CAAE,SAAU,EAUlB,OARI,EAAS,EAAM,KACJ,EAAM,EAA4B,MAAM,CAGnD,OAAO,GAAU,eACN,EAAM,GAAmB,CAAC,CAGlC,EAAK,EAAW,CAGzB,IAAM,MAA8B"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
let e=require(`@vielzeug/stateit`);function t(t){let n=Object.entries(t),r=n.some(([,t])=>(0,e.isSignal)(t)||typeof t==`function`),i=()=>n.filter(([,t])=>(0,e.isSignal)(t)?t.value:typeof t==`function`?!!t():!!t).map(([e])=>e).join(` `);return r?(0,e.computed)(i):i()}exports.classes=t;
|
|
2
|
-
//# sourceMappingURL=classes.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"classes.cjs","names":[],"sources":["../../src/directives/classes.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\ntype ClassValue = boolean | undefined | null | Signal<boolean> | ReadonlySignal<boolean> | (() => boolean);\n\n/**\n * Build a dynamic class string from an object map of class names to conditions.\n * Conditions can be static booleans, reactive Signals, or getter functions.\n * When any condition is reactive the returned value is a `ReadonlySignal<string>`\n * so it can be bound directly to a `class` attribute.\n *\n * @example\n * import { classes } from '@vielzeug/craftit/directives';\n *\n * // Static — returns a plain string\n * html`<div class=${classes({ foo: true, bar: false })}></div>`\n *\n * // Reactive — returns a signal; no arrow-function wrapper needed\n * html`<div class=${classes({ active: isActive, disabled: isDisabled })}></div>`\n */\nexport function classes(map: Record<string, ClassValue>): string | ReadonlySignal<string> {\n const entries = Object.entries(map);\n const hasReactive = entries.some(([, v]) => isSignal(v) || typeof v === 'function');\n\n const build = (): string =>\n entries\n .filter(([, v]) => {\n if (isSignal(v)) return (v as ReadonlySignal<boolean>).value;\n\n if (typeof v === 'function') return !!(v as () => boolean)();\n\n return !!v;\n })\n .map(([k]) => k)\n .join(' ');\n\n return hasReactive ? computed(build) : build();\n}\n"],"mappings":"mCAmBA,SAAgB,EAAQ,EAAkE,CACxF,IAAM,EAAU,OAAO,QAAQ,EAAI,CAC7B,EAAc,EAAQ,MAAM,EAAG,MAAA,EAAA,EAAA,UAAgB,EAAE,EAAI,OAAO,GAAM,WAAW,CAE7E,MACJ,EACG,QAAQ,EAAG,MACV,EAAA,EAAA,UAAa,EAAE,CAAU,EAA8B,MAEnD,OAAO,GAAM,WAAmB,CAAC,CAAE,GAAqB,CAErD,CAAC,CAAC,EACT,CACD,KAAK,CAAC,KAAO,EAAE,CACf,KAAK,IAAI,CAEd,OAAO,GAAA,EAAA,EAAA,UAAuB,EAAM,CAAG,GAAO"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
|
|
2
|
-
type ClassValue = boolean | undefined | null | Signal<boolean> | ReadonlySignal<boolean> | (() => boolean);
|
|
3
|
-
/**
|
|
4
|
-
* Build a dynamic class string from an object map of class names to conditions.
|
|
5
|
-
* Conditions can be static booleans, reactive Signals, or getter functions.
|
|
6
|
-
* When any condition is reactive the returned value is a `ReadonlySignal<string>`
|
|
7
|
-
* so it can be bound directly to a `class` attribute.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* import { classes } from '@vielzeug/craftit/directives';
|
|
11
|
-
*
|
|
12
|
-
* // Static — returns a plain string
|
|
13
|
-
* html`<div class=${classes({ foo: true, bar: false })}></div>`
|
|
14
|
-
*
|
|
15
|
-
* // Reactive — returns a signal; no arrow-function wrapper needed
|
|
16
|
-
* html`<div class=${classes({ active: isActive, disabled: isDisabled })}></div>`
|
|
17
|
-
*/
|
|
18
|
-
export declare function classes(map: Record<string, ClassValue>): string | ReadonlySignal<string>;
|
|
19
|
-
export {};
|
|
20
|
-
//# sourceMappingURL=classes.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"classes.d.ts","sourceRoot":"","sources":["../../src/directives/classes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEzF,KAAK,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;AAE3G;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAiBxF"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{computed as e,isSignal as t}from"@vielzeug/stateit";function n(n){let r=Object.entries(n),i=r.some(([,e])=>t(e)||typeof e==`function`),a=()=>r.filter(([,e])=>t(e)?e.value:typeof e==`function`?!!e():!!e).map(([e])=>e).join(` `);return i?e(a):a()}export{n as classes};
|
|
2
|
-
//# sourceMappingURL=classes.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"classes.js","names":[],"sources":["../../src/directives/classes.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\ntype ClassValue = boolean | undefined | null | Signal<boolean> | ReadonlySignal<boolean> | (() => boolean);\n\n/**\n * Build a dynamic class string from an object map of class names to conditions.\n * Conditions can be static booleans, reactive Signals, or getter functions.\n * When any condition is reactive the returned value is a `ReadonlySignal<string>`\n * so it can be bound directly to a `class` attribute.\n *\n * @example\n * import { classes } from '@vielzeug/craftit/directives';\n *\n * // Static — returns a plain string\n * html`<div class=${classes({ foo: true, bar: false })}></div>`\n *\n * // Reactive — returns a signal; no arrow-function wrapper needed\n * html`<div class=${classes({ active: isActive, disabled: isDisabled })}></div>`\n */\nexport function classes(map: Record<string, ClassValue>): string | ReadonlySignal<string> {\n const entries = Object.entries(map);\n const hasReactive = entries.some(([, v]) => isSignal(v) || typeof v === 'function');\n\n const build = (): string =>\n entries\n .filter(([, v]) => {\n if (isSignal(v)) return (v as ReadonlySignal<boolean>).value;\n\n if (typeof v === 'function') return !!(v as () => boolean)();\n\n return !!v;\n })\n .map(([k]) => k)\n .join(' ');\n\n return hasReactive ? computed(build) : build();\n}\n"],"mappings":"2DAmBA,SAAgB,EAAQ,EAAkE,CACxF,IAAM,EAAU,OAAO,QAAQ,EAAI,CAC7B,EAAc,EAAQ,MAAM,EAAG,KAAO,EAAS,EAAE,EAAI,OAAO,GAAM,WAAW,CAE7E,MACJ,EACG,QAAQ,EAAG,KACN,EAAS,EAAE,CAAU,EAA8B,MAEnD,OAAO,GAAM,WAAmB,CAAC,CAAE,GAAqB,CAErD,CAAC,CAAC,EACT,CACD,KAAK,CAAC,KAAO,EAAE,CACf,KAAK,IAAI,CAEd,OAAO,EAAc,EAAS,EAAM,CAAG,GAAO"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export { attrs } from './attr';
|
|
2
|
-
export { bind } from './bind';
|
|
3
|
-
export { choose } from './choose';
|
|
4
|
-
export { classes } from './classes';
|
|
5
|
-
export { each } from './each';
|
|
6
|
-
export { memo } from './memo';
|
|
7
|
-
export { on } from './on';
|
|
8
|
-
export { raw } from './raw';
|
|
9
|
-
export { spread } from './spread';
|
|
10
|
-
export { style } from './style';
|
|
11
|
-
export { until } from './until';
|
|
12
|
-
export { when } from './when';
|
|
13
|
-
//# sourceMappingURL=index.d.ts.map
|