@vielzeug/ore 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-element.cjs +1 -1
- package/dist/base-element.cjs.map +1 -1
- package/dist/base-element.d.ts +6 -0
- package/dist/base-element.d.ts.map +1 -1
- package/dist/base-element.js +1 -1
- package/dist/base-element.js.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/forms/field.cjs +1 -1
- package/dist/forms/field.cjs.map +1 -1
- package/dist/forms/field.d.ts +17 -0
- package/dist/forms/field.d.ts.map +1 -1
- package/dist/forms/field.js +1 -1
- package/dist/forms/field.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/ore.cjs +1 -1
- package/dist/ore.cjs.map +1 -1
- package/dist/ore.iife.js +1 -1
- package/dist/ore.iife.js.map +1 -1
- package/dist/ore.js +1 -1
- package/dist/ore.js.map +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.ts +9 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/testing/dom.cjs +2 -0
- package/dist/testing/dom.cjs.map +1 -0
- package/dist/testing/dom.d.ts +22 -0
- package/dist/testing/dom.d.ts.map +1 -0
- package/dist/testing/dom.js +2 -0
- package/dist/testing/dom.js.map +1 -0
- package/dist/testing/form-internals-polyfill.cjs +2 -0
- package/dist/testing/form-internals-polyfill.cjs.map +1 -0
- package/dist/testing/form-internals-polyfill.d.ts +17 -0
- package/dist/testing/form-internals-polyfill.d.ts.map +1 -0
- package/dist/testing/form-internals-polyfill.js +2 -0
- package/dist/testing/form-internals-polyfill.js.map +1 -0
- 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/render-hook.js.map +1 -1
- package/dist/testing/testing.cjs +1 -1
- package/dist/testing/testing.cjs.map +1 -1
- package/dist/testing/testing.d.ts +7 -1
- package/dist/testing/testing.d.ts.map +1 -1
- package/dist/testing/testing.js +1 -1
- package/dist/testing/testing.js.map +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.js +1 -1
- package/dist/utils/emit.cjs +1 -1
- package/dist/utils/emit.cjs.map +1 -1
- package/dist/utils/emit.d.ts +11 -4
- package/dist/utils/emit.d.ts.map +1 -1
- package/dist/utils/emit.js +1 -1
- package/dist/utils/emit.js.map +1 -1
- package/package.json +2 -2
package/dist/runtime.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./utils/dom.cjs");let n=require("@vielzeug/ripple");var r=null,i=(e,t)=>{let n=r;r=e;try{return t()}finally{r=n}},a=t=>{if(r)return r;throw new e.OreApiError(`${t}: ${e.ORE_ERRORS.lifecycleOutsideSetup}`)},o=()=>a(`getHost`).element,s=e=>r?((0,n.onCleanup)(e),!0):!1,c=n.onCleanup,l=e=>{a(`onMounted`).mountCallbacks.push(e)},u=e=>{let t=(0,n.effect)(e),r=()=>t.dispose();return s(r),r};function
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./utils/dom.cjs");let n=require("@vielzeug/ripple");var r=null,i=(e,t)=>{let n=r;r=e;try{return t()}finally{r=n}},a=t=>{if(r)return r;throw new e.OreApiError(`${t}: ${e.ORE_ERRORS.lifecycleOutsideSetup}`)},o=()=>a(`getHost`).element,s=e=>r?((0,n.onCleanup)(e),!0):!1,c=n.onCleanup,l=e=>{a(`onMounted`).mountCallbacks.push(e)},u=e=>{a(`onFormReset`).formResetCallbacks.push(e)},d=e=>{let t=(0,n.effect)(e),r=()=>t.dispose();return s(r),r};function f(e,n,r,i){if(a(`onEvent`),!e)return;let o=t.listen(e,n,r,i);s(o)||o()}var p=(e,t)=>d(()=>{let n=e.value;if(n)return t(n)});exports.getHost=o,exports.onCleanup=c,exports.onElement=p,exports.onEvent=f,exports.onFormReset=u,exports.onMounted=l,exports.requireSetupContext=a,exports.runWithContext=i,exports.tryRegisterCleanup=s,exports.watchEffect=d;
|
|
2
2
|
//# sourceMappingURL=runtime.cjs.map
|
package/dist/runtime.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.cjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * Component runtime — implicit \"current component\" context plus every lifecycle\n * hook a `setup()` function can call.\n *\n * Design note: hooks are plain module-level functions (not a bag/context object\n * passed into `setup`). They resolve the active component through a single\n * module-level pointer (`currentContext`), set for the duration of `setup()` and\n * of each queued `onMounted` callback. This is the same mechanism React/Vue/Solid\n * use for their composable hooks — it lets any helper function (not just the\n * top-level `setup()` body) call `onMounted`/`onCleanup`/`bind`/... directly,\n * with no context object to thread through every layer of a composable.\n */\nimport {\n type CleanupFn,\n effect as _effect,\n type EffectCallback,\n onCleanup as _onCleanup,\n type Readable,\n} from '@vielzeug/ripple';\n\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { listen as listenInternal } from './utils/dom';\n\n// ─── Runtime context ──────────────────────────────────────────────────────────\n// A single context object carries both the host element and mount callbacks,\n// eliminating two parallel globals that were always set together.\n\nexport type OnMountedCallback = () => CleanupFn | void;\n\nexport type RuntimeContext = {\n element: HTMLElement;\n mountCallbacks: OnMountedCallback[];\n};\n\nlet currentContext: RuntimeContext | null = null;\n\n/** @internal Execute fn with a given runtime context active. */\nexport const runWithContext = <T>(ctx: RuntimeContext, fn: () => T): T => {\n const prev = currentContext;\n\n currentContext = ctx;\n\n try {\n return fn();\n } finally {\n currentContext = prev;\n }\n};\n\n/**\n * Returns the current runtime context, throwing a consistently-worded error\n * (naming the calling API) if called outside `setup()`. Every lifecycle/context\n * hook below routes through this — it's the single place that decides both\n * \"are we inside setup?\" and what the resulting error looks like, so the error\n * message is never worse for one hook than another.\n * @internal\n */\nexport const requireSetupContext = (api: string): RuntimeContext => {\n if (currentContext) return currentContext;\n\n throw new OreApiError(`${api}: ${ORE_ERRORS.lifecycleOutsideSetup}`);\n};\n\n/**\n * Returns the current component's host element.\n * Only valid synchronously during component `setup()` (or inside a composable\n * called from it) — throws otherwise.\n */\nexport const getHost = (): HTMLElement => requireSetupContext('getHost').element;\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentContext) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to run on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts to the DOM.\n * Multiple callbacks run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n requireSetupContext('onMounted').mountCallbacks.push(fn);\n};\n\n/**\n * Create a reactive effect scoped to the component lifecycle.\n * Automatically cleaned up on component disconnect.\n * Returns a stop function that disposes the effect immediately.\n *\n * Named `watchEffect` (not `watch`) to avoid shadowing `@vielzeug/ripple`'s\n * `watch(source, callback)`, which has different semantics (explicit source,\n * old/new value pair) — the two are commonly imported in the same file.\n */\nexport const watchEffect = (fn: EffectCallback): (() => void) => {\n const sub = _effect(fn);\n const stop = (): void => sub.dispose();\n\n tryRegisterCleanup(stop);\n\n return stop;\n};\n\n/**\n * Attach a scoped event listener that is automatically removed on component disconnect.\n * Silently no-ops when `target` is `null` or `undefined` (safe for reactive targets).\n */\nexport function onEvent<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function onEvent(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n requireSetupContext('onEvent');\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n if (!tryRegisterCleanup(cleanup)) cleanup();\n}\n\n/**\n * Watch a ref signal and run a callback when it resolves to a non-null element.\n * The callback's return value is used as a cleanup function.\n */\nexport const onElement = <T extends HTMLElement>(\n ref: Readable<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): (() => void) => {\n return watchEffect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"+
|
|
1
|
+
{"version":3,"file":"runtime.cjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * Component runtime — implicit \"current component\" context plus every lifecycle\n * hook a `setup()` function can call.\n *\n * Design note: hooks are plain module-level functions (not a bag/context object\n * passed into `setup`). They resolve the active component through a single\n * module-level pointer (`currentContext`), set for the duration of `setup()` and\n * of each queued `onMounted` callback. This is the same mechanism React/Vue/Solid\n * use for their composable hooks — it lets any helper function (not just the\n * top-level `setup()` body) call `onMounted`/`onCleanup`/`bind`/... directly,\n * with no context object to thread through every layer of a composable.\n */\nimport {\n type CleanupFn,\n effect as _effect,\n type EffectCallback,\n onCleanup as _onCleanup,\n type Readable,\n} from '@vielzeug/ripple';\n\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { listen as listenInternal } from './utils/dom';\n\n// ─── Runtime context ──────────────────────────────────────────────────────────\n// A single context object carries both the host element and mount callbacks,\n// eliminating two parallel globals that were always set together.\n\nexport type OnMountedCallback = () => CleanupFn | void;\nexport type OnFormResetCallback = () => void;\n\nexport type RuntimeContext = {\n element: HTMLElement;\n formResetCallbacks: OnFormResetCallback[];\n mountCallbacks: OnMountedCallback[];\n};\n\nlet currentContext: RuntimeContext | null = null;\n\n/** @internal Execute fn with a given runtime context active. */\nexport const runWithContext = <T>(ctx: RuntimeContext, fn: () => T): T => {\n const prev = currentContext;\n\n currentContext = ctx;\n\n try {\n return fn();\n } finally {\n currentContext = prev;\n }\n};\n\n/**\n * Returns the current runtime context, throwing a consistently-worded error\n * (naming the calling API) if called outside `setup()`. Every lifecycle/context\n * hook below routes through this — it's the single place that decides both\n * \"are we inside setup?\" and what the resulting error looks like, so the error\n * message is never worse for one hook than another.\n * @internal\n */\nexport const requireSetupContext = (api: string): RuntimeContext => {\n if (currentContext) return currentContext;\n\n throw new OreApiError(`${api}: ${ORE_ERRORS.lifecycleOutsideSetup}`);\n};\n\n/**\n * Returns the current component's host element.\n * Only valid synchronously during component `setup()` (or inside a composable\n * called from it) — throws otherwise.\n */\nexport const getHost = (): HTMLElement => requireSetupContext('getHost').element;\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentContext) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to run on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts to the DOM.\n * Multiple callbacks run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n requireSetupContext('onMounted').mountCallbacks.push(fn);\n};\n\n/**\n * Register work to run when the ancestor `<form>` is reset (native `formResetCallback`,\n * only fires for `formAssociated: true` components). Multiple callbacks run in\n * registration order, every time the form resets — unlike `onMounted`, this isn't a\n * one-shot hook.\n */\nexport const onFormReset = (fn: OnFormResetCallback): void => {\n requireSetupContext('onFormReset').formResetCallbacks.push(fn);\n};\n\n/**\n * Create a reactive effect scoped to the component lifecycle.\n * Automatically cleaned up on component disconnect.\n * Returns a stop function that disposes the effect immediately.\n *\n * Named `watchEffect` (not `watch`) to avoid shadowing `@vielzeug/ripple`'s\n * `watch(source, callback)`, which has different semantics (explicit source,\n * old/new value pair) — the two are commonly imported in the same file.\n */\nexport const watchEffect = (fn: EffectCallback): (() => void) => {\n const sub = _effect(fn);\n const stop = (): void => sub.dispose();\n\n tryRegisterCleanup(stop);\n\n return stop;\n};\n\n/**\n * Attach a scoped event listener that is automatically removed on component disconnect.\n * Silently no-ops when `target` is `null` or `undefined` (safe for reactive targets).\n */\nexport function onEvent<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function onEvent(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n requireSetupContext('onEvent');\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n if (!tryRegisterCleanup(cleanup)) cleanup();\n}\n\n/**\n * Watch a ref signal and run a callback when it resolves to a non-null element.\n * The callback's return value is used as a cleanup function.\n */\nexport const onElement = <T extends HTMLElement>(\n ref: Readable<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): (() => void) => {\n return watchEffect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"+FAoCA,IAAI,EAAwC,KAG/B,GAAqB,EAAqB,IAAmB,CACxE,IAAM,EAAO,EAEb,EAAiB,EAEjB,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAiB,CACnB,CACF,EAUa,EAAuB,GAAgC,CAClE,GAAI,EAAgB,OAAO,EAE3B,MAAM,IAAI,EAAA,YAAY,GAAG,EAAI,IAAI,EAAA,WAAW,uBAAuB,CACrE,EAOa,MAA6B,EAAoB,SAAS,CAAC,CAAC,QAE5D,EAAsB,GAC5B,IAEL,EAAA,EAAA,UAAA,CAAW,CAAE,EAEN,IAJqB,GAWjB,EAAY,EAAA,UAMZ,EAAa,GAAgC,CACxD,EAAoB,WAAW,CAAC,CAAC,eAAe,KAAK,CAAE,CACzD,EAQa,EAAe,GAAkC,CAC5D,EAAoB,aAAa,CAAC,CAAC,mBAAmB,KAAK,CAAE,CAC/D,EAWa,EAAe,GAAqC,CAC/D,IAAM,GAAA,EAAA,EAAA,OAAA,CAAc,CAAE,EAChB,MAAmB,EAAI,QAAQ,EAIrC,OAFA,EAAmB,CAAI,EAEhB,CACT,EAYA,SAAgB,EACd,EACA,EACA,EACA,EACM,CAGN,GAFA,EAAoB,SAAS,EAEzB,CAAC,EAAQ,OAEb,IAAM,EAAU,EAAA,OAAe,EAAQ,EAAO,EAAU,CAAO,EAE1D,EAAmB,CAAO,GAAG,EAAQ,CAC5C,CAMA,IAAa,GACX,EACA,IAEO,MAAkB,CACvB,IAAM,EAAK,EAAI,MAEf,GAAI,EAAI,OAAO,EAAS,CAAE,CAC5B,CAAC"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -12,8 +12,10 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { type CleanupFn, type EffectCallback, type Readable } from '@vielzeug/ripple';
|
|
14
14
|
export type OnMountedCallback = () => CleanupFn | void;
|
|
15
|
+
export type OnFormResetCallback = () => void;
|
|
15
16
|
export type RuntimeContext = {
|
|
16
17
|
element: HTMLElement;
|
|
18
|
+
formResetCallbacks: OnFormResetCallback[];
|
|
17
19
|
mountCallbacks: OnMountedCallback[];
|
|
18
20
|
};
|
|
19
21
|
/**
|
|
@@ -33,6 +35,13 @@ export declare const onCleanup: (fn: CleanupFn) => void;
|
|
|
33
35
|
* Multiple callbacks run in registration order.
|
|
34
36
|
*/
|
|
35
37
|
export declare const onMounted: (fn: OnMountedCallback) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Register work to run when the ancestor `<form>` is reset (native `formResetCallback`,
|
|
40
|
+
* only fires for `formAssociated: true` components). Multiple callbacks run in
|
|
41
|
+
* registration order, every time the form resets — unlike `onMounted`, this isn't a
|
|
42
|
+
* one-shot hook.
|
|
43
|
+
*/
|
|
44
|
+
export declare const onFormReset: (fn: OnFormResetCallback) => void;
|
|
36
45
|
/**
|
|
37
46
|
* Create a reactive effect scoped to the component lifecycle.
|
|
38
47
|
* Automatically cleaned up on component disconnect.
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,cAAc,EAEnB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAC;AAS1B,MAAM,MAAM,iBAAiB,GAAG,MAAM,SAAS,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,cAAc,EAEnB,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAC;AAS1B,MAAM,MAAM,iBAAiB,GAAG,MAAM,SAAS,GAAG,IAAI,CAAC;AACvD,MAAM,MAAM,mBAAmB,GAAG,MAAM,IAAI,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,WAAW,CAAC;IACrB,kBAAkB,EAAE,mBAAmB,EAAE,CAAC;IAC1C,cAAc,EAAE,iBAAiB,EAAE,CAAC;CACrC,CAAC;AA+BF;;;;GAIG;AACH,eAAO,MAAM,OAAO,QAAO,WAAqD,CAAC;AAEjF,eAAO,MAAM,kBAAkB,GAAI,IAAI,SAAS,KAAG,OAMlD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,yBAAa,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,IAAI,iBAAiB,KAAG,IAEjD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,mBAAmB,KAAG,IAErD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,cAAc,KAAG,CAAC,MAAM,IAAI,CAO3D,CAAC;AAEF;;;GAGG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,mBAAmB,EACzD,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,CAAC,EAAE,uBAAuB,GAChC,IAAI,CAAC;AAgBR;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,EAC7C,KAAK,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,EACvB,UAAU,CAAC,EAAE,EAAE,CAAC,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI,KAChD,CAAC,MAAM,IAAI,CAMb,CAAC"}
|
package/dist/runtime.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ORE_ERRORS as e,OreApiError as t}from"./errors.js";import{listen as n}from"./utils/dom.js";import{effect as r,onCleanup as i}from"@vielzeug/ripple";var a=null,o=(e,t)=>{let n=a;a=e;try{return t()}finally{a=n}},s=n=>{if(a)return a;throw new t(`${n}: ${e.lifecycleOutsideSetup}`)},c=()=>s(`getHost`).element,l=e=>a?(i(e),!0):!1,u=i,d=e=>{s(`onMounted`).mountCallbacks.push(e)},f=e=>{let t=r(e),n=()=>t.dispose();return l(n),n};function
|
|
1
|
+
import{ORE_ERRORS as e,OreApiError as t}from"./errors.js";import{listen as n}from"./utils/dom.js";import{effect as r,onCleanup as i}from"@vielzeug/ripple";var a=null,o=(e,t)=>{let n=a;a=e;try{return t()}finally{a=n}},s=n=>{if(a)return a;throw new t(`${n}: ${e.lifecycleOutsideSetup}`)},c=()=>s(`getHost`).element,l=e=>a?(i(e),!0):!1,u=i,d=e=>{s(`onMounted`).mountCallbacks.push(e)},f=e=>{s(`onFormReset`).formResetCallbacks.push(e)},p=e=>{let t=r(e),n=()=>t.dispose();return l(n),n};function m(e,t,r,i){if(s(`onEvent`),!e)return;let a=n(e,t,r,i);l(a)||a()}var h=(e,t)=>p(()=>{let n=e.value;if(n)return t(n)});export{c as getHost,u as onCleanup,h as onElement,m as onEvent,f as onFormReset,d as onMounted,s as requireSetupContext,o as runWithContext,l as tryRegisterCleanup,p as watchEffect};
|
|
2
2
|
//# sourceMappingURL=runtime.js.map
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * Component runtime — implicit \"current component\" context plus every lifecycle\n * hook a `setup()` function can call.\n *\n * Design note: hooks are plain module-level functions (not a bag/context object\n * passed into `setup`). They resolve the active component through a single\n * module-level pointer (`currentContext`), set for the duration of `setup()` and\n * of each queued `onMounted` callback. This is the same mechanism React/Vue/Solid\n * use for their composable hooks — it lets any helper function (not just the\n * top-level `setup()` body) call `onMounted`/`onCleanup`/`bind`/... directly,\n * with no context object to thread through every layer of a composable.\n */\nimport {\n type CleanupFn,\n effect as _effect,\n type EffectCallback,\n onCleanup as _onCleanup,\n type Readable,\n} from '@vielzeug/ripple';\n\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { listen as listenInternal } from './utils/dom';\n\n// ─── Runtime context ──────────────────────────────────────────────────────────\n// A single context object carries both the host element and mount callbacks,\n// eliminating two parallel globals that were always set together.\n\nexport type OnMountedCallback = () => CleanupFn | void;\n\nexport type RuntimeContext = {\n element: HTMLElement;\n mountCallbacks: OnMountedCallback[];\n};\n\nlet currentContext: RuntimeContext | null = null;\n\n/** @internal Execute fn with a given runtime context active. */\nexport const runWithContext = <T>(ctx: RuntimeContext, fn: () => T): T => {\n const prev = currentContext;\n\n currentContext = ctx;\n\n try {\n return fn();\n } finally {\n currentContext = prev;\n }\n};\n\n/**\n * Returns the current runtime context, throwing a consistently-worded error\n * (naming the calling API) if called outside `setup()`. Every lifecycle/context\n * hook below routes through this — it's the single place that decides both\n * \"are we inside setup?\" and what the resulting error looks like, so the error\n * message is never worse for one hook than another.\n * @internal\n */\nexport const requireSetupContext = (api: string): RuntimeContext => {\n if (currentContext) return currentContext;\n\n throw new OreApiError(`${api}: ${ORE_ERRORS.lifecycleOutsideSetup}`);\n};\n\n/**\n * Returns the current component's host element.\n * Only valid synchronously during component `setup()` (or inside a composable\n * called from it) — throws otherwise.\n */\nexport const getHost = (): HTMLElement => requireSetupContext('getHost').element;\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentContext) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to run on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts to the DOM.\n * Multiple callbacks run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n requireSetupContext('onMounted').mountCallbacks.push(fn);\n};\n\n/**\n * Create a reactive effect scoped to the component lifecycle.\n * Automatically cleaned up on component disconnect.\n * Returns a stop function that disposes the effect immediately.\n *\n * Named `watchEffect` (not `watch`) to avoid shadowing `@vielzeug/ripple`'s\n * `watch(source, callback)`, which has different semantics (explicit source,\n * old/new value pair) — the two are commonly imported in the same file.\n */\nexport const watchEffect = (fn: EffectCallback): (() => void) => {\n const sub = _effect(fn);\n const stop = (): void => sub.dispose();\n\n tryRegisterCleanup(stop);\n\n return stop;\n};\n\n/**\n * Attach a scoped event listener that is automatically removed on component disconnect.\n * Silently no-ops when `target` is `null` or `undefined` (safe for reactive targets).\n */\nexport function onEvent<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function onEvent(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n requireSetupContext('onEvent');\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n if (!tryRegisterCleanup(cleanup)) cleanup();\n}\n\n/**\n * Watch a ref signal and run a callback when it resolves to a non-null element.\n * The callback's return value is used as a cleanup function.\n */\nexport const onElement = <T extends HTMLElement>(\n ref: Readable<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): (() => void) => {\n return watchEffect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * Component runtime — implicit \"current component\" context plus every lifecycle\n * hook a `setup()` function can call.\n *\n * Design note: hooks are plain module-level functions (not a bag/context object\n * passed into `setup`). They resolve the active component through a single\n * module-level pointer (`currentContext`), set for the duration of `setup()` and\n * of each queued `onMounted` callback. This is the same mechanism React/Vue/Solid\n * use for their composable hooks — it lets any helper function (not just the\n * top-level `setup()` body) call `onMounted`/`onCleanup`/`bind`/... directly,\n * with no context object to thread through every layer of a composable.\n */\nimport {\n type CleanupFn,\n effect as _effect,\n type EffectCallback,\n onCleanup as _onCleanup,\n type Readable,\n} from '@vielzeug/ripple';\n\nimport { OreApiError, ORE_ERRORS } from './errors';\nimport { listen as listenInternal } from './utils/dom';\n\n// ─── Runtime context ──────────────────────────────────────────────────────────\n// A single context object carries both the host element and mount callbacks,\n// eliminating two parallel globals that were always set together.\n\nexport type OnMountedCallback = () => CleanupFn | void;\nexport type OnFormResetCallback = () => void;\n\nexport type RuntimeContext = {\n element: HTMLElement;\n formResetCallbacks: OnFormResetCallback[];\n mountCallbacks: OnMountedCallback[];\n};\n\nlet currentContext: RuntimeContext | null = null;\n\n/** @internal Execute fn with a given runtime context active. */\nexport const runWithContext = <T>(ctx: RuntimeContext, fn: () => T): T => {\n const prev = currentContext;\n\n currentContext = ctx;\n\n try {\n return fn();\n } finally {\n currentContext = prev;\n }\n};\n\n/**\n * Returns the current runtime context, throwing a consistently-worded error\n * (naming the calling API) if called outside `setup()`. Every lifecycle/context\n * hook below routes through this — it's the single place that decides both\n * \"are we inside setup?\" and what the resulting error looks like, so the error\n * message is never worse for one hook than another.\n * @internal\n */\nexport const requireSetupContext = (api: string): RuntimeContext => {\n if (currentContext) return currentContext;\n\n throw new OreApiError(`${api}: ${ORE_ERRORS.lifecycleOutsideSetup}`);\n};\n\n/**\n * Returns the current component's host element.\n * Only valid synchronously during component `setup()` (or inside a composable\n * called from it) — throws otherwise.\n */\nexport const getHost = (): HTMLElement => requireSetupContext('getHost').element;\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentContext) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to run on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts to the DOM.\n * Multiple callbacks run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n requireSetupContext('onMounted').mountCallbacks.push(fn);\n};\n\n/**\n * Register work to run when the ancestor `<form>` is reset (native `formResetCallback`,\n * only fires for `formAssociated: true` components). Multiple callbacks run in\n * registration order, every time the form resets — unlike `onMounted`, this isn't a\n * one-shot hook.\n */\nexport const onFormReset = (fn: OnFormResetCallback): void => {\n requireSetupContext('onFormReset').formResetCallbacks.push(fn);\n};\n\n/**\n * Create a reactive effect scoped to the component lifecycle.\n * Automatically cleaned up on component disconnect.\n * Returns a stop function that disposes the effect immediately.\n *\n * Named `watchEffect` (not `watch`) to avoid shadowing `@vielzeug/ripple`'s\n * `watch(source, callback)`, which has different semantics (explicit source,\n * old/new value pair) — the two are commonly imported in the same file.\n */\nexport const watchEffect = (fn: EffectCallback): (() => void) => {\n const sub = _effect(fn);\n const stop = (): void => sub.dispose();\n\n tryRegisterCleanup(stop);\n\n return stop;\n};\n\n/**\n * Attach a scoped event listener that is automatically removed on component disconnect.\n * Silently no-ops when `target` is `null` or `undefined` (safe for reactive targets).\n */\nexport function onEvent<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function onEvent(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n requireSetupContext('onEvent');\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n if (!tryRegisterCleanup(cleanup)) cleanup();\n}\n\n/**\n * Watch a ref signal and run a callback when it resolves to a non-null element.\n * The callback's return value is used as a cleanup function.\n */\nexport const onElement = <T extends HTMLElement>(\n ref: Readable<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): (() => void) => {\n return watchEffect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"2JAoCA,IAAI,EAAwC,KAG/B,GAAqB,EAAqB,IAAmB,CACxE,IAAM,EAAO,EAEb,EAAiB,EAEjB,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAiB,CACnB,CACF,EAUa,EAAuB,GAAgC,CAClE,GAAI,EAAgB,OAAO,EAE3B,MAAM,IAAI,EAAY,GAAG,EAAI,IAAI,EAAW,uBAAuB,CACrE,EAOa,MAA6B,EAAoB,SAAS,CAAC,CAAC,QAE5D,EAAsB,GAC5B,GAEL,EAAW,CAAE,EAEN,IAJqB,GAWjB,EAAY,EAMZ,EAAa,GAAgC,CACxD,EAAoB,WAAW,CAAC,CAAC,eAAe,KAAK,CAAE,CACzD,EAQa,EAAe,GAAkC,CAC5D,EAAoB,aAAa,CAAC,CAAC,mBAAmB,KAAK,CAAE,CAC/D,EAWa,EAAe,GAAqC,CAC/D,IAAM,EAAM,EAAQ,CAAE,EAChB,MAAmB,EAAI,QAAQ,EAIrC,OAFA,EAAmB,CAAI,EAEhB,CACT,EAYA,SAAgB,EACd,EACA,EACA,EACA,EACM,CAGN,GAFA,EAAoB,SAAS,EAEzB,CAAC,EAAQ,OAEb,IAAM,EAAU,EAAe,EAAQ,EAAO,EAAU,CAAO,EAE1D,EAAmB,CAAO,GAAG,EAAQ,CAC5C,CAMA,IAAa,GACX,EACA,IAEO,MAAkB,CACvB,IAAM,EAAK,EAAI,MAEf,GAAI,EAAI,OAAO,EAAS,CAAE,CAC5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.cjs","names":[],"sources":["../../src/testing/dom.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree — `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this — it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered —\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n"],"mappings":"AAqBA,IAAa,GAAgB,EAAe,IAAgD,CAC1F,IAAM,EAAW,aAAgB,gBAAkB,EAAK,iBAAiB,CAAE,QAAS,EAAK,CAAC,EAAI,EAAK,SAEnG,IAAK,IAAM,KAAS,MAAM,KAAK,CAAQ,EAC/B,aAAiB,iBAAkB,EAAM,CAAoB,EAEnE,EAAa,EAAO,CAAK,CAE7B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM
|
|
3
|
+
* tree — `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned
|
|
4
|
+
* elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently
|
|
5
|
+
* replaced by what's actually assigned to it) for this — it's what "form owner" resolution,
|
|
6
|
+
* `:has()`, and plenty of other DOM algorithms are specified against.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Walks the flat tree starting at `root`, calling `visit` for every element encountered —
|
|
10
|
+
* expanding each `<slot>` via `assignedElements()` instead of descending into its (always
|
|
11
|
+
* empty, in jsdom) literal children.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // Find every form-associated element slotted (possibly through nested slots) under `form`,
|
|
16
|
+
* // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.
|
|
17
|
+
* const named: HTMLElement[] = [];
|
|
18
|
+
* walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const walkFlatTree: (root: Element, visit: (element: HTMLElement) => void) => void;
|
|
22
|
+
//# sourceMappingURL=dom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/testing/dom.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,KAAG,IAQnF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.js","names":[],"sources":["../../src/testing/dom.ts"],"sourcesContent":["/**\n * DOM traversal helpers for tests running under jsdom, which only implements the *light* DOM\n * tree — `Element.children`/`querySelectorAll()` never cross a `<slot>` into its assigned\n * elements. Real browsers use the *flat tree* (light DOM with each `<slot>` transparently\n * replaced by what's actually assigned to it) for this — it's what \"form owner\" resolution,\n * `:has()`, and plenty of other DOM algorithms are specified against.\n */\n\n/**\n * Walks the flat tree starting at `root`, calling `visit` for every element encountered —\n * expanding each `<slot>` via `assignedElements()` instead of descending into its (always\n * empty, in jsdom) literal children.\n *\n * @example\n * ```ts\n * // Find every form-associated element slotted (possibly through nested slots) under `form`,\n * // something `form.querySelectorAll('[name]')` can't do once a shadow boundary is involved.\n * const named: HTMLElement[] = [];\n * walkFlatTree(form, (el) => { if (el.hasAttribute('name')) named.push(el); });\n * ```\n */\nexport const walkFlatTree = (root: Element, visit: (element: HTMLElement) => void): void => {\n const children = root instanceof HTMLSlotElement ? root.assignedElements({ flatten: true }) : root.children;\n\n for (const child of Array.from(children)) {\n if (!(child instanceof HTMLSlotElement)) visit(child as HTMLElement);\n\n walkFlatTree(child, visit);\n }\n};\n"],"mappings":"AAqBA,IAAa,GAAgB,EAAe,IAAgD,CAC1F,IAAM,EAAW,aAAgB,gBAAkB,EAAK,iBAAiB,CAAE,QAAS,EAAK,CAAC,EAAI,EAAK,SAEnG,IAAK,IAAM,KAAS,MAAM,KAAK,CAAQ,EAC/B,aAAiB,iBAAkB,EAAM,CAAoB,EAEnE,EAAa,EAAO,CAAK,CAE7B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./dom.cjs");var t=()=>{if(typeof ElementInternals>`u`)return;let t=Symbol.for(`vielzeug.ore.testing.formInternalsPolyfillInstalled`),n=globalThis;if(n[t])return;n[t]=!0;let r=ElementInternals.prototype,i=new WeakMap,a=new WeakMap,o=new WeakMap,s=e=>{let t=i.get(e);return!t||!Object.values(t.flags).some(Boolean)};`setFormValue`in r||Object.defineProperty(r,"setFormValue",{configurable:!0,value:function(e){let t=o.get(this);t&&a.set(t,e)},writable:!0}),`setValidity`in r||Object.defineProperty(r,"setValidity",{configurable:!0,value:function(e={},t=``){if(Object.values(e).some(Boolean)&&!t)throw TypeError(`Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if one or more flags in the first argument are true.`);i.set(this,{flags:e,message:t})},writable:!0}),`checkValidity`in r||Object.defineProperty(r,"checkValidity",{configurable:!0,value:function(){return s(this)},writable:!0}),`reportValidity`in r||Object.defineProperty(r,"reportValidity",{configurable:!0,value:function(){return s(this)},writable:!0}),`validationMessage`in r||Object.defineProperty(r,"validationMessage",{configurable:!0,get(){return s(this)?``:i.get(this)?.message??``}}),`states`in r||Object.defineProperty(r,"states",{configurable:!0,get:function(){return this._states??=new Set,this._states}});let c=HTMLElement.prototype.attachInternals;HTMLElement.prototype.attachInternals=function(...e){let t=c.apply(this,e);return o.set(t,this),Object.defineProperties(this,{checkValidity:{configurable:!0,value:()=>t.checkValidity()},reportValidity:{configurable:!0,value:()=>t.reportValidity()},validationMessage:{configurable:!0,get:()=>t.validationMessage},validity:{configurable:!0,get:()=>t.validity}}),t};let l=(e,t,n)=>{if(n instanceof FormData){for(let[t,r]of n.entries())e.append(t,r);return}e.append(t,n)},u=globalThis.FormData;globalThis.FormData=class extends u{constructor(t,n){super(t,n),t instanceof HTMLFormElement&&e.walkFlatTree(t,e=>{let t=e.getAttribute(`name`),n=a.get(e);!t||n==null||e.hasAttribute(`disabled`)||l(this,t,n)})}};let d=HTMLFormElement.prototype.reset;HTMLFormElement.prototype.reset=function(...t){d.apply(this,t),e.walkFlatTree(this,e=>{e.formResetCallback?.()})}};exports.installFormInternalsPolyfill=t;
|
|
2
|
+
//# sourceMappingURL=form-internals-polyfill.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-internals-polyfill.cjs","names":[],"sources":["../../src/testing/form-internals-polyfill.ts"],"sourcesContent":["import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API — not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore/forms`),\n * so any package testing a form-associated component needs all of them, not just one — this is\n * called once, automatically, by `install()`.\n *\n * Deliberately lives here rather than in each consuming package's own `vitest.setup.ts`: the\n * gap is in `ore`'s own form-association feature, not in any one consumer, so the fix belongs\n * with the feature. `@vielzeug/refine`'s `<ore-form>` adds one more wrinkle on top — its fields\n * are slotted into a shadow `<form>` — which `walkFlatTree` already handles here, so refine\n * doesn't need a second, package-local copy of this polyfill at all.\n */\nexport const installFormInternalsPolyfill = (): void => {\n // Checked *before* consuming the flag below — an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return;\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.ore.testing.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return;\n\n flagHost[INSTALLED_FLAG] = true;\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n if (!('setFormValue' in proto)) {\n Object.defineProperty(proto, 'setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n }\n\n if (!('setValidity' in proto)) {\n Object.defineProperty(proto, 'setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this — see forms/field.ts — but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n }\n\n if (!('checkValidity' in proto)) {\n Object.defineProperty(proto, 'checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n }\n\n if (!('reportValidity' in proto)) {\n Object.defineProperty(proto, 'reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n }\n\n if (!('validationMessage' in proto)) {\n Object.defineProperty(proto, 'validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n }\n\n if (!('states' in proto)) {\n Object.defineProperty(proto, 'states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n }\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals) — not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value — real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets — patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jsdom implements none of the `ElementInternals` form-association API — not `setFormValue`,
|
|
3
|
+
* not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`
|
|
4
|
+
* mixin real browsers put on every `formAssociated: true` element, not even `FormData`
|
|
5
|
+
* collecting a form-associated element's set value, or `<form>.reset()` invoking
|
|
6
|
+
* `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore/forms`),
|
|
7
|
+
* so any package testing a form-associated component needs all of them, not just one — this is
|
|
8
|
+
* called once, automatically, by `install()`.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately lives here rather than in each consuming package's own `vitest.setup.ts`: the
|
|
11
|
+
* gap is in `ore`'s own form-association feature, not in any one consumer, so the fix belongs
|
|
12
|
+
* with the feature. `@vielzeug/refine`'s `<ore-form>` adds one more wrinkle on top — its fields
|
|
13
|
+
* are slotted into a shadow `<form>` — which `walkFlatTree` already handles here, so refine
|
|
14
|
+
* doesn't need a second, package-local copy of this polyfill at all.
|
|
15
|
+
*/
|
|
16
|
+
export declare const installFormInternalsPolyfill: () => void;
|
|
17
|
+
//# sourceMappingURL=form-internals-polyfill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-internals-polyfill.d.ts","sourceRoot":"","sources":["../../src/testing/form-internals-polyfill.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,4BAA4B,QAAO,IAqK/C,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{walkFlatTree as e}from"./dom.js";var t=()=>{if(typeof ElementInternals>`u`)return;let t=Symbol.for(`vielzeug.ore.testing.formInternalsPolyfillInstalled`),n=globalThis;if(n[t])return;n[t]=!0;let r=ElementInternals.prototype,i=new WeakMap,a=new WeakMap,o=new WeakMap,s=e=>{let t=i.get(e);return!t||!Object.values(t.flags).some(Boolean)};`setFormValue`in r||Object.defineProperty(r,"setFormValue",{configurable:!0,value:function(e){let t=o.get(this);t&&a.set(t,e)},writable:!0}),`setValidity`in r||Object.defineProperty(r,"setValidity",{configurable:!0,value:function(e={},t=``){if(Object.values(e).some(Boolean)&&!t)throw TypeError(`Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if one or more flags in the first argument are true.`);i.set(this,{flags:e,message:t})},writable:!0}),`checkValidity`in r||Object.defineProperty(r,"checkValidity",{configurable:!0,value:function(){return s(this)},writable:!0}),`reportValidity`in r||Object.defineProperty(r,"reportValidity",{configurable:!0,value:function(){return s(this)},writable:!0}),`validationMessage`in r||Object.defineProperty(r,"validationMessage",{configurable:!0,get(){return s(this)?``:i.get(this)?.message??``}}),`states`in r||Object.defineProperty(r,"states",{configurable:!0,get:function(){return this._states??=new Set,this._states}});let c=HTMLElement.prototype.attachInternals;HTMLElement.prototype.attachInternals=function(...e){let t=c.apply(this,e);return o.set(t,this),Object.defineProperties(this,{checkValidity:{configurable:!0,value:()=>t.checkValidity()},reportValidity:{configurable:!0,value:()=>t.reportValidity()},validationMessage:{configurable:!0,get:()=>t.validationMessage},validity:{configurable:!0,get:()=>t.validity}}),t};let l=(e,t,n)=>{if(n instanceof FormData){for(let[t,r]of n.entries())e.append(t,r);return}e.append(t,n)},u=globalThis.FormData;globalThis.FormData=class extends u{constructor(t,n){super(t,n),t instanceof HTMLFormElement&&e(t,e=>{let t=e.getAttribute(`name`),n=a.get(e);!t||n==null||e.hasAttribute(`disabled`)||l(this,t,n)})}};let d=HTMLFormElement.prototype.reset;HTMLFormElement.prototype.reset=function(...t){d.apply(this,t),e(this,e=>{e.formResetCallback?.()})}};export{t as installFormInternalsPolyfill};
|
|
2
|
+
//# sourceMappingURL=form-internals-polyfill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-internals-polyfill.js","names":[],"sources":["../../src/testing/form-internals-polyfill.ts"],"sourcesContent":["import { walkFlatTree } from './dom';\n\n/**\n * jsdom implements none of the `ElementInternals` form-association API — not `setFormValue`,\n * not `setValidity`, not the `checkValidity`/`reportValidity`/`validity`/`validationMessage`\n * mixin real browsers put on every `formAssociated: true` element, not even `FormData`\n * collecting a form-associated element's set value, or `<form>.reset()` invoking\n * `formResetCallback()`. Every one of those gaps is exercised by `useField()` (`@vielzeug/ore/forms`),\n * so any package testing a form-associated component needs all of them, not just one — this is\n * called once, automatically, by `install()`.\n *\n * Deliberately lives here rather than in each consuming package's own `vitest.setup.ts`: the\n * gap is in `ore`'s own form-association feature, not in any one consumer, so the fix belongs\n * with the feature. `@vielzeug/refine`'s `<ore-form>` adds one more wrinkle on top — its fields\n * are slotted into a shadow `<form>` — which `walkFlatTree` already handles here, so refine\n * doesn't need a second, package-local copy of this polyfill at all.\n */\nexport const installFormInternalsPolyfill = (): void => {\n // Checked *before* consuming the flag below — an environment without `ElementInternals`\n // installs nothing and should stay eligible to install for real later (e.g. a differently\n // configured environment in the same process), not get marked \"already installed\" for having\n // done nothing.\n if (typeof ElementInternals === 'undefined') return;\n\n const INSTALLED_FLAG = Symbol.for('vielzeug.ore.testing.formInternalsPolyfillInstalled');\n const flagHost = globalThis as Record<symbol, boolean | undefined>;\n\n if (flagHost[INSTALLED_FLAG]) return;\n\n flagHost[INSTALLED_FLAG] = true;\n\n const proto = ElementInternals.prototype as unknown as Record<string, unknown>;\n const validityState = new WeakMap<ElementInternals, { flags: ValidityStateFlags; message: string }>();\n const formValueByHost = new WeakMap<HTMLElement, File | FormData | string | null>();\n const hostByInternals = new WeakMap<ElementInternals, HTMLElement>();\n\n const isValid = (internals: ElementInternals): boolean => {\n const state = validityState.get(internals);\n\n return !state || !Object.values(state.flags).some(Boolean);\n };\n\n if (!('setFormValue' in proto)) {\n Object.defineProperty(proto, 'setFormValue', {\n configurable: true,\n value: function (this: ElementInternals, value: File | FormData | string | null) {\n const host = hostByInternals.get(this);\n\n if (host) formValueByHost.set(host, value);\n },\n writable: true,\n });\n }\n\n if (!('setValidity' in proto)) {\n Object.defineProperty(proto, 'setValidity', {\n configurable: true,\n // Matches the real platform contract: throws if any flag is true and message is empty.\n // `useField()` itself already guards against triggering this — see forms/field.ts — but\n // the polyfill enforcing it too means a test would still catch a *different* caller doing\n // the same thing wrong, instead of that bug only surfacing in a real browser.\n value: function (this: ElementInternals, flags: ValidityStateFlags = {}, message = '') {\n if (Object.values(flags).some(Boolean) && !message) {\n throw new TypeError(\n \"Failed to execute 'setValidity' on 'ElementInternals': The second argument must not be empty if \" +\n 'one or more flags in the first argument are true.',\n );\n }\n\n validityState.set(this, { flags, message });\n },\n writable: true,\n });\n }\n\n if (!('checkValidity' in proto)) {\n Object.defineProperty(proto, 'checkValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n }\n\n if (!('reportValidity' in proto)) {\n Object.defineProperty(proto, 'reportValidity', {\n configurable: true,\n value: function (this: ElementInternals) {\n return isValid(this);\n },\n writable: true,\n });\n }\n\n if (!('validationMessage' in proto)) {\n Object.defineProperty(proto, 'validationMessage', {\n configurable: true,\n get(this: ElementInternals) {\n return isValid(this) ? '' : (validityState.get(this)?.message ?? '');\n },\n });\n }\n\n if (!('states' in proto)) {\n Object.defineProperty(proto, 'states', {\n configurable: true,\n get: function (this: ElementInternals & { _states?: Set<string> }) {\n this._states ??= new Set();\n\n return this._states;\n },\n });\n }\n\n // Real browsers mix `checkValidity`/`reportValidity`/`validity`/`validationMessage` onto any\n // `formAssociated: true` custom element itself (delegating to its internals) — not just onto\n // `ElementInternals`. jsdom does neither; mirror it here so a component's own\n // `checkValidity()`/`reportValidity()`, and a test asserting against the element directly,\n // behave the same as they would in a real browser.\n const originalAttachInternals = HTMLElement.prototype.attachInternals;\n\n HTMLElement.prototype.attachInternals = function (this: HTMLElement, ...args: []): ElementInternals {\n const internals = originalAttachInternals.apply(this, args);\n\n hostByInternals.set(internals, this);\n\n Object.defineProperties(this, {\n checkValidity: { configurable: true, value: () => internals.checkValidity() },\n reportValidity: { configurable: true, value: () => internals.reportValidity() },\n validationMessage: { configurable: true, get: () => internals.validationMessage },\n validity: { configurable: true, get: () => internals.validity },\n });\n\n return internals;\n };\n\n const appendFormValue = (formData: FormData, name: string, value: File | FormData | string): void => {\n if (value instanceof FormData) {\n for (const [entryName, entryValue] of value.entries()) formData.append(entryName, entryValue);\n\n return;\n }\n\n formData.append(name, value);\n };\n\n // jsdom's `FormData` constructor never collects a form-associated custom element's set form\n // value — real browsers walk the flat tree for every form-associated element with a `name`.\n const NativeFormData = globalThis.FormData;\n\n globalThis.FormData = class FormDataWithFormAssociatedElements extends NativeFormData {\n constructor(form?: HTMLFormElement, submitter?: HTMLElement | null) {\n super(form as HTMLFormElement | undefined, submitter as HTMLElement | null | undefined);\n\n if (!(form instanceof HTMLFormElement)) return;\n\n walkFlatTree(form, (element) => {\n const name = element.getAttribute('name');\n const value = formValueByHost.get(element);\n\n if (!name || value == null || element.hasAttribute('disabled')) return;\n\n appendFormValue(this, name, value);\n });\n }\n };\n\n // jsdom never invokes the native `formResetCallback` lifecycle method on form-associated\n // custom elements when their form resets — patch `reset()` to do it (via the same flat-tree\n // walk, since a reset field can be nested behind a shadow boundary too), so `onFormReset()`\n // (see `@vielzeug/ore`'s runtime.ts) is testable against a real `<form>.reset()` call instead\n // of only by calling `element.formResetCallback()` directly.\n const originalReset = HTMLFormElement.prototype.reset;\n\n HTMLFormElement.prototype.reset = function (this: HTMLFormElement, ...args: []) {\n originalReset.apply(this, args);\n\n walkFlatTree(this, (element) => {\n (element as Partial<{ formResetCallback: () => void }>).formResetCallback?.();\n });\n };\n};\n"],"mappings":"wCAiBA,IAAa,MAA2C,CAKtD,GAAI,OAAO,iBAAqB,IAAa,OAE7C,IAAM,EAAiB,OAAO,IAAI,qDAAqD,EACjF,EAAW,WAEjB,GAAI,EAAS,GAAiB,OAE9B,EAAS,GAAkB,GAE3B,IAAM,EAAQ,iBAAiB,UACzB,EAAgB,IAAI,QACpB,EAAkB,IAAI,QACtB,EAAkB,IAAI,QAEtB,EAAW,GAAyC,CACxD,IAAM,EAAQ,EAAc,IAAI,CAAS,EAEzC,MAAO,CAAC,GAAS,CAAC,OAAO,OAAO,EAAM,KAAK,CAAC,CAAC,KAAK,OAAO,CAC3D,EAEM,iBAAkB,GACtB,OAAO,eAAe,EAAO,eAAgB,CAC3C,aAAc,GACd,MAAO,SAAkC,EAAwC,CAC/E,IAAM,EAAO,EAAgB,IAAI,IAAI,EAEjC,GAAM,EAAgB,IAAI,EAAM,CAAK,CAC3C,EACA,SAAU,EACZ,CAAC,EAGG,gBAAiB,GACrB,OAAO,eAAe,EAAO,cAAe,CAC1C,aAAc,GAKd,MAAO,SAAkC,EAA4B,CAAC,EAAG,EAAU,GAAI,CACrF,GAAI,OAAO,OAAO,CAAK,CAAC,CAAC,KAAK,OAAO,GAAK,CAAC,EACzC,MAAU,UACR,mJAEF,EAGF,EAAc,IAAI,KAAM,CAAE,QAAO,SAAQ,CAAC,CAC5C,EACA,SAAU,EACZ,CAAC,EAGG,kBAAmB,GACvB,OAAO,eAAe,EAAO,gBAAiB,CAC5C,aAAc,GACd,MAAO,UAAkC,CACvC,OAAO,EAAQ,IAAI,CACrB,EACA,SAAU,EACZ,CAAC,EAGG,mBAAoB,GACxB,OAAO,eAAe,EAAO,iBAAkB,CAC7C,aAAc,GACd,MAAO,UAAkC,CACvC,OAAO,EAAQ,IAAI,CACrB,EACA,SAAU,EACZ,CAAC,EAGG,sBAAuB,GAC3B,OAAO,eAAe,EAAO,oBAAqB,CAChD,aAAc,GACd,KAA4B,CAC1B,OAAO,EAAQ,IAAI,EAAI,GAAM,EAAc,IAAI,IAAI,CAAC,EAAE,SAAW,EACnE,CACF,CAAC,EAGG,WAAY,GAChB,OAAO,eAAe,EAAO,SAAU,CACrC,aAAc,GACd,IAAK,UAA8D,CAGjE,MAFA,MAAK,UAAY,IAAI,IAEd,KAAK,OACd,CACF,CAAC,EAQH,IAAM,EAA0B,YAAY,UAAU,gBAEtD,YAAY,UAAU,gBAAkB,SAA6B,GAAG,EAA4B,CAClG,IAAM,EAAY,EAAwB,MAAM,KAAM,CAAI,EAW1D,OATA,EAAgB,IAAI,EAAW,IAAI,EAEnC,OAAO,iBAAiB,KAAM,CAC5B,cAAe,CAAE,aAAc,GAAM,UAAa,EAAU,cAAc,CAAE,EAC5E,eAAgB,CAAE,aAAc,GAAM,UAAa,EAAU,eAAe,CAAE,EAC9E,kBAAmB,CAAE,aAAc,GAAM,QAAW,EAAU,iBAAkB,EAChF,SAAU,CAAE,aAAc,GAAM,QAAW,EAAU,QAAS,CAChE,CAAC,EAEM,CACT,EAEA,IAAM,GAAmB,EAAoB,EAAc,IAA0C,CACnG,GAAI,aAAiB,SAAU,CAC7B,IAAK,GAAM,CAAC,EAAW,KAAe,EAAM,QAAQ,EAAG,EAAS,OAAO,EAAW,CAAU,EAE5F,MACF,CAEA,EAAS,OAAO,EAAM,CAAK,CAC7B,EAIM,EAAiB,WAAW,SAElC,WAAW,SAAW,cAAiD,CAAe,CACpF,YAAY,EAAwB,EAAgC,CAClE,MAAM,EAAqC,CAA2C,EAEhF,aAAgB,iBAEtB,EAAa,EAAO,GAAY,CAC9B,IAAM,EAAO,EAAQ,aAAa,MAAM,EAClC,EAAQ,EAAgB,IAAI,CAAO,EAErC,CAAC,GAAQ,GAAS,MAAQ,EAAQ,aAAa,UAAU,GAE7D,EAAgB,KAAM,EAAM,CAAK,CACnC,CAAC,CACH,CACF,EAOA,IAAM,EAAgB,gBAAgB,UAAU,MAEhD,gBAAgB,UAAU,MAAQ,SAAiC,GAAG,EAAU,CAC9E,EAAc,MAAM,KAAM,CAAI,EAE9B,EAAa,KAAO,GAAY,CAC9B,EAAwD,oBAAoB,CAC9E,CAAC,CACH,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./flush.cjs"),t=require("../runtime.cjs"),n=require("../props.cjs");let r=require("@vielzeug/ripple");async function i(i,a){let o=typeof i!=`function`,s=o?i:void 0,c=o?a:i,l=(0,r.scope)(),u=document.createElement(`div`);document.body.appendChild(u);let d=[],f={element:u,mountCallbacks:d},p;try{l.run(()=>{t.runWithContext(f,()=>{let e=s?n.createProps(u,s):{};p=c(e)})});for(let e of d)try{l.run(()=>{t.runWithContext(f,()=>{let t=e();typeof t==`function`&&(0,r.onCleanup)(t)})})}catch{}}catch(e){throw l.dispose(),u.remove(),e}await e.flush();let m=!1;function h(){m||(m=!0,l.dispose(),u.remove())}return{dispose:h,get disposed(){return m},async flush(){await e.flush()},result:p,[Symbol.dispose](){h()}}}exports.renderHook=i;
|
|
1
|
+
const e=require("./flush.cjs"),t=require("../runtime.cjs"),n=require("../props.cjs");let r=require("@vielzeug/ripple");async function i(i,a){let o=typeof i!=`function`,s=o?i:void 0,c=o?a:i,l=(0,r.scope)(),u=document.createElement(`div`);document.body.appendChild(u);let d=[],f={element:u,formResetCallbacks:[],mountCallbacks:d},p;try{l.run(()=>{t.runWithContext(f,()=>{let e=s?n.createProps(u,s):{};p=c(e)})});for(let e of d)try{l.run(()=>{t.runWithContext(f,()=>{let t=e();typeof t==`function`&&(0,r.onCleanup)(t)})})}catch{}}catch(e){throw l.dispose(),u.remove(),e}await e.flush();let m=!1;function h(){m||(m=!0,l.dispose(),u.remove())}return{dispose:h,get disposed(){return m},async flush(){await e.flush()},result:p,[Symbol.dispose](){h()}}}exports.renderHook=i;
|
|
2
2
|
//# sourceMappingURL=render-hook.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-hook.cjs","names":[],"sources":["../../src/testing/render-hook.ts"],"sourcesContent":["/**\n * renderHook — test composable hooks (lifecycle, reactive state, etc.) in isolation\n * without rendering a full component template.\n */\n\nimport { onCleanup as _onCleanup, scope as _scope } from '@vielzeug/ripple';\n\nimport { createProps, type InferProps, type PropInputDefs } from '../props';\nimport { runWithContext } from '../runtime';\nimport { flush } from './flush';\n\nexport interface HookFixture<T> {\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n /** Teardown the hook (runs cleanups). Idempotent. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** Flush pending reactive updates */\n flush(): Promise<void>;\n /** The value returned by the setup function */\n result: T;\n}\n\n/**\n * Run a setup function in a component-like context and return the result.\n * `onMounted`/`onCleanup`/`bind`/... work exactly as they would inside a real\n * `setup()`, since they resolve the same implicit current-component context.\n *\n * @example No props\n * ```ts\n * const { result, flush } = await renderHook(() => {\n * const count = signal(0);\n * onMounted(() => { count.value = 1; });\n * return count;\n * });\n * expect(result.value).toBe(1);\n * ```\n *\n * @example With props\n * ```ts\n * const { result } = await renderHook(\n * { label: prop.string('hello') },\n * (props) => props.label,\n * );\n * expect(result.value).toBe('hello');\n * ```\n */\nexport async function renderHook<T>(setup: (_props: Record<never, never>) => T): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n propDefs: D,\n setup: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n setupOrDefs: ((_props: Record<never, never>) => T) | D,\n maybeSetup?: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>> {\n const hasPropDefs = typeof setupOrDefs !== 'function';\n const propDefs = hasPropDefs ? (setupOrDefs as D) : undefined;\n const setup = hasPropDefs ? maybeSetup! : (setupOrDefs as (_props: Record<never, never>) => T);\n\n const hostScope = _scope();\n // Minimal host element so getHost() works inside setup\n const hostEl = document.createElement('div');\n\n document.body.appendChild(hostEl);\n\n const mountCallbacks: Array<() => void | (() => void)> = [];\n const ctx = { element: hostEl, mountCallbacks };\n\n let result!: T;\n\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const props = propDefs ? createProps(hostEl, propDefs as PropInputDefs) : ({} as Record<never, never>);\n\n result = setup(props as InferProps<D>);\n });\n });\n\n // Run mount callbacks (simulates connectedCallback → queueMicrotask)\n for (const cb of mountCallbacks) {\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const cleanup = cb();\n\n if (typeof cleanup === 'function') _onCleanup(cleanup);\n });\n });\n } catch {\n /* test will surface the error via result */\n }\n }\n } catch (err) {\n hostScope.dispose();\n hostEl.remove();\n throw err;\n }\n\n await flush();\n\n let isDisposed = false;\n\n function dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n hostScope.dispose();\n hostEl.remove();\n }\n\n return {\n dispose,\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n async flush() {\n await flush();\n },\n\n result,\n\n [Symbol.dispose]() {\n dispose();\n },\n };\n}\n"],"mappings":"uHAqDA,eAAsB,EACpB,EACA,EACyB,CACzB,IAAM,EAAc,OAAO,GAAgB,WACrC,EAAW,EAAe,EAAoB,IAAA,GAC9C,EAAQ,EAAc,EAAe,EAErC,GAAA,EAAA,EAAA,MAAA,CAAmB,EAEnB,EAAS,SAAS,cAAc,KAAK,EAE3C,SAAS,KAAK,YAAY,CAAM,EAEhC,IAAM,EAAmD,CAAC,
|
|
1
|
+
{"version":3,"file":"render-hook.cjs","names":[],"sources":["../../src/testing/render-hook.ts"],"sourcesContent":["/**\n * renderHook — test composable hooks (lifecycle, reactive state, etc.) in isolation\n * without rendering a full component template.\n */\n\nimport { onCleanup as _onCleanup, scope as _scope } from '@vielzeug/ripple';\n\nimport { createProps, type InferProps, type PropInputDefs } from '../props';\nimport { runWithContext } from '../runtime';\nimport { flush } from './flush';\n\nexport interface HookFixture<T> {\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n /** Teardown the hook (runs cleanups). Idempotent. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** Flush pending reactive updates */\n flush(): Promise<void>;\n /** The value returned by the setup function */\n result: T;\n}\n\n/**\n * Run a setup function in a component-like context and return the result.\n * `onMounted`/`onCleanup`/`bind`/... work exactly as they would inside a real\n * `setup()`, since they resolve the same implicit current-component context.\n *\n * @example No props\n * ```ts\n * const { result, flush } = await renderHook(() => {\n * const count = signal(0);\n * onMounted(() => { count.value = 1; });\n * return count;\n * });\n * expect(result.value).toBe(1);\n * ```\n *\n * @example With props\n * ```ts\n * const { result } = await renderHook(\n * { label: prop.string('hello') },\n * (props) => props.label,\n * );\n * expect(result.value).toBe('hello');\n * ```\n */\nexport async function renderHook<T>(setup: (_props: Record<never, never>) => T): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n propDefs: D,\n setup: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n setupOrDefs: ((_props: Record<never, never>) => T) | D,\n maybeSetup?: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>> {\n const hasPropDefs = typeof setupOrDefs !== 'function';\n const propDefs = hasPropDefs ? (setupOrDefs as D) : undefined;\n const setup = hasPropDefs ? maybeSetup! : (setupOrDefs as (_props: Record<never, never>) => T);\n\n const hostScope = _scope();\n // Minimal host element so getHost() works inside setup\n const hostEl = document.createElement('div');\n\n document.body.appendChild(hostEl);\n\n const mountCallbacks: Array<() => void | (() => void)> = [];\n const formResetCallbacks: Array<() => void> = [];\n const ctx = { element: hostEl, formResetCallbacks, mountCallbacks };\n\n let result!: T;\n\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const props = propDefs ? createProps(hostEl, propDefs as PropInputDefs) : ({} as Record<never, never>);\n\n result = setup(props as InferProps<D>);\n });\n });\n\n // Run mount callbacks (simulates connectedCallback → queueMicrotask)\n for (const cb of mountCallbacks) {\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const cleanup = cb();\n\n if (typeof cleanup === 'function') _onCleanup(cleanup);\n });\n });\n } catch {\n /* test will surface the error via result */\n }\n }\n } catch (err) {\n hostScope.dispose();\n hostEl.remove();\n throw err;\n }\n\n await flush();\n\n let isDisposed = false;\n\n function dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n hostScope.dispose();\n hostEl.remove();\n }\n\n return {\n dispose,\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n async flush() {\n await flush();\n },\n\n result,\n\n [Symbol.dispose]() {\n dispose();\n },\n };\n}\n"],"mappings":"uHAqDA,eAAsB,EACpB,EACA,EACyB,CACzB,IAAM,EAAc,OAAO,GAAgB,WACrC,EAAW,EAAe,EAAoB,IAAA,GAC9C,EAAQ,EAAc,EAAe,EAErC,GAAA,EAAA,EAAA,MAAA,CAAmB,EAEnB,EAAS,SAAS,cAAc,KAAK,EAE3C,SAAS,KAAK,YAAY,CAAM,EAEhC,IAAM,EAAmD,CAAC,EAEpD,EAAM,CAAE,QAAS,EAAQ,mBAAA,CAAA,EAAoB,gBAAe,EAE9D,EAEJ,GAAI,CACF,EAAU,QAAU,CAClB,EAAA,eAAe,MAAW,CACxB,IAAM,EAAQ,EAAW,EAAA,YAAY,EAAQ,CAAyB,EAAK,CAAC,EAE5E,EAAS,EAAM,CAAsB,CACvC,CAAC,CACH,CAAC,EAGD,IAAK,IAAM,KAAM,EACf,GAAI,CACF,EAAU,QAAU,CAClB,EAAA,eAAe,MAAW,CACxB,IAAM,EAAU,EAAG,EAEf,OAAO,GAAY,aAAY,EAAA,EAAA,UAAA,CAAW,CAAO,CACvD,CAAC,CACH,CAAC,CACH,MAAQ,CAER,CAEJ,OAAS,EAAK,CAGZ,MAFA,EAAU,QAAQ,EAClB,EAAO,OAAO,EACR,CACR,CAEA,MAAM,EAAA,MAAM,EAEZ,IAAI,EAAa,GAEjB,SAAS,GAAU,CACb,IAEJ,EAAa,GACb,EAAU,QAAQ,EAClB,EAAO,OAAO,EAChB,CAEA,MAAO,CACL,UAEA,IAAI,UAAoB,CACtB,OAAO,CACT,EAEA,MAAM,OAAQ,CACZ,MAAM,EAAA,MAAM,CACd,EAEA,SAEA,CAAC,OAAO,UAAW,CACjB,EAAQ,CACV,CACF,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{flush as e}from"./flush.js";import{runWithContext as t}from"../runtime.js";import{createProps as n}from"../props.js";import{onCleanup as r,scope as i}from"@vielzeug/ripple";async function a(a,o){let s=typeof a!=`function`,c=s?a:void 0,l=s?o:a,u=i(),d=document.createElement(`div`);document.body.appendChild(d);let f=[],p={element:d,mountCallbacks:f},m;try{u.run(()=>{t(p,()=>{let e=c?n(d,c):{};m=l(e)})});for(let e of f)try{u.run(()=>{t(p,()=>{let t=e();typeof t==`function`&&r(t)})})}catch{}}catch(e){throw u.dispose(),d.remove(),e}await e();let h=!1;function g(){h||(h=!0,u.dispose(),d.remove())}return{dispose:g,get disposed(){return h},async flush(){await e()},result:m,[Symbol.dispose](){g()}}}export{a as renderHook};
|
|
1
|
+
import{flush as e}from"./flush.js";import{runWithContext as t}from"../runtime.js";import{createProps as n}from"../props.js";import{onCleanup as r,scope as i}from"@vielzeug/ripple";async function a(a,o){let s=typeof a!=`function`,c=s?a:void 0,l=s?o:a,u=i(),d=document.createElement(`div`);document.body.appendChild(d);let f=[],p={element:d,formResetCallbacks:[],mountCallbacks:f},m;try{u.run(()=>{t(p,()=>{let e=c?n(d,c):{};m=l(e)})});for(let e of f)try{u.run(()=>{t(p,()=>{let t=e();typeof t==`function`&&r(t)})})}catch{}}catch(e){throw u.dispose(),d.remove(),e}await e();let h=!1;function g(){h||(h=!0,u.dispose(),d.remove())}return{dispose:g,get disposed(){return h},async flush(){await e()},result:m,[Symbol.dispose](){g()}}}export{a as renderHook};
|
|
2
2
|
//# sourceMappingURL=render-hook.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-hook.js","names":[],"sources":["../../src/testing/render-hook.ts"],"sourcesContent":["/**\n * renderHook — test composable hooks (lifecycle, reactive state, etc.) in isolation\n * without rendering a full component template.\n */\n\nimport { onCleanup as _onCleanup, scope as _scope } from '@vielzeug/ripple';\n\nimport { createProps, type InferProps, type PropInputDefs } from '../props';\nimport { runWithContext } from '../runtime';\nimport { flush } from './flush';\n\nexport interface HookFixture<T> {\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n /** Teardown the hook (runs cleanups). Idempotent. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** Flush pending reactive updates */\n flush(): Promise<void>;\n /** The value returned by the setup function */\n result: T;\n}\n\n/**\n * Run a setup function in a component-like context and return the result.\n * `onMounted`/`onCleanup`/`bind`/... work exactly as they would inside a real\n * `setup()`, since they resolve the same implicit current-component context.\n *\n * @example No props\n * ```ts\n * const { result, flush } = await renderHook(() => {\n * const count = signal(0);\n * onMounted(() => { count.value = 1; });\n * return count;\n * });\n * expect(result.value).toBe(1);\n * ```\n *\n * @example With props\n * ```ts\n * const { result } = await renderHook(\n * { label: prop.string('hello') },\n * (props) => props.label,\n * );\n * expect(result.value).toBe('hello');\n * ```\n */\nexport async function renderHook<T>(setup: (_props: Record<never, never>) => T): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n propDefs: D,\n setup: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n setupOrDefs: ((_props: Record<never, never>) => T) | D,\n maybeSetup?: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>> {\n const hasPropDefs = typeof setupOrDefs !== 'function';\n const propDefs = hasPropDefs ? (setupOrDefs as D) : undefined;\n const setup = hasPropDefs ? maybeSetup! : (setupOrDefs as (_props: Record<never, never>) => T);\n\n const hostScope = _scope();\n // Minimal host element so getHost() works inside setup\n const hostEl = document.createElement('div');\n\n document.body.appendChild(hostEl);\n\n const mountCallbacks: Array<() => void | (() => void)> = [];\n const ctx = { element: hostEl, mountCallbacks };\n\n let result!: T;\n\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const props = propDefs ? createProps(hostEl, propDefs as PropInputDefs) : ({} as Record<never, never>);\n\n result = setup(props as InferProps<D>);\n });\n });\n\n // Run mount callbacks (simulates connectedCallback → queueMicrotask)\n for (const cb of mountCallbacks) {\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const cleanup = cb();\n\n if (typeof cleanup === 'function') _onCleanup(cleanup);\n });\n });\n } catch {\n /* test will surface the error via result */\n }\n }\n } catch (err) {\n hostScope.dispose();\n hostEl.remove();\n throw err;\n }\n\n await flush();\n\n let isDisposed = false;\n\n function dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n hostScope.dispose();\n hostEl.remove();\n }\n\n return {\n dispose,\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n async flush() {\n await flush();\n },\n\n result,\n\n [Symbol.dispose]() {\n dispose();\n },\n };\n}\n"],"mappings":"oLAqDA,eAAsB,EACpB,EACA,EACyB,CACzB,IAAM,EAAc,OAAO,GAAgB,WACrC,EAAW,EAAe,EAAoB,IAAA,GAC9C,EAAQ,EAAc,EAAe,EAErC,EAAY,EAAO,EAEnB,EAAS,SAAS,cAAc,KAAK,EAE3C,SAAS,KAAK,YAAY,CAAM,EAEhC,IAAM,EAAmD,CAAC,
|
|
1
|
+
{"version":3,"file":"render-hook.js","names":[],"sources":["../../src/testing/render-hook.ts"],"sourcesContent":["/**\n * renderHook — test composable hooks (lifecycle, reactive state, etc.) in isolation\n * without rendering a full component template.\n */\n\nimport { onCleanup as _onCleanup, scope as _scope } from '@vielzeug/ripple';\n\nimport { createProps, type InferProps, type PropInputDefs } from '../props';\nimport { runWithContext } from '../runtime';\nimport { flush } from './flush';\n\nexport interface HookFixture<T> {\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n /** Teardown the hook (runs cleanups). Idempotent. */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /** Flush pending reactive updates */\n flush(): Promise<void>;\n /** The value returned by the setup function */\n result: T;\n}\n\n/**\n * Run a setup function in a component-like context and return the result.\n * `onMounted`/`onCleanup`/`bind`/... work exactly as they would inside a real\n * `setup()`, since they resolve the same implicit current-component context.\n *\n * @example No props\n * ```ts\n * const { result, flush } = await renderHook(() => {\n * const count = signal(0);\n * onMounted(() => { count.value = 1; });\n * return count;\n * });\n * expect(result.value).toBe(1);\n * ```\n *\n * @example With props\n * ```ts\n * const { result } = await renderHook(\n * { label: prop.string('hello') },\n * (props) => props.label,\n * );\n * expect(result.value).toBe('hello');\n * ```\n */\nexport async function renderHook<T>(setup: (_props: Record<never, never>) => T): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n propDefs: D,\n setup: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>>;\nexport async function renderHook<D extends PropInputDefs, T>(\n setupOrDefs: ((_props: Record<never, never>) => T) | D,\n maybeSetup?: (props: InferProps<D>) => T,\n): Promise<HookFixture<T>> {\n const hasPropDefs = typeof setupOrDefs !== 'function';\n const propDefs = hasPropDefs ? (setupOrDefs as D) : undefined;\n const setup = hasPropDefs ? maybeSetup! : (setupOrDefs as (_props: Record<never, never>) => T);\n\n const hostScope = _scope();\n // Minimal host element so getHost() works inside setup\n const hostEl = document.createElement('div');\n\n document.body.appendChild(hostEl);\n\n const mountCallbacks: Array<() => void | (() => void)> = [];\n const formResetCallbacks: Array<() => void> = [];\n const ctx = { element: hostEl, formResetCallbacks, mountCallbacks };\n\n let result!: T;\n\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const props = propDefs ? createProps(hostEl, propDefs as PropInputDefs) : ({} as Record<never, never>);\n\n result = setup(props as InferProps<D>);\n });\n });\n\n // Run mount callbacks (simulates connectedCallback → queueMicrotask)\n for (const cb of mountCallbacks) {\n try {\n hostScope.run(() => {\n runWithContext(ctx, () => {\n const cleanup = cb();\n\n if (typeof cleanup === 'function') _onCleanup(cleanup);\n });\n });\n } catch {\n /* test will surface the error via result */\n }\n }\n } catch (err) {\n hostScope.dispose();\n hostEl.remove();\n throw err;\n }\n\n await flush();\n\n let isDisposed = false;\n\n function dispose() {\n if (isDisposed) return;\n\n isDisposed = true;\n hostScope.dispose();\n hostEl.remove();\n }\n\n return {\n dispose,\n\n get disposed(): boolean {\n return isDisposed;\n },\n\n async flush() {\n await flush();\n },\n\n result,\n\n [Symbol.dispose]() {\n dispose();\n },\n };\n}\n"],"mappings":"oLAqDA,eAAsB,EACpB,EACA,EACyB,CACzB,IAAM,EAAc,OAAO,GAAgB,WACrC,EAAW,EAAe,EAAoB,IAAA,GAC9C,EAAQ,EAAc,EAAe,EAErC,EAAY,EAAO,EAEnB,EAAS,SAAS,cAAc,KAAK,EAE3C,SAAS,KAAK,YAAY,CAAM,EAEhC,IAAM,EAAmD,CAAC,EAEpD,EAAM,CAAE,QAAS,EAAQ,mBAAA,CAAA,EAAoB,gBAAe,EAE9D,EAEJ,GAAI,CACF,EAAU,QAAU,CAClB,EAAe,MAAW,CACxB,IAAM,EAAQ,EAAW,EAAY,EAAQ,CAAyB,EAAK,CAAC,EAE5E,EAAS,EAAM,CAAsB,CACvC,CAAC,CACH,CAAC,EAGD,IAAK,IAAM,KAAM,EACf,GAAI,CACF,EAAU,QAAU,CAClB,EAAe,MAAW,CACxB,IAAM,EAAU,EAAG,EAEf,OAAO,GAAY,YAAY,EAAW,CAAO,CACvD,CAAC,CACH,CAAC,CACH,MAAQ,CAER,CAEJ,OAAS,EAAK,CAGZ,MAFA,EAAU,QAAQ,EAClB,EAAO,OAAO,EACR,CACR,CAEA,MAAM,EAAM,EAEZ,IAAI,EAAa,GAEjB,SAAS,GAAU,CACb,IAEJ,EAAa,GACb,EAAU,QAAQ,EAClB,EAAO,OAAO,EAChB,CAEA,MAAO,CACL,UAEA,IAAI,UAAoB,CACtB,OAAO,CACT,EAEA,MAAM,OAAQ,CACZ,MAAM,EAAM,CACd,EAEA,SAEA,CAAC,OAAO,UAAW,CACjB,EAAQ,CACV,CACF,CACF"}
|
package/dist/testing/testing.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./flush.cjs"),t=require("./
|
|
1
|
+
const e=require("./flush.cjs"),t=require("./dom.cjs"),n=require("./form-internals-polyfill.cjs"),r=require("./query.cjs"),i=require("./mount.cjs"),a=require("./events.cjs"),o=require("./interactions.cjs"),s=require("./wait.cjs"),c=require("./render-hook.cjs");function l(e){e(i.cleanup),n.installFormInternalsPolyfill()}exports.FLUSH_DEEP=e.FLUSH_DEEP,exports.cleanup=i.cleanup,exports.createPointerEvent=a.createPointerEvent,exports.fire=a.fire,exports.flush=e.flush,exports.install=l,exports.installFormInternalsPolyfill=n.installFormInternalsPolyfill,exports.mock=i.mock,exports.mount=i.mount,exports.mountComponent=i.mountComponent,exports.renderHook=c.renderHook,exports.user=o.user,exports.waitFor=s.waitFor,exports.waitForEvent=s.waitForEvent,exports.walkFlatTree=t.walkFlatTree,exports.within=r.within;
|
|
2
2
|
//# sourceMappingURL=testing.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.cjs","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for Ore components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n *\n * This barrel re-exports the full testing API for convenience.\n * For tree-shaking, import directly from the focused sub-modules.\n */\n\nimport { cleanup } from './mount';\n\nexport { fire, createPointerEvent } from './events';\nexport { FLUSH_DEEP, flush, type FlushOptions } from './flush';\nexport { user } from './interactions';\nexport { cleanup, mock, mount, mountComponent, type Fixture, type MountOptions, type MountSetup } from './mount';\nexport { within, type QueryScope } from './query';\nexport { waitFor, waitForEvent, type WaitOptions } from './wait';\nexport { renderHook, type HookFixture } from './render-hook';\n\n/**\n * Register auto-cleanup after each test
|
|
1
|
+
{"version":3,"file":"testing.cjs","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for Ore components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n *\n * This barrel re-exports the full testing API for convenience.\n * For tree-shaking, import directly from the focused sub-modules.\n */\n\nimport { installFormInternalsPolyfill } from './form-internals-polyfill';\nimport { cleanup } from './mount';\n\nexport { fire, createPointerEvent } from './events';\nexport { FLUSH_DEEP, flush, type FlushOptions } from './flush';\nexport { walkFlatTree } from './dom';\nexport { installFormInternalsPolyfill } from './form-internals-polyfill';\nexport { user } from './interactions';\nexport { cleanup, mock, mount, mountComponent, type Fixture, type MountOptions, type MountSetup } from './mount';\nexport { within, type QueryScope } from './query';\nexport { waitFor, waitForEvent, type WaitOptions } from './wait';\nexport { renderHook, type HookFixture } from './render-hook';\n\n/**\n * Register auto-cleanup after each test, and polyfill the jsdom/happy-dom gaps in\n * `ElementInternals`/`FormData`/`<form>.reset()` that `useField()` needs (see\n * `installFormInternalsPolyfill` — safe to call even in a suite with no form-associated\n * components; every patch it installs is a guarded no-op when its target is missing).\n * Call once in your test setup file.\n *\n * @example\n * // vitest.setup.ts\n * import { afterEach } from 'vitest';\n * import { install } from '@vielzeug/ore/testing';\n * install(afterEach);\n */\nexport function install(afterEachHook: (fn: () => void) => void): void {\n afterEachHook(cleanup);\n installFormInternalsPolyfill();\n}\n"],"mappings":"oQAmCA,SAAgB,EAAQ,EAA+C,CACrE,EAAc,EAAA,OAAO,EACrB,EAAA,6BAA6B,CAC/B"}
|
|
@@ -8,13 +8,19 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { fire, createPointerEvent } from './events';
|
|
10
10
|
export { FLUSH_DEEP, flush, type FlushOptions } from './flush';
|
|
11
|
+
export { walkFlatTree } from './dom';
|
|
12
|
+
export { installFormInternalsPolyfill } from './form-internals-polyfill';
|
|
11
13
|
export { user } from './interactions';
|
|
12
14
|
export { cleanup, mock, mount, mountComponent, type Fixture, type MountOptions, type MountSetup } from './mount';
|
|
13
15
|
export { within, type QueryScope } from './query';
|
|
14
16
|
export { waitFor, waitForEvent, type WaitOptions } from './wait';
|
|
15
17
|
export { renderHook, type HookFixture } from './render-hook';
|
|
16
18
|
/**
|
|
17
|
-
* Register auto-cleanup after each test
|
|
19
|
+
* Register auto-cleanup after each test, and polyfill the jsdom/happy-dom gaps in
|
|
20
|
+
* `ElementInternals`/`FormData`/`<form>.reset()` that `useField()` needs (see
|
|
21
|
+
* `installFormInternalsPolyfill` — safe to call even in a suite with no form-associated
|
|
22
|
+
* components; every patch it installs is a guarded no-op when its target is missing).
|
|
23
|
+
* Call once in your test setup file.
|
|
18
24
|
*
|
|
19
25
|
* @example
|
|
20
26
|
* // vitest.setup.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/testing/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/testing/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjH,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,GAAG,IAAI,CAGrE"}
|
package/dist/testing/testing.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{FLUSH_DEEP as e,flush as t}from"./flush.js";import{
|
|
1
|
+
import{FLUSH_DEEP as e,flush as t}from"./flush.js";import{walkFlatTree as n}from"./dom.js";import{installFormInternalsPolyfill as r}from"./form-internals-polyfill.js";import{within as i}from"./query.js";import{cleanup as a,mock as o,mount as s,mountComponent as c}from"./mount.js";import{createPointerEvent as l,fire as u}from"./events.js";import{user as d}from"./interactions.js";import{waitFor as f,waitForEvent as p}from"./wait.js";import{renderHook as m}from"./render-hook.js";function h(e){e(a),r()}export{e as FLUSH_DEEP,a as cleanup,l as createPointerEvent,u as fire,t as flush,h as install,r as installFormInternalsPolyfill,o as mock,s as mount,c as mountComponent,m as renderHook,d as user,f as waitFor,p as waitForEvent,n as walkFlatTree,i as within};
|
|
2
2
|
//# sourceMappingURL=testing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for Ore components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n *\n * This barrel re-exports the full testing API for convenience.\n * For tree-shaking, import directly from the focused sub-modules.\n */\n\nimport { cleanup } from './mount';\n\nexport { fire, createPointerEvent } from './events';\nexport { FLUSH_DEEP, flush, type FlushOptions } from './flush';\nexport { user } from './interactions';\nexport { cleanup, mock, mount, mountComponent, type Fixture, type MountOptions, type MountSetup } from './mount';\nexport { within, type QueryScope } from './query';\nexport { waitFor, waitForEvent, type WaitOptions } from './wait';\nexport { renderHook, type HookFixture } from './render-hook';\n\n/**\n * Register auto-cleanup after each test
|
|
1
|
+
{"version":3,"file":"testing.js","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for Ore components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n *\n * This barrel re-exports the full testing API for convenience.\n * For tree-shaking, import directly from the focused sub-modules.\n */\n\nimport { installFormInternalsPolyfill } from './form-internals-polyfill';\nimport { cleanup } from './mount';\n\nexport { fire, createPointerEvent } from './events';\nexport { FLUSH_DEEP, flush, type FlushOptions } from './flush';\nexport { walkFlatTree } from './dom';\nexport { installFormInternalsPolyfill } from './form-internals-polyfill';\nexport { user } from './interactions';\nexport { cleanup, mock, mount, mountComponent, type Fixture, type MountOptions, type MountSetup } from './mount';\nexport { within, type QueryScope } from './query';\nexport { waitFor, waitForEvent, type WaitOptions } from './wait';\nexport { renderHook, type HookFixture } from './render-hook';\n\n/**\n * Register auto-cleanup after each test, and polyfill the jsdom/happy-dom gaps in\n * `ElementInternals`/`FormData`/`<form>.reset()` that `useField()` needs (see\n * `installFormInternalsPolyfill` — safe to call even in a suite with no form-associated\n * components; every patch it installs is a guarded no-op when its target is missing).\n * Call once in your test setup file.\n *\n * @example\n * // vitest.setup.ts\n * import { afterEach } from 'vitest';\n * import { install } from '@vielzeug/ore/testing';\n * install(afterEach);\n */\nexport function install(afterEachHook: (fn: () => void) => void): void {\n afterEachHook(cleanup);\n installFormInternalsPolyfill();\n}\n"],"mappings":"ieAmCA,SAAgB,EAAQ,EAA+C,CACrE,EAAc,CAAO,EACrB,EAA6B,CAC/B"}
|
package/dist/testing.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./testing/flush.cjs"),t=require("./testing/
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./testing/flush.cjs"),t=require("./testing/dom.cjs"),n=require("./testing/form-internals-polyfill.cjs"),r=require("./testing/query.cjs"),i=require("./testing/mount.cjs"),a=require("./testing/events.cjs"),o=require("./testing/interactions.cjs"),s=require("./testing/wait.cjs"),c=require("./testing/render-hook.cjs"),l=require("./testing/testing.cjs");exports.FLUSH_DEEP=e.FLUSH_DEEP,exports.cleanup=i.cleanup,exports.createPointerEvent=a.createPointerEvent,exports.fire=a.fire,exports.flush=e.flush,exports.install=l.install,exports.installFormInternalsPolyfill=n.installFormInternalsPolyfill,exports.mock=i.mock,exports.mount=i.mount,exports.mountComponent=i.mountComponent,exports.renderHook=c.renderHook,exports.user=o.user,exports.waitFor=s.waitFor,exports.waitForEvent=s.waitForEvent,exports.walkFlatTree=t.walkFlatTree,exports.within=r.within;
|
package/dist/testing.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{FLUSH_DEEP as e,flush as t}from"./testing/flush.js";import{
|
|
1
|
+
import{FLUSH_DEEP as e,flush as t}from"./testing/flush.js";import{walkFlatTree as n}from"./testing/dom.js";import{installFormInternalsPolyfill as r}from"./testing/form-internals-polyfill.js";import{within as i}from"./testing/query.js";import{cleanup as a,mock as o,mount as s,mountComponent as c}from"./testing/mount.js";import{createPointerEvent as l,fire as u}from"./testing/events.js";import{user as d}from"./testing/interactions.js";import{waitFor as f,waitForEvent as p}from"./testing/wait.js";import{renderHook as m}from"./testing/render-hook.js";import{install as h}from"./testing/testing.js";export{e as FLUSH_DEEP,a as cleanup,l as createPointerEvent,u as fire,t as flush,h as install,r as installFormInternalsPolyfill,o as mock,s as mount,c as mountComponent,m as renderHook,d as user,f as waitFor,p as waitForEvent,n as walkFlatTree,i as within};
|
package/dist/utils/emit.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../runtime.cjs");var t={bubbles:!0,cancelable:!0,composed:!1},n=()=>{let n=e.getHost();return((e,...r)=>{let i=r.length>0?{...t,detail:r[0]}:t;n.dispatchEvent(new CustomEvent(String(e),i))})};exports.useEmit=n;
|
|
1
|
+
const e=require("../runtime.cjs");var t={bubbles:!0,cancelable:!0,composed:!1},n=()=>{let n=e.getHost();return((e,...r)=>{let i=r.length>0?{...t,detail:r[0]}:t;return n.dispatchEvent(new CustomEvent(String(e),i))})};exports.useEmit=n;
|
|
2
2
|
//# sourceMappingURL=emit.cjs.map
|
package/dist/utils/emit.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit.cjs","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\ntype StrictEmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K):
|
|
1
|
+
{"version":3,"file":"emit.cjs","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\ntype StrictEmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): boolean;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;\n};\n\ntype LooseEmitFn = (event: string, detail?: unknown) => boolean;\n\nexport type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseEmitFn;\n\nconst DEFAULT_FIRE_OPTIONS = { bubbles: true, cancelable: true, composed: false };\n\n/**\n * Returns a typed `emit()` function bound to the current component's host element.\n * Call once during `setup()` — the `Emits` type parameter maps event names to\n * their `detail` payload type.\n *\n * Every event is dispatched `cancelable: true`, and `emit()` returns `dispatchEvent`'s\n * own boolean result — `false` when a listener called `preventDefault()`. Components\n * that need to know whether a listener cancelled an event (e.g. to skip a default\n * action) read this return value directly instead of hand-rolling `dispatchEvent`.\n *\n * @example\n * ```ts\n * type Events = { close: undefined; change: { value: string } };\n *\n * setup(props) {\n * const emit = useEmit<Events>();\n * emit('close');\n *\n * const notCancelled = emit('change', { value: 'ok' });\n * if (notCancelled) props.value.value = 'ok';\n * }\n * ```\n */\nexport const useEmit = <T extends Record<string, unknown> = Record<string, never>>(): EmitFn<T> => {\n const host = getHost();\n\n return ((event: keyof T, ...rest: unknown[]) => {\n const customEventInit = rest.length > 0 ? { ...DEFAULT_FIRE_OPTIONS, detail: rest[0] } : DEFAULT_FIRE_OPTIONS;\n\n return host.dispatchEvent(new CustomEvent<unknown>(String(event), customEventInit));\n }) as EmitFn<T>;\n};\n"],"mappings":"kCAoBA,IAAM,EAAuB,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,EAAM,EAyBnE,MAAsF,CACjG,IAAM,EAAO,EAAA,QAAQ,EAErB,QAAS,EAAgB,GAAG,IAAoB,CAC9C,IAAM,EAAkB,EAAK,OAAS,EAAI,CAAE,GAAG,EAAsB,OAAQ,EAAK,EAAG,EAAI,EAEzF,OAAO,EAAK,cAAc,IAAI,YAAqB,OAAO,CAAK,EAAG,CAAe,CAAC,CACpF,EACF"}
|
package/dist/utils/emit.d.ts
CHANGED
|
@@ -6,16 +6,21 @@ type KeysWithoutDetail<T extends Record<string, unknown>> = {
|
|
|
6
6
|
[P in keyof T]: [T[P]] extends [NoDetail] ? P : never;
|
|
7
7
|
}[keyof T];
|
|
8
8
|
type StrictEmitFn<T extends Record<string, unknown>> = {
|
|
9
|
-
<K extends KeysWithoutDetail<T>>(event: K):
|
|
10
|
-
<K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]):
|
|
9
|
+
<K extends KeysWithoutDetail<T>>(event: K): boolean;
|
|
10
|
+
<K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;
|
|
11
11
|
};
|
|
12
|
-
type LooseEmitFn = (event: string, detail?: unknown) =>
|
|
12
|
+
type LooseEmitFn = (event: string, detail?: unknown) => boolean;
|
|
13
13
|
export type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseEmitFn;
|
|
14
14
|
/**
|
|
15
15
|
* Returns a typed `emit()` function bound to the current component's host element.
|
|
16
16
|
* Call once during `setup()` — the `Emits` type parameter maps event names to
|
|
17
17
|
* their `detail` payload type.
|
|
18
18
|
*
|
|
19
|
+
* Every event is dispatched `cancelable: true`, and `emit()` returns `dispatchEvent`'s
|
|
20
|
+
* own boolean result — `false` when a listener called `preventDefault()`. Components
|
|
21
|
+
* that need to know whether a listener cancelled an event (e.g. to skip a default
|
|
22
|
+
* action) read this return value directly instead of hand-rolling `dispatchEvent`.
|
|
23
|
+
*
|
|
19
24
|
* @example
|
|
20
25
|
* ```ts
|
|
21
26
|
* type Events = { close: undefined; change: { value: string } };
|
|
@@ -23,7 +28,9 @@ export type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseE
|
|
|
23
28
|
* setup(props) {
|
|
24
29
|
* const emit = useEmit<Events>();
|
|
25
30
|
* emit('close');
|
|
26
|
-
*
|
|
31
|
+
*
|
|
32
|
+
* const notCancelled = emit('change', { value: 'ok' });
|
|
33
|
+
* if (notCancelled) props.value.value = 'ok';
|
|
27
34
|
* }
|
|
28
35
|
* ```
|
|
29
36
|
*/
|
package/dist/utils/emit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/utils/emit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,KAAK,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AACzC,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;KACzD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK;CACtD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACrD,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/utils/emit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,KAAK,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AACzC,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;KACzD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK;CACtD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACrD,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACpD,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACrF,CAAC;AAEF,KAAK,WAAW,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;AAEhE,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;AAItF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAK,MAAM,CAAC,CAAC,CAQ7F,CAAC"}
|
package/dist/utils/emit.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getHost as e}from"../runtime.js";var t={bubbles:!0,cancelable:!0,composed:!1},n=()=>{let n=e();return((e,...r)=>{let i=r.length>0?{...t,detail:r[0]}:t;n.dispatchEvent(new CustomEvent(String(e),i))})};export{n as useEmit};
|
|
1
|
+
import{getHost as e}from"../runtime.js";var t={bubbles:!0,cancelable:!0,composed:!1},n=()=>{let n=e();return((e,...r)=>{let i=r.length>0?{...t,detail:r[0]}:t;return n.dispatchEvent(new CustomEvent(String(e),i))})};export{n as useEmit};
|
|
2
2
|
//# sourceMappingURL=emit.js.map
|
package/dist/utils/emit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit.js","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\ntype StrictEmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K):
|
|
1
|
+
{"version":3,"file":"emit.js","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\ntype StrictEmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): boolean;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;\n};\n\ntype LooseEmitFn = (event: string, detail?: unknown) => boolean;\n\nexport type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseEmitFn;\n\nconst DEFAULT_FIRE_OPTIONS = { bubbles: true, cancelable: true, composed: false };\n\n/**\n * Returns a typed `emit()` function bound to the current component's host element.\n * Call once during `setup()` — the `Emits` type parameter maps event names to\n * their `detail` payload type.\n *\n * Every event is dispatched `cancelable: true`, and `emit()` returns `dispatchEvent`'s\n * own boolean result — `false` when a listener called `preventDefault()`. Components\n * that need to know whether a listener cancelled an event (e.g. to skip a default\n * action) read this return value directly instead of hand-rolling `dispatchEvent`.\n *\n * @example\n * ```ts\n * type Events = { close: undefined; change: { value: string } };\n *\n * setup(props) {\n * const emit = useEmit<Events>();\n * emit('close');\n *\n * const notCancelled = emit('change', { value: 'ok' });\n * if (notCancelled) props.value.value = 'ok';\n * }\n * ```\n */\nexport const useEmit = <T extends Record<string, unknown> = Record<string, never>>(): EmitFn<T> => {\n const host = getHost();\n\n return ((event: keyof T, ...rest: unknown[]) => {\n const customEventInit = rest.length > 0 ? { ...DEFAULT_FIRE_OPTIONS, detail: rest[0] } : DEFAULT_FIRE_OPTIONS;\n\n return host.dispatchEvent(new CustomEvent<unknown>(String(event), customEventInit));\n }) as EmitFn<T>;\n};\n"],"mappings":"wCAoBA,IAAM,EAAuB,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,EAAM,EAyBnE,MAAsF,CACjG,IAAM,EAAO,EAAQ,EAErB,QAAS,EAAgB,GAAG,IAAoB,CAC9C,IAAM,EAAkB,EAAK,OAAS,EAAI,CAAE,GAAG,EAAsB,OAAQ,EAAK,EAAG,EAAI,EAEzF,OAAO,EAAK,cAAc,IAAI,YAAqB,OAAO,CAAK,EAAG,CAAe,CAAC,CACpF,EACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/ore",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Custom element authoring primitives — reactive templates, signals, slots, and automatic lifecycle management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@types/node": "^26.1.0",
|
|
72
72
|
"axe-core": "^4.12.1",
|
|
73
73
|
"jsdom": "^29.1.1",
|
|
74
|
-
"typescript": "
|
|
74
|
+
"typescript": "^6.0.3",
|
|
75
75
|
"vite": "^8.1.3",
|
|
76
76
|
"vitest": "^4.1.10"
|
|
77
77
|
}
|