@vielzeug/ore 26.11.4 → 26.11.6
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.js +12 -25
- 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/bindings.cjs +1 -1
- package/dist/template/bindings.cjs.map +1 -1
- package/dist/template/bindings.js +1 -1
- package/dist/template/instantiator.cjs +1 -1
- package/dist/template/instantiator.cjs.map +1 -1
- package/dist/template/instantiator.js +1 -1
- package/dist/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
package/dist/base-element.cjs
CHANGED
|
@@ -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("./utils/css.cjs");let i=require("@vielzeug/ripple");var a={SETUP_DONE:`setup_done`,SETUP_RUNNING:`setup_running`,UNINITIALIZED:`uninitialized`,UNMOUNTED:`unmounted`},o=()=>({formResetCallbacks:[],generation:0,mountCallbacks:[],phase:a.UNINITIALIZED,scope:(0,i.createScope)(),templateResult:null}),s=e=>(typeof e==`object`||typeof e==`function`)&&e!==null&&`then`in e&&typeof e.then==`function`,c=class extends HTMLElement{static _definition;static _normalizedPropDefs;static formAssociated=!1;static observedAttributes=[];_component;constructor(){super();let e=this.constructor._definition;e?.shadow!==!1&&this.attachShadow({mode:`open`,...e?.shadow}),this._component=o()}connectedCallback(){(0,i.untrack)(()=>{this._component.phase===a.UNINITIALIZED&&this._runSetup(),this._init()})}attributeChangedCallback(e,n,r){if(n===r)return;let a=t.getPropMeta(this,e);if(!a)return;let o=a.parse(r);Object.is((0,i.untrack)(()=>a.signal.value),o)||(a.signal.value=o)}disconnectedCallback(){this._component.generation++,this._component.phase=a.UNMOUNTED,this._resetSetupState()}_resetSetupState(){this._component.scope.dispose(),this._component.formResetCallbacks=[],this._component.mountCallbacks=[],this._component.phase=a.UNINITIALIZED,this._component.scope=(0,i.createScope)(),this._component.templateResult=null}formResetCallback(){for(let e of this._component.formResetCallbacks)try{e()}catch(e){this._reportLifecycleError(e,`form-reset`)}}_reportLifecycleError(t,n){let r=t instanceof Error?t:Error(String(t)),i=new e.OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${n})`,{cause:r,component:this.localName,phase:n});e.reportRuntimeError(i,this)}_runSetup(){this._component.phase=a.SETUP_RUNNING;let r=this.constructor._definition,i=this.constructor._normalizedPropDefs,o=n.createRuntimeContext(this);try{let c;if(this._component.scope.run(()=>{c=n.runWithContext(o,()=>{let e=i?t.createProps(this,i):{};return r.setup(e)})}),this._component.mountCallbacks.push(...o.mountCallbacks),this._component.formResetCallbacks.push(...o.formResetCallbacks),s(c))throw new e.OreApiError(e.ORE_ERRORS.asyncSetupUnsupported);this._component.templateResult=c??null,this._component.phase=a.SETUP_DONE}catch(e){throw this._reportLifecycleError(e,`setup`),this._resetSetupState(),e}}_isStale(e){return this._component.generation!==e||!this.isConnected}_applyResult(e){if(!e)return;let t=this.shadowRoot??this,r=n.createRuntimeContext(this);t.replaceChildren(),this._component.scope.run(()=>{n.runWithContext(r,()=>{e.mount(t,null,n.onCleanup)})})}_init(){this._applyStyles(),this._mountTemplate(),this._component.phase===a.SETUP_DONE&&this._scheduleMountCallbacks()}_applyStyles(){let e=this.constructor._definition;this.shadowRoot&&e?.styles?.length&&(this.shadowRoot.adoptedStyleSheets=e.styles.map(r.loadStylesheet))}_mountTemplate(){let e=this._component.templateResult;e&&this._applyResult(e)}_scheduleMountCallbacks(){if(this._component.mountCallbacks.length===0)return;let e=this._component.generation,t=n.beginPendingWork();queueMicrotask(()=>{try{if(this._isStale(e))return;let t=this._component.mountCallbacks.splice(0);for(let e=0;e<t.length;e++){let r=t[e];try{let e=n.createRuntimeContext(this);this._component.scope.run(()=>{n.runWithContext(e,()=>{let e=r();typeof e==`function`&&n.onCleanup(e)})}),e.mountCallbacks.length>0&&t.push(...e.mountCallbacks),e.formResetCallbacks.length>0&&this._component.formResetCallbacks.push(...e.formResetCallbacks)}catch(e){this._reportLifecycleError(e,`mounted`)}}}finally{t()}})}};exports.BaseElement=c;
|
|
2
2
|
//# sourceMappingURL=base-element.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-element.cjs","names":["createScope","getPropMeta","untrack","OreLifecycleError","createRuntimeContext","runWithContext","createProps","OreApiError","ORE_ERRORS","onCleanup","loadStylesheet","beginPendingWork","require_errors","require_runtime","require_props","require_css","_vielzeug_ripple","ComponentPhase","createComponentState","isPromiseLike","value","BaseElement","def","oldValue","newValue","propMeta","name","parsed","callback","error","err","oreError","phase","normalizedPropDefs","ctx","setupResult","setupProps","capturedGeneration","result","host","context","endWork","batch","i","nestedCtx","cleanup"],"sources":["../src/base-element.ts"],"sourcesContent":["import { createScope, type Scope, untrack } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from './component-types';\n\nimport { ORE_ERRORS, OreApiError, type OreErrorPhase, OreLifecycleError, reportRuntimeError } from './errors';\nimport { createProps, getPropMeta, type InferProps, type PropInputDefs, type PropsDef } from './props';\nimport {\n beginPendingWork,\n createRuntimeContext,\n type OnFormResetCallback,\n type OnMountedCallback,\n onCleanup,\n runWithContext,\n} from './runtime';\nimport type { HTMLResult } from './template/result';\nimport { loadStylesheet } from './utils/css';\n\n// ─── Component phases ─────────────────────────────────────────────────────────\n// Internal to BaseElement: the only state machine in the package.\n\nconst ComponentPhase = {\n SETUP_DONE: 'setup_done',\n SETUP_RUNNING: 'setup_running',\n UNINITIALIZED: 'uninitialized',\n UNMOUNTED: 'unmounted',\n} as const;\n\ntype ComponentPhase = (typeof ComponentPhase)[keyof typeof ComponentPhase];\n\n// ─── Internal component state ─────────────────────────────────────────────────\n\ntype ComponentState = {\n /** Registered via `onFormReset()`: persists across mount callbacks, unlike `mountCallbacks`. */\n formResetCallbacks: OnFormResetCallback[];\n /** Incremented on every disconnect: invalidates queued mount callbacks. */\n generation: number;\n mountCallbacks: OnMountedCallback[];\n phase: ComponentPhase;\n scope: Scope;\n templateResult: HTMLResult | null;\n};\n\nconst createComponentState = (): ComponentState => ({\n formResetCallbacks: [],\n generation: 0,\n mountCallbacks: [],\n phase: ComponentPhase.UNINITIALIZED,\n scope: createScope(),\n templateResult: null,\n});\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n (typeof value === 'object' || typeof value === 'function') &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function';\n\n// ─── BaseElement ──────────────────────────────────────────────────────────────\n\n/**\n * Phase transitions:\n *\n * ```\n * UNINITIALIZED ──_runSetup()──► SETUP_DONE\n * SETUP_DONE ──disconnectedCallback()──► UNMOUNTED ──(reset)──► UNINITIALIZED\n * ```\n *\n * `generation` increments on every disconnect. Scheduled mount callbacks capture\n * it so callbacks belonging to a disconnected instance cannot run after a\n * reconnect (see `_isStale`).\n *\n * Why this lives on the class instead of a standalone pure reducer: every\n * transition here is triggered by running actual user code (`def.setup()`,\n * `onMounted` callbacks) inside a reactive `scope.run()` + `runWithContext()`\n *: there is no meaningful \"decide the next phase\" step that can be separated\n * from \"run the side-effecting thing that produces the phase change\" without\n * introducing a data-only effect-description layer that this package has no\n * other use for. That's why the methods below stay as direct, readable\n * procedural steps instead of a reducer + effect interpreter.\n */\nexport class BaseElement extends HTMLElement {\n static _definition: ComponentDefinition;\n static _normalizedPropDefs: PropsDef<Record<never, never>> | undefined;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n private _component: ComponentState;\n\n constructor() {\n super();\n\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (def?.shadow !== false) {\n this.attachShadow({ mode: 'open', ...(def?.shadow as Partial<ShadowRootInit> | undefined) });\n }\n\n this._component = createComponentState();\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (this._component.phase === ComponentPhase.UNINITIALIZED) this._runSetup();\n\n this._init();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const propMeta = getPropMeta(this, name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n )\n propMeta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n this._component.generation++;\n this._component.phase = ComponentPhase.UNMOUNTED;\n this._resetSetupState();\n }\n\n /** Dispose one connection's resources before its state can be rebuilt. */\n private _resetSetupState(): void {\n this._component.scope.dispose();\n // Reset mutable fields for next connection, keeping the same object for stable references.\n this._component.formResetCallbacks = [];\n this._component.mountCallbacks = [];\n this._component.phase = ComponentPhase.UNINITIALIZED;\n this._component.scope = createScope();\n this._component.templateResult = null;\n }\n\n /**\n * Native form-association lifecycle callback: the browser calls this on every\n * `formAssociated: true` element inside a `<form>` when that form is reset.\n * Runs every `onFormReset()` callback registered during `setup()`.\n */\n formResetCallback(): void {\n for (const callback of this._component.formResetCallbacks) {\n try {\n callback();\n } catch (error) {\n this._reportLifecycleError(error, 'form-reset');\n }\n }\n }\n\n private _reportLifecycleError(error: unknown, phase: OreErrorPhase): void {\n const err = error instanceof Error ? error : new Error(String(error));\n const oreError = new OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${phase})`, {\n cause: err,\n component: this.localName,\n phase,\n });\n\n reportRuntimeError(oreError, this);\n }\n\n private _runSetup(): void {\n this._component.phase = ComponentPhase.SETUP_RUNNING;\n\n const def = (this.constructor as typeof BaseElement)._definition;\n const normalizedPropDefs = (this.constructor as typeof BaseElement)._normalizedPropDefs;\n const ctx = createRuntimeContext(this);\n\n try {\n let setupResult: HTMLResult | null | undefined;\n\n this._component.scope.run(() => {\n setupResult = runWithContext(ctx, () => {\n const setupProps = normalizedPropDefs\n ? createProps(this, normalizedPropDefs)\n : ({} as InferProps<PropInputDefs>);\n\n return def.setup(setupProps as InferProps<PropInputDefs>);\n });\n });\n this._component.mountCallbacks.push(...ctx.mountCallbacks);\n this._component.formResetCallbacks.push(...ctx.formResetCallbacks);\n\n if (isPromiseLike(setupResult)) throw new OreApiError(ORE_ERRORS.asyncSetupUnsupported);\n\n this._component.templateResult = setupResult ?? null;\n this._component.phase = ComponentPhase.SETUP_DONE;\n } catch (error) {\n this._reportLifecycleError(error, 'setup');\n // Setup is atomic: a failed run must not leave partial effects or cleanups\n // live until a later disconnect.\n this._resetSetupState();\n throw error;\n }\n }\n\n private _isStale(capturedGeneration: number): boolean {\n return this._component.generation !== capturedGeneration || !this.isConnected;\n }\n\n private _applyResult(result: HTMLResult | null): void {\n if (!result) return;\n\n const host: Element | ShadowRoot = this.shadowRoot ?? this;\n\n // Mounting can register component cleanup, so preserve a runtime context here too.\n const context = createRuntimeContext(this);\n\n host.replaceChildren();\n this._component.scope.run(() => {\n runWithContext(context, () => {\n result.mount(host, null, onCleanup);\n });\n });\n }\n\n private _init(): void {\n this._applyStyles();\n this._mountTemplate();\n\n // Setup completes before the template mounts, so callbacks always observe live DOM.\n if (this._component.phase === ComponentPhase.SETUP_DONE) this._scheduleMountCallbacks();\n }\n\n private _applyStyles(): void {\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (this.shadowRoot && def?.styles?.length) {\n this.shadowRoot.adoptedStyleSheets = def.styles.map(loadStylesheet);\n }\n }\n\n private _mountTemplate(): void {\n const result = this._component.templateResult;\n\n if (!result) return;\n\n this._applyResult(result);\n }\n\n private _scheduleMountCallbacks(): void {\n if (this._component.mountCallbacks.length === 0) return;\n\n const capturedGeneration = this._component.generation;\n // Tracked as pending work for the duration of this microtask: ended in a `finally`\n // so a thrown callback (already caught per-callback below, but defensive here too)\n // never leaves the counter stuck above zero. See runtime.ts's beginPendingWork().\n const endWork = beginPendingWork();\n\n queueMicrotask(() => {\n try {\n if (this._isStale(capturedGeneration)) return;\n\n // Snapshot callbacks so in-loop registrations don't extend this iteration.\n // Nested onMounted registrations are appended to `batch` and run in the same\n // microtask: no recursive scheduling. Index-based loop because the array\n // grows as nested callbacks are discovered.\n const batch = this._component.mountCallbacks.splice(0);\n\n for (let i = 0; i < batch.length; i++) {\n const callback = batch[i];\n\n try {\n const nestedCtx = createRuntimeContext(this);\n\n this._component.scope.run(() => {\n runWithContext(nestedCtx, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') onCleanup(cleanup);\n });\n });\n\n if (nestedCtx.mountCallbacks.length > 0) {\n batch.push(...nestedCtx.mountCallbacks);\n }\n\n if (nestedCtx.formResetCallbacks.length > 0) {\n this._component.formResetCallbacks.push(...nestedCtx.formResetCallbacks);\n }\n } catch (error) {\n this._reportLifecycleError(error, 'mounted');\n }\n }\n } finally {\n endWork();\n }\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"base-element.cjs","names":["createScope","getPropMeta","untrack","OreLifecycleError","createRuntimeContext","runWithContext","createProps","OreApiError","ORE_ERRORS","onCleanup","loadStylesheet","beginPendingWork","require_errors","require_props","require_runtime","require_css","_vielzeug_ripple","ComponentPhase","createComponentState","isPromiseLike","value","BaseElement","def","oldValue","newValue","propMeta","name","parsed","callback","error","err","oreError","phase","normalizedPropDefs","ctx","setupResult","setupProps","capturedGeneration","result","host","context","endWork","batch","i","nestedCtx","cleanup"],"sources":["../src/base-element.ts"],"sourcesContent":["import { createScope, type Scope, untrack } from '@vielzeug/ripple';\n\nimport type { ComponentDefinition } from './component-types';\n\nimport { ORE_ERRORS, OreApiError, type OreErrorPhase, OreLifecycleError, reportRuntimeError } from './errors';\nimport { createProps, getPropMeta, type InferProps, type PropInputDefs, type PropsDef } from './props';\nimport {\n beginPendingWork,\n createRuntimeContext,\n type OnFormResetCallback,\n type OnMountedCallback,\n onCleanup,\n runWithContext,\n} from './runtime';\nimport type { HTMLResult } from './template/result';\nimport { loadStylesheet } from './utils/css';\n\n// ─── Component phases ─────────────────────────────────────────────────────────\n// Internal to BaseElement: the only state machine in the package.\n\nconst ComponentPhase = {\n SETUP_DONE: 'setup_done',\n SETUP_RUNNING: 'setup_running',\n UNINITIALIZED: 'uninitialized',\n UNMOUNTED: 'unmounted',\n} as const;\n\ntype ComponentPhase = (typeof ComponentPhase)[keyof typeof ComponentPhase];\n\n// ─── Internal component state ─────────────────────────────────────────────────\n\ntype ComponentState = {\n /** Registered via `onFormReset()`: persists across mount callbacks, unlike `mountCallbacks`. */\n formResetCallbacks: OnFormResetCallback[];\n /** Incremented on every disconnect: invalidates queued mount callbacks. */\n generation: number;\n mountCallbacks: OnMountedCallback[];\n phase: ComponentPhase;\n scope: Scope;\n templateResult: HTMLResult | null;\n};\n\nconst createComponentState = (): ComponentState => ({\n formResetCallbacks: [],\n generation: 0,\n mountCallbacks: [],\n phase: ComponentPhase.UNINITIALIZED,\n scope: createScope(),\n templateResult: null,\n});\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n (typeof value === 'object' || typeof value === 'function') &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function';\n\n// ─── BaseElement ──────────────────────────────────────────────────────────────\n\n/**\n * Phase transitions:\n *\n * ```\n * UNINITIALIZED ──_runSetup()──► SETUP_DONE\n * SETUP_DONE ──disconnectedCallback()──► UNMOUNTED ──(reset)──► UNINITIALIZED\n * ```\n *\n * `generation` increments on every disconnect. Scheduled mount callbacks capture\n * it so callbacks belonging to a disconnected instance cannot run after a\n * reconnect (see `_isStale`).\n *\n * Why this lives on the class instead of a standalone pure reducer: every\n * transition here is triggered by running actual user code (`def.setup()`,\n * `onMounted` callbacks) inside a reactive `scope.run()` + `runWithContext()`\n *: there is no meaningful \"decide the next phase\" step that can be separated\n * from \"run the side-effecting thing that produces the phase change\" without\n * introducing a data-only effect-description layer that this package has no\n * other use for. That's why the methods below stay as direct, readable\n * procedural steps instead of a reducer + effect interpreter.\n */\nexport class BaseElement extends HTMLElement {\n static _definition: ComponentDefinition;\n static _normalizedPropDefs: PropsDef<Record<never, never>> | undefined;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n private _component: ComponentState;\n\n constructor() {\n super();\n\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (def?.shadow !== false) {\n this.attachShadow({ mode: 'open', ...(def?.shadow as Partial<ShadowRootInit> | undefined) });\n }\n\n this._component = createComponentState();\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (this._component.phase === ComponentPhase.UNINITIALIZED) this._runSetup();\n\n this._init();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const propMeta = getPropMeta(this, name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n )\n propMeta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n this._component.generation++;\n this._component.phase = ComponentPhase.UNMOUNTED;\n this._resetSetupState();\n }\n\n /** Dispose one connection's resources before its state can be rebuilt. */\n private _resetSetupState(): void {\n this._component.scope.dispose();\n // Reset mutable fields for next connection, keeping the same object for stable references.\n this._component.formResetCallbacks = [];\n this._component.mountCallbacks = [];\n this._component.phase = ComponentPhase.UNINITIALIZED;\n this._component.scope = createScope();\n this._component.templateResult = null;\n }\n\n /**\n * Native form-association lifecycle callback: the browser calls this on every\n * `formAssociated: true` element inside a `<form>` when that form is reset.\n * Runs every `onFormReset()` callback registered during `setup()`.\n */\n formResetCallback(): void {\n for (const callback of this._component.formResetCallbacks) {\n try {\n callback();\n } catch (error) {\n this._reportLifecycleError(error, 'form-reset');\n }\n }\n }\n\n private _reportLifecycleError(error: unknown, phase: OreErrorPhase): void {\n const err = error instanceof Error ? error : new Error(String(error));\n const oreError = new OreLifecycleError(`<${this.localName}> failed during ${this._component.phase} (${phase})`, {\n cause: err,\n component: this.localName,\n phase,\n });\n\n reportRuntimeError(oreError, this);\n }\n\n private _runSetup(): void {\n this._component.phase = ComponentPhase.SETUP_RUNNING;\n\n const def = (this.constructor as typeof BaseElement)._definition;\n const normalizedPropDefs = (this.constructor as typeof BaseElement)._normalizedPropDefs;\n const ctx = createRuntimeContext(this);\n\n try {\n let setupResult: HTMLResult | null | undefined;\n\n this._component.scope.run(() => {\n setupResult = runWithContext(ctx, () => {\n const setupProps = normalizedPropDefs\n ? createProps(this, normalizedPropDefs)\n : ({} as InferProps<PropInputDefs>);\n\n return def.setup(setupProps as InferProps<PropInputDefs>);\n });\n });\n this._component.mountCallbacks.push(...ctx.mountCallbacks);\n this._component.formResetCallbacks.push(...ctx.formResetCallbacks);\n\n if (isPromiseLike(setupResult)) throw new OreApiError(ORE_ERRORS.asyncSetupUnsupported);\n\n this._component.templateResult = setupResult ?? null;\n this._component.phase = ComponentPhase.SETUP_DONE;\n } catch (error) {\n this._reportLifecycleError(error, 'setup');\n // Setup is atomic: a failed run must not leave partial effects or cleanups\n // live until a later disconnect.\n this._resetSetupState();\n throw error;\n }\n }\n\n private _isStale(capturedGeneration: number): boolean {\n return this._component.generation !== capturedGeneration || !this.isConnected;\n }\n\n private _applyResult(result: HTMLResult | null): void {\n if (!result) return;\n\n const host: Element | ShadowRoot = this.shadowRoot ?? this;\n\n // Mounting can register component cleanup, so preserve a runtime context here too.\n const context = createRuntimeContext(this);\n\n host.replaceChildren();\n this._component.scope.run(() => {\n runWithContext(context, () => {\n result.mount(host, null, onCleanup);\n });\n });\n }\n\n private _init(): void {\n this._applyStyles();\n this._mountTemplate();\n\n // Setup completes before the template mounts, so callbacks always observe live DOM.\n if (this._component.phase === ComponentPhase.SETUP_DONE) this._scheduleMountCallbacks();\n }\n\n private _applyStyles(): void {\n const def = (this.constructor as typeof BaseElement)._definition;\n\n if (this.shadowRoot && def?.styles?.length) {\n this.shadowRoot.adoptedStyleSheets = def.styles.map(loadStylesheet);\n }\n }\n\n private _mountTemplate(): void {\n const result = this._component.templateResult;\n\n if (!result) return;\n\n this._applyResult(result);\n }\n\n private _scheduleMountCallbacks(): void {\n if (this._component.mountCallbacks.length === 0) return;\n\n const capturedGeneration = this._component.generation;\n // Tracked as pending work for the duration of this microtask: ended in a `finally`\n // so a thrown callback (already caught per-callback below, but defensive here too)\n // never leaves the counter stuck above zero. See runtime.ts's beginPendingWork().\n const endWork = beginPendingWork();\n\n queueMicrotask(() => {\n try {\n if (this._isStale(capturedGeneration)) return;\n\n // Snapshot callbacks so in-loop registrations don't extend this iteration.\n // Nested onMounted registrations are appended to `batch` and run in the same\n // microtask: no recursive scheduling. Index-based loop because the array\n // grows as nested callbacks are discovered.\n const batch = this._component.mountCallbacks.splice(0);\n\n for (let i = 0; i < batch.length; i++) {\n const callback = batch[i];\n\n try {\n const nestedCtx = createRuntimeContext(this);\n\n this._component.scope.run(() => {\n runWithContext(nestedCtx, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') onCleanup(cleanup);\n });\n });\n\n if (nestedCtx.mountCallbacks.length > 0) {\n batch.push(...nestedCtx.mountCallbacks);\n }\n\n if (nestedCtx.formResetCallbacks.length > 0) {\n this._component.formResetCallbacks.push(...nestedCtx.formResetCallbacks);\n }\n } catch (error) {\n this._reportLifecycleError(error, 'mounted');\n }\n }\n } finally {\n endWork();\n }\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/base-element.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ORE_ERRORS as e,OreApiError as t,OreLifecycleError as n,reportRuntimeError as r}from"./errors.js";import{
|
|
1
|
+
import{ORE_ERRORS as e,OreApiError as t,OreLifecycleError as n,reportRuntimeError as r}from"./errors.js";import{createProps as i,getPropMeta as a}from"./props.js";import{beginPendingWork as o,createRuntimeContext as s,onCleanup as c,runWithContext as l}from"./runtime.js";import{loadStylesheet as u}from"./utils/css.js";import{createScope as d,untrack as f}from"@vielzeug/ripple";var p={SETUP_DONE:`setup_done`,SETUP_RUNNING:`setup_running`,UNINITIALIZED:`uninitialized`,UNMOUNTED:`unmounted`},m=()=>({formResetCallbacks:[],generation:0,mountCallbacks:[],phase:p.UNINITIALIZED,scope:d(),templateResult:null}),h=e=>(typeof e==`object`||typeof e==`function`)&&e!==null&&`then`in e&&typeof e.then==`function`,g=class extends HTMLElement{static _definition;static _normalizedPropDefs;static formAssociated=!1;static observedAttributes=[];_component;constructor(){super();let e=this.constructor._definition;e?.shadow!==!1&&this.attachShadow({mode:`open`,...e?.shadow}),this._component=m()}connectedCallback(){f(()=>{this._component.phase===p.UNINITIALIZED&&this._runSetup(),this._init()})}attributeChangedCallback(e,t,n){if(t===n)return;let r=a(this,e);if(!r)return;let i=r.parse(n);Object.is(f(()=>r.signal.value),i)||(r.signal.value=i)}disconnectedCallback(){this._component.generation++,this._component.phase=p.UNMOUNTED,this._resetSetupState()}_resetSetupState(){this._component.scope.dispose(),this._component.formResetCallbacks=[],this._component.mountCallbacks=[],this._component.phase=p.UNINITIALIZED,this._component.scope=d(),this._component.templateResult=null}formResetCallback(){for(let e of this._component.formResetCallbacks)try{e()}catch(e){this._reportLifecycleError(e,`form-reset`)}}_reportLifecycleError(e,t){let i=e instanceof Error?e:Error(String(e)),a=new n(`<${this.localName}> failed during ${this._component.phase} (${t})`,{cause:i,component:this.localName,phase:t});r(a,this)}_runSetup(){this._component.phase=p.SETUP_RUNNING;let n=this.constructor._definition,r=this.constructor._normalizedPropDefs,a=s(this);try{let o;if(this._component.scope.run(()=>{o=l(a,()=>{let e=r?i(this,r):{};return n.setup(e)})}),this._component.mountCallbacks.push(...a.mountCallbacks),this._component.formResetCallbacks.push(...a.formResetCallbacks),h(o))throw new t(e.asyncSetupUnsupported);this._component.templateResult=o??null,this._component.phase=p.SETUP_DONE}catch(e){throw this._reportLifecycleError(e,`setup`),this._resetSetupState(),e}}_isStale(e){return this._component.generation!==e||!this.isConnected}_applyResult(e){if(!e)return;let t=this.shadowRoot??this,n=s(this);t.replaceChildren(),this._component.scope.run(()=>{l(n,()=>{e.mount(t,null,c)})})}_init(){this._applyStyles(),this._mountTemplate(),this._component.phase===p.SETUP_DONE&&this._scheduleMountCallbacks()}_applyStyles(){let e=this.constructor._definition;this.shadowRoot&&e?.styles?.length&&(this.shadowRoot.adoptedStyleSheets=e.styles.map(u))}_mountTemplate(){let e=this._component.templateResult;e&&this._applyResult(e)}_scheduleMountCallbacks(){if(this._component.mountCallbacks.length===0)return;let e=this._component.generation,t=o();queueMicrotask(()=>{try{if(this._isStale(e))return;let t=this._component.mountCallbacks.splice(0);for(let e=0;e<t.length;e++){let n=t[e];try{let e=s(this);this._component.scope.run(()=>{l(e,()=>{let e=n();typeof e==`function`&&c(e)})}),e.mountCallbacks.length>0&&t.push(...e.mountCallbacks),e.formResetCallbacks.length>0&&this._component.formResetCallbacks.push(...e.formResetCallbacks)}catch(e){this._reportLifecycleError(e,`mounted`)}}}finally{t()}})}};export{g as BaseElement};
|
|
2
2
|
//# sourceMappingURL=base-element.js.map
|
package/dist/define.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./
|
|
1
|
+
const e=require("./base-element.cjs"),t=require("./errors.cjs"),n=require("./props.cjs"),r=require("./utils/dom.cjs");function i(i,a){if(!i)throw new t.OreApiError(t.ORE_ERRORS.defineRequiresTag);if(customElements.get(i))throw new t.OreApiError(t.ORE_ERRORS.defineDuplicate(i));let{props:o}=a,s=(()=>{if(!o)return;let e=n.validatePropDefs(o);if(e.length>0)throw new t.OreApiError(t.ORE_ERRORS.validationFailed(i,e));let r={};for(let[e,t]of Object.entries(o))r[e]=n.normalizePropDefinition(t,e);return r})(),c=s?Object.keys(s).map(r.toKebab):[],l=class extends e.BaseElement{static _definition=a;static _normalizedPropDefs=s;static formAssociated=a.formAssociated??!1;static observedAttributes=c};return Object.defineProperty(l,"name",{value:i}),customElements.define(i,l),l}exports.define=i;
|
|
2
2
|
//# sourceMappingURL=define.cjs.map
|
package/dist/define.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.cjs","names":["OreApiError","ORE_ERRORS","validatePropDefs","normalizePropDefinition","toKebab","BaseElement","
|
|
1
|
+
{"version":3,"file":"define.cjs","names":["OreApiError","ORE_ERRORS","validatePropDefs","normalizePropDefinition","toKebab","BaseElement","require_base_element","require_errors","require_props","require_dom","define","tag","propDefs","definition","normalizedPropDefs","errors","normalized","key","def","observedAttrs","ComponentClass"],"sources":["../src/define.ts"],"sourcesContent":["import { BaseElement } from './base-element';\nimport type { ComponentDefinition } from './component-types';\nimport { ORE_ERRORS, OreApiError } from './errors';\nimport { normalizePropDefinition, type PropInputDefs, type PropsDef, validatePropDefs } from './props';\nimport { toKebab } from './utils/dom';\n\n/**\n * Create and register a web component.\n *\n * The `setup` function runs for each connection and returns an `HTMLResult`.\n * Disconnecting disposes its state; reconnecting rebuilds it. All reactive\n * behaviour within a connection is expressed through directives inside the\n * template: not by re-evaluating setup itself.\n *\n * Everything besides `props`: lifecycle hooks, host bindings, context, slots,\n * emit: is a free function imported from `@vielzeug/ore` and called directly\n * from inside `setup()` (or from a composable it calls):\n *\n * ```ts\n * import { define, html, prop, onMounted, useEmit, useSlots } from '@vielzeug/ore';\n *\n * define<{ count?: number }>('my-counter', {\n * props: { count: prop.number(0) },\n * setup(props) {\n * const emit = useEmit<{ increment: number }>();\n * const slots = useSlots<'header' | 'footer'>();\n *\n * onMounted(() => console.log('mounted'));\n *\n * return html`<button @click=${() => emit('increment', props.count.value + 1)}>${props.count}</button>`;\n * },\n * });\n * ```\n *\n * Returns the registered class, so callers keep a handle for `instanceof` or\n * subclassing without a follow-up `customElements.get(tag)` cast.\n */\nexport function define<Props extends Record<string, unknown> = Record<never, never>>(\n tag: string,\n definition: ComponentDefinition<Props>,\n): CustomElementConstructor {\n if (!tag) throw new OreApiError(ORE_ERRORS.defineRequiresTag);\n if (customElements.get(tag)) throw new OreApiError(ORE_ERRORS.defineDuplicate(tag));\n\n const { props: propDefs } = definition;\n\n const normalizedPropDefs: PropsDef<Props> | undefined = (() => {\n if (!propDefs) return undefined;\n\n const errors = validatePropDefs(propDefs as Record<string, unknown>);\n\n if (errors.length > 0) throw new OreApiError(ORE_ERRORS.validationFailed(tag, errors));\n\n const normalized: PropInputDefs = {};\n\n for (const [key, def] of Object.entries(propDefs)) {\n normalized[key] = normalizePropDefinition(def, key);\n }\n\n return normalized as PropsDef<Props>;\n })();\n\n const observedAttrs = normalizedPropDefs ? Object.keys(normalizedPropDefs).map(toKebab) : [];\n\n const ComponentClass = class extends BaseElement {\n static override _definition = definition as unknown as ComponentDefinition;\n static override _normalizedPropDefs = normalizedPropDefs as PropsDef<Record<never, never>> | undefined;\n static override formAssociated = definition.formAssociated ?? false;\n static override observedAttributes = observedAttrs;\n };\n\n // Prop validation and class construction above are side-effect-free; registration\n // is intentionally the last, and only global side effect of define().\n Object.defineProperty(ComponentClass, 'name', { value: tag });\n customElements.define(tag, ComponentClass);\n\n return ComponentClass;\n}\n"],"mappings":"A,sHAqCA,SAAgBU,EACd,EACA,EAC0B,CAC1B,GAAI,CAACC,EAAK,MAAM,IAAIX,EAAAA,YAAYC,EAAAA,WAAW,iBAAiB,EAC5D,GAAI,eAAe,IAAIU,CAAG,EAAG,MAAM,IAAIX,EAAAA,YAAYC,EAAAA,WAAW,gBAAgBU,CAAG,CAAC,EAElF,GAAM,CAAE,MAAOC,GAAaC,EAEtBC,OAAyD,CAC7D,GAAI,CAACF,EAAU,OAEf,IAAMG,EAASb,EAAAA,iBAAiBU,CAAmC,EAEnE,GAAIG,EAAO,OAAS,EAAG,MAAM,IAAIf,EAAAA,YAAYC,EAAAA,WAAW,iBAAiBU,EAAKI,CAAM,CAAC,EAErF,IAAMC,EAA4B,CAAC,EAEnC,IAAK,GAAM,CAACC,EAAKC,KAAQ,OAAO,QAAQN,CAAQ,EAC9C,EAAWK,GAAOd,EAAAA,wBAAwBe,EAAKD,CAAG,EAGpD,OAAOD,CACT,EAAA,CAAG,EAEGG,EAAgBL,EAAqB,OAAO,KAAKA,CAAkB,CAAC,CAAC,IAAIV,EAAAA,OAAO,EAAI,CAAC,EAErFgB,EAAiB,cAAcf,EAAAA,WAAY,CAC/C,OAAgB,YAAcQ,EAC9B,OAAgB,oBAAsBC,EACtC,OAAgB,eAAiBD,EAAW,gBAAkB,GAC9D,OAAgB,mBAAqBM,CACvC,EAOA,OAHA,OAAO,eAAeC,EAAgB,OAAQ,CAAE,MAAOT,CAAI,CAAC,EAC5D,eAAe,OAAOA,EAAKS,CAAc,EAElCA,CACT,C"}
|
package/dist/define.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{BaseElement as e}from"./base-element.js";import{ORE_ERRORS as t,OreApiError as n}from"./errors.js";import{normalizePropDefinition as r,validatePropDefs as i}from"./props.js";import{toKebab as a}from"./utils/dom.js";function o(o,s){if(!o)throw new n(t.defineRequiresTag);if(customElements.get(o))throw new n(t.defineDuplicate(o));let{props:c}=s,l=(()=>{if(!c)return;let e=i(c);if(e.length>0)throw new n(t.validationFailed(o,e));let a={};for(let[e,t]of Object.entries(c))a[e]=r(t,e);return a})(),u=l?Object.keys(l).map(a):[],d=class extends e{static _definition=s;static _normalizedPropDefs=l;static formAssociated=s.formAssociated??!1;static observedAttributes=u};return Object.defineProperty(d,"name",{value:o}),customElements.define(o,d),d}export{o as define};
|
|
2
2
|
//# sourceMappingURL=define.js.map
|
package/dist/directives/each.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../errors.cjs"),t=require("../
|
|
1
|
+
const e=require("../errors.cjs"),t=require("../template/result.cjs"),n=require("../utils/dom.cjs");let r=require("@vielzeug/ripple");var i=(e,t,n,i,a)=>{let o=(0,r.signal)(e),s=(0,r.signal)(t),c=(0,r.createScope)(),l=[],u=[];return c.run(()=>{u=n(o,s).mount(i,a,e=>l.push(e))}),{cleanups:l,data:o,index:s,nodes:u,scope:c}},a=e=>{e.scope.dispose(),n.runAll(e.cleanups),n.removeNodes(e.nodes)},o=(t,n,o,s,c,l,u)=>{for(let e=0;e<n.length;e++){let a=o[e];if(t.has(a))continue;let d=(0,r.untrack)(()=>i(n[e],e,s,c,l));u.push(d),t.set(a,d)}let d=[];(0,r.batch)(()=>{for(let r=0;r<n.length;r++){let i=t.get(o[r]);e.invariant(i,`each() reconcile phase 2 lost an entry created in phase 1`),i.data.value=n[r],i.index.value=r,d.push(i)}});let f=l;for(let e=d.length-1;e>=0;e--){let t=d[e],n=t.nodes[0],r=t.nodes[t.nodes.length-1];if(n&&r!==f.previousSibling)for(let e of t.nodes)c.insertBefore(e,f);f=n??f}let p=new Set(o);for(let[e,n]of t)p.has(e)||(a(n),t.delete(e));return d},s=(e,t)=>{for(let n of t){a(n);for(let[t,r]of e)if(r===n){e.delete(t);break}}},c=(t,n)=>{let r=[],i=new Set;for(let a=0;a<t.length;a++){let o=n(t[a],a);if(i.has(o))throw new e.OreApiError(e.ORE_ERRORS.eachDuplicateKey(String(o),a));i.add(o),r.push(o)}return r},l=(t,n)=>{let r=t instanceof Error?t:Error(String(t));e.reportRuntimeError(new e.OreLifecycleError(`each() failed to reconcile a list update: ${r.message}`,{cause:r,component:`each()`,phase:`each-reconcile`}),n)};function u(i,u,d,f){let p=Array.isArray(i)?(0,r.signal)(i):typeof i==`function`?(0,r.computed)(i):i;return t.createDirectiveResult((t,i)=>{let m=t.parentNode;e.invariant(m,`each() anchor comment has no parent node`);let h=document.createComment(`each/end`);m.insertBefore(h,t.nextSibling);let g=new Map,_=[],v=null,y=[],b=()=>{f&&(v=f().mount(m,h,e=>y.push(e)))},x=()=>{v&&(n.runAll(y),n.removeNodes(v),v=null,y=[])},S=(0,r.effect)(()=>{let e=p.value??[];if(e.length===0){for(let e of(0,r.untrack)(()=>_))a(e);g=new Map,_=[],v||(0,r.untrack)(b);return}let n;try{n=(0,r.untrack)(()=>c(e,u))}catch(e){l(e,t);return}x();let i=[];try{_=(0,r.untrack)(()=>o(g,e,n,d,m,h,i))}catch(e){l(e,t),(0,r.untrack)(()=>s(g,i))}});i(()=>S.dispose()),i(()=>{x();for(let e of _)a(e);h.remove()})})}exports.each=u;
|
|
2
2
|
//# sourceMappingURL=each.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"each.cjs","names":["signal","createScope","untrack","OreApiError","ORE_ERRORS","OreLifecycleError","computed","createDirectiveResult","rawEffect","require_errors","require_dom","require_result","_vielzeug_ripple","createItem","dataSignal","item","indexSignal","index","scope","cleanups","nodes","render","parent","insertBefore","fn","removeItem","entry","reconcileItems","i","next","key","nextKeys","itemsMap","endMarker","createdThisPass","nextOrdered","cursor","j","firstNode","lastNode","node","nextKeySet","rollbackCreated","created","candidate","collectKeys","keys","seen","keyFn","reportEachError","cause","error","anchor","each","listSignal","list","itemsOrdered","fallbackNodes","fallbackCleanups","mountFallback","fallback","clearFallback","sub","nextList","registerCleanup"],"sources":["../../src/directives/each.ts"],"sourcesContent":["import {\n batch,\n computed,\n createScope,\n type Readable,\n effect as rawEffect,\n type Scope,\n type Signal,\n signal,\n untrack,\n} from '@vielzeug/ripple';\n\nimport { invariant, ORE_ERRORS, OreApiError, OreLifecycleError, reportRuntimeError } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../template/result';\nimport { type MaybeReactive, removeNodes, runAll } from '../utils/dom';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype MaybeReactiveArray<T> = MaybeReactive<T[]>;\ntype ItemKey = number | string;\n\ntype ItemEntry<T> = {\n cleanups: (() => void)[];\n data: Signal<T>;\n index: Signal<number>;\n nodes: Node[];\n scope: Scope;\n};\n\n// ─── Item lifecycle ───────────────────────────────────────────────────────────\n\nconst createItem = <T>(\n item: T,\n index: number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n): ItemEntry<T> => {\n const dataSignal: Signal<T> = signal(item);\n const indexSignal: Signal<number> = signal(index);\n const scope = createScope();\n const cleanups: (() => void)[] = [];\n let nodes: Node[] = [];\n\n scope.run(() => {\n const result = render(dataSignal, indexSignal);\n\n nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n });\n\n return { cleanups, data: dataSignal, index: indexSignal, nodes, scope };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\n entry.scope.dispose();\n runAll(entry.cleanups);\n removeNodes(entry.nodes);\n};\n\n// ─── Reconciler ───────────────────────────────────────────────────────────────\n\n/**\n * Reconciles the live item map against the next array. The pass is transactional:\n * new entries are created first, existing entries are updated in-place via signal\n * writes, and stale entries are destroyed only after the whole pass has succeeded.\n * If creation throws (user render code), the caller rolls back the entries created\n * during this pass and the previous list state survives: the last good render stays\n * on screen. Returns the ordered list of entries matching nextList.\n */\nconst reconcileItems = <T>(\n itemsMap: Map<ItemKey, ItemEntry<T>>,\n next: T[],\n nextKeys: ItemKey[],\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n endMarker: Node,\n createdThisPass: ItemEntry<T>[],\n): ItemEntry<T>[] => {\n // Phase 1: create every missing entry. This is the only step that can throw\n // (user render code), and it records what it created so a failure is undoable.\n for (let i = 0; i < next.length; i++) {\n const key = nextKeys[i];\n\n if (itemsMap.has(key)) continue;\n\n const entry = untrack(() => createItem(next[i], i, render, parent, endMarker));\n\n createdThisPass.push(entry);\n itemsMap.set(key, entry);\n }\n\n // Phase 2: ordered list + in-place updates for reused entries (signal writes).\n const nextOrdered: ItemEntry<T>[] = [];\n\n batch(() => {\n for (let i = 0; i < next.length; i++) {\n const entry = itemsMap.get(nextKeys[i]);\n\n invariant(entry, 'each() reconcile phase 2 lost an entry created in phase 1');\n\n entry.data.value = next[i];\n entry.index.value = i;\n nextOrdered.push(entry);\n }\n });\n\n // DOM ordering: right-to-left pass: move any item not already adjacent to cursor.\n // An item is in place when its last node directly precedes the cursor; items may\n // span several nodes (whitespace text around an element), so compare the last one.\n // Moving an already-placed item would disconnect and reconnect its custom elements.\n // O(n) DOM operations in the worst case; optimal for the typical small list sizes\n // encountered in UI components (tabs, options, menu items).\n let cursor: Node = endMarker;\n\n for (let j = nextOrdered.length - 1; j >= 0; j--) {\n const entry = nextOrdered[j];\n const firstNode = entry.nodes[0];\n const lastNode = entry.nodes[entry.nodes.length - 1];\n\n if (firstNode && lastNode !== cursor.previousSibling) {\n for (const node of entry.nodes) parent.insertBefore(node, cursor);\n }\n\n cursor = firstNode ?? cursor;\n }\n\n // Phase 3: commit: destroy stale entries only now that the pass has succeeded.\n const nextKeySet = new Set(nextKeys);\n\n for (const [key, entry] of itemsMap) {\n if (!nextKeySet.has(key)) {\n removeItem(entry);\n itemsMap.delete(key);\n }\n }\n\n return nextOrdered;\n};\n\n/** Undo a failed reconcile pass: destroy entries created during it, restoring the last good list. */\nconst rollbackCreated = <T>(itemsMap: Map<ItemKey, ItemEntry<T>>, created: ItemEntry<T>[]): void => {\n for (const entry of created) {\n removeItem(entry);\n\n for (const [key, candidate] of itemsMap) {\n if (candidate === entry) {\n itemsMap.delete(key);\n break;\n }\n }\n }\n};\n\nconst collectKeys = <T>(next: T[], keyFn: (item: T, index: number) => ItemKey): ItemKey[] => {\n const keys: ItemKey[] = [];\n const seen = new Set<ItemKey>();\n\n for (let i = 0; i < next.length; i++) {\n const key = keyFn(next[i], i);\n\n if (seen.has(key)) throw new OreApiError(ORE_ERRORS.eachDuplicateKey(String(key), i));\n\n seen.add(key);\n keys.push(key);\n }\n\n return keys;\n};\n\nconst reportEachError = (error: unknown, anchor: Comment): void => {\n const cause = error instanceof Error ? error : new Error(String(error));\n\n reportRuntimeError(\n new OreLifecycleError(`each() failed to reconcile a list update: ${cause.message}`, {\n cause,\n component: 'each()',\n phase: 'each-reconcile',\n }),\n anchor,\n );\n};\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Renders a keyed list of items as a `DirectiveResult`.\n *\n * Each item is rendered by the provided render function.\n * Items are reused by key when the list changes; only stale items are destroyed.\n *\n * The render function receives a `Readable<T>` signal and a `Readable<number>` index\n * signal. Use `item.value` to read the current item inside reactive expressions:\n *\n * ```ts\n * html`${each(items, (item) => item.id, (item) => html`<li>${() => item.value.name}</li>`)}`\n * ```\n *\n * **Plain array:** when a plain `T[]` is passed (not a signal or getter), it is\n * treated as a one-time static render. Mutations to the original array are not\n * tracked. Pass a `Signal<T[]>` or `() => T[]` for reactive lists.\n *\n * **Optional fallback:** the fourth argument renders when the list is empty.\n *\n * **Key choice:** pass a stable item identifier (e.g. `item.id`), never the\n * array index: an index-based key reassigns to a different item whenever the\n * list is reordered or an item is inserted/removed before it, causing full\n * item teardown/recreation instead of the in-place update `each()` is built\n * for.\n *\n * **Duplicate keys:** a reconciliation failure (e.g. duplicate keys, see `eachDuplicateKey`)\n * does not throw past this function: an uncaught exception inside the reactive effect that\n * drives `each()` would risk corrupting unrelated effects scheduled in the same update batch.\n * Instead the last valid list is preserved and the failure is reported via the `ore:error` DOM event\n * (see `OreLifecycleError`, phase `'each-reconcile'`) plus a dev-only console log: listen for\n * `ore:error` on `document`/`window` to observe this in every build, including production.\n */\nexport function each<T>(\n list: MaybeReactiveArray<T>,\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n fallback?: () => HTMLResult,\n): DirectiveResult {\n const listSignal = Array.isArray(list)\n ? signal(list as T[])\n : typeof list === 'function'\n ? computed(list as () => T[])\n : list;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'each() anchor comment has no parent node');\n\n const endMarker = document.createComment('each/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let itemsMap = new Map<ItemKey, ItemEntry<T>>();\n let itemsOrdered: ItemEntry<T>[] = [];\n let fallbackNodes: Node[] | null = null;\n let fallbackCleanups: (() => void)[] = [];\n\n const mountFallback = (): void => {\n if (!fallback) return;\n\n const result = fallback();\n\n fallbackNodes = result.mount(parent, endMarker, (fn) => fallbackCleanups.push(fn));\n };\n\n const clearFallback = (): void => {\n if (fallbackNodes) {\n runAll(fallbackCleanups);\n removeNodes(fallbackNodes);\n fallbackNodes = null;\n fallbackCleanups = [];\n }\n };\n\n const sub = rawEffect(() => {\n const nextList = listSignal.value ?? [];\n\n if (nextList.length === 0) {\n for (const entry of untrack(() => itemsOrdered)) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n\n if (!fallbackNodes) untrack(mountFallback);\n\n return;\n }\n\n let nextKeys: ItemKey[];\n\n try {\n nextKeys = untrack(() => collectKeys(nextList, keyFn));\n } catch (error) {\n reportEachError(error, anchor);\n return;\n }\n\n clearFallback();\n\n const createdThisPass: ItemEntry<T>[] = [];\n\n try {\n itemsOrdered = untrack(() =>\n reconcileItems(itemsMap, nextList, nextKeys, render, parent, endMarker, createdThisPass),\n );\n } catch (error) {\n // Undo this pass instead of tearing the list down: entries created before the\n // throw are removed, everything that was on screen stays exactly as it was.\n reportEachError(error, anchor);\n untrack(() => rollbackCreated(itemsMap, createdThisPass));\n }\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n clearFallback();\n for (const entry of itemsOrdered) removeItem(entry);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"each.cjs","names":["signal","createScope","untrack","OreApiError","ORE_ERRORS","OreLifecycleError","computed","createDirectiveResult","rawEffect","require_errors","require_result","require_dom","_vielzeug_ripple","createItem","dataSignal","item","indexSignal","index","scope","cleanups","nodes","render","parent","insertBefore","fn","removeItem","entry","reconcileItems","i","next","key","nextKeys","itemsMap","endMarker","createdThisPass","nextOrdered","cursor","j","firstNode","lastNode","node","nextKeySet","rollbackCreated","created","candidate","collectKeys","keys","seen","keyFn","reportEachError","cause","error","anchor","each","listSignal","list","itemsOrdered","fallbackNodes","fallbackCleanups","mountFallback","fallback","clearFallback","sub","nextList","registerCleanup"],"sources":["../../src/directives/each.ts"],"sourcesContent":["import {\n batch,\n computed,\n createScope,\n type Readable,\n effect as rawEffect,\n type Scope,\n type Signal,\n signal,\n untrack,\n} from '@vielzeug/ripple';\n\nimport { invariant, ORE_ERRORS, OreApiError, OreLifecycleError, reportRuntimeError } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult } from '../template/result';\nimport { type MaybeReactive, removeNodes, runAll } from '../utils/dom';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype MaybeReactiveArray<T> = MaybeReactive<T[]>;\ntype ItemKey = number | string;\n\ntype ItemEntry<T> = {\n cleanups: (() => void)[];\n data: Signal<T>;\n index: Signal<number>;\n nodes: Node[];\n scope: Scope;\n};\n\n// ─── Item lifecycle ───────────────────────────────────────────────────────────\n\nconst createItem = <T>(\n item: T,\n index: number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n): ItemEntry<T> => {\n const dataSignal: Signal<T> = signal(item);\n const indexSignal: Signal<number> = signal(index);\n const scope = createScope();\n const cleanups: (() => void)[] = [];\n let nodes: Node[] = [];\n\n scope.run(() => {\n const result = render(dataSignal, indexSignal);\n\n nodes = result.mount(parent, insertBefore, (fn) => cleanups.push(fn));\n });\n\n return { cleanups, data: dataSignal, index: indexSignal, nodes, scope };\n};\n\nconst removeItem = <T>(entry: ItemEntry<T>): void => {\n entry.scope.dispose();\n runAll(entry.cleanups);\n removeNodes(entry.nodes);\n};\n\n// ─── Reconciler ───────────────────────────────────────────────────────────────\n\n/**\n * Reconciles the live item map against the next array. The pass is transactional:\n * new entries are created first, existing entries are updated in-place via signal\n * writes, and stale entries are destroyed only after the whole pass has succeeded.\n * If creation throws (user render code), the caller rolls back the entries created\n * during this pass and the previous list state survives: the last good render stays\n * on screen. Returns the ordered list of entries matching nextList.\n */\nconst reconcileItems = <T>(\n itemsMap: Map<ItemKey, ItemEntry<T>>,\n next: T[],\n nextKeys: ItemKey[],\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n parent: ParentNode,\n endMarker: Node,\n createdThisPass: ItemEntry<T>[],\n): ItemEntry<T>[] => {\n // Phase 1: create every missing entry. This is the only step that can throw\n // (user render code), and it records what it created so a failure is undoable.\n for (let i = 0; i < next.length; i++) {\n const key = nextKeys[i];\n\n if (itemsMap.has(key)) continue;\n\n const entry = untrack(() => createItem(next[i], i, render, parent, endMarker));\n\n createdThisPass.push(entry);\n itemsMap.set(key, entry);\n }\n\n // Phase 2: ordered list + in-place updates for reused entries (signal writes).\n const nextOrdered: ItemEntry<T>[] = [];\n\n batch(() => {\n for (let i = 0; i < next.length; i++) {\n const entry = itemsMap.get(nextKeys[i]);\n\n invariant(entry, 'each() reconcile phase 2 lost an entry created in phase 1');\n\n entry.data.value = next[i];\n entry.index.value = i;\n nextOrdered.push(entry);\n }\n });\n\n // DOM ordering: right-to-left pass: move any item not already adjacent to cursor.\n // An item is in place when its last node directly precedes the cursor; items may\n // span several nodes (whitespace text around an element), so compare the last one.\n // Moving an already-placed item would disconnect and reconnect its custom elements.\n // O(n) DOM operations in the worst case; optimal for the typical small list sizes\n // encountered in UI components (tabs, options, menu items).\n let cursor: Node = endMarker;\n\n for (let j = nextOrdered.length - 1; j >= 0; j--) {\n const entry = nextOrdered[j];\n const firstNode = entry.nodes[0];\n const lastNode = entry.nodes[entry.nodes.length - 1];\n\n if (firstNode && lastNode !== cursor.previousSibling) {\n for (const node of entry.nodes) parent.insertBefore(node, cursor);\n }\n\n cursor = firstNode ?? cursor;\n }\n\n // Phase 3: commit: destroy stale entries only now that the pass has succeeded.\n const nextKeySet = new Set(nextKeys);\n\n for (const [key, entry] of itemsMap) {\n if (!nextKeySet.has(key)) {\n removeItem(entry);\n itemsMap.delete(key);\n }\n }\n\n return nextOrdered;\n};\n\n/** Undo a failed reconcile pass: destroy entries created during it, restoring the last good list. */\nconst rollbackCreated = <T>(itemsMap: Map<ItemKey, ItemEntry<T>>, created: ItemEntry<T>[]): void => {\n for (const entry of created) {\n removeItem(entry);\n\n for (const [key, candidate] of itemsMap) {\n if (candidate === entry) {\n itemsMap.delete(key);\n break;\n }\n }\n }\n};\n\nconst collectKeys = <T>(next: T[], keyFn: (item: T, index: number) => ItemKey): ItemKey[] => {\n const keys: ItemKey[] = [];\n const seen = new Set<ItemKey>();\n\n for (let i = 0; i < next.length; i++) {\n const key = keyFn(next[i], i);\n\n if (seen.has(key)) throw new OreApiError(ORE_ERRORS.eachDuplicateKey(String(key), i));\n\n seen.add(key);\n keys.push(key);\n }\n\n return keys;\n};\n\nconst reportEachError = (error: unknown, anchor: Comment): void => {\n const cause = error instanceof Error ? error : new Error(String(error));\n\n reportRuntimeError(\n new OreLifecycleError(`each() failed to reconcile a list update: ${cause.message}`, {\n cause,\n component: 'each()',\n phase: 'each-reconcile',\n }),\n anchor,\n );\n};\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Renders a keyed list of items as a `DirectiveResult`.\n *\n * Each item is rendered by the provided render function.\n * Items are reused by key when the list changes; only stale items are destroyed.\n *\n * The render function receives a `Readable<T>` signal and a `Readable<number>` index\n * signal. Use `item.value` to read the current item inside reactive expressions:\n *\n * ```ts\n * html`${each(items, (item) => item.id, (item) => html`<li>${() => item.value.name}</li>`)}`\n * ```\n *\n * **Plain array:** when a plain `T[]` is passed (not a signal or getter), it is\n * treated as a one-time static render. Mutations to the original array are not\n * tracked. Pass a `Signal<T[]>` or `() => T[]` for reactive lists.\n *\n * **Optional fallback:** the fourth argument renders when the list is empty.\n *\n * **Key choice:** pass a stable item identifier (e.g. `item.id`), never the\n * array index: an index-based key reassigns to a different item whenever the\n * list is reordered or an item is inserted/removed before it, causing full\n * item teardown/recreation instead of the in-place update `each()` is built\n * for.\n *\n * **Duplicate keys:** a reconciliation failure (e.g. duplicate keys, see `eachDuplicateKey`)\n * does not throw past this function: an uncaught exception inside the reactive effect that\n * drives `each()` would risk corrupting unrelated effects scheduled in the same update batch.\n * Instead the last valid list is preserved and the failure is reported via the `ore:error` DOM event\n * (see `OreLifecycleError`, phase `'each-reconcile'`) plus a dev-only console log: listen for\n * `ore:error` on `document`/`window` to observe this in every build, including production.\n */\nexport function each<T>(\n list: MaybeReactiveArray<T>,\n keyFn: (item: T, index: number) => string | number,\n render: (item: Readable<T>, index: Readable<number>) => HTMLResult,\n fallback?: () => HTMLResult,\n): DirectiveResult {\n const listSignal = Array.isArray(list)\n ? signal(list as T[])\n : typeof list === 'function'\n ? computed(list as () => T[])\n : list;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'each() anchor comment has no parent node');\n\n const endMarker = document.createComment('each/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let itemsMap = new Map<ItemKey, ItemEntry<T>>();\n let itemsOrdered: ItemEntry<T>[] = [];\n let fallbackNodes: Node[] | null = null;\n let fallbackCleanups: (() => void)[] = [];\n\n const mountFallback = (): void => {\n if (!fallback) return;\n\n const result = fallback();\n\n fallbackNodes = result.mount(parent, endMarker, (fn) => fallbackCleanups.push(fn));\n };\n\n const clearFallback = (): void => {\n if (fallbackNodes) {\n runAll(fallbackCleanups);\n removeNodes(fallbackNodes);\n fallbackNodes = null;\n fallbackCleanups = [];\n }\n };\n\n const sub = rawEffect(() => {\n const nextList = listSignal.value ?? [];\n\n if (nextList.length === 0) {\n for (const entry of untrack(() => itemsOrdered)) removeItem(entry);\n itemsMap = new Map();\n itemsOrdered = [];\n\n if (!fallbackNodes) untrack(mountFallback);\n\n return;\n }\n\n let nextKeys: ItemKey[];\n\n try {\n nextKeys = untrack(() => collectKeys(nextList, keyFn));\n } catch (error) {\n reportEachError(error, anchor);\n return;\n }\n\n clearFallback();\n\n const createdThisPass: ItemEntry<T>[] = [];\n\n try {\n itemsOrdered = untrack(() =>\n reconcileItems(itemsMap, nextList, nextKeys, render, parent, endMarker, createdThisPass),\n );\n } catch (error) {\n // Undo this pass instead of tearing the list down: entries created before the\n // throw are removed, everything that was on screen stays exactly as it was.\n reportEachError(error, anchor);\n untrack(() => rollbackCreated(itemsMap, createdThisPass));\n }\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n clearFallback();\n for (const entry of itemsOrdered) removeItem(entry);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"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"}
|
package/dist/directives/each.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ORE_ERRORS as e,OreApiError as t,OreLifecycleError as n,invariant as r,reportRuntimeError as i}from"../errors.js";import{
|
|
1
|
+
import{ORE_ERRORS as e,OreApiError as t,OreLifecycleError as n,invariant as r,reportRuntimeError as i}from"../errors.js";import{createDirectiveResult as a}from"../template/result.js";import{removeNodes as o,runAll as s}from"../utils/dom.js";import{batch as c,computed as l,createScope as u,effect as d,signal as f,untrack as p}from"@vielzeug/ripple";var m=(e,t,n,r,i)=>{let a=f(e),o=f(t),s=u(),c=[],l=[];return s.run(()=>{l=n(a,o).mount(r,i,e=>c.push(e))}),{cleanups:c,data:a,index:o,nodes:l,scope:s}},h=e=>{e.scope.dispose(),s(e.cleanups),o(e.nodes)},g=(e,t,n,i,a,o,s)=>{for(let r=0;r<t.length;r++){let c=n[r];if(e.has(c))continue;let l=p(()=>m(t[r],r,i,a,o));s.push(l),e.set(c,l)}let l=[];c(()=>{for(let i=0;i<t.length;i++){let a=e.get(n[i]);r(a,`each() reconcile phase 2 lost an entry created in phase 1`),a.data.value=t[i],a.index.value=i,l.push(a)}});let u=o;for(let e=l.length-1;e>=0;e--){let t=l[e],n=t.nodes[0],r=t.nodes[t.nodes.length-1];if(n&&r!==u.previousSibling)for(let e of t.nodes)a.insertBefore(e,u);u=n??u}let d=new Set(n);for(let[t,n]of e)d.has(t)||(h(n),e.delete(t));return l},_=(e,t)=>{for(let n of t){h(n);for(let[t,r]of e)if(r===n){e.delete(t);break}}},v=(n,r)=>{let i=[],a=/* @__PURE__ */ new Set;for(let o=0;o<n.length;o++){let s=r(n[o],o);if(a.has(s))throw new t(e.eachDuplicateKey(String(s),o));a.add(s),i.push(s)}return i},y=(e,t)=>{let r=e instanceof Error?e:Error(String(e));i(new n(`each() failed to reconcile a list update: ${r.message}`,{cause:r,component:`each()`,phase:`each-reconcile`}),t)};function b(e,t,n,i){let c=Array.isArray(e)?f(e):typeof e==`function`?l(e):e;return a((e,a)=>{let l=e.parentNode;r(l,`each() anchor comment has no parent node`);let u=document.createComment(`each/end`);l.insertBefore(u,e.nextSibling);let f=/* @__PURE__ */ new Map,m=[],b=null,x=[],S=()=>{i&&(b=i().mount(l,u,e=>x.push(e)))},C=()=>{b&&(s(x),o(b),b=null,x=[])},w=d(()=>{let r=c.value??[];if(r.length===0){for(let e of p(()=>m))h(e);f=/* @__PURE__ */ new Map,m=[],b||p(S);return}let i;try{i=p(()=>v(r,t))}catch(t){y(t,e);return}C();let a=[];try{m=p(()=>g(f,r,i,n,l,u,a))}catch(t){y(t,e),p(()=>_(f,a))}});a(()=>w.dispose()),a(()=>{C();for(let e of m)h(e);u.remove()})})}export{b as each};
|
|
2
2
|
//# sourceMappingURL=each.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../errors.cjs"),t=require("../
|
|
1
|
+
const e=require("../errors.cjs"),t=require("../template/result.cjs"),n=require("../utils/dom.cjs");let r=require("@vielzeug/ripple");var i=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function a(a){let o=typeof a==`function`?(0,r.computed)(a):(0,r.isReactive)(a)?a:null;return t.createDirectiveResult((t,s)=>{let c=t.parentNode;e.invariant(c,`unsafeHtml() anchor comment has no parent node`);let l=document.createComment(`unsafe-html/end`);if(c.insertBefore(l,t.nextSibling),o){let e=n.createReplaceableSlot(),t=(0,r.effect)(()=>{e.clear(),e.setNodes(i(o.value,c,l))});s(()=>t.dispose()),s(()=>{e.clear(),l.remove()})}else i(a,c,l),s(()=>l.remove())})}exports.unsafeHtml=a;
|
|
2
2
|
//# sourceMappingURL=unsafe-html.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unsafe-html.cjs","names":["computed","isReactive","createDirectiveResult","createReplaceableSlot","rawEffect","require_errors","
|
|
1
|
+
{"version":3,"file":"unsafe-html.cjs","names":["computed","isReactive","createDirectiveResult","createReplaceableSlot","rawEffect","require_errors","require_result","require_dom","_vielzeug_ripple","parseHtml","tpl","html","nodes","node","parent","insertBefore","unsafeHtml","src","value","anchor","endMarker","slot","stop","registerCleanup"],"sources":["../../src/directives/unsafe-html.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../template/result';\nimport { createReplaceableSlot } from '../utils/dom';\n\nconst parseHtml = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders HTML without escaping as a DirectiveResult.\n *\n * This is intentionally named `unsafeHtml`: sanitization is an application\n * boundary, not mutable process-wide framework configuration. Sanitize\n * untrusted content before passing it here.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function unsafeHtml(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n const isFn = typeof value === 'function';\n const src: Readable<string> | null = isFn ? computed(value as () => string) : isReactive(value) ? value : null;\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'unsafeHtml() anchor comment has no parent node');\n\n const endMarker = document.createComment('unsafe-html/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (src) {\n const slot = createReplaceableSlot();\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseHtml(src.value, parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseHtml(value as string, parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"A,qIAMA,IAAMS,GAAa,EAAc,EAAoB,IAA+B,CAClF,IAAMC,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAYC,EAEhB,IAAMC,EAAQ,MAAM,KAAKF,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAMG,KAAQD,EAAOE,EAAO,aAAaD,EAAME,CAAY,EAEhE,OAAOH,CACT,EAYA,SAAgBI,EAAW,EAAqF,CAE9G,IAAMC,EADO,OAAOC,GAAU,YAAA,EACclB,EAAAA,SAAAA,CAASkB,CAAqB,GAAA,EAAIjB,EAAAA,WAAAA,CAAWiB,CAAK,EAAIA,EAAQ,KAE1G,OAAOhB,EAAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAMY,EAASK,EAAO,WAEtBd,EAAA,UAAUS,EAAQ,gDAAgD,EAElE,IAAMM,EAAY,SAAS,cAAc,iBAAiB,EAI1D,GAFAN,EAAO,aAAaM,EAAWD,EAAO,WAAW,EAE7CF,EAAK,CACP,IAAMI,EAAOlB,EAAAA,sBAAsB,EAE7BmB,GAAA,EAAOlB,EAAAA,OAAAA,KAAgB,CAC3BiB,EAAK,MAAM,EACXA,EAAK,SAASZ,EAAUQ,EAAI,MAAOH,EAAQM,CAAS,CAAC,CACvD,CAAC,EAEDG,MAAsBD,EAAK,QAAQ,CAAC,EACpCC,MAAsB,CACpBF,EAAK,MAAM,EACXD,EAAU,OAAO,CACnB,CAAC,CACH,MACEX,EAAUS,EAAiBJ,EAAQM,CAAS,EAE5CG,MAAsBH,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH,C"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{invariant as e}from"../errors.js";import{
|
|
1
|
+
import{invariant as e}from"../errors.js";import{createDirectiveResult as t}from"../template/result.js";import{createReplaceableSlot as n}from"../utils/dom.js";import{computed as r,effect as i,isReactive as a}from"@vielzeug/ripple";var o=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function s(s){let c=typeof s==`function`?r(s):a(s)?s:null;return t((t,r)=>{let a=t.parentNode;e(a,`unsafeHtml() anchor comment has no parent node`);let l=document.createComment(`unsafe-html/end`);if(a.insertBefore(l,t.nextSibling),c){let e=n(),t=i(()=>{e.clear(),e.setNodes(o(c.value,a,l))});r(()=>t.dispose()),r(()=>{e.clear(),l.remove()})}else o(s,a,l),r(()=>l.remove())})}export{s as unsafeHtml};
|
|
2
2
|
//# sourceMappingURL=unsafe-html.js.map
|
package/dist/directives/when.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../errors.cjs"),t=require("../
|
|
1
|
+
const e=require("../errors.cjs"),t=require("../template/result.cjs"),n=require("../utils/dom.cjs");let r=require("@vielzeug/ripple");var i=`when() anchor comment has no parent node`;function a(a,o,s){return typeof a!=`function`&&!(0,r.isReactive)(a)?t.createDirectiveResult((r,c)=>{let l=a?o():s?s():null;if(!l||!t.isHtmlResult(l))return;let u=r.parentNode;e.invariant(u,i);let d=l.mount(u,r,c);c(()=>n.removeNodes(d))}):t.createDirectiveResult((c,l)=>{let u=(typeof a==`function`?(0,r.computed)(a):null)??a,d=c.parentNode;e.invariant(d,i);let f=document.createComment(`when/end`);d.insertBefore(f,c.nextSibling);let p=n.createReplaceableSlot(),m=(0,r.effect)(()=>{let e=u.value;p.clear();let n=e?o():s?s():null;n&&t.isHtmlResult(n)&&p.setNodes((0,r.untrack)(()=>n.mount(d,f,p.registerCleanup)))});l(()=>m.dispose()),l(()=>{p.clear(),f.remove()})})}exports.when=a;
|
|
2
2
|
//# sourceMappingURL=when.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"when.cjs","names":["isReactive","createDirectiveResult","isHtmlResult","removeNodes","computed","createReplaceableSlot","rawEffect","untrack","require_errors","
|
|
1
|
+
{"version":3,"file":"when.cjs","names":["isReactive","createDirectiveResult","isHtmlResult","removeNodes","computed","createReplaceableSlot","rawEffect","untrack","require_errors","require_result","require_dom","_vielzeug_ripple","NO_PARENT_MSG","when","condition","branch","truthy","falsy","parent","anchor","nodes","registerCleanup","conditionSignal","endMarker","slot","sub","next"],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, isReactive, type Readable, effect as rawEffect, untrack } from '@vielzeug/ripple';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../template/result';\nimport { createReplaceableSlot, type MaybeReactive, removeNodes } from '../utils/dom';\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = branch.mount(parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => branch.mount(parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"A,qIAQA,IAAMY,EAAgB,2CActB,SAAgBC,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAOC,GAAc,YAAc,EAAA,EAACd,EAAAA,WAAAA,CAAWc,CAAS,EACnDb,EAAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAMc,EAASD,EAAYE,EAAO,EAAIC,EAAQA,EAAM,EAAI,KAExD,GAAI,CAACF,GAAU,CAACb,EAAAA,aAAaa,CAAM,EAAG,OAEtC,IAAMG,EAASC,EAAO,WAEtBX,EAAA,UAAUU,EAAQN,CAAa,EAE/B,IAAMQ,EAAQL,EAAO,MAAMG,EAAQC,EAAQE,CAAe,EAE1DA,MAAsBlB,EAAAA,YAAYiB,CAAK,CAAC,CAC1C,CAAC,EAGInB,EAAAA,uBAAuB,EAAQ,IAAoB,CAExD,IAAMqB,GADgB,OAAOR,GAAc,YAAA,EAAaV,EAAAA,SAAAA,CAASU,CAA0B,EAAI,OACrDA,EAEpCI,EAASC,EAAO,WAEtBX,EAAA,UAAUU,EAAQN,CAAa,EAE/B,IAAMW,EAAY,SAAS,cAAc,UAAU,EAEnDL,EAAO,aAAaK,EAAWJ,EAAO,WAAW,EAEjD,IAAMK,EAAOnB,EAAAA,sBAAsB,EAE7BoB,GAAA,EAAMnB,EAAAA,OAAAA,KAAgB,CAC1B,IAAMoB,EAAOJ,EAAgB,MAE7BE,EAAK,MAAM,EAEX,IAAMT,EAASW,EAAOV,EAAO,EAAIC,EAAQA,EAAM,EAAI,KAE9CF,GAAWb,EAAAA,aAAaa,CAAM,GAEnCS,EAAK,UAAA,EAASjB,EAAAA,QAAAA,KAAcQ,EAAO,MAAMG,EAAQK,EAAWC,EAAK,eAAe,CAAC,CAAC,CACpF,CAAC,EAEDH,MAAsBI,EAAI,QAAQ,CAAC,EACnCJ,MAAsB,CACpBG,EAAK,MAAM,EACXD,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH,C"}
|
package/dist/directives/when.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{invariant as e}from"../errors.js";import{
|
|
1
|
+
import{invariant as e}from"../errors.js";import{createDirectiveResult as t,isHtmlResult as n}from"../template/result.js";import{createReplaceableSlot as r,removeNodes as i}from"../utils/dom.js";import{computed as a,effect as o,isReactive as s,untrack as c}from"@vielzeug/ripple";var l=`when() anchor comment has no parent node`;function u(u,d,f){return typeof u!=`function`&&!s(u)?t((t,r)=>{let a=u?d():f?f():null;if(!a||!n(a))return;let o=t.parentNode;e(o,l);let s=a.mount(o,t,r);r(()=>i(s))}):t((t,i)=>{let s=(typeof u==`function`?a(u):null)??u,p=t.parentNode;e(p,l);let m=document.createComment(`when/end`);p.insertBefore(m,t.nextSibling);let h=r(),g=o(()=>{let e=s.value;h.clear();let t=e?d():f?f():null;t&&n(t)&&h.setNodes(c(()=>t.mount(p,m,h.registerCleanup)))});i(()=>g.dispose()),i(()=>{h.clear(),m.remove()})})}export{u as when};
|
|
2
2
|
//# sourceMappingURL=when.js.map
|
package/dist/host-bind.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./
|
|
1
|
+
const e=require("./runtime.cjs"),t=require("./utils/aria.cjs"),n=require("./utils/dom.cjs");let r=require("@vielzeug/ripple");var i=(t,r)=>{let i=r?.target??e.getHost(),o=[];if(t.attr)for(let[e,n]of Object.entries(t.attr)){let t=s(i,a(e),n);t&&o.push(t)}if(t.class&&o.push(l(i,t.class)),t.style)for(let[e,n]of Object.entries(t.style)){let t=c(i,e,n);t&&o.push(t)}if(t.on){let{target:e,...a}=r??{};for(let e of Object.keys(t.on)){let r=t.on[e];r&&o.push(n.listen(i,e,r,a))}}let u=()=>{for(let e of o)e()};return e.tryRegisterCleanup(u),u},a=t.normalizeHostAttrKey,o=(t,n)=>{if(typeof t==`function`)return e.watchEffect(()=>{n(t())});if((0,r.isReactive)(t))return e.watchEffect(()=>{n(t.value)});n(t)};function s(e,t,r){return o(r,r=>n.setAttr(e,t,r))}function c(e,t,r){let i=n.cssDeclarationName(t);if(!i)return;let a=!1;return o(r,t=>{let r=n.cssDeclarationValue(t);r?(a=!0,e.style.setProperty(i,r)):a&&e.style.removeProperty(i)})}function l(t,r){let i=typeof r==`function`?r:()=>Object.fromEntries([...n.resolveClassTokens(r)].map(e=>[e,!0])),a=new Set;return e.watchEffect(()=>{let e=new Set;for(let[n,r]of Object.entries(i()))r&&(e.add(n),a.has(n)||t.classList.add(n));for(let n of a)e.has(n)||t.classList.remove(n);a=e})}exports.bind=i;
|
|
2
2
|
//# sourceMappingURL=host-bind.cjs.map
|
package/dist/host-bind.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-bind.cjs","names":["getHost","listen","normalizeHostAttrKey","watchEffect","isReactive","setAttr","cssDeclarationName","cssDeclarationValue","resolveClassTokens","
|
|
1
|
+
{"version":3,"file":"host-bind.cjs","names":["getHost","listen","normalizeHostAttrKey","watchEffect","isReactive","setAttr","cssDeclarationName","cssDeclarationValue","resolveClassTokens","require_runtime","require_aria","require_dom","_vielzeug_ripple","bind","el","options","disposers","config","key","value","dispose","applyAttribute","toHostAttr","applyClassMap","applyStyle","_t","listenerOptions","event","listener","cleanup","applyReactiveBinding","updater","host","name","next","cssName","owned","declaration","v","getMap","cls","prev","active"],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API: reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeHostAttrKey } from './utils/aria';\nimport {\n cssDeclarationName,\n cssDeclarationValue,\n listen,\n type MaybeReactive,\n resolveClassTokens,\n setAttr,\n} from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue = MaybeReactive<string | number | boolean | null | undefined>;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type AttributeBindings = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = MaybeReactive<boolean>;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n attr?: AttributeBindings;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | undefined => {\n if (typeof value === 'function') {\n return watchEffect(() => {\n updater(value());\n return undefined;\n });\n }\n\n if (isReactive(value)) {\n return watchEffect(() => {\n updater(value.value);\n return undefined;\n });\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | undefined {\n const cssName = cssDeclarationName(name);\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n const declaration = cssDeclarationValue(v);\n\n if (declaration) {\n owned = true;\n host.style.setProperty(cssName, declaration);\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => Object.fromEntries([...resolveClassTokens(value)].map((cls) => [cls, true]));\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"A,8HAwDA,IAAaa,GAAQ,EAAwB,IAAwC,CACnF,IAAMC,EAAMC,GAAS,QAAsCf,EAAAA,QAAQ,EAC7DgB,EAA+B,CAAC,EAEtC,GAAIC,EAAO,KACT,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQF,EAAO,IAAI,EAAG,CAEtD,IAAMG,EAAUC,EAAeP,EADlBQ,EAAWJ,CACW,EAAMC,CAAK,EAE1CC,GAASJ,EAAU,KAAKI,CAAO,CACrC,CAOF,GAJIH,EAAO,OACTD,EAAU,KAAKO,EAAcT,EAAIG,EAAO,KAAK,CAAC,EAG5CA,EAAO,MACT,IAAK,GAAM,CAACC,EAAKC,KAAU,OAAO,QAAQF,EAAO,KAAK,EAAG,CACvD,IAAMG,EAAUI,EAAWV,EAAII,EAAKC,CAAK,EAErCC,GAASJ,EAAU,KAAKI,CAAO,CACrC,CAGF,GAAIH,EAAO,GAAI,CACb,GAAM,CAAE,OAAQQ,EAAI,GAAGC,GAAoBX,GAAW,CAAC,EAEvD,IAAK,IAAMY,KAAS,OAAO,KAAKV,EAAO,EAAE,EAAoC,CAC3E,IAAMW,EAAWX,EAAO,GAAGU,GAEtBC,GAELZ,EAAU,KAAKf,EAAAA,OAAOa,EAAIa,EAAiBC,EAA2BF,CAAe,CAAC,CACxF,CACF,CAEA,IAAMG,MAAsB,CAC1B,IAAK,IAAMT,KAAWJ,EAAWI,EAAQ,CAC3C,EAIA,OAFAX,EAAA,mBAAmBoB,CAAO,EAEnBA,CACT,EAEMP,EAAapB,EAAAA,qBAEb4B,GACJ,EACA,IAC6B,CAC7B,GAAI,OAAOX,GAAU,WACnB,OAAOhB,EAAAA,gBAAkB,CACvB4B,EAAQZ,EAAM,CAAC,CAEjB,CAAC,EAGH,IAAA,EAAIf,EAAAA,WAAAA,CAAWe,CAAK,EAClB,OAAOhB,EAAAA,gBAAkB,CACvB4B,EAAQZ,EAAM,KAAK,CAErB,CAAC,EAGHY,EAAQZ,CAAK,CACf,EAEA,SAASE,EAAe,EAAmB,EAAc,EAAmD,CAC1G,OAAOS,EAAqBX,EAAQ,GAASd,EAAAA,QAAQ2B,EAAMC,EAAMC,CAAI,CAAC,CACxE,CAEA,SAASV,EAAW,EAAmB,EAAc,EAAmD,CACtG,IAAMW,EAAU7B,EAAAA,mBAAmB2B,CAAI,EAEvC,GAAI,CAACE,EAAS,OAEd,IAAIC,EAAQ,GAUZ,OAAON,EAAqBX,EATV,GAA0D,CAC1E,IAAMkB,EAAc9B,EAAAA,oBAAoB+B,CAAC,EAErCD,GACF,EAAQ,GACRL,EAAK,MAAM,YAAYG,EAASE,CAAW,GAClCD,GAAOJ,EAAK,MAAM,eAAeG,CAAO,CACrD,CAE2C,CAC7C,CAEA,SAASZ,EACP,EACA,EACY,CACZ,IAAMgB,EACJ,OAAOpB,GAAU,WACbA,MAC+B,OAAO,YAAY,CAAC,GAAGX,EAAAA,mBAAmBW,CAAK,CAAC,CAAC,CAAC,IAAK,GAAQ,CAACqB,EAAK,EAAI,CAAC,CAAC,EAE5GC,EAAO,IAAI,IAkBf,OAhBYtC,EAAAA,gBAAkB,CAC5B,IAAM+B,EAAO,IAAI,IAEjB,IAAK,GAAM,CAACM,EAAKE,KAAW,OAAO,QAAQH,EAAO,CAAC,EAC5CG,IAELR,EAAK,IAAIM,CAAG,EAEPC,EAAK,IAAID,CAAG,GAAGR,EAAK,UAAU,IAAIQ,CAAG,GAE5C,IAAK,IAAMA,KAAOC,EACXP,EAAK,IAAIM,CAAG,GAAGR,EAAK,UAAU,OAAOQ,CAAG,EAE/C,EAAON,CACT,CAEO,CACT,C"}
|
package/dist/host-bind.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{getHost as e,tryRegisterCleanup as t,watchEffect as n}from"./runtime.js";import{normalizeHostAttrKey as r}from"./utils/aria.js";import{cssDeclarationName as i,cssDeclarationValue as a,listen as o,resolveClassTokens as s,setAttr as c}from"./utils/dom.js";import{isReactive as l}from"@vielzeug/ripple";var u=(n,r)=>{let i=r?.target??e(),a=[];if(n.attr)for(let[e,t]of Object.entries(n.attr)){let n=p(i,d(e),t);n&&a.push(n)}if(n.class&&a.push(h(i,n.class)),n.style)for(let[e,t]of Object.entries(n.style)){let n=m(i,e,t);n&&a.push(n)}if(n.on){let{target:e,...t}=r??{};for(let e of Object.keys(n.on)){let r=n.on[e];r&&a.push(o(i,e,r,t))}}let s=()=>{for(let e of a)e()};return t(s),s},d=r,f=(e,t)=>{if(typeof e==`function`)return n(()=>{t(e())});if(l(e))return n(()=>{t(e.value)});t(e)};function p(e,t,n){return f(n,n=>c(e,t,n))}function m(e,t,n){let r=i(t);if(!r)return;let o=!1;return f(n,t=>{let n=a(t);n?(o=!0,e.style.setProperty(r,n)):o&&e.style.removeProperty(r)})}function h(e,t){let r=typeof t==`function`?t:()=>Object.fromEntries([...s(t)].map(e=>[e,!0])),i=/* @__PURE__ */ new Set;return n(()=>{let t=/* @__PURE__ */ new Set;for(let[n,a]of Object.entries(r()))a&&(t.add(n),i.has(n)||e.classList.add(n));for(let n of i)t.has(n)||e.classList.remove(n);i=t})}export{u as bind};
|
|
2
2
|
//# sourceMappingURL=host-bind.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./context.cjs"),t=require("./define.cjs"),n=require("./directives/classMap.cjs"),r=require("./directives/each.cjs"),i=require("./directives/live.cjs"),a=require("./directives/model.cjs"),o=require("./directives/styleMap.cjs"),s=require("./directives/unsafe-html.cjs"),c=require("./directives/when.cjs"),l=require("./errors.cjs"),u=require("./forms/field.cjs"),d=require("./host-bind.cjs"),f=require("./props.cjs"),p=require("./runtime.cjs"),m=require("./slots.cjs"),h=require("./template/instantiator.cjs"),g=require("./template/result.cjs"),_=require("./utils/css.cjs"),v=require("./utils/emit.cjs"),y=require("./utils/id.cjs");exports.OreApiError=l.OreApiError,exports.OreError=l.OreError,exports.OreInternalError=l.OreInternalError,exports.OreLifecycleError=l.OreLifecycleError,exports.bind=d.bind,exports.classMap=n.classMap,exports.createContext=e.createContext,exports.createId=y.createId,exports.css=_.css,exports.define=t.define,exports.each=r.each,exports.getHost=p.getHost,exports.html=h.html,exports.inject=e.inject,exports.injectStrict=e.injectStrict,exports.live=i.live,exports.model=a.model,exports.onCleanup=p.onCleanup,exports.onElement=p.onElement,exports.onEvent=p.onEvent,exports.onFormReset=p.onFormReset,exports.onMounted=p.onMounted,exports.prop=f.prop,exports.provide=e.provide,exports.ref=g.ref,exports.styleMap=o.styleMap,exports.unsafeHtml=s.unsafeHtml,exports.useEmit=v.useEmit,exports.useField=u.useField,exports.useSlots=m.useSlots,exports.watchEffect=p.watchEffect,exports.when=c.when;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{createContext as e,inject as t,injectStrict as n,provide as r}from"./context.js";import{define as i}from"./define.js";import{classMap as a}from"./directives/classMap.js";import{each as o}from"./directives/each.js";import{live as s}from"./directives/live.js";import{model as c}from"./directives/model.js";import{styleMap as l}from"./directives/styleMap.js";import{unsafeHtml as u}from"./directives/unsafe-html.js";import{when as d}from"./directives/when.js";import{OreApiError as f,OreError as p,OreInternalError as m,OreLifecycleError as h}from"./errors.js";import{useField as g}from"./forms/field.js";import{bind as _}from"./host-bind.js";import{prop as v}from"./props.js";import{getHost as y,onCleanup as b,onElement as x,onEvent as S,onFormReset as C,onMounted as w,watchEffect as T}from"./runtime.js";import{useSlots as E}from"./slots.js";import{html as D}from"./template/instantiator.js";import{ref as O}from"./template/result.js";import{css as k}from"./utils/css.js";import{useEmit as A}from"./utils/emit.js";import{createId as j}from"./utils/id.js";export{f as OreApiError,p as OreError,m as OreInternalError,h as OreLifecycleError,_ as bind,a as classMap,e as createContext,j as createId,k as css,i as define,o as each,y as getHost,D as html,t as inject,n as injectStrict,s as live,c as model,b as onCleanup,x as onElement,S as onEvent,C as onFormReset,w as onMounted,v as prop,r as provide,O as ref,l as styleMap,u as unsafeHtml,A as useEmit,g as useField,E as useSlots,T as watchEffect,d as when};
|
package/dist/ore.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { batch as e, computed as t, createScope as n, effect as r, isReactive as i, signal as a, untrack as o } from "@vielzeug/ripple";
|
|
2
|
-
|
|
3
|
-
//#region src/errors.ts
|
|
2
|
+
// src/errors.ts
|
|
4
3
|
var OreError = class extends Error {
|
|
5
4
|
constructor(e, t) {
|
|
6
5
|
super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
|
|
@@ -41,8 +40,7 @@ var s = {
|
|
|
41
40
|
function invariant(e, t) {
|
|
42
41
|
if (!e) throw new OreInternalError(s.invariantViolated(t));
|
|
43
42
|
}
|
|
44
|
-
|
|
45
|
-
//#region src/utils/dom.ts
|
|
43
|
+
// src/utils/dom.ts
|
|
46
44
|
var resolveMaybeReactive = (e) => typeof e == "function" ? e() : i(e) ? e.value : e, c = /[;{}]/g, sanitizeCssToken = (e) => e.replace(c, ""), runAll = (e) => {
|
|
47
45
|
for (let t = e.length - 1; t >= 0; t--) e[t]?.();
|
|
48
46
|
}, removeNodes = (e) => {
|
|
@@ -179,8 +177,7 @@ var injectStrict = (e) => {
|
|
|
179
177
|
function createContext(e) {
|
|
180
178
|
return Symbol(e);
|
|
181
179
|
}
|
|
182
|
-
|
|
183
|
-
//#region src/props.ts
|
|
180
|
+
// src/props.ts
|
|
184
181
|
function _jsOnlyProp(e) {
|
|
185
182
|
return {
|
|
186
183
|
default: e,
|
|
@@ -297,8 +294,7 @@ function createProps(e, t) {
|
|
|
297
294
|
for (let [r, i] of Object.entries(t)) n[r] = registerProp(e, r, toKebab(r), i);
|
|
298
295
|
return n;
|
|
299
296
|
}
|
|
300
|
-
|
|
301
|
-
//#region src/utils/brand.ts
|
|
297
|
+
// src/utils/brand.ts
|
|
302
298
|
var makeBrand = (e) => {
|
|
303
299
|
let t = Symbol.for(e), stamp = (e) => Object.assign(e, { [t]: !0 }), is = (e) => typeof e == "object" && !!e && t in e;
|
|
304
300
|
return {
|
|
@@ -457,8 +453,7 @@ var makeBrand = (e) => {
|
|
|
457
453
|
});
|
|
458
454
|
}
|
|
459
455
|
};
|
|
460
|
-
|
|
461
|
-
//#region src/define.ts
|
|
456
|
+
// src/define.ts
|
|
462
457
|
function define(e, t) {
|
|
463
458
|
if (!e) throw new OreApiError(s.defineRequiresTag);
|
|
464
459
|
if (customElements.get(e)) throw new OreApiError(s.defineDuplicate(e));
|
|
@@ -477,11 +472,9 @@ function define(e, t) {
|
|
|
477
472
|
};
|
|
478
473
|
return Object.defineProperty(ComponentClass, "name", { value: e }), customElements.define(e, ComponentClass), ComponentClass;
|
|
479
474
|
}
|
|
480
|
-
|
|
481
|
-
//#region src/directives/classMap.ts
|
|
475
|
+
// src/directives/classMap.ts
|
|
482
476
|
var classMap = (e) => t(() => [...resolveClassTokens(e)].join(" "));
|
|
483
|
-
|
|
484
|
-
//#region src/template/result.ts
|
|
477
|
+
// src/template/result.ts
|
|
485
478
|
function ref() {
|
|
486
479
|
return a(null);
|
|
487
480
|
}
|
|
@@ -497,8 +490,7 @@ function createHtmlResult(e, t) {
|
|
|
497
490
|
mount
|
|
498
491
|
});
|
|
499
492
|
}
|
|
500
|
-
|
|
501
|
-
//#region src/directives/each.ts
|
|
493
|
+
// src/directives/each.ts
|
|
502
494
|
var createItem = (e, t, r, i, o) => {
|
|
503
495
|
let s = a(e), c = a(t), l = n(), u = [], d = [];
|
|
504
496
|
return l.run(() => {
|
|
@@ -599,8 +591,7 @@ function each(e, n, i, s) {
|
|
|
599
591
|
});
|
|
600
592
|
});
|
|
601
593
|
}
|
|
602
|
-
|
|
603
|
-
//#region src/directives/live.ts
|
|
594
|
+
// src/directives/live.ts
|
|
604
595
|
var k = makeBrand("ore:live"), live = (e) => k.stamp({ source: e }), A = k.is, j = makeBrand("ore:model"), M = j.is, modelDefaultGet = (e) => e instanceof HTMLInputElement && (e.type === "checkbox" || e.type === "radio") ? e.checked : e.value, modelDefaultEvent = (e) => e instanceof HTMLInputElement && (e.type === "checkbox" || e.type === "radio") || e instanceof HTMLSelectElement ? "change" : "input", model = (e, t) => j.stamp({
|
|
605
596
|
event: t?.event,
|
|
606
597
|
get: t?.get,
|
|
@@ -637,8 +628,7 @@ function unsafeHtml(e) {
|
|
|
637
628
|
} else parseHtml(e, a, o), i(() => o.remove());
|
|
638
629
|
});
|
|
639
630
|
}
|
|
640
|
-
|
|
641
|
-
//#region src/directives/when.ts
|
|
631
|
+
// src/directives/when.ts
|
|
642
632
|
var N = "when() anchor comment has no parent node";
|
|
643
633
|
function when(e, n, a) {
|
|
644
634
|
return typeof e != "function" && !i(e) ? createDirectiveResult((t, r) => {
|
|
@@ -664,8 +654,7 @@ function when(e, n, a) {
|
|
|
664
654
|
});
|
|
665
655
|
});
|
|
666
656
|
}
|
|
667
|
-
|
|
668
|
-
//#region src/forms/field.ts
|
|
657
|
+
// src/forms/field.ts
|
|
669
658
|
var P = /* @__PURE__ */ new WeakMap(), F = /* @__PURE__ */ new WeakSet(), useField = (e) => {
|
|
670
659
|
let t = getHost();
|
|
671
660
|
if (!t.constructor.formAssociated) throw new OreApiError(s.defineFieldRequiresFormAssociated(t.localName));
|
|
@@ -750,8 +739,7 @@ function applyClassMap(e, t) {
|
|
|
750
739
|
r = t;
|
|
751
740
|
});
|
|
752
741
|
}
|
|
753
|
-
|
|
754
|
-
//#region src/slots.ts
|
|
742
|
+
// src/slots.ts
|
|
755
743
|
var L = "default", normalizeSlotName = (e) => e || L, createSlots = (e) => {
|
|
756
744
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), ensureSlotEntry = (e) => {
|
|
757
745
|
let n = t.get(e);
|
|
@@ -1181,7 +1169,6 @@ var L = "default", normalizeSlotName = (e) => e || L, createSlots = (e) => {
|
|
|
1181
1169
|
return e.dispatchEvent(new CustomEvent(String(t), r));
|
|
1182
1170
|
});
|
|
1183
1171
|
}, $ = 0, ee = Math.random().toString(36).slice(2, 6), createId = (e = "id") => `${e}-${ee}${++$}`;
|
|
1184
|
-
//#endregion
|
|
1185
1172
|
export { OreApiError, OreError, OreInternalError, OreLifecycleError, bind, classMap, createContext, createId, css, define, each, getHost, html, inject, injectStrict, live, model, onCleanup, onElement, onEvent, onFormReset, onMounted, v as prop, provide, ref, styleMap, unsafeHtml, useEmit, useField, useSlots, watchEffect, when };
|
|
1186
1173
|
|
|
1187
1174
|
//# sourceMappingURL=ore.js.map
|