@vielzeug/ore 26.11.5 → 26.11.7
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/dist/base-element.cjs +1 -1
- package/dist/base-element.cjs.map +1 -1
- package/dist/base-element.js +1 -1
- package/dist/define.cjs +1 -1
- package/dist/define.cjs.map +1 -1
- package/dist/define.js +1 -1
- package/dist/directives/each.cjs +1 -1
- package/dist/directives/each.cjs.map +1 -1
- package/dist/directives/each.js +1 -1
- package/dist/directives/unsafe-html.cjs +1 -1
- package/dist/directives/unsafe-html.cjs.map +1 -1
- package/dist/directives/unsafe-html.js +1 -1
- package/dist/directives/when.cjs +1 -1
- package/dist/directives/when.cjs.map +1 -1
- package/dist/directives/when.js +1 -1
- package/dist/host-bind.cjs +1 -1
- package/dist/host-bind.cjs.map +1 -1
- package/dist/host-bind.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/ore.cjs +1 -1
- package/dist/ore.cjs.map +1 -1
- package/dist/ore.iife.js +1 -1
- package/dist/ore.iife.js.map +1 -1
- package/dist/ore.js +27 -41
- package/dist/ore.js.map +1 -1
- package/dist/props.cjs +1 -1
- package/dist/props.cjs.map +1 -1
- package/dist/props.js +1 -1
- package/dist/template/binding-types.d.ts +10 -1
- package/dist/template/binding-types.d.ts.map +1 -1
- package/dist/template/bindings.cjs +1 -1
- package/dist/template/bindings.cjs.map +1 -1
- 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/instantiator.cjs +1 -1
- package/dist/template/instantiator.cjs.map +1 -1
- package/dist/template/instantiator.d.ts.map +1 -1
- package/dist/template/instantiator.js +1 -1
- package/dist/template/instantiator.js.map +1 -1
- package/dist/testing/mount.cjs +1 -1
- package/dist/testing/mount.cjs.map +1 -1
- package/dist/testing/mount.js +1 -1
- package/dist/testing/render-hook.cjs +1 -1
- package/dist/testing/render-hook.cjs.map +1 -1
- package/dist/testing/render-hook.js +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +1 -1
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instantiator.js","names":["NODE_SLOT_NO_PARENT_MSG","toHtmlValues","raw","embedStaticResult","parent","anchor","invariant","result","chainedApplies","compileTemplate","compiled","getStaticTemplate","strings","fragment","bindings","boundSlots","value","values","i","slot","SlotKind","commentPath","followPath","elementPath","comment","isDirectiveResult","isHtmlResult","isReactive","sig","computed","item","resolveStaticText","el","name","signalValue","h","isModelSource","OreApiError","ORE_ERRORS","modelDefaultEvent","modelDefaultGet","createAttrBindingFromValue","createHtmlResult","binding","applyBinding","registerCleanup","chainedApply","html"],"sources":["../../src/template/instantiator.ts"],"sourcesContent":["/**\n * template/instantiator.ts: Template instantiation and the `html` tagged literal.\n *\n * Responsibilities:\n * - Clone a compiled static template and wire up live bindings.\n * - Expose `compileTemplate()` and `html` as the public authoring API.\n */\n\nimport { computed, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { isModelSource, modelDefaultEvent, modelDefaultGet } from '../directives/model';\nimport { invariant, ORE_ERRORS, OreApiError } from '../errors';\nimport type { Binding, HtmlBindingValue } from './binding-types';\nimport { applyBinding, createAttrBindingFromValue, resolveStaticText } from './bindings';\nimport { followPath, getStaticTemplate, SlotKind } from './compiler';\nimport {\n type CompiledHTMLResult,\n createHtmlResult,\n type HTMLResult,\n isDirectiveResult,\n isHtmlResult,\n type Ref,\n type RefCallback,\n} from './result';\n\n// ─── Template instantiation ──────────────────────────────────────────────────\n\nconst NODE_SLOT_NO_PARENT_MSG = 'html`...`: node-slot comment anchor has no parent node';\n\n/** Normalize a reactive node-slot value to the HtmlBinding signal's array shape. */\nconst toHtmlValues = (raw: unknown): HtmlBindingValue[] =>\n Array.isArray(raw) ? (raw as HtmlBindingValue[]) : [raw as HtmlBindingValue];\n\n/**\n * Static-embed an already-created HTMLResult at a node-slot anchor: move its\n * fragment children into place and chain its apply into the outer apply phase\n * (so embedded reactive wiring starts when the host template mounts, not now).\n */\nconst embedStaticResult = (\n result: CompiledHTMLResult,\n anchor: Comment,\n chainedApplies: Array<(rc: (fn: () => void) => void) => void>,\n): void => {\n const parent = anchor.parentNode;\n\n invariant(parent, NODE_SLOT_NO_PARENT_MSG);\n\n while (result.fragment.firstChild) parent.insertBefore(result.fragment.firstChild, anchor);\n\n chainedApplies.push(result.apply.bind(result));\n};\n\n/**\n * Instantiate a compiled template: clone the cached DOM template, navigate\n * to each binding target using pre-recorded paths, and build bindings with\n * direct node references. Returns an HTMLResult ready to mount.\n */\nexport const compileTemplate = (strings: TemplateStringsArray, values: unknown[]): HTMLResult => {\n const compiled = getStaticTemplate(strings);\n const fragment = compiled.element.content.cloneNode(true) as DocumentFragment;\n const bindings: Binding[] = [];\n // For static HTMLResult embeds: chain their apply calls\n const chainedApplies: Array<(rc: (fn: () => void) => void) => void> = [];\n\n // Phase 1: Resolve all binding targets BEFORE any DOM modifications\n type BoundSlot = { comment?: Comment; el?: HTMLElement; slot: (typeof compiled.slots)[number]; value: unknown };\n\n const boundSlots: BoundSlot[] = compiled.slots.map((slot, i) => {\n const value = values[i];\n\n if (slot.kind === SlotKind.NODE) {\n const commentPath = slot.commentId !== undefined ? compiled.commentPaths.get(slot.commentId) : undefined;\n\n invariant(commentPath, `compiled template is missing a comment path for node slot ${slot.commentId}`);\n\n return { comment: followPath(fragment, commentPath) as Comment, slot, value };\n }\n\n const elementPath = slot.elementId !== undefined ? compiled.elementPaths.get(slot.elementId) : undefined;\n\n invariant(elementPath, `compiled template is missing an element path for slot ${slot.elementId}`);\n\n return { el: followPath(fragment, elementPath) as HTMLElement, slot, value };\n });\n\n // Phase 2: Build bindings (may modify DOM for static content).\n for (const { comment, el, slot, value } of boundSlots) {\n if (slot.kind === SlotKind.NODE) {\n const anchor = comment;\n\n invariant(anchor, 'compiled template produced a node slot without a comment anchor');\n\n if (isDirectiveResult(value)) {\n bindings.push({ anchor, directive: value, type: 'directive' });\n continue;\n }\n\n if (isHtmlResult(value)) {\n // Static embed: move fragment children into place, chain apply\n embedStaticResult(value, anchor, chainedApplies);\n anchor.remove();\n continue;\n }\n\n if (typeof value === 'function' || isReactive(value)) {\n // Always use the html binding for reactive values: it handles both text\n // values and HTMLResult values, preventing silent \"[object Object]\"\n // corruption when a signal's runtime type changes from null/string to HTMLResult.\n const sig =\n typeof value === 'function'\n ? computed(() => toHtmlValues((value as () => unknown)()))\n : computed(() => toHtmlValues((value as Readable<unknown>).value));\n\n bindings.push({ anchor, signal: sig, type: 'html' });\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (isHtmlResult(item)) {\n embedStaticResult(item, anchor, chainedApplies);\n } else {\n const parent = anchor.parentNode;\n\n invariant(parent, NODE_SLOT_NO_PARENT_MSG);\n parent.insertBefore(document.createTextNode(resolveStaticText(item)), anchor);\n }\n }\n anchor.remove();\n continue;\n }\n\n // Static primitive: replace with text node, no binding\n anchor.replaceWith(document.createTextNode(resolveStaticText(value)));\n continue;\n }\n\n // Element slot\n invariant(el, 'compiled template produced an element slot without an element');\n\n if (slot.kind === SlotKind.EVENT) {\n const name = slot.name;\n\n invariant(name, 'compiled template produced an event slot without an event name');\n\n if (typeof value === 'function') {\n bindings.push({\n el,\n handler: value as (e: Event) => void,\n modifiers: slot.eventModifiers,\n name,\n type: 'event',\n });\n } else if (isReactive(value)) {\n const signalValue = value as Readable<unknown>;\n const handler = (e: Event) => {\n const h = signalValue.value;\n\n if (typeof h === 'function') (h as (e: Event) => void)(e);\n };\n\n bindings.push({ el, handler, modifiers: slot.eventModifiers, name, type: 'event' });\n }\n\n continue;\n }\n\n if (slot.kind === SlotKind.PROP) {\n const name = slot.name;\n\n invariant(name, 'compiled template produced a prop slot without a property name');\n\n if (typeof value === 'function') {\n bindings.push({ el, name, signal: computed(value as () => unknown), type: 'prop' });\n } else if (isReactive(value)) {\n bindings.push({ el, name, signal: value as Readable<unknown>, type: 'prop' });\n } else {\n bindings.push({ el, name, type: 'prop', value });\n }\n\n continue;\n }\n\n if (slot.kind === SlotKind.REF) {\n if (value) {\n bindings.push({ el, ref: value as Ref<Element> | RefCallback<Element>, type: 'ref' });\n }\n\n continue;\n }\n\n // attr / boolAttr\n invariant(slot.name, 'compiled template produced an attr slot without an attribute name');\n\n if (isModelSource(value)) {\n if (slot.mode !== 'attr') throw new OreApiError(ORE_ERRORS.modelRequiresValueBinding(slot.name));\n\n bindings.push({\n el,\n event: value.event ?? modelDefaultEvent(el),\n get: (value.get ?? modelDefaultGet) as (el: HTMLElement) => unknown,\n signal: value.source as Signal<unknown>,\n type: 'model',\n });\n continue;\n }\n\n bindings.push(createAttrBindingFromValue(el, slot.mode ?? 'attr', slot.name, value));\n }\n\n return createHtmlResult(fragment, (registerCleanup) => {\n for (const binding of bindings) applyBinding(binding, registerCleanup);\n for (const chainedApply of chainedApplies) chainedApply(registerCleanup);\n });\n};\n\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): HTMLResult =>\n compileTemplate(strings, values);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"instantiator.js","names":["NODE_SLOT_NO_PARENT_MSG","embedStaticResult","parent","anchor","invariant","result","chainedApplies","compileTemplate","compiled","getStaticTemplate","strings","fragment","bindings","boundSlots","value","values","i","slot","SlotKind","commentPath","followPath","elementPath","comment","isDirectiveResult","isHtmlResult","isReactive","item","resolveStaticText","el","name","signalValue","h","computed","isModelSource","OreApiError","ORE_ERRORS","modelDefaultEvent","modelDefaultGet","createAttrBindingFromValue","createHtmlResult","binding","applyBinding","registerCleanup","chainedApply","html"],"sources":["../../src/template/instantiator.ts"],"sourcesContent":["/**\n * template/instantiator.ts: Template instantiation and the `html` tagged literal.\n *\n * Responsibilities:\n * - Clone a compiled static template and wire up live bindings.\n * - Expose `compileTemplate()` and `html` as the public authoring API.\n */\n\nimport { computed, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { isModelSource, modelDefaultEvent, modelDefaultGet } from '../directives/model';\nimport { invariant, ORE_ERRORS, OreApiError } from '../errors';\nimport type { Binding } from './binding-types';\nimport { applyBinding, createAttrBindingFromValue, resolveStaticText } from './bindings';\nimport { followPath, getStaticTemplate, SlotKind } from './compiler';\nimport {\n type CompiledHTMLResult,\n createHtmlResult,\n type HTMLResult,\n isDirectiveResult,\n isHtmlResult,\n type Ref,\n type RefCallback,\n} from './result';\n\n// ─── Template instantiation ──────────────────────────────────────────────────\n\nconst NODE_SLOT_NO_PARENT_MSG = 'html`...`: node-slot comment anchor has no parent node';\n\n/**\n * Static-embed an already-created HTMLResult at a node-slot anchor: move its\n * fragment children into place and chain its apply into the outer apply phase\n * (so embedded reactive wiring starts when the host template mounts, not now).\n */\nconst embedStaticResult = (\n result: CompiledHTMLResult,\n anchor: Comment,\n chainedApplies: Array<(rc: (fn: () => void) => void) => void>,\n): void => {\n const parent = anchor.parentNode;\n\n invariant(parent, NODE_SLOT_NO_PARENT_MSG);\n\n while (result.fragment.firstChild) parent.insertBefore(result.fragment.firstChild, anchor);\n\n chainedApplies.push(result.apply.bind(result));\n};\n\n/**\n * Instantiate a compiled template: clone the cached DOM template, navigate\n * to each binding target using pre-recorded paths, and build bindings with\n * direct node references. Returns an HTMLResult ready to mount.\n */\nexport const compileTemplate = (strings: TemplateStringsArray, values: unknown[]): HTMLResult => {\n const compiled = getStaticTemplate(strings);\n const fragment = compiled.element.content.cloneNode(true) as DocumentFragment;\n const bindings: Binding[] = [];\n // For static HTMLResult embeds: chain their apply calls\n const chainedApplies: Array<(rc: (fn: () => void) => void) => void> = [];\n\n // Phase 1: Resolve all binding targets BEFORE any DOM modifications\n type BoundSlot = { comment?: Comment; el?: HTMLElement; slot: (typeof compiled.slots)[number]; value: unknown };\n\n const boundSlots: BoundSlot[] = compiled.slots.map((slot, i) => {\n const value = values[i];\n\n if (slot.kind === SlotKind.NODE) {\n const commentPath = slot.commentId !== undefined ? compiled.commentPaths.get(slot.commentId) : undefined;\n\n invariant(commentPath, `compiled template is missing a comment path for node slot ${slot.commentId}`);\n\n return { comment: followPath(fragment, commentPath) as Comment, slot, value };\n }\n\n const elementPath = slot.elementId !== undefined ? compiled.elementPaths.get(slot.elementId) : undefined;\n\n invariant(elementPath, `compiled template is missing an element path for slot ${slot.elementId}`);\n\n return { el: followPath(fragment, elementPath) as HTMLElement, slot, value };\n });\n\n // Phase 2: Build bindings (may modify DOM for static content).\n for (const { comment, el, slot, value } of boundSlots) {\n if (slot.kind === SlotKind.NODE) {\n const anchor = comment;\n\n invariant(anchor, 'compiled template produced a node slot without a comment anchor');\n\n if (isDirectiveResult(value)) {\n bindings.push({ anchor, directive: value, type: 'directive' });\n continue;\n }\n\n if (isHtmlResult(value)) {\n // Static embed: move fragment children into place, chain apply\n embedStaticResult(value, anchor, chainedApplies);\n anchor.remove();\n continue;\n }\n\n if (typeof value === 'function' || isReactive(value)) {\n // Always use the html binding for reactive values: it handles both text\n // values and HTMLResult values, preventing silent \"[object Object]\"\n // corruption when a signal's runtime type changes from null/string to HTMLResult.\n // The source is handed over raw, without a memo computed, so the render effect\n // itself is the observer and the owner of anything the value builds (see HtmlBinding).\n bindings.push({ anchor, source: value as (() => unknown) | Readable<unknown>, type: 'html' });\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (isHtmlResult(item)) {\n embedStaticResult(item, anchor, chainedApplies);\n } else {\n const parent = anchor.parentNode;\n\n invariant(parent, NODE_SLOT_NO_PARENT_MSG);\n parent.insertBefore(document.createTextNode(resolveStaticText(item)), anchor);\n }\n }\n anchor.remove();\n continue;\n }\n\n // Static primitive: replace with text node, no binding\n anchor.replaceWith(document.createTextNode(resolveStaticText(value)));\n continue;\n }\n\n // Element slot\n invariant(el, 'compiled template produced an element slot without an element');\n\n if (slot.kind === SlotKind.EVENT) {\n const name = slot.name;\n\n invariant(name, 'compiled template produced an event slot without an event name');\n\n if (typeof value === 'function') {\n bindings.push({\n el,\n handler: value as (e: Event) => void,\n modifiers: slot.eventModifiers,\n name,\n type: 'event',\n });\n } else if (isReactive(value)) {\n const signalValue = value as Readable<unknown>;\n const handler = (e: Event) => {\n const h = signalValue.value;\n\n if (typeof h === 'function') (h as (e: Event) => void)(e);\n };\n\n bindings.push({ el, handler, modifiers: slot.eventModifiers, name, type: 'event' });\n }\n\n continue;\n }\n\n if (slot.kind === SlotKind.PROP) {\n const name = slot.name;\n\n invariant(name, 'compiled template produced a prop slot without a property name');\n\n if (typeof value === 'function') {\n bindings.push({ el, name, signal: computed(value as () => unknown), type: 'prop' });\n } else if (isReactive(value)) {\n bindings.push({ el, name, signal: value as Readable<unknown>, type: 'prop' });\n } else {\n bindings.push({ el, name, type: 'prop', value });\n }\n\n continue;\n }\n\n if (slot.kind === SlotKind.REF) {\n if (value) {\n bindings.push({ el, ref: value as Ref<Element> | RefCallback<Element>, type: 'ref' });\n }\n\n continue;\n }\n\n // attr / boolAttr\n invariant(slot.name, 'compiled template produced an attr slot without an attribute name');\n\n if (isModelSource(value)) {\n if (slot.mode !== 'attr') throw new OreApiError(ORE_ERRORS.modelRequiresValueBinding(slot.name));\n\n bindings.push({\n el,\n event: value.event ?? modelDefaultEvent(el),\n get: (value.get ?? modelDefaultGet) as (el: HTMLElement) => unknown,\n signal: value.source as Signal<unknown>,\n type: 'model',\n });\n continue;\n }\n\n bindings.push(createAttrBindingFromValue(el, slot.mode ?? 'attr', slot.name, value));\n }\n\n return createHtmlResult(fragment, (registerCleanup) => {\n for (const binding of bindings) applyBinding(binding, registerCleanup);\n for (const chainedApply of chainedApplies) chainedApply(registerCleanup);\n });\n};\n\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): HTMLResult =>\n compileTemplate(strings, values);\n"],"mappings":"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"}
|
package/dist/testing/mount.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../
|
|
1
|
+
const e=require("../define.cjs"),t=require("../utils/dom.cjs"),n=require("./flush.cjs"),r=require("./render-hook.cjs"),i=require("./reset.cjs");let a=require("@vielzeug/assay");var o=[],s=0;function c(e,n,r){t.setAttr(e,n,r)}var l=e=>e instanceof Error?e:Error(String(e)),u=async e=>{if(typeof window>`u`)return e();let t=null,n=e=>{t=l(e.error??e.message),e.preventDefault()},r=e=>{t=l(e.reason),e.preventDefault()};window.addEventListener(`error`,n),window.addEventListener(`unhandledrejection`,r);try{let n=await e();if(t)throw t;return n}finally{window.removeEventListener(`error`,n),window.removeEventListener(`unhandledrejection`,r)}};async function d(t,r={}){let{attrs:i={},componentOptions:l,container:d=document.body,html:f,props:p={}}=r,m,h;typeof t==`string`?m=t:(m=`trial-${++s}`,h={...l??{},setup:t}),h&&e.define(m,h);let g=document.createElement(m);f&&(g.innerHTML=f),Object.keys(p).length&&Object.assign(g,p);for(let[e,t]of Object.entries(i))c(g,e,t);try{await u(async()=>{d.appendChild(g),o.push(g),await n.flush()})}catch(e){g.remove();let t=o.indexOf(g);throw t!==-1&&o.splice(t,1),e}let _=!1;function v(){if(_)return;_=!0,g.remove();let e=o.indexOf(g);e!==-1&&o.splice(e,1)}return{...(0,a.within)(g.shadowRoot??g),async act(e){await e(),await n.flush()},async attr(e,t){c(g,e,t),await n.flush()},async attrs(e){for(let[t,n]of Object.entries(e))c(g,t,n);await n.flush()},dispose:v,get disposed(){return _},element:g,flush:n.flush,get shadow(){return g.shadowRoot},[Symbol.dispose](){v()}}}function f(){for(let e of o)e.remove();o.length=0,r._disposeRenderHooks(),i.resetOreForTests()}exports._mountedElements=o,exports.cleanup=f,exports.mount=d;
|
|
2
2
|
//# sourceMappingURL=mount.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount.cjs","names":["flush","within","require_dom","require_define","require_flush","require_render_hook","require_reset","_vielzeug_assay","_mountedElements","_componentTagCounter","applyAttr","element","name","value","toError","withWindowErrorCapture","action","captured","onError","event","onUnhandledRejection","result","mount","options","tagName","inlineDefinition","tagOrSetup","componentOptions","html","props","attrs","container","err","i","isDisposed","dispose","fn","record","cleanup","el"],"sources":["../../src/testing/mount.ts"],"sourcesContent":["/**\n * Component mounting utilities for test environments.\n */\n\nimport { type QueryScope, within } from '@vielzeug/assay';\nimport type { Readable } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from '../component-types';\nimport { define } from '../define';\nimport type { HTMLResult } from '../template/result';\nimport { setAttr } from '../utils/dom';\nimport { type FlushOptions, flush } from './flush';\nimport { _disposeRenderHooks } from './render-hook';\nimport { resetOreForTests } from './reset';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n// Fixture inherits Assay's complete QueryScope. Keeping that relationship structural means new\n// scoped query capabilities are immediately available to fixtures without a duplicate contract.\n/**\n * A mounted component ready for assertions. All inherited `QueryScope` methods are scoped to\n * `element.shadowRoot`, falling back to `element` for light-DOM components (`shadow: false`).\n */\nexport interface Fixture<T extends HTMLElement = HTMLElement> extends QueryScope {\n /** Run a callback then flush: the standard way to trigger and assert a reactive update */\n act(fn: () => unknown): Promise<void>;\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 /** Remove the component from the DOM. Idempotent. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** The component element */\n element: T;\n /** Wait for all reactive updates and animation frames */\n flush(options?: FlushOptions): Promise<void>;\n /** The component's shadow root (null for light-DOM components) */\n readonly shadow: ShadowRoot | null;\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n}\n\nexport interface MountOptions {\n /** HTML attributes to set on the element */\n attrs?: Record<string, string | number | boolean>;\n /** Extra component options when passing an inline setup function */\n componentOptions?: Omit<ComponentDefinition<Record<string, unknown>>, 'setup'>;\n /** Parent container (default: document.body) */\n container?: HTMLElement | ShadowRoot;\n /** Inner HTML for slot content */\n html?: string;\n /** Properties assigned directly onto the element */\n props?: Record<string, unknown>;\n}\n\ntype MountProps = { readonly [x: string]: Readable<unknown> };\n\n// Bivariant callback type keeps inline test callbacks ergonomic across varying prop specializations.\nexport type MountSetup = {\n bivarianceHack: (props: MountProps) => HTMLResult | null;\n}['bivarianceHack'];\n\n// ─── Test environment state ───────────────────────────────────────────────────\n\nexport const _mountedElements: HTMLElement[] = [];\n\n// Monotonic across the whole test run: never reset: custom element registrations\n// are permanent, so a re-used tag name would throw on re-define. Deterministic\n// within a run (trial-1, trial-2, ...) without a random suffix.\nlet _componentTagCounter = 0;\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction applyAttr(element: Element, name: string, value: string | number | boolean): void {\n // Same write path as the runtime's attribute bindings, so tests never set up\n // states the runtime itself can't produce (e.g. boolean true → \"true\").\n setAttr(element, name, 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// ─── API ─────────────────────────────────────────────────────────────────────\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 let tagName: string;\n let inlineDefinition: ComponentDefinition<Record<string, unknown>> | undefined;\n\n if (typeof tagOrSetup === 'string') {\n tagName = tagOrSetup;\n } else {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = {\n ...(componentOptions ?? {}),\n setup: tagOrSetup,\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 try {\n await withWindowErrorCapture(async () => {\n container.appendChild(element);\n _mountedElements.push(element);\n await flush();\n });\n } catch (err) {\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n\n throw err;\n }\n\n let isDisposed = false;\n\n function dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n }\n\n const scope = within((element.shadowRoot ?? element) as Element);\n\n return {\n ...scope,\n\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 dispose,\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n element,\n\n flush,\n\n get shadow(): ShadowRoot | null {\n return element.shadowRoot;\n },\n\n [Symbol.dispose]() {\n dispose();\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 _disposeRenderHooks();\n resetOreForTests();\n}\n\n/** @internal re-export for within() */\nexport type { QueryScope };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mount.cjs","names":["flush","within","require_define","require_dom","require_flush","require_render_hook","require_reset","_vielzeug_assay","_mountedElements","_componentTagCounter","applyAttr","element","name","value","toError","withWindowErrorCapture","action","captured","onError","event","onUnhandledRejection","result","mount","options","tagName","inlineDefinition","tagOrSetup","componentOptions","html","props","attrs","container","err","i","isDisposed","dispose","fn","record","cleanup","el"],"sources":["../../src/testing/mount.ts"],"sourcesContent":["/**\n * Component mounting utilities for test environments.\n */\n\nimport { type QueryScope, within } from '@vielzeug/assay';\nimport type { Readable } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from '../component-types';\nimport { define } from '../define';\nimport type { HTMLResult } from '../template/result';\nimport { setAttr } from '../utils/dom';\nimport { type FlushOptions, flush } from './flush';\nimport { _disposeRenderHooks } from './render-hook';\nimport { resetOreForTests } from './reset';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n// Fixture inherits Assay's complete QueryScope. Keeping that relationship structural means new\n// scoped query capabilities are immediately available to fixtures without a duplicate contract.\n/**\n * A mounted component ready for assertions. All inherited `QueryScope` methods are scoped to\n * `element.shadowRoot`, falling back to `element` for light-DOM components (`shadow: false`).\n */\nexport interface Fixture<T extends HTMLElement = HTMLElement> extends QueryScope {\n /** Run a callback then flush: the standard way to trigger and assert a reactive update */\n act(fn: () => unknown): Promise<void>;\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 /** Remove the component from the DOM. Idempotent. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** The component element */\n element: T;\n /** Wait for all reactive updates and animation frames */\n flush(options?: FlushOptions): Promise<void>;\n /** The component's shadow root (null for light-DOM components) */\n readonly shadow: ShadowRoot | null;\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n}\n\nexport interface MountOptions {\n /** HTML attributes to set on the element */\n attrs?: Record<string, string | number | boolean>;\n /** Extra component options when passing an inline setup function */\n componentOptions?: Omit<ComponentDefinition<Record<string, unknown>>, 'setup'>;\n /** Parent container (default: document.body) */\n container?: HTMLElement | ShadowRoot;\n /** Inner HTML for slot content */\n html?: string;\n /** Properties assigned directly onto the element */\n props?: Record<string, unknown>;\n}\n\ntype MountProps = { readonly [x: string]: Readable<unknown> };\n\n// Bivariant callback type keeps inline test callbacks ergonomic across varying prop specializations.\nexport type MountSetup = {\n bivarianceHack: (props: MountProps) => HTMLResult | null;\n}['bivarianceHack'];\n\n// ─── Test environment state ───────────────────────────────────────────────────\n\nexport const _mountedElements: HTMLElement[] = [];\n\n// Monotonic across the whole test run: never reset: custom element registrations\n// are permanent, so a re-used tag name would throw on re-define. Deterministic\n// within a run (trial-1, trial-2, ...) without a random suffix.\nlet _componentTagCounter = 0;\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction applyAttr(element: Element, name: string, value: string | number | boolean): void {\n // Same write path as the runtime's attribute bindings, so tests never set up\n // states the runtime itself can't produce (e.g. boolean true → \"true\").\n setAttr(element, name, 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// ─── API ─────────────────────────────────────────────────────────────────────\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 let tagName: string;\n let inlineDefinition: ComponentDefinition<Record<string, unknown>> | undefined;\n\n if (typeof tagOrSetup === 'string') {\n tagName = tagOrSetup;\n } else {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = {\n ...(componentOptions ?? {}),\n setup: tagOrSetup,\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 try {\n await withWindowErrorCapture(async () => {\n container.appendChild(element);\n _mountedElements.push(element);\n await flush();\n });\n } catch (err) {\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n\n throw err;\n }\n\n let isDisposed = false;\n\n function dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n }\n\n const scope = within((element.shadowRoot ?? element) as Element);\n\n return {\n ...scope,\n\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 dispose,\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n element,\n\n flush,\n\n get shadow(): ShadowRoot | null {\n return element.shadowRoot;\n },\n\n [Symbol.dispose]() {\n dispose();\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 _disposeRenderHooks();\n resetOreForTests();\n}\n\n/** @internal re-export for within() */\nexport type { QueryScope };\n"],"mappings":"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"}
|
package/dist/testing/mount.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{define as e}from"../define.js";import{setAttr as t}from"../utils/dom.js";import{flush as n}from"./flush.js";import{_disposeRenderHooks as r}from"./render-hook.js";import{resetOreForTests as i}from"./reset.js";import{within as a}from"@vielzeug/assay";var o=[],s=0;function c(e,n,r){t(e,n,r)}var l=e=>e instanceof Error?e:Error(String(e)),u=async e=>{if(typeof window>`u`)return e();let t=null,n=e=>{t=l(e.error??e.message),e.preventDefault()},r=e=>{t=l(e.reason),e.preventDefault()};window.addEventListener(`error`,n),window.addEventListener(`unhandledrejection`,r);try{let n=await e();if(t)throw t;return n}finally{window.removeEventListener(`error`,n),window.removeEventListener(`unhandledrejection`,r)}};async function d(t,r={}){let{attrs:i={},componentOptions:l,container:d=document.body,html:f,props:p={}}=r,m,h;typeof t==`string`?m=t:(m=`trial-${++s}`,h={...l??{},setup:t}),h&&e(m,h);let g=document.createElement(m);f&&(g.innerHTML=f),Object.keys(p).length&&Object.assign(g,p);for(let[e,t]of Object.entries(i))c(g,e,t);try{await u(async()=>{d.appendChild(g),o.push(g),await n()})}catch(e){g.remove();let t=o.indexOf(g);throw t!==-1&&o.splice(t,1),e}let _=!1;function v(){if(_)return;_=!0,g.remove();let e=o.indexOf(g);e!==-1&&o.splice(e,1)}return{...a(g.shadowRoot??g),async act(e){await e(),await n()},async attr(e,t){c(g,e,t),await n()},async attrs(e){for(let[t,n]of Object.entries(e))c(g,t,n);await n()},dispose:v,get disposed(){return _},element:g,flush:n,get shadow(){return g.shadowRoot},[Symbol.dispose](){v()}}}function f(){for(let e of o)e.remove();o.length=0,r(),i()}export{o as _mountedElements,f as cleanup,d as mount};
|
|
2
2
|
//# sourceMappingURL=mount.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../errors.cjs"),t=require("../
|
|
1
|
+
const e=require("../errors.cjs"),t=require("../props.cjs"),n=require("../runtime.cjs"),r=require("./flush.cjs");let i=require("@vielzeug/ripple");var a=new Set,o=()=>{for(let e of[...a])e()};async function s(o,s){let c=typeof o!=`function`,l=c?o:void 0,u=c?s:o,d=(0,i.createScope)(),f=document.createElement(`div`);document.body.appendChild(f);let p=n.createRuntimeContext(f),{mountCallbacks:m}=p,h;try{d.run(()=>{n.runWithContext(p,()=>{let e=l?t.createProps(f,l):{};h=u(e)})});for(let t of m)try{d.run(()=>{n.runWithContext(p,()=>{let e=t();typeof e==`function`&&n.onCleanup(e)})})}catch(t){let n=t instanceof Error?t:Error(String(t));e.reportRuntimeError(new e.OreLifecycleError(`renderHook() mount callback failed`,{cause:n,component:`renderHook`,phase:`mounted`}),f)}}catch(e){throw d.dispose(),f.remove(),e}await r.flush();let g=!1;function _(){g||(g=!0,d.dispose(),f.remove(),a.delete(_))}return a.add(_),{dispose:_,get disposed(){return g},async flush(){await r.flush()},result:h,[Symbol.dispose](){_()}}}exports._disposeRenderHooks=o,exports.renderHook=s;
|
|
2
2
|
//# sourceMappingURL=render-hook.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-hook.cjs","names":["createScope","createRuntimeContext","createProps","OreLifecycleError","flush","require_errors","
|
|
1
|
+
{"version":3,"file":"render-hook.cjs","names":["createScope","createRuntimeContext","createProps","OreLifecycleError","flush","require_errors","require_props","require_runtime","require_flush","_vielzeug_ripple","hookDisposers","_disposeRenderHooks","dispose","renderHook","hasPropDefs","setupOrDefs","propDefs","setup","maybeSetup","hostScope","hostEl","ctx","result","props","cb","mountCallbacks","cleanup","error","err","isDisposed"],"sources":["../../src/testing/render-hook.ts"],"sourcesContent":["/**\n * renderHook: test composable hooks (lifecycle, reactive state, etc.) in isolation\n * without rendering a full component template.\n */\n\nimport { createScope } from '@vielzeug/ripple';\n\nimport { OreLifecycleError, reportRuntimeError } from '../errors';\nimport { createProps, type InferProps, type PropInputDefs } from '../props';\nimport { createRuntimeContext, onCleanup, runWithContext } from '../runtime';\nimport { flush } from './flush';\n\nexport interface HookFixture<T> {\n /** Teardown the hook (runs cleanups). Idempotent. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** Flush pending reactive updates */\n flush(): Promise<void>;\n /** The value returned by the setup function */\n result: T;\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n}\n\nconst hookDisposers = new Set<() => void>();\n\n/** @internal Dispose every active hook fixture for test isolation. */\nexport const _disposeRenderHooks = (): void => {\n for (const dispose of [...hookDisposers]) dispose();\n};\n\n/**\n * Run a setup function in a component-like context and return the result.\n * `onMounted`/`onCleanup`/`bind`/... work exactly as they would inside a real\n * `setup()`, since they resolve the same implicit current-component context.\n *\n * @example No props\n * ```ts\n * const { result, flush } = await renderHook(() => {\n * const count = signal(0);\n * onMounted(() => { count.value = 1; });\n * return count;\n * });\n * expect(result.value).toBe(1);\n * ```\n *\n * @example With props\n * ```ts\n * const { result } = await renderHook(\n * { label: prop.string('hello') },\n * (props) => props.label,\n * );\n * expect(result.value).toBe('hello');\n * ```\n */\nexport async function renderHook<T>(setup: (_props: Record<never, never>) => T): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n propDefs: D,\n setup: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n setupOrDefs: ((_props: Record<never, never>) => T) | D,\n maybeSetup?: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>> {\n const hasPropDefs = typeof setupOrDefs !== 'function';\n const propDefs = hasPropDefs ? (setupOrDefs as D) : undefined;\n const setup = hasPropDefs ? maybeSetup! : (setupOrDefs as (_props: Record<never, never>) => T);\n\n const hostScope = createScope();\n // Minimal host element so getHost() works inside setup\n const hostEl = document.createElement('div');\n\n document.body.appendChild(hostEl);\n\n // Built via the runtime's own factory, so the harness can never desync from a\n // new required RuntimeContext field. Note: `onFormReset()` registrations land\n // in this context's formResetCallbacks but are never fired: renderHook has no\n // ancestor <form>; test form-reset behaviour through mount() instead.\n const ctx = createRuntimeContext(hostEl);\n const { mountCallbacks } = ctx;\n\n let result!: T;\n\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const props = propDefs ? createProps(hostEl, propDefs as PropInputDefs) : ({} as Record<never, never>);\n\n result = setup(props as InferProps<D>);\n });\n });\n\n // Run mount callbacks (simulates connectedCallback → queueMicrotask)\n for (const cb of mountCallbacks) {\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const cleanup = cb();\n\n if (typeof cleanup === 'function') onCleanup(cleanup);\n });\n });\n } catch (error) {\n // Mirror BaseElement's real onMounted error handling (see\n // base-element.ts's `_scheduleMountCallbacks`): report the error\n // (console + `ore:error` event on the host) and keep running the\n // remaining callbacks, instead of hiding the failure entirely.\n const err = error instanceof Error ? error : new Error(String(error));\n\n reportRuntimeError(\n new OreLifecycleError(`renderHook() mount callback failed`, {\n cause: err,\n component: 'renderHook',\n phase: 'mounted',\n }),\n hostEl,\n );\n }\n }\n } catch (err) {\n hostScope.dispose();\n hostEl.remove();\n throw err;\n }\n\n await flush();\n\n let isDisposed = false;\n\n function dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n hostScope.dispose();\n hostEl.remove();\n hookDisposers.delete(dispose);\n }\n\n hookDisposers.add(dispose);\n\n return {\n dispose,\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n async flush() {\n await flush();\n },\n\n result,\n\n [Symbol.dispose]() {\n dispose();\n },\n };\n}\n"],"mappings":"A,kJAyBA,IAAMU,EAAgB,IAAI,IAGbC,MAAkC,CAC7C,IAAK,IAAMC,IAAW,CAAC,GAAGF,CAAa,EAAGE,EAAQ,CACpD,EA+BA,eAAsBC,EACpB,EACA,EACyB,CACzB,IAAMC,EAAc,OAAOC,GAAgB,WACrCC,EAAWF,EAAeC,EAAoB,IAAA,GAC9CE,EAAQH,EAAcI,EAAeH,EAErCI,GAAA,EAAYnB,EAAAA,YAAAA,CAAY,EAExBoB,EAAS,SAAS,cAAc,KAAK,EAE3C,SAAS,KAAK,YAAYA,CAAM,EAMhC,IAAMC,EAAMpB,EAAAA,qBAAqBmB,CAAM,EACjC,CAAE,kBAAmBC,EAEvBC,EAEJ,GAAI,CACFH,EAAU,QAAU,CAClBZ,EAAA,eAAec,MAAW,CACxB,IAAME,EAAQP,EAAWd,EAAAA,YAAYkB,EAAQJ,CAAyB,EAAK,CAAC,EAE5E,EAASC,EAAMM,CAAsB,CACvC,CAAC,CACH,CAAC,EAGD,IAAK,IAAMC,KAAMC,EACf,GAAI,CACFN,EAAU,QAAU,CAClBZ,EAAA,eAAec,MAAW,CACxB,IAAMK,EAAUF,EAAG,EAEf,OAAOE,GAAY,YAAYnB,EAAA,UAAUmB,CAAO,CACtD,CAAC,CACH,CAAC,CACH,OAASC,EAAO,CAKd,IAAMC,EAAMD,aAAiB,MAAQA,EAAY,MAAM,OAAOA,CAAK,CAAC,EAEpEtB,EAAA,mBACE,IAAIF,EAAAA,kBAAkB,qCAAsC,CAC1D,MAAOyB,EACP,UAAW,aACX,MAAO,SACT,CAAC,EACDR,CACF,CACF,CAEJ,OAASQ,EAAK,CAGZ,MAFAT,EAAU,QAAQ,EAClBC,EAAO,OAAO,EACRQ,CACR,CAEA,MAAMxB,EAAAA,MAAM,EAEZ,IAAIyB,EAAa,GAEjB,SAASjB,GAAU,CACbiB,IAEJ,EAAa,GACbV,EAAU,QAAQ,EAClBC,EAAO,OAAO,EACdV,EAAc,OAAOE,CAAO,EAC9B,CAIA,OAFAF,EAAc,IAAIE,CAAO,EAElB,CACL,UAEA,IAAI,UAAoB,CACtB,OAAOiB,CACT,EAEA,MAAM,OAAQ,CACZ,MAAMzB,EAAAA,MAAM,CACd,EAEA,SAEA,CAAC,OAAO,UAAW,CACjBQ,EAAQ,CACV,CACF,CACF,C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{OreLifecycleError as e,reportRuntimeError as t}from"../errors.js";import{
|
|
1
|
+
import{OreLifecycleError as e,reportRuntimeError as t}from"../errors.js";import{createProps as n}from"../props.js";import{createRuntimeContext as r,onCleanup as i,runWithContext as a}from"../runtime.js";import{flush as o}from"./flush.js";import{createScope as s}from"@vielzeug/ripple";var c=/* @__PURE__ */ new Set,l=()=>{for(let e of[...c])e()};async function u(l,u){let d=typeof l!=`function`,f=d?l:void 0,p=d?u:l,m=s(),h=document.createElement(`div`);document.body.appendChild(h);let g=r(h),{mountCallbacks:_}=g,v;try{m.run(()=>{a(g,()=>{let e=f?n(h,f):{};v=p(e)})});for(let n of _)try{m.run(()=>{a(g,()=>{let e=n();typeof e==`function`&&i(e)})})}catch(n){let r=n instanceof Error?n:Error(String(n));t(new e(`renderHook() mount callback failed`,{cause:r,component:`renderHook`,phase:`mounted`}),h)}}catch(e){throw m.dispose(),h.remove(),e}await o();let y=!1;function b(){y||(y=!0,m.dispose(),h.remove(),c.delete(b))}return c.add(b),{dispose:b,get disposed(){return y},async flush(){await o()},result:v,[Symbol.dispose](){b()}}}export{l as _disposeRenderHooks,u as renderHook};
|
|
2
2
|
//# sourceMappingURL=render-hook.js.map
|
package/dist/testing.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./testing/
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./testing/mount.cjs"),t=require("./testing/flush.cjs"),n=require("./testing/render-hook.cjs");function r(t){t(e.cleanup)}exports.OreTimeoutError=t.OreTimeoutError,exports.cleanup=e.cleanup,exports.flush=t.flush,exports.install=r,exports.mount=e.mount,exports.renderHook=n.renderHook;
|
|
2
2
|
//# sourceMappingURL=testing.cjs.map
|
package/dist/testing.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.cjs","names":["cleanup","
|
|
1
|
+
{"version":3,"file":"testing.cjs","names":["cleanup","require_mount","require_flush","require_render_hook","install","afterEachHook"],"sources":["../src/testing/index.ts"],"sourcesContent":["/**\n * Testing utilities for Ore components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n *\n * This is the package's only public testing entry point.\n */\n\nimport { cleanup } from './mount';\n\n// Testing-only error: flush() is its only thrower in this package (a pending-work timeout :\n// see flush.ts). Exported here (not from the main `.` entry) so components with no interest\n// in the testing sub-path don't carry a testing-only error class in their public type surface.\n// Generic DOM interaction helpers belong to @vielzeug/assay, not this Ore-specific test API:\n// including the jsdom ElementInternals/FormData polyfill, which form-associated-component\n// suites install directly from assay (`installFormInternalsPolyfill`).\nexport { type FlushOptions, flush, OreTimeoutError } from './flush';\nexport { cleanup, type Fixture, type MountOptions, type MountSetup, mount } from './mount';\nexport { type HookFixture, renderHook } from './render-hook';\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/ore/testing';\n * install(afterEach);\n */\nexport function install(afterEachHook: (fn: () => void) => void): void {\n afterEachHook(cleanup);\n}\n"],"mappings":"A,kLA6BA,SAAgBI,EAAQ,EAA+C,CACrEC,EAAcL,EAAAA,OAAO,CACvB,C"}
|
package/dist/testing.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{cleanup as e,mount as t}from"./testing/mount.js";import{OreTimeoutError as n,flush as r}from"./testing/flush.js";import{renderHook as i}from"./testing/render-hook.js";function a(t){t(e)}export{n as OreTimeoutError,e as cleanup,r as flush,a as install,t as mount,i as renderHook};
|
|
2
2
|
//# sourceMappingURL=testing.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/ore",
|
|
3
|
-
"version": "26.11.
|
|
3
|
+
"version": "26.11.7",
|
|
4
4
|
"description": "Functional web-component authoring on top of ripple",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,19 +43,19 @@
|
|
|
43
43
|
"registry": "https://registry.npmjs.org/"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
|
-
"build": "vite build &&
|
|
46
|
+
"build": "vite build && bun run --silent build:bundle && bun run --silent build:types",
|
|
47
47
|
"build:bundle": "vite build --config vite.bundle.config.ts",
|
|
48
48
|
"build:types": "tsc -p tsconfig.declarations.json",
|
|
49
49
|
"fix": "biome check --write src vitest.setup.ts",
|
|
50
50
|
"lint": "biome ci src vitest.setup.ts",
|
|
51
|
-
"prepublishOnly": "
|
|
51
|
+
"prepublishOnly": "bun run --silent build",
|
|
52
52
|
"preview": "vite preview",
|
|
53
53
|
"test": "vitest",
|
|
54
54
|
"test:types": "tsc -p tsconfig.json --noEmit"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@vielzeug/assay": "^26.11.
|
|
58
|
-
"@vielzeug/ripple": "^26.11.
|
|
57
|
+
"@vielzeug/assay": "^26.11.7",
|
|
58
|
+
"@vielzeug/ripple": "^26.11.7"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
61
61
|
"@vielzeug/assay": {
|
|
@@ -63,13 +63,13 @@
|
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@types/node": "^26.6.
|
|
67
|
-
"@vielzeug/assay": "26.11.
|
|
68
|
-
"@vielzeug/ripple": "26.11.
|
|
66
|
+
"@types/node": "^26.6.6",
|
|
67
|
+
"@vielzeug/assay": "26.11.7",
|
|
68
|
+
"@vielzeug/ripple": "26.11.7",
|
|
69
69
|
"axe-core": "^4.14.0",
|
|
70
|
-
"jsdom": "^
|
|
70
|
+
"jsdom": "^31.0.0",
|
|
71
71
|
"typescript": "^6.0.3",
|
|
72
|
-
"vite": "^8.3.
|
|
73
|
-
"vitest": "^5.0
|
|
72
|
+
"vite": "^8.3.6",
|
|
73
|
+
"vitest": "^5.1.0"
|
|
74
74
|
}
|
|
75
75
|
}
|