@vielzeug/ore 1.2.3 → 1.3.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.
Files changed (149) hide show
  1. package/dist/aria.cjs +1 -1
  2. package/dist/aria.cjs.map +1 -1
  3. package/dist/aria.d.ts +9 -8
  4. package/dist/aria.d.ts.map +1 -1
  5. package/dist/aria.js +1 -1
  6. package/dist/aria.js.map +1 -1
  7. package/dist/base-element.cjs +1 -1
  8. package/dist/base-element.cjs.map +1 -1
  9. package/dist/base-element.d.ts.map +1 -1
  10. package/dist/base-element.js +1 -1
  11. package/dist/base-element.js.map +1 -1
  12. package/dist/directives/classMap.cjs +1 -1
  13. package/dist/directives/classMap.cjs.map +1 -1
  14. package/dist/directives/classMap.d.ts.map +1 -1
  15. package/dist/directives/classMap.js +1 -1
  16. package/dist/directives/classMap.js.map +1 -1
  17. package/dist/directives/each.cjs +1 -1
  18. package/dist/directives/each.cjs.map +1 -1
  19. package/dist/directives/each.d.ts +8 -1
  20. package/dist/directives/each.d.ts.map +1 -1
  21. package/dist/directives/each.js +1 -1
  22. package/dist/directives/each.js.map +1 -1
  23. package/dist/directives/index.d.ts +34 -5
  24. package/dist/directives/index.d.ts.map +1 -1
  25. package/dist/directives/raw.cjs +1 -1
  26. package/dist/directives/raw.cjs.map +1 -1
  27. package/dist/directives/raw.js +1 -1
  28. package/dist/directives/raw.js.map +1 -1
  29. package/dist/directives/styleMap.cjs +1 -1
  30. package/dist/directives/styleMap.cjs.map +1 -1
  31. package/dist/directives/styleMap.d.ts.map +1 -1
  32. package/dist/directives/styleMap.js +1 -1
  33. package/dist/directives/styleMap.js.map +1 -1
  34. package/dist/directives/when.cjs +1 -1
  35. package/dist/directives/when.cjs.map +1 -1
  36. package/dist/directives/when.d.ts.map +1 -1
  37. package/dist/directives/when.js +1 -1
  38. package/dist/directives/when.js.map +1 -1
  39. package/dist/directives.cjs +1 -1
  40. package/dist/directives.js +1 -1
  41. package/dist/errors.cjs.map +1 -1
  42. package/dist/errors.d.ts +16 -3
  43. package/dist/errors.d.ts.map +1 -1
  44. package/dist/errors.js.map +1 -1
  45. package/dist/host-bind.cjs +1 -1
  46. package/dist/host-bind.cjs.map +1 -1
  47. package/dist/host-bind.d.ts +6 -0
  48. package/dist/host-bind.d.ts.map +1 -1
  49. package/dist/host-bind.js +1 -1
  50. package/dist/host-bind.js.map +1 -1
  51. package/dist/index.cjs +1 -1
  52. package/dist/index.d.ts +8 -3
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +1 -1
  55. package/dist/ore.cjs +2 -2
  56. package/dist/ore.cjs.map +1 -1
  57. package/dist/ore.iife.js +2 -2
  58. package/dist/ore.iife.js.map +1 -1
  59. package/dist/ore.js +2 -2
  60. package/dist/ore.js.map +1 -1
  61. package/dist/runtime.cjs +1 -1
  62. package/dist/runtime.cjs.map +1 -1
  63. package/dist/runtime.d.ts.map +1 -1
  64. package/dist/runtime.js +1 -1
  65. package/dist/runtime.js.map +1 -1
  66. package/dist/slots.cjs +1 -1
  67. package/dist/slots.cjs.map +1 -1
  68. package/dist/slots.d.ts.map +1 -1
  69. package/dist/slots.js +1 -1
  70. package/dist/slots.js.map +1 -1
  71. package/dist/template/bindings.cjs +1 -1
  72. package/dist/template/bindings.cjs.map +1 -1
  73. package/dist/template/bindings.d.ts.map +1 -1
  74. package/dist/template/bindings.js +1 -1
  75. package/dist/template/bindings.js.map +1 -1
  76. package/dist/template/instantiator.cjs.map +1 -1
  77. package/dist/template/instantiator.d.ts.map +1 -1
  78. package/dist/template/instantiator.js.map +1 -1
  79. package/dist/testing/flush.cjs +1 -1
  80. package/dist/testing/flush.cjs.map +1 -1
  81. package/dist/testing/flush.d.ts +30 -26
  82. package/dist/testing/flush.d.ts.map +1 -1
  83. package/dist/testing/flush.js +1 -1
  84. package/dist/testing/flush.js.map +1 -1
  85. package/dist/testing/index.d.ts +30 -1
  86. package/dist/testing/index.d.ts.map +1 -1
  87. package/dist/testing/interactions.cjs +1 -1
  88. package/dist/testing/interactions.cjs.map +1 -1
  89. package/dist/testing/interactions.d.ts.map +1 -1
  90. package/dist/testing/interactions.js +1 -1
  91. package/dist/testing/interactions.js.map +1 -1
  92. package/dist/testing/mount.cjs +1 -1
  93. package/dist/testing/mount.cjs.map +1 -1
  94. package/dist/testing/mount.d.ts +8 -14
  95. package/dist/testing/mount.d.ts.map +1 -1
  96. package/dist/testing/mount.js +1 -1
  97. package/dist/testing/mount.js.map +1 -1
  98. package/dist/testing/render-hook.cjs +1 -1
  99. package/dist/testing/render-hook.js +1 -1
  100. package/dist/testing.cjs +2 -1
  101. package/dist/testing.cjs.map +1 -0
  102. package/dist/testing.js +2 -1
  103. package/dist/testing.js.map +1 -0
  104. package/dist/utils/aria.cjs.map +1 -1
  105. package/dist/utils/aria.d.ts +1 -1
  106. package/dist/utils/aria.js.map +1 -1
  107. package/dist/utils/dom.cjs +1 -1
  108. package/dist/utils/dom.cjs.map +1 -1
  109. package/dist/utils/dom.d.ts +36 -0
  110. package/dist/utils/dom.d.ts.map +1 -1
  111. package/dist/utils/dom.js +1 -1
  112. package/dist/utils/dom.js.map +1 -1
  113. package/dist/utils/id.cjs +1 -1
  114. package/dist/utils/id.cjs.map +1 -1
  115. package/dist/utils/id.d.ts +11 -2
  116. package/dist/utils/id.d.ts.map +1 -1
  117. package/dist/utils/id.js +1 -1
  118. package/dist/utils/id.js.map +1 -1
  119. package/package.json +3 -8
  120. package/dist/devtools.cjs +0 -2
  121. package/dist/devtools.cjs.map +0 -1
  122. package/dist/devtools.d.ts +0 -32
  123. package/dist/devtools.d.ts.map +0 -1
  124. package/dist/devtools.js +0 -2
  125. package/dist/devtools.js.map +0 -1
  126. package/dist/testing/events.cjs +0 -2
  127. package/dist/testing/events.cjs.map +0 -1
  128. package/dist/testing/events.d.ts +0 -37
  129. package/dist/testing/events.d.ts.map +0 -1
  130. package/dist/testing/events.js +0 -2
  131. package/dist/testing/events.js.map +0 -1
  132. package/dist/testing/query.cjs +0 -2
  133. package/dist/testing/query.cjs.map +0 -1
  134. package/dist/testing/query.d.ts +0 -24
  135. package/dist/testing/query.d.ts.map +0 -1
  136. package/dist/testing/query.js +0 -2
  137. package/dist/testing/query.js.map +0 -1
  138. package/dist/testing/testing.cjs +0 -2
  139. package/dist/testing/testing.cjs.map +0 -1
  140. package/dist/testing/testing.d.ts +0 -32
  141. package/dist/testing/testing.d.ts.map +0 -1
  142. package/dist/testing/testing.js +0 -2
  143. package/dist/testing/testing.js.map +0 -1
  144. package/dist/testing/wait.cjs +0 -2
  145. package/dist/testing/wait.cjs.map +0 -1
  146. package/dist/testing/wait.d.ts +0 -35
  147. package/dist/testing/wait.d.ts.map +0 -1
  148. package/dist/testing/wait.js +0 -2
  149. package/dist/testing/wait.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","names":[],"sources":["../src/testing/index.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\n// Testing-only error: flush() is its only thrower in this package (a pending-work timeout —\n// see flush.ts). Exported here (not from the main `.` entry) so components with no interest\n// in the testing sub-path don't carry a testing-only error class in their public type surface.\n// waitFor()/waitForEvent() throw @vielzeug/assay's own AssayTimeoutError instead — re-exported\n// below alongside them, since it's a generic DOM-testing concern, not an ore-specific one.\nexport { OreTimeoutError } from '../errors';\n\n// Generic DOM-testing primitives with no ore-specific logic — re-exported from @vielzeug/assay\n// (used by other @vielzeug/* UI packages too) rather than duplicated here.\nexport {\n fire,\n createPointerEvent,\n within,\n waitFor,\n waitForEvent,\n type QueryScope,\n type WaitOptions,\n} from '@vielzeug/assay';\n\nexport { debugFlush, 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 { 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":"ohBAmDA,SAAgB,EAAQ,EAA+C,CACrE,EAAc,CAAO,EACrB,EAA6B,CAC/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"aria.cjs","names":[],"sources":["../../src/utils/aria.ts"],"sourcesContent":["/**\n * Shared ARIA attribute key normalisation helpers.\n *\n * Two flavours are needed across the codebase:\n *\n * - `normalizeAriaKey` — always adds the `aria-` prefix for non-role keys.\n * Used by `syncAria()` where every config key is an ARIA attribute.\n *\n * - `normalizeHostAttrKey` — passes non-ARIA keys through unchanged.\n * Used by `host.bind({ attr: ... })` where keys may be arbitrary HTML attributes.\n */\n\n/** Normalise an aria config key to a full `aria-*` attribute name. */\nexport const normalizeAriaKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', 'expanded' → 'aria-expanded'\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : `aria-${key}`;\n};\n\n/** Normalise a host-bind attr key: aria-camelCase → aria-kebab-case; other keys pass through. */\nexport const normalizeHostAttrKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', other keys unchanged\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : key;\n};\n"],"mappings":"AAaA,IAAa,EAAoB,GAC3B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM,QAAQ,IAIpE,EAAwB,GAC/B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM"}
1
+ {"version":3,"file":"aria.cjs","names":[],"sources":["../../src/utils/aria.ts"],"sourcesContent":["/**\n * Shared ARIA attribute key normalisation helpers.\n *\n * Two flavours are needed across the codebase:\n *\n * - `normalizeAriaKey` — always adds the `aria-` prefix for non-role keys.\n * Used by `aria()` and `bind({ aria: ... })`, where every config key is an ARIA attribute.\n *\n * - `normalizeHostAttrKey` — passes non-ARIA keys through unchanged.\n * Used by `host.bind({ attr: ... })` where keys may be arbitrary HTML attributes.\n */\n\n/** Normalise an aria config key to a full `aria-*` attribute name. */\nexport const normalizeAriaKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', 'expanded' → 'aria-expanded'\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : `aria-${key}`;\n};\n\n/** Normalise a host-bind attr key: aria-camelCase → aria-kebab-case; other keys pass through. */\nexport const normalizeHostAttrKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', other keys unchanged\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : key;\n};\n"],"mappings":"AAaA,IAAa,EAAoB,GAC3B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM,QAAQ,IAIpE,EAAwB,GAC/B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM"}
@@ -4,7 +4,7 @@
4
4
  * Two flavours are needed across the codebase:
5
5
  *
6
6
  * - `normalizeAriaKey` — always adds the `aria-` prefix for non-role keys.
7
- * Used by `syncAria()` where every config key is an ARIA attribute.
7
+ * Used by `aria()` and `bind({ aria: ... })`, where every config key is an ARIA attribute.
8
8
  *
9
9
  * - `normalizeHostAttrKey` — passes non-ARIA keys through unchanged.
10
10
  * Used by `host.bind({ attr: ... })` where keys may be arbitrary HTML attributes.
@@ -1 +1 @@
1
- {"version":3,"file":"aria.js","names":[],"sources":["../../src/utils/aria.ts"],"sourcesContent":["/**\n * Shared ARIA attribute key normalisation helpers.\n *\n * Two flavours are needed across the codebase:\n *\n * - `normalizeAriaKey` — always adds the `aria-` prefix for non-role keys.\n * Used by `syncAria()` where every config key is an ARIA attribute.\n *\n * - `normalizeHostAttrKey` — passes non-ARIA keys through unchanged.\n * Used by `host.bind({ attr: ... })` where keys may be arbitrary HTML attributes.\n */\n\n/** Normalise an aria config key to a full `aria-*` attribute name. */\nexport const normalizeAriaKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', 'expanded' → 'aria-expanded'\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : `aria-${key}`;\n};\n\n/** Normalise a host-bind attr key: aria-camelCase → aria-kebab-case; other keys pass through. */\nexport const normalizeHostAttrKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', other keys unchanged\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : key;\n};\n"],"mappings":"AAaA,IAAa,EAAoB,GAC3B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM,QAAQ,IAIpE,EAAwB,GAC/B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM"}
1
+ {"version":3,"file":"aria.js","names":[],"sources":["../../src/utils/aria.ts"],"sourcesContent":["/**\n * Shared ARIA attribute key normalisation helpers.\n *\n * Two flavours are needed across the codebase:\n *\n * - `normalizeAriaKey` — always adds the `aria-` prefix for non-role keys.\n * Used by `aria()` and `bind({ aria: ... })`, where every config key is an ARIA attribute.\n *\n * - `normalizeHostAttrKey` — passes non-ARIA keys through unchanged.\n * Used by `host.bind({ attr: ... })` where keys may be arbitrary HTML attributes.\n */\n\n/** Normalise an aria config key to a full `aria-*` attribute name. */\nexport const normalizeAriaKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', 'expanded' → 'aria-expanded'\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : `aria-${key}`;\n};\n\n/** Normalise a host-bind attr key: aria-camelCase → aria-kebab-case; other keys pass through. */\nexport const normalizeHostAttrKey = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n // 'ariaLabel' → 'aria-label', other keys unchanged\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : key;\n};\n"],"mappings":"AAaA,IAAa,EAAoB,GAC3B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM,QAAQ,IAIpE,EAAwB,GAC/B,IAAQ,QAAU,EAAI,WAAW,OAAO,EAAU,EAG/C,EAAI,WAAW,MAAM,EAAI,QAAQ,EAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAM"}
@@ -1,2 +1,2 @@
1
- const e=require("../_dev.cjs");var t=e=>{for(let t=e.length-1;t>=0;t--)e[t]()},n=e=>{for(let t of e)t.remove()},r=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),i=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,a=(t,n,a)=>{let o=n.toLowerCase();if(/^on[a-z]/i.test(n)){e.warn(`Blocked setAttribute("${n}", ...) — inline event handler attributes are not supported. Use @${n.slice(2)} binding syntax instead.`),t.removeAttribute(n);return}if(o===`srcdoc`){e.warn(`Blocked setAttribute("srcdoc", ...) — "srcdoc" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`),t.removeAttribute(n);return}if(a==null||a===!1){t.removeAttribute(n);return}let s=a===!0?`true`:String(a);if(r.has(o)&&i.test(s)){e.warn(`Blocked dangerous URL scheme in attribute "${n}". Only safe URLs are permitted in URL-accepting attributes.`),t.removeAttribute(n);return}t.setAttribute(n,s)},o=(e,t,n,r)=>{if(!e)return()=>{};let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},s=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),c=e=>Array.isArray(e)||typeof e==`object`&&!!e;exports.isStructuredValue=c,exports.listen=o,exports.removeNodes=n,exports.runAll=t,exports.setAttr=a,exports.toKebab=s;
1
+ const e=require("../_dev.cjs");let t=require("@vielzeug/ripple");var n=e=>typeof e==`function`?e():(0,t.isReactive)(e)?e.value:e,r=/[;{}]/g,i=e=>e.replace(r,``),a=e=>{for(let t=e.length-1;t>=0;t--)e[t]()},o=e=>{for(let t of e)t.remove()},s=()=>{let e=[],t=[];return{clear(){a(t),o(e),t=[],e=[]},get nodes(){return e},registerCleanup(e){t.push(e)},setNodes(t){e=t}}},c=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),l=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,u=(t,n,r)=>{let i=n.toLowerCase();if(/^on[a-z]/i.test(n)){e.warn(`Blocked setAttribute("${n}", ...) — inline event handler attributes are not supported. Use @${n.slice(2)} binding syntax instead.`),t.removeAttribute(n);return}if(i===`srcdoc`){e.warn(`Blocked setAttribute("srcdoc", ...) — "srcdoc" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`),t.removeAttribute(n);return}if(r==null||r===!1){t.removeAttribute(n);return}let a=r===!0?`true`:String(r);if(c.has(i)&&l.test(a)){e.warn(`Blocked dangerous URL scheme in attribute "${n}". Only safe URLs are permitted in URL-accepting attributes.`),t.removeAttribute(n);return}t.setAttribute(n,a)},d=(e,t,n,r)=>{if(!e)return()=>{};let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},f=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),p=e=>Array.isArray(e)||typeof e==`object`&&!!e;exports.UNSAFE_CSS_CHARS=r,exports.createReplaceableSlot=s,exports.isStructuredValue=p,exports.listen=d,exports.removeNodes=o,exports.resolveMaybeReactive=n,exports.runAll=a,exports.sanitizeCssToken=i,exports.setAttr=u,exports.toKebab=f;
2
2
  //# sourceMappingURL=dom.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom.cjs","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { warn } from '../_dev';\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) return () => {};\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"+BAMA,IAAa,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAC1B,EAAA,KACE,yBAAyB,EAAK,oEAAoE,EAAK,MAAM,CAAC,EAAE,yBAClH,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAC1B,EAAA,KACE,iMACF,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAChE,EAAA,KACE,8CAA8C,EAAK,6DACrD,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAAI,UAAa,CAAC,EAEvB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
1
+ {"version":3,"file":"dom.cjs","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive signal — the\n * same three-way branch `classMap`/`styleMap`/`bind()`'s class-map binding each used to\n * hand-implement separately (with one silently diverging: only the `bind()` copy coerced with\n * `Boolean(...)`). One shared implementation here is the single source of truth.\n */\nexport const resolveMaybeReactive = <T>(value: T | Readable<T> | (() => T)): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\" — a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `raw()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping — this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes — read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) return () => {};\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"iEAcA,IAAa,EAA2B,GACtC,OAAO,GAAU,WAAc,EAAkB,GAAA,EAAA,EAAA,WAAA,CAAe,CAAK,EAAI,EAAM,MAAQ,EAO5E,EAAmB,SAEnB,EAAoB,GAA0B,EAAM,QAAQ,EAAkB,EAAE,EAEhF,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EAuBa,MAA+C,CAC1D,IAAI,EAAgB,CAAC,EACjB,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACN,EAAO,CAAQ,EACf,EAAY,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAO,CACT,EACA,gBAAgB,EAAI,CAClB,EAAS,KAAK,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQ,CACV,CACF,CACF,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAC1B,EAAA,KACE,yBAAyB,EAAK,oEAAoE,EAAK,MAAM,CAAC,EAAE,yBAClH,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAC1B,EAAA,KACE,iMACF,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAChE,EAAA,KACE,8CAA8C,EAAK,6DACrD,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAAI,UAAa,CAAC,EAEvB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
@@ -1,8 +1,44 @@
1
1
  /**
2
2
  * Low-level DOM utilities used throughout the runtime and binding layers.
3
3
  */
4
+ import { type Readable } from '@vielzeug/ripple';
5
+ /**
6
+ * Resolves a value that may be a plain value, a getter function, or a reactive signal — the
7
+ * same three-way branch `classMap`/`styleMap`/`bind()`'s class-map binding each used to
8
+ * hand-implement separately (with one silently diverging: only the `bind()` copy coerced with
9
+ * `Boolean(...)`). One shared implementation here is the single source of truth.
10
+ */
11
+ export declare const resolveMaybeReactive: <T>(value: T | Readable<T> | (() => T)) => T;
12
+ /**
13
+ * Characters that can break out of a CSS declaration in an inline style value or property name.
14
+ * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not
15
+ * inline style values, and signal an injection attempt there.
16
+ */
17
+ export declare const UNSAFE_CSS_CHARS: RegExp;
18
+ export declare const sanitizeCssToken: (value: string) => string;
4
19
  export declare const runAll: (fns: (() => void)[]) => void;
5
20
  export declare const removeNodes: (nodes: Node[]) => void;
21
+ /**
22
+ * Tracks "whatever is currently rendered in one spot" — a list of live DOM nodes plus the
23
+ * cleanup functions that were registered while mounting them. `clear()` tears both down and
24
+ * resets to empty, ready for the next render.
25
+ *
26
+ * Every directive/binding that swaps its rendered content when a reactive source changes
27
+ * (`when()`, `raw()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this
28
+ * bookkeeping — this is the one shared implementation instead of four independently-maintained
29
+ * `currentNodes`/`currentCleanups` variable pairs.
30
+ */
31
+ export type ReplaceableSlot = {
32
+ /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */
33
+ clear(): void;
34
+ /** Currently tracked nodes — read after mounting to know what's live. */
35
+ readonly nodes: Node[];
36
+ /** Pass as the `registerCleanup` callback to whatever mounts the next render. */
37
+ registerCleanup(fn: () => void): void;
38
+ /** Replace the tracked node list (call once mounting the next render is complete). */
39
+ setNodes(nodes: Node[]): void;
40
+ };
41
+ export declare const createReplaceableSlot: () => ReplaceableSlot;
6
42
  export declare const setAttr: (el: Element, name: string, val: unknown) => void;
7
43
  export declare const listen: (el: EventTarget | null | undefined, name: string, handler: EventListener, options?: AddEventListenerOptions) => (() => void);
8
44
  export declare const toKebab: (str: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,eAAO,MAAM,MAAM,GAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,IAAI,EAAE,KAAG,IAI3C,CAAC;AAiCF,eAAO,MAAM,OAAO,GAAI,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,OAAO,KAAG,IAuCjE,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,IAAI,WAAW,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,MAAM,EACZ,SAAS,aAAa,EACtB,UAAU,uBAAuB,KAChC,CAAC,MAAM,IAAI,CAQb,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAA6D,CAAC;AAEpG,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACW,CAAC"}
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI7D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAG,CACiB,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAW,CAAC;AAEzC,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,MAA6C,CAAC;AAE/F,eAAO,MAAM,MAAM,GAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,IAAI,EAAE,KAAG,IAI3C,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gGAAgG;IAChG,KAAK,IAAI,IAAI,CAAC;IACd,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACvB,iFAAiF;IACjF,eAAe,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACtC,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,eAqBxC,CAAC;AAiCF,eAAO,MAAM,OAAO,GAAI,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,OAAO,KAAG,IAuCjE,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,IAAI,WAAW,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,MAAM,EACZ,SAAS,aAAa,EACtB,UAAU,uBAAuB,KAChC,CAAC,MAAM,IAAI,CAQb,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAA6D,CAAC;AAEpG,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACW,CAAC"}
package/dist/utils/dom.js CHANGED
@@ -1,2 +1,2 @@
1
- import{warn as e}from"../_dev.js";var t=e=>{for(let t=e.length-1;t>=0;t--)e[t]()},n=e=>{for(let t of e)t.remove()},r=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),i=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,a=(t,n,a)=>{let o=n.toLowerCase();if(/^on[a-z]/i.test(n)){e(`Blocked setAttribute("${n}", ...) — inline event handler attributes are not supported. Use @${n.slice(2)} binding syntax instead.`),t.removeAttribute(n);return}if(o===`srcdoc`){e(`Blocked setAttribute("srcdoc", ...) — "srcdoc" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`),t.removeAttribute(n);return}if(a==null||a===!1){t.removeAttribute(n);return}let s=a===!0?`true`:String(a);if(r.has(o)&&i.test(s)){e(`Blocked dangerous URL scheme in attribute "${n}". Only safe URLs are permitted in URL-accepting attributes.`),t.removeAttribute(n);return}t.setAttribute(n,s)},o=(e,t,n,r)=>{if(!e)return()=>{};let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},s=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),c=e=>Array.isArray(e)||typeof e==`object`&&!!e;export{c as isStructuredValue,o as listen,n as removeNodes,t as runAll,a as setAttr,s as toKebab};
1
+ import{warn as e}from"../_dev.js";import{isReactive as t}from"@vielzeug/ripple";var n=e=>typeof e==`function`?e():t(e)?e.value:e,r=/[;{}]/g,i=e=>e.replace(r,``),a=e=>{for(let t=e.length-1;t>=0;t--)e[t]()},o=e=>{for(let t of e)t.remove()},s=()=>{let e=[],t=[];return{clear(){a(t),o(e),t=[],e=[]},get nodes(){return e},registerCleanup(e){t.push(e)},setNodes(t){e=t}}},c=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),l=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,u=(t,n,r)=>{let i=n.toLowerCase();if(/^on[a-z]/i.test(n)){e(`Blocked setAttribute("${n}", ...) — inline event handler attributes are not supported. Use @${n.slice(2)} binding syntax instead.`),t.removeAttribute(n);return}if(i===`srcdoc`){e(`Blocked setAttribute("srcdoc", ...) — "srcdoc" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`),t.removeAttribute(n);return}if(r==null||r===!1){t.removeAttribute(n);return}let a=r===!0?`true`:String(r);if(c.has(i)&&l.test(a)){e(`Blocked dangerous URL scheme in attribute "${n}". Only safe URLs are permitted in URL-accepting attributes.`),t.removeAttribute(n);return}t.setAttribute(n,a)},d=(e,t,n,r)=>{if(!e)return()=>{};let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},f=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),p=e=>Array.isArray(e)||typeof e==`object`&&!!e;export{r as UNSAFE_CSS_CHARS,s as createReplaceableSlot,p as isStructuredValue,d as listen,o as removeNodes,n as resolveMaybeReactive,a as runAll,i as sanitizeCssToken,u as setAttr,f as toKebab};
2
2
  //# sourceMappingURL=dom.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom.js","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { warn } from '../_dev';\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) return () => {};\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"kCAMA,IAAa,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAC1B,EACE,yBAAyB,EAAK,oEAAoE,EAAK,MAAM,CAAC,EAAE,yBAClH,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAC1B,EACE,iMACF,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAChE,EACE,8CAA8C,EAAK,6DACrD,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAAI,UAAa,CAAC,EAEvB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
1
+ {"version":3,"file":"dom.js","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive signal — the\n * same three-way branch `classMap`/`styleMap`/`bind()`'s class-map binding each used to\n * hand-implement separately (with one silently diverging: only the `bind()` copy coerced with\n * `Boolean(...)`). One shared implementation here is the single source of truth.\n */\nexport const resolveMaybeReactive = <T>(value: T | Readable<T> | (() => T)): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\" — a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `raw()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping — this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes — read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) return () => {};\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"gFAcA,IAAa,EAA2B,GACtC,OAAO,GAAU,WAAc,EAAkB,EAAI,EAAW,CAAK,EAAI,EAAM,MAAQ,EAO5E,EAAmB,SAEnB,EAAoB,GAA0B,EAAM,QAAQ,EAAkB,EAAE,EAEhF,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EAuBa,MAA+C,CAC1D,IAAI,EAAgB,CAAC,EACjB,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACN,EAAO,CAAQ,EACf,EAAY,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAO,CACT,EACA,gBAAgB,EAAI,CAClB,EAAS,KAAK,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQ,CACV,CACF,CACF,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAC1B,EACE,yBAAyB,EAAK,oEAAoE,EAAK,MAAM,CAAC,EAAE,yBAClH,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAC1B,EACE,iMACF,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAChE,EACE,8CAA8C,EAAK,6DACrD,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAAI,UAAa,CAAC,EAEvB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
package/dist/utils/id.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};exports._resetIdCounter=r,exports.createId=i,exports.createStableId=a,exports.resetIdCounter=o;
1
+ var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};exports._resetIdCounter=r,exports.createId=i,exports.createStableId=a,exports.resetStableIdCounter=o;
2
2
  //# sourceMappingURL=id.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"id.cjs","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the stable ID counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n */\nexport const resetIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAEa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAMlE,MAA6B,CACxC,EAAiB,CACnB"}
1
+ {"version":3,"file":"id.cjs","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\n/**\n * Generates a monotonically-increasing, unique-within-this-process ID with an optional prefix.\n * No public reset — this is for uniqueness, not cross-test determinism; use `createStableId()`\n * (and `resetStableIdCounter()`) when a test needs IDs to restart from the same value each run.\n */\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the `createStableId()` counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n *\n * Named to match `createStableId()` precisely — `createId()` has no public reset (it's meant\n * for non-deterministic, monotonically-unique IDs; nothing in the package relies on it\n * restarting from a fixed value across tests).\n */\nexport const resetStableIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAOa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAUlE,MAAmC,CAC9C,EAAiB,CACnB"}
@@ -3,6 +3,11 @@
3
3
  * Template binding no longer uses this for marker IDs — binding targets are resolved
4
4
  * via path navigation on cloned template nodes.
5
5
  */
6
+ /**
7
+ * Generates a monotonically-increasing, unique-within-this-process ID with an optional prefix.
8
+ * No public reset — this is for uniqueness, not cross-test determinism; use `createStableId()`
9
+ * (and `resetStableIdCounter()`) when a test needs IDs to restart from the same value each run.
10
+ */
6
11
  export declare const createId: (prefix?: string) => string;
7
12
  /**
8
13
  * Generates a stable, unique ID with an optional semantic prefix.
@@ -11,8 +16,12 @@ export declare const createId: (prefix?: string) => string;
11
16
  */
12
17
  export declare const createStableId: (prefix?: string) => string;
13
18
  /**
14
- * Resets the stable ID counter to 0. Use in test `beforeEach` hooks when you need
19
+ * Resets the `createStableId()` counter to 0. Use in test `beforeEach` hooks when you need
15
20
  * deterministic IDs across test runs.
21
+ *
22
+ * Named to match `createStableId()` precisely — `createId()` has no public reset (it's meant
23
+ * for non-deterministic, monotonically-unique IDs; nothing in the package relies on it
24
+ * restarting from a fixed value across tests).
16
25
  */
17
- export declare const resetIdCounter: () => void;
26
+ export declare const resetStableIdCounter: () => void;
18
27
  //# sourceMappingURL=id.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,eAAO,MAAM,QAAQ,GAAI,eAAa,KAAG,MAAqC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,eAAa,KAAG,MAAgD,CAAC;AAEhG;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,IAEjC,CAAC"}
1
+ {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,eAAa,KAAG,MAAqC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,eAAa,KAAG,MAAgD,CAAC;AAEhG;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,QAAO,IAEvC,CAAC"}
package/dist/utils/id.js CHANGED
@@ -1,2 +1,2 @@
1
- var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};export{r as _resetIdCounter,i as createId,a as createStableId,o as resetIdCounter};
1
+ var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};export{r as _resetIdCounter,i as createId,a as createStableId,o as resetStableIdCounter};
2
2
  //# sourceMappingURL=id.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"id.js","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the stable ID counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n */\nexport const resetIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAEa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAMlE,MAA6B,CACxC,EAAiB,CACnB"}
1
+ {"version":3,"file":"id.js","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\n/**\n * Generates a monotonically-increasing, unique-within-this-process ID with an optional prefix.\n * No public reset — this is for uniqueness, not cross-test determinism; use `createStableId()`\n * (and `resetStableIdCounter()`) when a test needs IDs to restart from the same value each run.\n */\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the `createStableId()` counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n *\n * Named to match `createStableId()` precisely — `createId()` has no public reset (it's meant\n * for non-deterministic, monotonically-unique IDs; nothing in the package relies on it\n * restarting from a fixed value across tests).\n */\nexport const resetStableIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAOa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAUlE,MAAmC,CAC9C,EAAiB,CACnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/ore",
3
- "version": "1.2.3",
3
+ "version": "1.3.0",
4
4
  "description": "Custom element authoring primitives — reactive templates, signals, slots, and automatic lifecycle management",
5
5
  "type": "module",
6
6
  "files": [
@@ -16,12 +16,6 @@
16
16
  "import": "./dist/index.js",
17
17
  "require": "./dist/index.cjs"
18
18
  },
19
- "./devtools": {
20
- "source": "./src/devtools.ts",
21
- "types": "./dist/devtools.d.ts",
22
- "import": "./dist/devtools.js",
23
- "require": "./dist/devtools.cjs"
24
- },
25
19
  "./directives": {
26
20
  "source": "./src/directives/index.ts",
27
21
  "types": "./dist/directives/index.d.ts",
@@ -65,7 +59,8 @@
65
59
  "node": ">=22"
66
60
  },
67
61
  "dependencies": {
68
- "@vielzeug/ripple": "1.2.3"
62
+ "@vielzeug/assay": "1.0.0",
63
+ "@vielzeug/ripple": "1.3.0"
69
64
  },
70
65
  "devDependencies": {
71
66
  "@types/node": "^26.1.0",
package/dist/devtools.cjs DELETED
@@ -1,2 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./testing/flush.cjs");async function t(t){return e.flush({...t,logger:console.debug})}exports.debugFlush=t;
2
- //# sourceMappingURL=devtools.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"devtools.cjs","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/ore — debug utilities for component update visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n * ```\n */\n\nimport type { FlushOptions } from './testing/flush';\n\nimport { flush } from './testing/flush';\n\n/**\n * Flushes pending reactive updates with debug logging pre-wired to `console.debug`.\n *\n * Equivalent to `flush({ ...options, logger: console.debug })` but imported from a\n * dedicated sub-path so the `console.debug` reference is tree-shaken from production\n * bundles when this sub-path is not imported.\n *\n * Logs each turn and timing phase to `console.debug` so you can diagnose\n * unexpected update order or timing issues.\n *\n * @example\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n *\n * // in a test\n * await debugFlush();\n * // [flush] starting with maxTurns=5\n * // [flush] microtask turn 1/5\n * // ...\n * ```\n */\nexport async function debugFlush(options?: Omit<FlushOptions, 'logger'>): Promise<void> {\n return flush({ ...options, logger: console.debug });\n}\n"],"mappings":"0GAkCA,eAAsB,EAAW,EAAuD,CACtF,OAAO,EAAA,MAAM,CAAE,GAAG,EAAS,OAAQ,QAAQ,KAAM,CAAC,CACpD"}
@@ -1,32 +0,0 @@
1
- /**
2
- * @vielzeug/ore — debug utilities for component update visualisation.
3
- *
4
- * Import from the dedicated sub-path so it is tree-shaken from production bundles:
5
- * ```ts
6
- * import { debugFlush } from '@vielzeug/ore/devtools';
7
- * ```
8
- */
9
- import type { FlushOptions } from './testing/flush';
10
- /**
11
- * Flushes pending reactive updates with debug logging pre-wired to `console.debug`.
12
- *
13
- * Equivalent to `flush({ ...options, logger: console.debug })` but imported from a
14
- * dedicated sub-path so the `console.debug` reference is tree-shaken from production
15
- * bundles when this sub-path is not imported.
16
- *
17
- * Logs each turn and timing phase to `console.debug` so you can diagnose
18
- * unexpected update order or timing issues.
19
- *
20
- * @example
21
- * ```ts
22
- * import { debugFlush } from '@vielzeug/ore/devtools';
23
- *
24
- * // in a test
25
- * await debugFlush();
26
- * // [flush] starting with maxTurns=5
27
- * // [flush] microtask turn 1/5
28
- * // ...
29
- * ```
30
- */
31
- export declare function debugFlush(options?: Omit<FlushOptions, 'logger'>): Promise<void>;
32
- //# sourceMappingURL=devtools.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF"}
package/dist/devtools.js DELETED
@@ -1,2 +0,0 @@
1
- import{flush as e}from"./testing/flush.js";async function t(t){return e({...t,logger:console.debug})}export{t as debugFlush};
2
- //# sourceMappingURL=devtools.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"devtools.js","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/ore — debug utilities for component update visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n * ```\n */\n\nimport type { FlushOptions } from './testing/flush';\n\nimport { flush } from './testing/flush';\n\n/**\n * Flushes pending reactive updates with debug logging pre-wired to `console.debug`.\n *\n * Equivalent to `flush({ ...options, logger: console.debug })` but imported from a\n * dedicated sub-path so the `console.debug` reference is tree-shaken from production\n * bundles when this sub-path is not imported.\n *\n * Logs each turn and timing phase to `console.debug` so you can diagnose\n * unexpected update order or timing issues.\n *\n * @example\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n *\n * // in a test\n * await debugFlush();\n * // [flush] starting with maxTurns=5\n * // [flush] microtask turn 1/5\n * // ...\n * ```\n */\nexport async function debugFlush(options?: Omit<FlushOptions, 'logger'>): Promise<void> {\n return flush({ ...options, logger: console.debug });\n}\n"],"mappings":"2CAkCA,eAAsB,EAAW,EAAuD,CACtF,OAAO,EAAM,CAAE,GAAG,EAAS,OAAQ,QAAQ,KAAM,CAAC,CACpD"}
@@ -1,2 +0,0 @@
1
- var e=(e,t={})=>typeof PointerEvent<`u`?new PointerEvent(e,t):new MouseEvent(e,t),t={blur:(e,t)=>e.dispatchEvent(new FocusEvent(`blur`,{bubbles:!0,...t})),change:(e,t)=>e.dispatchEvent(new Event(`change`,{bubbles:!0,...t})),click:(e,t)=>e.dispatchEvent(new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),custom(e,t,n){e.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n}))},event(e,t){e.dispatchEvent(t)},focus:(e,t,n)=>e.dispatchEvent(new FocusEvent(`focus`,{bubbles:!0,...n})),input:(e,t)=>e.dispatchEvent(new Event(`input`,{bubbles:!0,...t})),keyboard:(e,t,n)=>e.dispatchEvent(new KeyboardEvent(t,{bubbles:!0,cancelable:!0,...n})),keyDown:(e,t)=>e.dispatchEvent(new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),keyUp:(e,t)=>e.dispatchEvent(new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),mouse:(e,t,n)=>e.dispatchEvent(new MouseEvent(t,{bubbles:!0,cancelable:!0,...n})),pointerDown:(t,n)=>t.dispatchEvent(e(`pointerdown`,{bubbles:!0,cancelable:!0,...n})),pointerEnter:(t,n)=>t.dispatchEvent(e(`pointerenter`,{bubbles:!1,...n})),pointerLeave:(t,n)=>t.dispatchEvent(e(`pointerleave`,{bubbles:!1,...n})),pointerUp:(t,n)=>t.dispatchEvent(e(`pointerup`,{bubbles:!0,cancelable:!0,...n})),submit:(e,t)=>e.dispatchEvent(new Event(`submit`,{bubbles:!0,cancelable:!0,...t})),touch(e,t,n){typeof TouchEvent<`u`?e.dispatchEvent(new TouchEvent(t,{bubbles:!0,cancelable:!0,...n})):e.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,...n}))}};exports.createPointerEvent=e,exports.fire=t;
2
- //# sourceMappingURL=events.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.cjs","names":[],"sources":["../../src/testing/events.ts"],"sourcesContent":["/**\n * Synchronous DOM event dispatchers for test environments.\n */\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nexport const createPointerEvent = (type: string, init: PointerEventInit = {}): Event => {\n if (typeof PointerEvent !== 'undefined') {\n return new PointerEvent(type, init);\n }\n\n return new MouseEvent(type, init);\n};\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Fire low-level DOM events synchronously.\n *\n * @example\n * fire.click(button);\n * fire.keyDown(input, { key: 'Enter' });\n * fire.custom(el, 'value-change', { detail: 42 });\n */\nexport const fire = {\n blur: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('blur', { bubbles: true, ...opts })),\n change: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('change', { bubbles: true, ...opts })),\n click: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, ...opts })),\n /** Fire a CustomEvent. Pass `{ detail: ... }` for event detail. */\n custom(el: Element, name: string, opts?: CustomEventInit): void {\n el.dispatchEvent(new CustomEvent(name, { bubbles: true, cancelable: true, composed: false, ...opts }));\n },\n /** Dispatch any pre-built Event instance directly. */\n event(el: Element, event: Event): void {\n el.dispatchEvent(event);\n },\n focus: (el: Element, _name?: string, opts?: FocusEventInit) =>\n el.dispatchEvent(new FocusEvent('focus', { bubbles: true, ...opts })),\n input: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('input', { bubbles: true, ...opts })),\n /** Fire a KeyboardEvent with a given type (keydown, keyup, keypress). */\n keyboard: (el: Element, type: string, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent(type, { bubbles: true, cancelable: true, ...opts })),\n keyDown: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...opts })),\n keyUp: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...opts })),\n /** Fire a MouseEvent with a given type (click, mousedown, etc.). */\n mouse: (el: Element, type: string, opts?: MouseEventInit) =>\n el.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, ...opts })),\n pointerDown: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerdown', { bubbles: true, cancelable: true, ...opts })),\n pointerEnter: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerenter', { bubbles: false, ...opts })),\n pointerLeave: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerleave', { bubbles: false, ...opts })),\n pointerUp: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerup', { bubbles: true, cancelable: true, ...opts })),\n submit: (el: Element, opts?: EventInit) =>\n el.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true, ...opts })),\n /** Fire a touch event; falls back to CustomEvent in environments without TouchEvent. */\n touch(el: Element, type: string, opts?: EventInit): void {\n if (typeof TouchEvent !== 'undefined') {\n el.dispatchEvent(new TouchEvent(type, { bubbles: true, cancelable: true, ...opts }));\n } else {\n el.dispatchEvent(new CustomEvent(type, { bubbles: true, cancelable: true, ...opts }));\n }\n },\n} as const;\n"],"mappings":"AAMA,IAAa,GAAsB,EAAc,EAAyB,CAAC,IACrE,OAAO,aAAiB,IACnB,IAAI,aAAa,EAAM,CAAI,EAG7B,IAAI,WAAW,EAAM,CAAI,EAarB,EAAO,CAClB,MAAO,EAAa,IAA0B,EAAG,cAAc,IAAI,WAAW,OAAQ,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EACjH,QAAS,EAAa,IAAqB,EAAG,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EAC3G,OAAQ,EAAa,IACnB,EAAG,cAAc,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAExF,OAAO,EAAa,EAAc,EAA8B,CAC9D,EAAG,cAAc,IAAI,YAAY,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,GAAO,GAAG,CAAK,CAAC,CAAC,CACvG,EAEA,MAAM,EAAa,EAAoB,CACrC,EAAG,cAAc,CAAK,CACxB,EACA,OAAQ,EAAa,EAAgB,IACnC,EAAG,cAAc,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EACtE,OAAQ,EAAa,IAAqB,EAAG,cAAc,IAAI,MAAM,QAAS,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EAEzG,UAAW,EAAa,EAAc,IACpC,EAAG,cAAc,IAAI,cAAc,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EACxF,SAAU,EAAa,IACrB,EAAG,cAAc,IAAI,cAAc,UAAW,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAC7F,OAAQ,EAAa,IACnB,EAAG,cAAc,IAAI,cAAc,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAE3F,OAAQ,EAAa,EAAc,IACjC,EAAG,cAAc,IAAI,WAAW,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EACrF,aAAc,EAAa,IACzB,EAAG,cAAc,EAAmB,cAAe,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAClG,cAAe,EAAa,IAC1B,EAAG,cAAc,EAAmB,eAAgB,CAAE,QAAS,GAAO,GAAG,CAAK,CAAC,CAAC,EAClF,cAAe,EAAa,IAC1B,EAAG,cAAc,EAAmB,eAAgB,CAAE,QAAS,GAAO,GAAG,CAAK,CAAC,CAAC,EAClF,WAAY,EAAa,IACvB,EAAG,cAAc,EAAmB,YAAa,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAChG,QAAS,EAAa,IACpB,EAAG,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAEpF,MAAM,EAAa,EAAc,EAAwB,CACnD,OAAO,WAAe,IACxB,EAAG,cAAc,IAAI,WAAW,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAEnF,EAAG,cAAc,IAAI,YAAY,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,CAExF,CACF"}
@@ -1,37 +0,0 @@
1
- /**
2
- * Synchronous DOM event dispatchers for test environments.
3
- */
4
- export declare const createPointerEvent: (type: string, init?: PointerEventInit) => Event;
5
- /**
6
- * Fire low-level DOM events synchronously.
7
- *
8
- * @example
9
- * fire.click(button);
10
- * fire.keyDown(input, { key: 'Enter' });
11
- * fire.custom(el, 'value-change', { detail: 42 });
12
- */
13
- export declare const fire: {
14
- readonly blur: (el: Element, opts?: FocusEventInit) => boolean;
15
- readonly change: (el: Element, opts?: EventInit) => boolean;
16
- readonly click: (el: Element, opts?: PointerEventInit) => boolean;
17
- /** Fire a CustomEvent. Pass `{ detail: ... }` for event detail. */
18
- readonly custom: (el: Element, name: string, opts?: CustomEventInit) => void;
19
- /** Dispatch any pre-built Event instance directly. */
20
- readonly event: (el: Element, event: Event) => void;
21
- readonly focus: (el: Element, _name?: string, opts?: FocusEventInit) => boolean;
22
- readonly input: (el: Element, opts?: EventInit) => boolean;
23
- /** Fire a KeyboardEvent with a given type (keydown, keyup, keypress). */
24
- readonly keyboard: (el: Element, type: string, opts?: KeyboardEventInit) => boolean;
25
- readonly keyDown: (el: Element, opts?: KeyboardEventInit) => boolean;
26
- readonly keyUp: (el: Element, opts?: KeyboardEventInit) => boolean;
27
- /** Fire a MouseEvent with a given type (click, mousedown, etc.). */
28
- readonly mouse: (el: Element, type: string, opts?: MouseEventInit) => boolean;
29
- readonly pointerDown: (el: Element, opts?: PointerEventInit) => boolean;
30
- readonly pointerEnter: (el: Element, opts?: PointerEventInit) => boolean;
31
- readonly pointerLeave: (el: Element, opts?: PointerEventInit) => boolean;
32
- readonly pointerUp: (el: Element, opts?: PointerEventInit) => boolean;
33
- readonly submit: (el: Element, opts?: EventInit) => boolean;
34
- /** Fire a touch event; falls back to CustomEvent in environments without TouchEvent. */
35
- readonly touch: (el: Element, type: string, opts?: EventInit) => void;
36
- };
37
- //# sourceMappingURL=events.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/testing/events.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,EAAE,OAAM,gBAAqB,KAAG,KAM9E,CAAC;AAIF;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI;wBACJ,OAAO,SAAS,cAAc;0BAC5B,OAAO,SAAS,SAAS;yBAC1B,OAAO,SAAS,gBAAgB;IAE5C,mEAAmE;0BACxD,OAAO,QAAQ,MAAM,SAAS,eAAe,KAAG,IAAI;IAG/D,sDAAsD;yBAC5C,OAAO,SAAS,KAAK,KAAG,IAAI;yBAG1B,OAAO,UAAU,MAAM,SAAS,cAAc;yBAE9C,OAAO,SAAS,SAAS;IACrC,yEAAyE;4BAC1D,OAAO,QAAQ,MAAM,SAAS,iBAAiB;2BAEhD,OAAO,SAAS,iBAAiB;yBAEnC,OAAO,SAAS,iBAAiB;IAE7C,oEAAoE;yBACxD,OAAO,QAAQ,MAAM,SAAS,cAAc;+BAEtC,OAAO,SAAS,gBAAgB;gCAE/B,OAAO,SAAS,gBAAgB;gCAEhC,OAAO,SAAS,gBAAgB;6BAEnC,OAAO,SAAS,gBAAgB;0BAEnC,OAAO,SAAS,SAAS;IAEtC,wFAAwF;yBAC9E,OAAO,QAAQ,MAAM,SAAS,SAAS,KAAG,IAAI;CAOhD,CAAC"}
@@ -1,2 +0,0 @@
1
- var e=(e,t={})=>typeof PointerEvent<`u`?new PointerEvent(e,t):new MouseEvent(e,t),t={blur:(e,t)=>e.dispatchEvent(new FocusEvent(`blur`,{bubbles:!0,...t})),change:(e,t)=>e.dispatchEvent(new Event(`change`,{bubbles:!0,...t})),click:(e,t)=>e.dispatchEvent(new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),custom(e,t,n){e.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,composed:!1,...n}))},event(e,t){e.dispatchEvent(t)},focus:(e,t,n)=>e.dispatchEvent(new FocusEvent(`focus`,{bubbles:!0,...n})),input:(e,t)=>e.dispatchEvent(new Event(`input`,{bubbles:!0,...t})),keyboard:(e,t,n)=>e.dispatchEvent(new KeyboardEvent(t,{bubbles:!0,cancelable:!0,...n})),keyDown:(e,t)=>e.dispatchEvent(new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),keyUp:(e,t)=>e.dispatchEvent(new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),mouse:(e,t,n)=>e.dispatchEvent(new MouseEvent(t,{bubbles:!0,cancelable:!0,...n})),pointerDown:(t,n)=>t.dispatchEvent(e(`pointerdown`,{bubbles:!0,cancelable:!0,...n})),pointerEnter:(t,n)=>t.dispatchEvent(e(`pointerenter`,{bubbles:!1,...n})),pointerLeave:(t,n)=>t.dispatchEvent(e(`pointerleave`,{bubbles:!1,...n})),pointerUp:(t,n)=>t.dispatchEvent(e(`pointerup`,{bubbles:!0,cancelable:!0,...n})),submit:(e,t)=>e.dispatchEvent(new Event(`submit`,{bubbles:!0,cancelable:!0,...t})),touch(e,t,n){typeof TouchEvent<`u`?e.dispatchEvent(new TouchEvent(t,{bubbles:!0,cancelable:!0,...n})):e.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,...n}))}};export{e as createPointerEvent,t as fire};
2
- //# sourceMappingURL=events.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.js","names":[],"sources":["../../src/testing/events.ts"],"sourcesContent":["/**\n * Synchronous DOM event dispatchers for test environments.\n */\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nexport const createPointerEvent = (type: string, init: PointerEventInit = {}): Event => {\n if (typeof PointerEvent !== 'undefined') {\n return new PointerEvent(type, init);\n }\n\n return new MouseEvent(type, init);\n};\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Fire low-level DOM events synchronously.\n *\n * @example\n * fire.click(button);\n * fire.keyDown(input, { key: 'Enter' });\n * fire.custom(el, 'value-change', { detail: 42 });\n */\nexport const fire = {\n blur: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('blur', { bubbles: true, ...opts })),\n change: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('change', { bubbles: true, ...opts })),\n click: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, ...opts })),\n /** Fire a CustomEvent. Pass `{ detail: ... }` for event detail. */\n custom(el: Element, name: string, opts?: CustomEventInit): void {\n el.dispatchEvent(new CustomEvent(name, { bubbles: true, cancelable: true, composed: false, ...opts }));\n },\n /** Dispatch any pre-built Event instance directly. */\n event(el: Element, event: Event): void {\n el.dispatchEvent(event);\n },\n focus: (el: Element, _name?: string, opts?: FocusEventInit) =>\n el.dispatchEvent(new FocusEvent('focus', { bubbles: true, ...opts })),\n input: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('input', { bubbles: true, ...opts })),\n /** Fire a KeyboardEvent with a given type (keydown, keyup, keypress). */\n keyboard: (el: Element, type: string, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent(type, { bubbles: true, cancelable: true, ...opts })),\n keyDown: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...opts })),\n keyUp: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...opts })),\n /** Fire a MouseEvent with a given type (click, mousedown, etc.). */\n mouse: (el: Element, type: string, opts?: MouseEventInit) =>\n el.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, ...opts })),\n pointerDown: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerdown', { bubbles: true, cancelable: true, ...opts })),\n pointerEnter: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerenter', { bubbles: false, ...opts })),\n pointerLeave: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerleave', { bubbles: false, ...opts })),\n pointerUp: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerup', { bubbles: true, cancelable: true, ...opts })),\n submit: (el: Element, opts?: EventInit) =>\n el.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true, ...opts })),\n /** Fire a touch event; falls back to CustomEvent in environments without TouchEvent. */\n touch(el: Element, type: string, opts?: EventInit): void {\n if (typeof TouchEvent !== 'undefined') {\n el.dispatchEvent(new TouchEvent(type, { bubbles: true, cancelable: true, ...opts }));\n } else {\n el.dispatchEvent(new CustomEvent(type, { bubbles: true, cancelable: true, ...opts }));\n }\n },\n} as const;\n"],"mappings":"AAMA,IAAa,GAAsB,EAAc,EAAyB,CAAC,IACrE,OAAO,aAAiB,IACnB,IAAI,aAAa,EAAM,CAAI,EAG7B,IAAI,WAAW,EAAM,CAAI,EAarB,EAAO,CAClB,MAAO,EAAa,IAA0B,EAAG,cAAc,IAAI,WAAW,OAAQ,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EACjH,QAAS,EAAa,IAAqB,EAAG,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EAC3G,OAAQ,EAAa,IACnB,EAAG,cAAc,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAExF,OAAO,EAAa,EAAc,EAA8B,CAC9D,EAAG,cAAc,IAAI,YAAY,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,GAAO,GAAG,CAAK,CAAC,CAAC,CACvG,EAEA,MAAM,EAAa,EAAoB,CACrC,EAAG,cAAc,CAAK,CACxB,EACA,OAAQ,EAAa,EAAgB,IACnC,EAAG,cAAc,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EACtE,OAAQ,EAAa,IAAqB,EAAG,cAAc,IAAI,MAAM,QAAS,CAAE,QAAS,GAAM,GAAG,CAAK,CAAC,CAAC,EAEzG,UAAW,EAAa,EAAc,IACpC,EAAG,cAAc,IAAI,cAAc,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EACxF,SAAU,EAAa,IACrB,EAAG,cAAc,IAAI,cAAc,UAAW,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAC7F,OAAQ,EAAa,IACnB,EAAG,cAAc,IAAI,cAAc,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAE3F,OAAQ,EAAa,EAAc,IACjC,EAAG,cAAc,IAAI,WAAW,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EACrF,aAAc,EAAa,IACzB,EAAG,cAAc,EAAmB,cAAe,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAClG,cAAe,EAAa,IAC1B,EAAG,cAAc,EAAmB,eAAgB,CAAE,QAAS,GAAO,GAAG,CAAK,CAAC,CAAC,EAClF,cAAe,EAAa,IAC1B,EAAG,cAAc,EAAmB,eAAgB,CAAE,QAAS,GAAO,GAAG,CAAK,CAAC,CAAC,EAClF,WAAY,EAAa,IACvB,EAAG,cAAc,EAAmB,YAAa,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAChG,QAAS,EAAa,IACpB,EAAG,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAEpF,MAAM,EAAa,EAAc,EAAwB,CACnD,OAAO,WAAe,IACxB,EAAG,cAAc,IAAI,WAAW,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,EAEnF,EAAG,cAAc,IAAI,YAAY,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,CAAK,CAAC,CAAC,CAExF,CACF"}
@@ -1,2 +0,0 @@
1
- function e(e,t,n){for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null}function t(e,t,n){return Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t)}function n(n){return{query:e=>n.querySelector(e),queryAll:e=>Array.from(n.querySelectorAll(e)),queryAllByTestId:e=>Array.from(n.querySelectorAll(`[data-testid="${e}"]`)),queryAllByText:(e,r=`*`)=>t(n,e,r),queryByTestId:e=>n.querySelector(`[data-testid="${e}"]`),queryByText:(t,r=`*`)=>e(n,t,r)}}exports.queryAllByText=t,exports.queryByText=e,exports.within=n;
2
- //# sourceMappingURL=query.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.cjs","names":[],"sources":["../../src/testing/query.ts"],"sourcesContent":["/**\n * DOM query helpers for test environments.\n */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any DOM element — see {@link within} */\nexport interface QueryScope {\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nexport function queryByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E | null {\n for (const el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n}\n\nexport function queryAllByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E[] {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to any element — useful for slotted/light DOM content.\n *\n * @example\n * const panel = fixture.query('.panel')!;\n * const { query } = within(panel);\n * expect(query('.title')?.textContent).toBe('Hello');\n */\nexport function within(element: Element): QueryScope {\n return {\n query: <E extends Element = Element>(selector: string) => element.querySelector<E>(selector),\n queryAll: <E extends Element = Element>(selector: string) => Array.from(element.querySelectorAll<E>(selector)),\n queryAllByTestId: <E extends Element = Element>(testId: string) =>\n Array.from(element.querySelectorAll<E>(`[data-testid=\"${testId}\"]`)),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(element, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) =>\n element.querySelector<E>(`[data-testid=\"${testId}\"]`),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(element, text, selector),\n };\n}\n"],"mappings":"AAkBA,SAAgB,EACd,EACA,EACA,EACU,CACV,IAAK,IAAM,KAAM,EAAK,iBAAoB,CAAQ,EAChD,GAAI,EAAG,aAAa,KAAK,IAAM,EAAM,OAAO,EAG9C,OAAO,IACT,CAEA,SAAgB,EACd,EACA,EACA,EACK,CACL,OAAO,MAAM,KAAK,EAAK,iBAAoB,CAAQ,CAAC,CAAC,CAAC,OAAQ,GAAO,EAAG,aAAa,KAAK,IAAM,CAAI,CACtG,CAYA,SAAgB,EAAO,EAA8B,CACnD,MAAO,CACL,MAAqC,GAAqB,EAAQ,cAAiB,CAAQ,EAC3F,SAAwC,GAAqB,MAAM,KAAK,EAAQ,iBAAoB,CAAQ,CAAC,EAC7G,iBAAgD,GAC9C,MAAM,KAAK,EAAQ,iBAAoB,iBAAiB,EAAO,GAAG,CAAC,EACrE,gBAA8C,EAAc,EAAW,MACrE,EAAkB,EAAS,EAAM,CAAQ,EAC3C,cAA6C,GAC3C,EAAQ,cAAiB,iBAAiB,EAAO,GAAG,EACtD,aAA2C,EAAc,EAAW,MAAQ,EAAe,EAAS,EAAM,CAAQ,CACpH,CACF"}
@@ -1,24 +0,0 @@
1
- /**
2
- * DOM query helpers for test environments.
3
- */
4
- /** Scoped query helpers for any DOM element — see {@link within} */
5
- export interface QueryScope {
6
- query<E extends Element = Element>(selector: string): E | null;
7
- queryAll<E extends Element = Element>(selector: string): E[];
8
- queryByText<E extends Element = Element>(text: string, selector?: string): E | null;
9
- queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];
10
- queryByTestId<E extends Element = Element>(testId: string): E | null;
11
- queryAllByTestId<E extends Element = Element>(testId: string): E[];
12
- }
13
- export declare function queryByText<E extends Element = Element>(root: Element | ShadowRoot, text: string, selector: string): E | null;
14
- export declare function queryAllByText<E extends Element = Element>(root: Element | ShadowRoot, text: string, selector: string): E[];
15
- /**
16
- * Create query helpers scoped to any element — useful for slotted/light DOM content.
17
- *
18
- * @example
19
- * const panel = fixture.query('.panel')!;
20
- * const { query } = within(panel);
21
- * expect(query('.title')?.textContent).toBe('Hello');
22
- */
23
- export declare function within(element: Element): QueryScope;
24
- //# sourceMappingURL=query.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/testing/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IAC/D,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAC7D,WAAW,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IACpF,cAAc,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAClF,aAAa,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IACrE,gBAAgB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;CACpE;AAID,wBAAgB,WAAW,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EACrD,IAAI,EAAE,OAAO,GAAG,UAAU,EAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,CAAC,GAAG,IAAI,CAMV;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EACxD,IAAI,EAAE,OAAO,GAAG,UAAU,EAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,CAAC,EAAE,CAEL;AAID;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAYnD"}
@@ -1,2 +0,0 @@
1
- function e(e,t,n){for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null}function t(e,t,n){return Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t)}function n(n){return{query:e=>n.querySelector(e),queryAll:e=>Array.from(n.querySelectorAll(e)),queryAllByTestId:e=>Array.from(n.querySelectorAll(`[data-testid="${e}"]`)),queryAllByText:(e,r=`*`)=>t(n,e,r),queryByTestId:e=>n.querySelector(`[data-testid="${e}"]`),queryByText:(t,r=`*`)=>e(n,t,r)}}export{t as queryAllByText,e as queryByText,n as within};
2
- //# sourceMappingURL=query.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query.js","names":[],"sources":["../../src/testing/query.ts"],"sourcesContent":["/**\n * DOM query helpers for test environments.\n */\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Scoped query helpers for any DOM element — see {@link within} */\nexport interface QueryScope {\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nexport function queryByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E | null {\n for (const el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n}\n\nexport function queryAllByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E[] {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Create query helpers scoped to any element — useful for slotted/light DOM content.\n *\n * @example\n * const panel = fixture.query('.panel')!;\n * const { query } = within(panel);\n * expect(query('.title')?.textContent).toBe('Hello');\n */\nexport function within(element: Element): QueryScope {\n return {\n query: <E extends Element = Element>(selector: string) => element.querySelector<E>(selector),\n queryAll: <E extends Element = Element>(selector: string) => Array.from(element.querySelectorAll<E>(selector)),\n queryAllByTestId: <E extends Element = Element>(testId: string) =>\n Array.from(element.querySelectorAll<E>(`[data-testid=\"${testId}\"]`)),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(element, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) =>\n element.querySelector<E>(`[data-testid=\"${testId}\"]`),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(element, text, selector),\n };\n}\n"],"mappings":"AAkBA,SAAgB,EACd,EACA,EACA,EACU,CACV,IAAK,IAAM,KAAM,EAAK,iBAAoB,CAAQ,EAChD,GAAI,EAAG,aAAa,KAAK,IAAM,EAAM,OAAO,EAG9C,OAAO,IACT,CAEA,SAAgB,EACd,EACA,EACA,EACK,CACL,OAAO,MAAM,KAAK,EAAK,iBAAoB,CAAQ,CAAC,CAAC,CAAC,OAAQ,GAAO,EAAG,aAAa,KAAK,IAAM,CAAI,CACtG,CAYA,SAAgB,EAAO,EAA8B,CACnD,MAAO,CACL,MAAqC,GAAqB,EAAQ,cAAiB,CAAQ,EAC3F,SAAwC,GAAqB,MAAM,KAAK,EAAQ,iBAAoB,CAAQ,CAAC,EAC7G,iBAAgD,GAC9C,MAAM,KAAK,EAAQ,iBAAoB,iBAAiB,EAAO,GAAG,CAAC,EACrE,gBAA8C,EAAc,EAAW,MACrE,EAAkB,EAAS,EAAM,CAAQ,EAC3C,cAA6C,GAC3C,EAAQ,cAAiB,iBAAiB,EAAO,GAAG,EACtD,aAA2C,EAAc,EAAW,MAAQ,EAAe,EAAS,EAAM,CAAQ,CACpH,CACF"}
@@ -1,2 +0,0 @@
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
- //# sourceMappingURL=testing.cjs.map
@@ -1 +0,0 @@
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"}
@@ -1,32 +0,0 @@
1
- /**
2
- * Testing utilities for Ore components
3
- *
4
- * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)
5
- *
6
- * This barrel re-exports the full testing API for convenience.
7
- * For tree-shaking, import directly from the focused sub-modules.
8
- */
9
- export { fire, createPointerEvent } from './events';
10
- export { FLUSH_DEEP, flush, type FlushOptions } from './flush';
11
- export { walkFlatTree } from './dom';
12
- export { installFormInternalsPolyfill } from './form-internals-polyfill';
13
- export { user } from './interactions';
14
- export { cleanup, mock, mount, mountComponent, type Fixture, type MountOptions, type MountSetup } from './mount';
15
- export { within, type QueryScope } from './query';
16
- export { waitFor, waitForEvent, type WaitOptions } from './wait';
17
- export { renderHook, type HookFixture } from './render-hook';
18
- /**
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.
24
- *
25
- * @example
26
- * // vitest.setup.ts
27
- * import { afterEach } from 'vitest';
28
- * import { install } from '@vielzeug/ore/testing';
29
- * install(afterEach);
30
- */
31
- export declare function install(afterEachHook: (fn: () => void) => void): void;
32
- //# sourceMappingURL=testing.d.ts.map
@@ -1 +0,0 @@
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"}
@@ -1,2 +0,0 @@
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
- //# sourceMappingURL=testing.js.map
@@ -1 +0,0 @@
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"}
@@ -1,2 +0,0 @@
1
- const e=require("../errors.cjs");async function t(t,{interval:n=50,message:r,timeout:i=1e3}={}){let a=Date.now()+i,o,s=async()=>{try{let e=await t();return e===void 0||!!e}catch(e){return o=e,!1}};for(;Date.now()<a;){if(await s())return;await new Promise(e=>setTimeout(e,n))}if(await s())return;let c=r??`waitFor timed out after ${i}ms`;throw o instanceof Error?(o.message=`${c}\n${o.message}`,o):new e.OreTimeoutError(o==null?c:`${c}\nCause: ${o}`)}function n(t,n,r=1e3){return new Promise((i,a)=>{let o=e=>{clearTimeout(s),i(e)},s=setTimeout(()=>{t.removeEventListener(n,o),a(new e.OreTimeoutError(`waitForEvent: "${n}" timed out after ${r}ms`))},r);t.addEventListener(n,o,{once:!0})})}exports.waitFor=t,exports.waitForEvent=n;
2
- //# sourceMappingURL=wait.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"wait.cjs","names":[],"sources":["../../src/testing/wait.ts"],"sourcesContent":["/**\n * Async waiting utilities for test environments.\n */\n\nimport { OreTimeoutError } from '../errors';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface WaitOptions {\n /** Maximum wait time in ms (default: 1000) */\n timeout?: number;\n /** Polling interval in ms (default: 50) */\n interval?: number;\n /** Message included in timeout error */\n message?: string;\n}\n\n// ─── API ─────────────────────────────────────────────────────────────────────\n\n/**\n * Poll until a callback returns truthy (or void) without throwing.\n * Supports both boolean conditions and `expect()` assertions.\n *\n * - Returns truthy → success\n * - Returns `undefined` (e.g. bare `expect()` call) → success\n * - Returns falsy value → retry\n * - Throws → retry, re-throw original error on timeout\n *\n * @example\n * await waitFor(() => query('.status')?.textContent === 'loaded');\n * await waitFor(() => expect(count).toBe(3));\n */\nexport async function waitFor(\n fn: () => unknown,\n { interval = 50, message, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n const attempt = async (): Promise<boolean> => {\n try {\n const result = await fn();\n\n return result === undefined || !!result;\n } catch (e) {\n lastError = e;\n\n return false;\n }\n };\n\n while (Date.now() < deadline) {\n if (await attempt()) return;\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n if (await attempt()) return;\n\n const base = message ?? `waitFor timed out after ${timeout}ms`;\n\n if (lastError instanceof Error) {\n lastError.message = `${base}\\n${lastError.message}`;\n throw lastError;\n }\n\n throw new OreTimeoutError(lastError != null ? `${base}\\nCause: ${lastError}` : base);\n}\n\n/**\n * Resolve when the target element emits the given event.\n *\n * @example\n * const promise = waitForEvent(el, 'change');\n * fire.click(trigger);\n * const event = await promise;\n */\nexport function waitForEvent<T extends Event = Event>(element: Element, name: string, timeout = 1000): Promise<T> {\n return new Promise((resolve, reject) => {\n const onEvent = (e: Event): void => {\n clearTimeout(timer);\n resolve(e as T);\n };\n const timer = setTimeout(() => {\n element.removeEventListener(name, onEvent);\n reject(new OreTimeoutError(`waitForEvent: \"${name}\" timed out after ${timeout}ms`));\n }, timeout);\n\n element.addEventListener(name, onEvent, { once: true });\n });\n}\n"],"mappings":"iCAgCA,eAAsB,EACpB,EACA,CAAE,WAAW,GAAI,UAAS,UAAU,KAAsB,CAAC,EAC5C,CACf,IAAM,EAAW,KAAK,IAAI,EAAI,EAC1B,EAEE,EAAU,SAA8B,CAC5C,GAAI,CACF,IAAM,EAAS,MAAM,EAAG,EAExB,OAAO,IAAW,IAAA,IAAa,CAAC,CAAC,CACnC,OAAS,EAAG,CAGV,MAFA,GAAY,EAEL,EACT,CACF,EAEA,KAAO,KAAK,IAAI,EAAI,GAAU,CAC5B,GAAI,MAAM,EAAQ,EAAG,OAErB,MAAM,IAAI,QAAS,GAAM,WAAW,EAAG,CAAQ,CAAC,CAClD,CAEA,GAAI,MAAM,EAAQ,EAAG,OAErB,IAAM,EAAO,GAAW,2BAA2B,EAAQ,IAO3D,MALI,aAAqB,OACvB,EAAU,QAAU,GAAG,EAAK,IAAI,EAAU,UACpC,GAGF,IAAI,EAAA,gBAAgB,GAAa,KAAwC,EAAjC,GAAG,EAAK,WAAW,GAAkB,CACrF,CAUA,SAAgB,EAAsC,EAAkB,EAAc,EAAU,IAAkB,CAChH,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,IAAM,EAAW,GAAmB,CAClC,aAAa,CAAK,EAClB,EAAQ,CAAM,CAChB,EACM,EAAQ,eAAiB,CAC7B,EAAQ,oBAAoB,EAAM,CAAO,EACzC,EAAO,IAAI,EAAA,gBAAgB,kBAAkB,EAAK,oBAAoB,EAAQ,GAAG,CAAC,CACpF,EAAG,CAAO,EAEV,EAAQ,iBAAiB,EAAM,EAAS,CAAE,KAAM,EAAK,CAAC,CACxD,CAAC,CACH"}