@vielzeug/ore 1.2.2 → 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 (153) 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/props.cjs.map +1 -1
  62. package/dist/props.d.ts +12 -0
  63. package/dist/props.d.ts.map +1 -1
  64. package/dist/props.js.map +1 -1
  65. package/dist/runtime.cjs +1 -1
  66. package/dist/runtime.cjs.map +1 -1
  67. package/dist/runtime.d.ts.map +1 -1
  68. package/dist/runtime.js +1 -1
  69. package/dist/runtime.js.map +1 -1
  70. package/dist/slots.cjs +1 -1
  71. package/dist/slots.cjs.map +1 -1
  72. package/dist/slots.d.ts.map +1 -1
  73. package/dist/slots.js +1 -1
  74. package/dist/slots.js.map +1 -1
  75. package/dist/template/bindings.cjs +1 -1
  76. package/dist/template/bindings.cjs.map +1 -1
  77. package/dist/template/bindings.d.ts.map +1 -1
  78. package/dist/template/bindings.js +1 -1
  79. package/dist/template/bindings.js.map +1 -1
  80. package/dist/template/instantiator.cjs.map +1 -1
  81. package/dist/template/instantiator.d.ts.map +1 -1
  82. package/dist/template/instantiator.js.map +1 -1
  83. package/dist/testing/flush.cjs +1 -1
  84. package/dist/testing/flush.cjs.map +1 -1
  85. package/dist/testing/flush.d.ts +30 -26
  86. package/dist/testing/flush.d.ts.map +1 -1
  87. package/dist/testing/flush.js +1 -1
  88. package/dist/testing/flush.js.map +1 -1
  89. package/dist/testing/index.d.ts +30 -1
  90. package/dist/testing/index.d.ts.map +1 -1
  91. package/dist/testing/interactions.cjs +1 -1
  92. package/dist/testing/interactions.cjs.map +1 -1
  93. package/dist/testing/interactions.d.ts.map +1 -1
  94. package/dist/testing/interactions.js +1 -1
  95. package/dist/testing/interactions.js.map +1 -1
  96. package/dist/testing/mount.cjs +1 -1
  97. package/dist/testing/mount.cjs.map +1 -1
  98. package/dist/testing/mount.d.ts +8 -14
  99. package/dist/testing/mount.d.ts.map +1 -1
  100. package/dist/testing/mount.js +1 -1
  101. package/dist/testing/mount.js.map +1 -1
  102. package/dist/testing/render-hook.cjs +1 -1
  103. package/dist/testing/render-hook.js +1 -1
  104. package/dist/testing.cjs +2 -1
  105. package/dist/testing.cjs.map +1 -0
  106. package/dist/testing.js +2 -1
  107. package/dist/testing.js.map +1 -0
  108. package/dist/utils/aria.cjs.map +1 -1
  109. package/dist/utils/aria.d.ts +1 -1
  110. package/dist/utils/aria.js.map +1 -1
  111. package/dist/utils/dom.cjs +1 -1
  112. package/dist/utils/dom.cjs.map +1 -1
  113. package/dist/utils/dom.d.ts +36 -0
  114. package/dist/utils/dom.d.ts.map +1 -1
  115. package/dist/utils/dom.js +1 -1
  116. package/dist/utils/dom.js.map +1 -1
  117. package/dist/utils/id.cjs +1 -1
  118. package/dist/utils/id.cjs.map +1 -1
  119. package/dist/utils/id.d.ts +11 -2
  120. package/dist/utils/id.d.ts.map +1 -1
  121. package/dist/utils/id.js +1 -1
  122. package/dist/utils/id.js.map +1 -1
  123. package/package.json +4 -9
  124. package/dist/devtools.cjs +0 -2
  125. package/dist/devtools.cjs.map +0 -1
  126. package/dist/devtools.d.ts +0 -32
  127. package/dist/devtools.d.ts.map +0 -1
  128. package/dist/devtools.js +0 -2
  129. package/dist/devtools.js.map +0 -1
  130. package/dist/testing/events.cjs +0 -2
  131. package/dist/testing/events.cjs.map +0 -1
  132. package/dist/testing/events.d.ts +0 -37
  133. package/dist/testing/events.d.ts.map +0 -1
  134. package/dist/testing/events.js +0 -2
  135. package/dist/testing/events.js.map +0 -1
  136. package/dist/testing/query.cjs +0 -2
  137. package/dist/testing/query.cjs.map +0 -1
  138. package/dist/testing/query.d.ts +0 -24
  139. package/dist/testing/query.d.ts.map +0 -1
  140. package/dist/testing/query.js +0 -2
  141. package/dist/testing/query.js.map +0 -1
  142. package/dist/testing/testing.cjs +0 -2
  143. package/dist/testing/testing.cjs.map +0 -1
  144. package/dist/testing/testing.d.ts +0 -32
  145. package/dist/testing/testing.d.ts.map +0 -1
  146. package/dist/testing/testing.js +0 -2
  147. package/dist/testing/testing.js.map +0 -1
  148. package/dist/testing/wait.cjs +0 -2
  149. package/dist/testing/wait.cjs.map +0 -1
  150. package/dist/testing/wait.d.ts +0 -35
  151. package/dist/testing/wait.d.ts.map +0 -1
  152. package/dist/testing/wait.js +0 -2
  153. package/dist/testing/wait.js.map +0 -1
@@ -1,2 +1,2 @@
1
- const e=require("../_dev.cjs"),t=require("../errors.cjs"),n=require("../types/bindings.cjs"),r=require("../utils/dom.cjs");let i=require("@vielzeug/ripple");var a=null,o=!1,s=e=>{a=e,e||(o=!1)},c=()=>{a=null,o=!1},l=t=>a?a(t):(t&&!o&&(o=!0,e.warn(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),u=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function d(e){if(typeof e==`function`){let t=(0,i.computed)(e);return n.createDirectiveResult((e,n)=>{n(()=>t.dispose()),d(t).mount(e,n)})}return n.createDirectiveResult((n,a)=>{let o=n.parentNode;t.invariant(o,`raw() anchor comment has no parent node`);let s=document.createComment(`raw/end`);if(o.insertBefore(s,n.nextSibling),(0,i.isReactive)(e)){let t=[],n=e,c=(0,i.effect)(()=>{r.removeNodes(t),t=u(l(n.value),o,s)});a(()=>c.dispose()),a(()=>{r.removeNodes(t),s.remove()})}else u(l(e),o,s),a(()=>s.remove())})}exports._resetRawSanitizer=c,exports.raw=d,exports.setRawSanitizer=s;
1
+ const e=require("../_dev.cjs"),t=require("../errors.cjs"),n=require("../types/bindings.cjs"),r=require("../utils/dom.cjs");let i=require("@vielzeug/ripple");var a=null,o=!1,s=e=>{a=e,e||(o=!1)},c=()=>{a=null,o=!1},l=t=>a?a(t):(t&&!o&&(o=!0,e.warn(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),u=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function d(e){if(typeof e==`function`){let t=(0,i.computed)(e);return n.createDirectiveResult((e,n)=>{n(()=>t.dispose()),d(t).mount(e,n)})}return n.createDirectiveResult((n,a)=>{let o=n.parentNode;t.invariant(o,`raw() anchor comment has no parent node`);let s=document.createComment(`raw/end`);if(o.insertBefore(s,n.nextSibling),(0,i.isReactive)(e)){let t=r.createReplaceableSlot(),n=e,c=(0,i.effect)(()=>{t.clear(),t.setNodes(u(l(n.value),o,s))});a(()=>c.dispose()),a(()=>{t.clear(),s.remove()})}else u(l(e),o,s),a(()=>s.remove())})}exports._resetRawSanitizer=c,exports.raw=d,exports.setRawSanitizer=s;
2
2
  //# sourceMappingURL=raw.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"raw.cjs","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { removeNodes } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function raw(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'raw() anchor comment has no parent node');\n\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n let currentNodes: Node[] = [];\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n removeNodes(currentNodes);\n currentNodes = parseRaw(sanitize(src.value), parent, endMarker);\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n removeNodes(currentNodes);\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"6JASA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EAAA,KACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,GAAA,EAAA,EAAA,SAAA,CAAa,CAAK,EAExB,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,yCAAyC,EAE3D,IAAM,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,GAEjD,EAAA,EAAA,WAAA,CAAe,CAAK,EAAG,CACrB,IAAI,EAAuB,CAAC,EACtB,EAAM,EAEN,GAAA,EAAA,EAAA,OAAA,KAAuB,CAC3B,EAAA,YAAY,CAAY,EACxB,EAAe,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAA,YAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
1
+ {"version":3,"file":"raw.cjs","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { createReplaceableSlot } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function raw(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'raw() anchor comment has no parent node');\n\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n const slot = createReplaceableSlot();\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseRaw(sanitize(src.value), parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"6JASA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EAAA,KACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,GAAA,EAAA,EAAA,SAAA,CAAa,CAAK,EAExB,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,yCAAyC,EAE3D,IAAM,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,GAEjD,EAAA,EAAA,WAAA,CAAe,CAAK,EAAG,CACrB,IAAM,EAAO,EAAA,sBAAsB,EAC7B,EAAM,EAEN,GAAA,EAAA,EAAA,OAAA,KAAuB,CAC3B,EAAK,MAAM,EACX,EAAK,SAAS,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAAC,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
@@ -1,2 +1,2 @@
1
- import{warn as e}from"../_dev.js";import{invariant as t}from"../errors.js";import{createDirectiveResult as n}from"../types/bindings.js";import{removeNodes as r}from"../utils/dom.js";import{computed as i,effect as a,isReactive as o}from"@vielzeug/ripple";var s=null,c=!1,l=e=>{s=e,e||(c=!1)},u=()=>{s=null,c=!1},d=t=>s?s(t):(t&&!c&&(c=!0,e(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),f=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function p(e){if(typeof e==`function`){let t=i(e);return n((e,n)=>{n(()=>t.dispose()),p(t).mount(e,n)})}return n((n,i)=>{let s=n.parentNode;t(s,`raw() anchor comment has no parent node`);let c=document.createComment(`raw/end`);if(s.insertBefore(c,n.nextSibling),o(e)){let t=[],n=e,o=a(()=>{r(t),t=f(d(n.value),s,c)});i(()=>o.dispose()),i(()=>{r(t),c.remove()})}else f(d(e),s,c),i(()=>c.remove())})}export{u as _resetRawSanitizer,p as raw,l as setRawSanitizer};
1
+ import{warn as e}from"../_dev.js";import{invariant as t}from"../errors.js";import{createDirectiveResult as n}from"../types/bindings.js";import{createReplaceableSlot as r}from"../utils/dom.js";import{computed as i,effect as a,isReactive as o}from"@vielzeug/ripple";var s=null,c=!1,l=e=>{s=e,e||(c=!1)},u=()=>{s=null,c=!1},d=t=>s?s(t):(t&&!c&&(c=!0,e(`raw() was called without a sanitizer registered. Passing user-supplied HTML directly to raw() is an XSS risk. Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).`)),t),f=(e,t,n)=>{let r=document.createElement(`template`);r.innerHTML=e;let i=Array.from(r.content.cloneNode(!0).childNodes);for(let e of i)t.insertBefore(e,n);return i};function p(e){if(typeof e==`function`){let t=i(e);return n((e,n)=>{n(()=>t.dispose()),p(t).mount(e,n)})}return n((n,i)=>{let s=n.parentNode;t(s,`raw() anchor comment has no parent node`);let c=document.createComment(`raw/end`);if(s.insertBefore(c,n.nextSibling),o(e)){let t=r(),n=e,o=a(()=>{t.clear(),t.setNodes(f(d(n.value),s,c))});i(()=>o.dispose()),i(()=>{t.clear(),c.remove()})}else f(d(e),s,c),i(()=>c.remove())})}export{u as _resetRawSanitizer,p as raw,l as setRawSanitizer};
2
2
  //# sourceMappingURL=raw.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"raw.js","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { removeNodes } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function raw(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'raw() anchor comment has no parent node');\n\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n let currentNodes: Node[] = [];\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n removeNodes(currentNodes);\n currentNodes = parseRaw(sanitize(src.value), parent, endMarker);\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n removeNodes(currentNodes);\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"8PASA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,EAAI,EAAS,CAAK,EAExB,OAAO,GAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,yCAAyC,EAE3D,IAAM,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,EAE7C,EAAW,CAAK,EAAG,CACrB,IAAI,EAAuB,CAAC,EACtB,EAAM,EAEN,EAAO,MAAgB,CAC3B,EAAY,CAAY,EACxB,EAAe,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
1
+ {"version":3,"file":"raw.js","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, type Signal } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult } from '../types/bindings';\nimport { createReplaceableSlot } from '../utils/dom';\n\ntype RawSanitizer = (html: string) => string;\n\nlet _sanitizer: RawSanitizer | null = null;\nlet _warned = false;\n\nexport const setRawSanitizer = (fn: RawSanitizer | null): void => {\n _sanitizer = fn;\n\n if (!fn) _warned = false;\n};\n\n/** @internal */\nexport const _resetRawSanitizer = (): void => {\n _sanitizer = null;\n _warned = false;\n};\n\nconst sanitize = (value: string): string => {\n if (_sanitizer) return _sanitizer(value);\n\n if (value && !_warned) {\n _warned = true;\n warn(\n 'raw() was called without a sanitizer registered. ' +\n 'Passing user-supplied HTML directly to raw() is an XSS risk. ' +\n 'Register a sanitizer with setRawSanitizer() — e.g. setRawSanitizer(DOMPURIFY.sanitize).',\n );\n }\n\n return value;\n};\n\nconst parseRaw = (html: string, parent: ParentNode, insertBefore: Node): Node[] => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n const nodes = Array.from(tpl.content.cloneNode(true).childNodes);\n\n for (const node of nodes) parent.insertBefore(node, insertBefore);\n\n return nodes;\n};\n\n/**\n * Renders a trusted HTML string without escaping as a DirectiveResult.\n * Only use with content you control — passing user-supplied strings\n * directly is an XSS risk. Register a sanitizer with setRawSanitizer()\n * to add a runtime safety net.\n *\n * Supports static strings, signals, and getter functions `() => string`.\n * When reactive, the DOM is updated in-place whenever the value changes.\n */\nexport function raw(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult {\n if (typeof value === 'function') {\n const c = computed(value);\n\n return createDirectiveResult((anchor, registerCleanup) => {\n registerCleanup(() => c.dispose());\n raw(c).mount(anchor, registerCleanup);\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const parent = anchor.parentNode;\n\n invariant(parent, 'raw() anchor comment has no parent node');\n\n const endMarker = document.createComment('raw/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n if (isReactive(value)) {\n const slot = createReplaceableSlot();\n const src = value as Readable<string>;\n\n const stop = rawEffect(() => {\n slot.clear();\n slot.setNodes(parseRaw(sanitize(src.value), parent, endMarker));\n });\n\n registerCleanup(() => stop.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n } else {\n parseRaw(sanitize(value), parent, endMarker);\n\n registerCleanup(() => endMarker.remove());\n }\n });\n}\n"],"mappings":"wQASA,IAAI,EAAkC,KAClC,EAAU,GAED,EAAmB,GAAkC,CAChE,EAAa,EAER,IAAI,EAAU,GACrB,EAGa,MAAiC,CAC5C,EAAa,KACb,EAAU,EACZ,EAEM,EAAY,GACZ,EAAmB,EAAW,CAAK,GAEnC,GAAS,CAAC,IACZ,EAAU,GACV,EACE,uMAGF,GAGK,GAGH,GAAY,EAAc,EAAoB,IAA+B,CACjF,IAAM,EAAM,SAAS,cAAc,UAAU,EAE7C,EAAI,UAAY,EAEhB,IAAM,EAAQ,MAAM,KAAK,EAAI,QAAQ,UAAU,EAAI,CAAC,CAAC,UAAU,EAE/D,IAAK,IAAM,KAAQ,EAAO,EAAO,aAAa,EAAM,CAAY,EAEhE,OAAO,CACT,EAWA,SAAgB,EAAI,EAAqF,CACvG,GAAI,OAAO,GAAU,WAAY,CAC/B,IAAM,EAAI,EAAS,CAAK,EAExB,OAAO,GAAuB,EAAQ,IAAoB,CACxD,MAAsB,EAAE,QAAQ,CAAC,EACjC,EAAI,CAAC,CAAC,CAAC,MAAM,EAAQ,CAAe,CACtC,CAAC,CACH,CAEA,OAAO,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,yCAAyC,EAE3D,IAAM,EAAY,SAAS,cAAc,SAAS,EAIlD,GAFA,EAAO,aAAa,EAAW,EAAO,WAAW,EAE7C,EAAW,CAAK,EAAG,CACrB,IAAM,EAAO,EAAsB,EAC7B,EAAM,EAEN,EAAO,MAAgB,CAC3B,EAAK,MAAM,EACX,EAAK,SAAS,EAAS,EAAS,EAAI,KAAK,EAAG,EAAQ,CAAS,CAAC,CAChE,CAAC,EAED,MAAsB,EAAK,QAAQ,CAAC,EACpC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,MACE,EAAS,EAAS,CAAK,EAAG,EAAQ,CAAS,EAE3C,MAAsB,EAAU,OAAO,CAAC,CAE5C,CAAC,CACH"}
@@ -1,2 +1,2 @@
1
- const e=require("../utils/dom.cjs");let t=require("@vielzeug/ripple");var n=e=>{let n=typeof e==`function`?e():(0,t.isReactive)(e)?e.value:e;return n==null||n===!1?``:String(n).replace(/[;{}]/g,``)},r=/[;{}]/g,i=i=>(0,t.computed)(()=>{let t=[];for(let[a,o]of Object.entries(i)){let i=n(o);if(!i)continue;let s=e.toKebab(a).replace(r,``);s&&t.push(`${s}:${i}`)}return t.join(`;`)});exports.styleMap=i;
1
+ const e=require("../utils/dom.cjs");let t=require("@vielzeug/ripple");var n=t=>{let n=e.resolveMaybeReactive(t);return n==null||n===!1?``:e.sanitizeCssToken(String(n))},r=r=>(0,t.computed)(()=>{let t=[];for(let[i,a]of Object.entries(r)){let r=n(a);if(!r)continue;let o=e.sanitizeCssToken(e.toKebab(i));o&&t.push(`${o}:${r}`)}return t.join(`;`)});exports.styleMap=r;
2
2
  //# sourceMappingURL=styleMap.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"styleMap.cjs","names":[],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { toKebab } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\nconst toStyleValue = (value: StyleInput): string => {\n const resolved = typeof value === 'function' ? value() : isReactive(value) ? value.value : value;\n\n if (resolved == null || resolved === false) return '';\n\n // Strip characters that can break out of a CSS declaration in inline styles.\n // Semicolons end the current declaration; braces are meaningful in stylesheets\n // but not inline style values and signal injection attempts.\n return String(resolved).replace(/[;{}]/g, '');\n};\n\n// Strip characters that can break out of a CSS declaration in inline styles.\n// This is applied to both property names and values: semicolons end declarations\n// and braces are meaningful in stylesheet rules (but not inline style values).\nconst UNSAFE_CSS_CHARS = /[;{}]/g;\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div :style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = toStyleValue(input);\n\n if (!value) continue;\n\n const safeName = toKebab(name).replace(UNSAFE_CSS_CHARS, '');\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"sEAaA,IAAM,EAAgB,GAA8B,CAClD,IAAM,EAAW,OAAO,GAAU,WAAa,EAAM,GAAA,EAAA,EAAA,WAAA,CAAe,CAAK,EAAI,EAAM,MAAQ,EAO3F,OALI,GAAY,MAAQ,IAAa,GAAc,GAK5C,OAAO,CAAQ,CAAC,CAAC,QAAQ,SAAU,EAAE,CAC9C,EAKM,EAAmB,SAsBZ,EAAY,IACvB,EAAA,EAAA,SAAA,KAAsB,CACpB,IAAM,EAAyB,CAAC,EAEhC,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAM,EAAG,CAClD,IAAM,EAAQ,EAAa,CAAK,EAEhC,GAAI,CAAC,EAAO,SAEZ,IAAM,EAAW,EAAA,QAAQ,CAAI,CAAC,CAAC,QAAQ,EAAkB,EAAE,EAEtD,GAEL,EAAa,KAAK,GAAG,EAAS,GAAG,GAAO,CAC1C,CAEA,OAAO,EAAa,KAAK,GAAG,CAC9B,CAAC"}
1
+ {"version":3,"file":"styleMap.cjs","names":[],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\n\nimport { resolveMaybeReactive, sanitizeCssToken, toKebab } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\nconst toStyleValue = (value: StyleInput): string => {\n const resolved = resolveMaybeReactive(value);\n\n if (resolved == null || resolved === false) return '';\n\n return sanitizeCssToken(String(resolved));\n};\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div :style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = toStyleValue(input);\n\n if (!value) continue;\n\n const safeName = sanitizeCssToken(toKebab(name));\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"sEAaA,IAAM,EAAgB,GAA8B,CAClD,IAAM,EAAW,EAAA,qBAAqB,CAAK,EAI3C,OAFI,GAAY,MAAQ,IAAa,GAAc,GAE5C,EAAA,iBAAiB,OAAO,CAAQ,CAAC,CAC1C,EAsBa,EAAY,IACvB,EAAA,EAAA,SAAA,KAAsB,CACpB,IAAM,EAAyB,CAAC,EAEhC,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAM,EAAG,CAClD,IAAM,EAAQ,EAAa,CAAK,EAEhC,GAAI,CAAC,EAAO,SAEZ,IAAM,EAAW,EAAA,iBAAiB,EAAA,QAAQ,CAAI,CAAC,EAE1C,GAEL,EAAa,KAAK,GAAG,EAAS,GAAG,GAAO,CAC1C,CAEA,OAAO,EAAa,KAAK,GAAG,CAC9B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"styleMap.d.ts","sourceRoot":"","sources":["../../src/directives/styleMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIvE,KAAK,UAAU,GACX,MAAM,GACN,MAAM,GACN,IAAI,GACJ,SAAS,GACT,KAAK,GACL,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,GAClD,QAAQ,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;AAkBzD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,KAAG,QAAQ,CAAC,MAAM,CAkB5E,CAAC"}
1
+ {"version":3,"file":"styleMap.d.ts","sourceRoot":"","sources":["../../src/directives/styleMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI3D,KAAK,UAAU,GACX,MAAM,GACN,MAAM,GACN,IAAI,GACJ,SAAS,GACT,KAAK,GACL,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,GAClD,QAAQ,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;AAUzD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,KAAG,QAAQ,CAAC,MAAM,CAkB5E,CAAC"}
@@ -1,2 +1,2 @@
1
- import{toKebab as e}from"../utils/dom.js";import{computed as t,isReactive as n}from"@vielzeug/ripple";var r=e=>{let t=typeof e==`function`?e():n(e)?e.value:e;return t==null||t===!1?``:String(t).replace(/[;{}]/g,``)},i=/[;{}]/g,a=n=>t(()=>{let t=[];for(let[a,o]of Object.entries(n)){let n=r(o);if(!n)continue;let s=e(a).replace(i,``);s&&t.push(`${s}:${n}`)}return t.join(`;`)});export{a as styleMap};
1
+ import{resolveMaybeReactive as e,sanitizeCssToken as t,toKebab as n}from"../utils/dom.js";import{computed as r}from"@vielzeug/ripple";var i=n=>{let r=e(n);return r==null||r===!1?``:t(String(r))},a=e=>r(()=>{let r=[];for(let[a,o]of Object.entries(e)){let e=i(o);if(!e)continue;let s=t(n(a));s&&r.push(`${s}:${e}`)}return r.join(`;`)});export{a as styleMap};
2
2
  //# sourceMappingURL=styleMap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"styleMap.js","names":[],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { toKebab } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\nconst toStyleValue = (value: StyleInput): string => {\n const resolved = typeof value === 'function' ? value() : isReactive(value) ? value.value : value;\n\n if (resolved == null || resolved === false) return '';\n\n // Strip characters that can break out of a CSS declaration in inline styles.\n // Semicolons end the current declaration; braces are meaningful in stylesheets\n // but not inline style values and signal injection attempts.\n return String(resolved).replace(/[;{}]/g, '');\n};\n\n// Strip characters that can break out of a CSS declaration in inline styles.\n// This is applied to both property names and values: semicolons end declarations\n// and braces are meaningful in stylesheet rules (but not inline style values).\nconst UNSAFE_CSS_CHARS = /[;{}]/g;\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div :style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = toStyleValue(input);\n\n if (!value) continue;\n\n const safeName = toKebab(name).replace(UNSAFE_CSS_CHARS, '');\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"sGAaA,IAAM,EAAgB,GAA8B,CAClD,IAAM,EAAW,OAAO,GAAU,WAAa,EAAM,EAAI,EAAW,CAAK,EAAI,EAAM,MAAQ,EAO3F,OALI,GAAY,MAAQ,IAAa,GAAc,GAK5C,OAAO,CAAQ,CAAC,CAAC,QAAQ,SAAU,EAAE,CAC9C,EAKM,EAAmB,SAsBZ,EAAY,GAChB,MAAe,CACpB,IAAM,EAAyB,CAAC,EAEhC,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAM,EAAG,CAClD,IAAM,EAAQ,EAAa,CAAK,EAEhC,GAAI,CAAC,EAAO,SAEZ,IAAM,EAAW,EAAQ,CAAI,CAAC,CAAC,QAAQ,EAAkB,EAAE,EAEtD,GAEL,EAAa,KAAK,GAAG,EAAS,GAAG,GAAO,CAC1C,CAEA,OAAO,EAAa,KAAK,GAAG,CAC9B,CAAC"}
1
+ {"version":3,"file":"styleMap.js","names":[],"sources":["../../src/directives/styleMap.ts"],"sourcesContent":["import { computed, type Readable } from '@vielzeug/ripple';\n\nimport { resolveMaybeReactive, sanitizeCssToken, toKebab } from '../utils/dom';\n\ntype StyleInput =\n | string\n | number\n | null\n | undefined\n | false\n | (() => string | number | null | undefined | false)\n | Readable<string | number | null | undefined | false>;\n\nconst toStyleValue = (value: StyleInput): string => {\n const resolved = resolveMaybeReactive(value);\n\n if (resolved == null || resolved === false) return '';\n\n return sanitizeCssToken(String(resolved));\n};\n\n/**\n * Builds a reactive inline style string from a style object.\n *\n * Takes a record of CSS property names (camelCase) with values that can be:\n * - Static strings/numbers\n * - Functions that return strings/numbers\n * - Signals for reactive updates\n *\n * @example\n * ```ts\n * const color = signal('red');\n * const size = signal(16);\n *\n * html`<div :style=${styleMap({\n * backgroundColor: color,\n * width: () => `${size.value}px`,\n * padding: '10px'\n * })}></div>`\n * ```\n */\nexport const styleMap = (record: Record<string, StyleInput>): Readable<string> => {\n return computed(() => {\n const declarations: string[] = [];\n\n for (const [name, input] of Object.entries(record)) {\n const value = toStyleValue(input);\n\n if (!value) continue;\n\n const safeName = sanitizeCssToken(toKebab(name));\n\n if (!safeName) continue;\n\n declarations.push(`${safeName}:${value}`);\n }\n\n return declarations.join(';');\n });\n};\n"],"mappings":"sIAaA,IAAM,EAAgB,GAA8B,CAClD,IAAM,EAAW,EAAqB,CAAK,EAI3C,OAFI,GAAY,MAAQ,IAAa,GAAc,GAE5C,EAAiB,OAAO,CAAQ,CAAC,CAC1C,EAsBa,EAAY,GAChB,MAAe,CACpB,IAAM,EAAyB,CAAC,EAEhC,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,CAAM,EAAG,CAClD,IAAM,EAAQ,EAAa,CAAK,EAEhC,GAAI,CAAC,EAAO,SAEZ,IAAM,EAAW,EAAiB,EAAQ,CAAI,CAAC,EAE1C,GAEL,EAAa,KAAK,GAAG,EAAS,GAAG,GAAO,CAC1C,CAEA,OAAO,EAAa,KAAK,GAAG,CAC9B,CAAC"}
@@ -1,2 +1,2 @@
1
- const e=require("../errors.cjs"),t=require("../types/bindings.cjs"),n=require("../utils/dom.cjs");let r=require("@vielzeug/ripple");var i=`when() anchor comment has no parent node`,a=(e,t,n,r)=>e.mount(t,n,r);function o(o,s,c){return typeof o!=`function`&&!(0,r.isReactive)(o)?t.createDirectiveResult((r,l)=>{let u=o?s():c?c():null;if(!u||!t.isHtmlResult(u))return;let d=r.parentNode;e.invariant(d,i);let f=a(u,d,r,l);l(()=>n.removeNodes(f))}):t.createDirectiveResult((l,u)=>{let d=typeof o==`function`?(0,r.computed)(o):null,f=d??o;d&&u(()=>d.dispose());let p=l.parentNode;e.invariant(p,i);let m=document.createComment(`when/end`);p.insertBefore(m,l.nextSibling);let h=[],g=[],_=(0,r.effect)(()=>{let e=f.value;n.runAll(g),n.removeNodes(h),g=[],h=[];let i=e?s():c?c():null;if(!i||!t.isHtmlResult(i))return;let o=[];h=(0,r.untrack)(()=>a(i,p,m,e=>o.push(e))),g=o});u(()=>_.dispose()),u(()=>{n.runAll(g),n.removeNodes(h),m.remove()})})}exports.when=o;
1
+ const e=require("../errors.cjs"),t=require("../types/bindings.cjs"),n=require("../utils/dom.cjs");let r=require("@vielzeug/ripple");var i=`when() anchor comment has no parent node`,a=(e,t,n,r)=>e.mount(t,n,r);function o(o,s,c){return typeof o!=`function`&&!(0,r.isReactive)(o)?t.createDirectiveResult((r,l)=>{let u=o?s():c?c():null;if(!u||!t.isHtmlResult(u))return;let d=r.parentNode;e.invariant(d,i);let f=a(u,d,r,l);l(()=>n.removeNodes(f))}):t.createDirectiveResult((l,u)=>{let d=typeof o==`function`?(0,r.computed)(o):null,f=d??o;d&&u(()=>d.dispose());let p=l.parentNode;e.invariant(p,i);let m=document.createComment(`when/end`);p.insertBefore(m,l.nextSibling);let h=n.createReplaceableSlot(),g=(0,r.effect)(()=>{let e=f.value;h.clear();let n=e?s():c?c():null;!n||!t.isHtmlResult(n)||h.setNodes((0,r.untrack)(()=>a(n,p,m,h.registerCleanup)))});u(()=>g.dispose()),u(()=>{h.clear(),m.remove()})})}exports.when=o;
2
2
  //# sourceMappingURL=when.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"when.cjs","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, untrack } from '@vielzeug/ripple';\n\nimport type { RegisterCleanup } from '../template';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { removeNodes, runAll } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = mountBranch(branch, parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let currentNodes: Node[] = [];\n let currentCleanups: (() => void)[] = [];\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n runAll(currentCleanups);\n removeNodes(currentNodes);\n currentCleanups = [];\n currentNodes = [];\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const branchCleanups: (() => void)[] = [];\n\n currentNodes = untrack(() => mountBranch(branch, parent, endMarker, (fn) => branchCleanups.push(fn)));\n currentCleanups = branchCleanups;\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n runAll(currentCleanups);\n removeNodes(currentNodes);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"oIAYA,IAAM,EAAgB,2CAEhB,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,EAAA,EAAA,EAAA,WAAA,CAAY,CAAS,EACnD,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAQ,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAA,YAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,YAAA,EAAA,EAAA,SAAA,CAAsB,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAI,EAAuB,CAAC,EACxB,EAAkC,CAAC,EAEjC,GAAA,EAAA,EAAA,OAAA,KAAsB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAA,OAAO,CAAe,EACtB,EAAA,YAAY,CAAY,EACxB,EAAkB,CAAC,EACnB,EAAe,CAAC,EAEhB,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAEnD,GAAI,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,EAAG,OAEtC,IAAM,EAAiC,CAAC,EAExC,GAAA,EAAA,EAAA,QAAA,KAA6B,EAAY,EAAQ,EAAQ,EAAY,GAAO,EAAe,KAAK,CAAE,CAAC,CAAC,EACpG,EAAkB,CACpB,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAA,OAAO,CAAe,EACtB,EAAA,YAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
1
+ {"version":3,"file":"when.cjs","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, untrack } from '@vielzeug/ripple';\n\nimport type { RegisterCleanup } from '../template';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { createReplaceableSlot, removeNodes } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = mountBranch(branch, parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => mountBranch(branch, parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"oIAYA,IAAM,EAAgB,2CAEhB,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,EAAA,EAAA,EAAA,WAAA,CAAY,CAAS,EACnD,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAQ,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAA,YAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,EAAA,uBAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,YAAA,EAAA,EAAA,SAAA,CAAsB,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAEtB,EAAA,UAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAM,EAAO,EAAA,sBAAsB,EAE7B,GAAA,EAAA,EAAA,OAAA,KAAsB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAK,MAAM,EAEX,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAE/C,CAAC,GAAU,CAAC,EAAA,aAAa,CAAM,GAEnC,EAAK,UAAA,EAAA,EAAA,QAAA,KAAuB,EAAY,EAAQ,EAAQ,EAAW,EAAK,eAAe,CAAC,CAAC,CAC3F,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAW,MAAM,kBAAkB,CAAC;AAKrG,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAgB,MAAM,mBAAmB,CAAC;AAG/G,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpD,KAAK,cAAc,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAW5D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,cAAc,EAC5B,KAAK,CAAC,EAAE,MAAM,cAAc,GAC3B,eAAe,CA2DjB"}
1
+ {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAW,MAAM,kBAAkB,CAAC;AAKrG,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAgB,MAAM,mBAAmB,CAAC;AAG/G,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpD,KAAK,cAAc,GAAG,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AAW5D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,cAAc,EAC5B,KAAK,CAAC,EAAE,MAAM,cAAc,GAC3B,eAAe,CAmDjB"}
@@ -1,2 +1,2 @@
1
- import{invariant as e}from"../errors.js";import{createDirectiveResult as t,isHtmlResult as n}from"../types/bindings.js";import{removeNodes as r,runAll as i}from"../utils/dom.js";import{computed as a,effect as o,isReactive as s,untrack as c}from"@vielzeug/ripple";var l=`when() anchor comment has no parent node`,u=(e,t,n,r)=>e.mount(t,n,r);function d(d,f,p){return typeof d!=`function`&&!s(d)?t((t,i)=>{let a=d?f():p?p():null;if(!a||!n(a))return;let o=t.parentNode;e(o,l);let s=u(a,o,t,i);i(()=>r(s))}):t((t,s)=>{let m=typeof d==`function`?a(d):null,h=m??d;m&&s(()=>m.dispose());let g=t.parentNode;e(g,l);let _=document.createComment(`when/end`);g.insertBefore(_,t.nextSibling);let v=[],y=[],b=o(()=>{let e=h.value;i(y),r(v),y=[],v=[];let t=e?f():p?p():null;if(!t||!n(t))return;let a=[];v=c(()=>u(t,g,_,e=>a.push(e))),y=a});s(()=>b.dispose()),s(()=>{i(y),r(v),_.remove()})})}export{d as when};
1
+ import{invariant as e}from"../errors.js";import{createDirectiveResult as t,isHtmlResult as n}from"../types/bindings.js";import{createReplaceableSlot as r,removeNodes as i}from"../utils/dom.js";import{computed as a,effect as o,isReactive as s,untrack as c}from"@vielzeug/ripple";var l=`when() anchor comment has no parent node`,u=(e,t,n,r)=>e.mount(t,n,r);function d(d,f,p){return typeof d!=`function`&&!s(d)?t((t,r)=>{let a=d?f():p?p():null;if(!a||!n(a))return;let o=t.parentNode;e(o,l);let s=u(a,o,t,r);r(()=>i(s))}):t((t,i)=>{let s=typeof d==`function`?a(d):null,m=s??d;s&&i(()=>s.dispose());let h=t.parentNode;e(h,l);let g=document.createComment(`when/end`);h.insertBefore(g,t.nextSibling);let _=r(),v=o(()=>{let e=m.value;_.clear();let t=e?f():p?p():null;!t||!n(t)||_.setNodes(c(()=>u(t,h,g,_.registerCleanup)))});i(()=>v.dispose()),i(()=>{_.clear(),g.remove()})})}export{d as when};
2
2
  //# sourceMappingURL=when.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, untrack } from '@vielzeug/ripple';\n\nimport type { RegisterCleanup } from '../template';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { removeNodes, runAll } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = mountBranch(branch, parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n let currentNodes: Node[] = [];\n let currentCleanups: (() => void)[] = [];\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n runAll(currentCleanups);\n removeNodes(currentNodes);\n currentCleanups = [];\n currentNodes = [];\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const branchCleanups: (() => void)[] = [];\n\n currentNodes = untrack(() => mountBranch(branch, parent, endMarker, (fn) => branchCleanups.push(fn)));\n currentCleanups = branchCleanups;\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n runAll(currentCleanups);\n removeNodes(currentNodes);\n endMarker.remove();\n });\n });\n}\n"],"mappings":"uQAYA,IAAM,EAAgB,2CAEhB,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,CAAC,EAAW,CAAS,EACnD,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,CAAa,EAE/B,IAAM,EAAQ,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,WAAa,EAAS,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAI,EAAuB,CAAC,EACxB,EAAkC,CAAC,EAEjC,EAAM,MAAgB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAO,CAAe,EACtB,EAAY,CAAY,EACxB,EAAkB,CAAC,EACnB,EAAe,CAAC,EAEhB,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAEnD,GAAI,CAAC,GAAU,CAAC,EAAa,CAAM,EAAG,OAEtC,IAAM,EAAiC,CAAC,EAExC,EAAe,MAAc,EAAY,EAAQ,EAAQ,EAAY,GAAO,EAAe,KAAK,CAAE,CAAC,CAAC,EACpG,EAAkB,CACpB,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAO,CAAe,EACtB,EAAY,CAAY,EACxB,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
1
+ {"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, effect as rawEffect, isReactive, type Readable, untrack } from '@vielzeug/ripple';\n\nimport type { RegisterCleanup } from '../template';\n\nimport { invariant } from '../errors';\nimport { createDirectiveResult, type DirectiveResult, type HTMLResult, isHtmlResult } from '../types/bindings';\nimport { createReplaceableSlot, removeNodes } from '../utils/dom';\n\ntype MaybeReactive<T> = T | (() => T) | Readable<T>;\n\ntype WhenRenderable = HTMLResult | null | undefined | false;\n\nconst NO_PARENT_MSG = 'when() anchor comment has no parent node';\n\nconst mountBranch = (\n result: HTMLResult,\n parent: ParentNode,\n insertBefore: Node,\n registerCleanup: RegisterCleanup,\n): Node[] => result.mount(parent, insertBefore, registerCleanup);\n\n/**\n * Conditionally renders one of two branches as a `DirectiveResult`.\n *\n * The condition may be a boolean, signal, or getter function.\n * When the condition changes, the current branch is cleaned up and\n * the new branch is mounted in its place.\n *\n * @example\n * ```ts\n * html`${when(isLoggedIn, () => html`<p>Welcome</p>`, () => html`<p>Log in</p>`)}`\n * ```\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): DirectiveResult {\n if (typeof condition !== 'function' && !isReactive(condition)) {\n return createDirectiveResult((anchor, registerCleanup) => {\n const branch = condition ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const nodes = mountBranch(branch, parent, anchor, registerCleanup);\n\n registerCleanup(() => removeNodes(nodes));\n });\n }\n\n return createDirectiveResult((anchor, registerCleanup) => {\n const ownedComputed = typeof condition === 'function' ? computed(condition as () => boolean) : null;\n const conditionSignal = ownedComputed ?? (condition as Readable<boolean>);\n\n if (ownedComputed) registerCleanup(() => ownedComputed.dispose());\n\n const parent = anchor.parentNode;\n\n invariant(parent, NO_PARENT_MSG);\n\n const endMarker = document.createComment('when/end');\n\n parent.insertBefore(endMarker, anchor.nextSibling);\n\n const slot = createReplaceableSlot();\n\n const sub = rawEffect(() => {\n const next = conditionSignal.value;\n\n slot.clear();\n\n const branch = next ? truthy() : falsy ? falsy() : null;\n\n if (!branch || !isHtmlResult(branch)) return;\n\n slot.setNodes(untrack(() => mountBranch(branch, parent, endMarker, slot.registerCleanup)));\n });\n\n registerCleanup(() => sub.dispose());\n registerCleanup(() => {\n slot.clear();\n endMarker.remove();\n });\n });\n}\n"],"mappings":"sRAYA,IAAM,EAAgB,2CAEhB,GACJ,EACA,EACA,EACA,IACW,EAAO,MAAM,EAAQ,EAAc,CAAe,EAc/D,SAAgB,EACd,EACA,EACA,EACiB,CAiBjB,OAhBI,OAAO,GAAc,YAAc,CAAC,EAAW,CAAS,EACnD,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAS,EAAY,EAAO,EAAI,EAAQ,EAAM,EAAI,KAExD,GAAI,CAAC,GAAU,CAAC,EAAa,CAAM,EAAG,OAEtC,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,CAAa,EAE/B,IAAM,EAAQ,EAAY,EAAQ,EAAQ,EAAQ,CAAe,EAEjE,MAAsB,EAAY,CAAK,CAAC,CAC1C,CAAC,EAGI,GAAuB,EAAQ,IAAoB,CACxD,IAAM,EAAgB,OAAO,GAAc,WAAa,EAAS,CAA0B,EAAI,KACzF,EAAkB,GAAkB,EAEtC,GAAe,MAAsB,EAAc,QAAQ,CAAC,EAEhE,IAAM,EAAS,EAAO,WAEtB,EAAU,EAAQ,CAAa,EAE/B,IAAM,EAAY,SAAS,cAAc,UAAU,EAEnD,EAAO,aAAa,EAAW,EAAO,WAAW,EAEjD,IAAM,EAAO,EAAsB,EAE7B,EAAM,MAAgB,CAC1B,IAAM,EAAO,EAAgB,MAE7B,EAAK,MAAM,EAEX,IAAM,EAAS,EAAO,EAAO,EAAI,EAAQ,EAAM,EAAI,KAE/C,CAAC,GAAU,CAAC,EAAa,CAAM,GAEnC,EAAK,SAAS,MAAc,EAAY,EAAQ,EAAQ,EAAW,EAAK,eAAe,CAAC,CAAC,CAC3F,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EACnC,MAAsB,CACpB,EAAK,MAAM,EACX,EAAU,OAAO,CACnB,CAAC,CACH,CAAC,CACH"}
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./directives/classMap.cjs"),t=require("./directives/each.cjs"),n=require("./directives/live.cjs"),r=require("./directives/model.cjs"),i=require("./directives/raw.cjs"),a=require("./directives/styleMap.cjs"),o=require("./directives/when.cjs");exports.classMap=e.classMap,exports.each=t.each,exports.live=n.live,exports.model=r.model,exports.raw=i.raw,exports.setRawSanitizer=i.setRawSanitizer,exports.styleMap=a.styleMap,exports.when=o.when;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./directives/live.cjs"),t=require("./types/bindings.cjs"),n=require("./directives/raw.cjs");exports.createDirectiveResult=t.createDirectiveResult,exports.createSpreadObject=t.createSpreadObject,exports.isDirectiveResult=t.isDirectiveResult,exports.isSpreadObject=t.isSpreadObject,exports.live=e.live,exports.raw=n.raw,exports.setRawSanitizer=n.setRawSanitizer;
@@ -1 +1 @@
1
- import{classMap as e}from"./directives/classMap.js";import{each as t}from"./directives/each.js";import{live as n}from"./directives/live.js";import{model as r}from"./directives/model.js";import{raw as i,setRawSanitizer as a}from"./directives/raw.js";import{styleMap as o}from"./directives/styleMap.js";import{when as s}from"./directives/when.js";export{e as classMap,t as each,n as live,r as model,i as raw,a as setRawSanitizer,o as styleMap,s as when};
1
+ import{live as e}from"./directives/live.js";import{createDirectiveResult as t,createSpreadObject as n,isDirectiveResult as r,isSpreadObject as i}from"./types/bindings.js";import{raw as a,setRawSanitizer as o}from"./directives/raw.js";export{t as createDirectiveResult,n as createSpreadObject,r as isDirectiveResult,i as isSpreadObject,e as live,a as raw,o as setRawSanitizer};
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OreError {\n return err instanceof OreError;\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * Thrown when an internal invariant fails — e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'` — synchronous setup() threw\n * - `'async-setup'` — async setup() promise rejected\n * - `'mounted'` — an onMounted callback threw\n * - `'form-reset'` — an onFormReset callback threw\n */\nexport type OreErrorPhase = 'async-setup' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n */\nexport function reportRuntimeError(error: OreLifecycleError, element: HTMLElement): void {\n logError(`<${error.component}> setup error (phase: ${error.phase}):`, error.cause);\n\n element.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\n/** Thrown by `waitFor` and `waitForEvent` in the testing sub-path when a condition is not met within the timeout. */\nexport class OreTimeoutError extends OreError {}\n\nexport const ORE_ERRORS = {\n defineDuplicate: (tag: string): string => `define('${tag}') called twice — custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invalidDynamicTagName: (tagName: string): string =>\n `html\\`...\\`: dynamic tag name \"${tagName}\" is not a valid HTML element name`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n mismatchedDynamicCloseTag: 'html`...`: dynamic closing tag has no matching dynamic opening tag',\n propInvalidReflect: 'Structured props cannot use reflect:true — use prop.json() with reflect:false',\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold — e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first — `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"8BAKA,IAAa,EAAb,MAAa,UAAiB,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAA+B,CACvC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAiC,CAAS,CACxC,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAOa,EAAb,cAAsC,CAAS,CAC7C,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAea,EAAb,cAAuC,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAM,EAAS,CAAE,MAAO,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAY,EAAQ,UACzB,KAAK,MAAQ,EAAQ,KACvB,CACF,EAKA,SAAgB,EAAmB,EAA0B,EAA4B,CACvF,EAAA,MAAS,IAAI,EAAM,UAAU,wBAAwB,EAAM,MAAM,IAAK,EAAM,KAAK,EAEjF,EAAQ,cACN,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQ,CACV,CAAC,CACH,CACF,CAKA,IAAa,EAAb,cAAqC,CAAS,CAAC,EAElC,EAAa,CACxB,gBAAkB,GAAwB,WAAW,EAAI,qDACzD,kCAAoC,GAClC,+BAA+B,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAwB,GACtB,kCAAkC,EAAQ,oCAC5C,kBAAoB,GAA4B,uBAAuB,IACvE,sBAAuB,wDACvB,0BAA2B,qEAC3B,mBAAoB,gFACpB,kBAAmB,EAAa,IAA6B,0BAA0B,EAAI,MAAM,EAAO,KAAK;CAAI,GACnH,EAYA,SAAgB,EAAU,EAAoB,EAAoC,CAChF,GAAI,CAAC,EAAW,MAAM,IAAI,EAAiB,EAAW,kBAAkB,CAAO,CAAC,CAClF"}
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OreError {\n return err instanceof OreError;\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * Thrown when an internal invariant fails — e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'` — synchronous setup() threw\n * - `'async-setup'` — async setup() promise rejected\n * - `'mounted'` — an onMounted callback threw\n * - `'form-reset'` — an onFormReset callback threw\n * - `'each-reconcile'` — `each()` failed to reconcile a list update (e.g. duplicate keys)\n */\nexport type OreErrorPhase = 'async-setup' | 'each-reconcile' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n *\n * `target` only needs to be an `EventTarget` (not specifically an `HTMLElement`) — component\n * lifecycle errors dispatch on the host element, but non-lifecycle failures (e.g. `each()`\n * reconciliation, which has no single \"component\" to attribute the error to) dispatch on\n * whatever live DOM node is available, such as the directive's own anchor `Comment`. Either way\n * the event still bubbles and crosses shadow boundaries (`composed: true`), so a listener on\n * `document`/`window` observes every report regardless of where it originated.\n *\n * The console log (via `_dev.ts`'s `error()`) is still dev-gated like the rest of the package's\n * console diagnostics, but the `ore:error` DOM event dispatch below is **not** — it fires in\n * every build, so consumers always have a way to observe runtime failures programmatically even\n * when console output is stripped in production.\n */\nexport function reportRuntimeError(error: OreLifecycleError, target: EventTarget): void {\n logError(`<${error.component}> setup error (phase: ${error.phase}):`, error.cause);\n\n target.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\n/** Thrown by `flush()` in the testing sub-path when pending component work doesn't settle within the timeout. */\nexport class OreTimeoutError extends OreError {}\n\nexport const ORE_ERRORS = {\n defineDuplicate: (tag: string): string => `define('${tag}') called twice — custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invalidDynamicTagName: (tagName: string): string =>\n `html\\`...\\`: dynamic tag name \"${tagName}\" is not a valid HTML element name`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n mismatchedDynamicCloseTag: 'html`...`: dynamic closing tag has no matching dynamic opening tag',\n propInvalidReflect: 'Structured props cannot use reflect:true — use prop.json() with reflect:false',\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold — e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first — `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"8BAKA,IAAa,EAAb,MAAa,UAAiB,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAA+B,CACvC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAiC,CAAS,CACxC,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAOa,EAAb,cAAsC,CAAS,CAC7C,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAgBa,EAAb,cAAuC,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAM,EAAS,CAAE,MAAO,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAY,EAAQ,UACzB,KAAK,MAAQ,EAAQ,KACvB,CACF,EAiBA,SAAgB,EAAmB,EAA0B,EAA2B,CACtF,EAAA,MAAS,IAAI,EAAM,UAAU,wBAAwB,EAAM,MAAM,IAAK,EAAM,KAAK,EAEjF,EAAO,cACL,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQ,CACV,CAAC,CACH,CACF,CAKA,IAAa,EAAb,cAAqC,CAAS,CAAC,EAElC,EAAa,CACxB,gBAAkB,GAAwB,WAAW,EAAI,qDACzD,kCAAoC,GAClC,+BAA+B,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAwB,GACtB,kCAAkC,EAAQ,oCAC5C,kBAAoB,GAA4B,uBAAuB,IACvE,sBAAuB,wDACvB,0BAA2B,qEAC3B,mBAAoB,gFACpB,kBAAmB,EAAa,IAA6B,0BAA0B,EAAI,MAAM,EAAO,KAAK;CAAI,GACnH,EAYA,SAAgB,EAAU,EAAoB,EAAoC,CAChF,GAAI,CAAC,EAAW,MAAM,IAAI,EAAiB,EAAW,kBAAkB,CAAO,CAAC,CAClF"}
package/dist/errors.d.ts CHANGED
@@ -21,8 +21,9 @@ export declare class OreInternalError extends OreError {
21
21
  * - `'async-setup'` — async setup() promise rejected
22
22
  * - `'mounted'` — an onMounted callback threw
23
23
  * - `'form-reset'` — an onFormReset callback threw
24
+ * - `'each-reconcile'` — `each()` failed to reconcile a list update (e.g. duplicate keys)
24
25
  */
25
- export type OreErrorPhase = 'async-setup' | 'form-reset' | 'mounted' | 'setup';
26
+ export type OreErrorPhase = 'async-setup' | 'each-reconcile' | 'form-reset' | 'mounted' | 'setup';
26
27
  /**
27
28
  * Structured error thrown by the Ore runtime when component setup fails.
28
29
  * Provides component name and original cause for debugging.
@@ -38,9 +39,21 @@ export declare class OreLifecycleError extends OreError {
38
39
  }
39
40
  /**
40
41
  * Report a runtime error via the ore:error event and console.
42
+ *
43
+ * `target` only needs to be an `EventTarget` (not specifically an `HTMLElement`) — component
44
+ * lifecycle errors dispatch on the host element, but non-lifecycle failures (e.g. `each()`
45
+ * reconciliation, which has no single "component" to attribute the error to) dispatch on
46
+ * whatever live DOM node is available, such as the directive's own anchor `Comment`. Either way
47
+ * the event still bubbles and crosses shadow boundaries (`composed: true`), so a listener on
48
+ * `document`/`window` observes every report regardless of where it originated.
49
+ *
50
+ * The console log (via `_dev.ts`'s `error()`) is still dev-gated like the rest of the package's
51
+ * console diagnostics, but the `ore:error` DOM event dispatch below is **not** — it fires in
52
+ * every build, so consumers always have a way to observe runtime failures programmatically even
53
+ * when console output is stripped in production.
41
54
  */
42
- export declare function reportRuntimeError(error: OreLifecycleError, element: HTMLElement): void;
43
- /** Thrown by `waitFor` and `waitForEvent` in the testing sub-path when a condition is not met within the timeout. */
55
+ export declare function reportRuntimeError(error: OreLifecycleError, target: EventTarget): void;
56
+ /** Thrown by `flush()` in the testing sub-path when pending component work doesn't settle within the timeout. */
44
57
  export declare class OreTimeoutError extends OreError {
45
58
  }
46
59
  export declare const ORE_ERRORS: {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAIA,kGAAkG;AAClG,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAMhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,QAAQ;CAGzC;AAED,sGAAsG;AACtG,qBAAa,WAAY,SAAQ,QAAQ;gBAC3B,OAAO,EAAE,MAAM;CAG5B;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;gBAChC,OAAO,EAAE,MAAM;CAG5B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/E;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE;CAKhG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAUvF;AAID,qHAAqH;AACrH,qBAAa,eAAgB,SAAQ,QAAQ;CAAG;AAEhD,eAAO,MAAM,UAAU;oCACE,MAAM,KAAG,MAAM;sDACG,MAAM,KAAG,MAAM;;qCAGhC,MAAM,SAAS,MAAM,KAAG,MAAM;uCAC5B,MAAM,OAAO,MAAM,KAAG,MAAM;8CACrB,MAAM,KAAG,MAAM;0CAEnB,MAAM,KAAG,MAAM;;;;qCAIpB,MAAM,UAAU,MAAM,EAAE,KAAG,MAAM;CACjD,CAAC;AAEX;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAEhF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAIA,kGAAkG;AAClG,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAMhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,QAAQ;CAGzC;AAED,sGAAsG;AACtG,qBAAa,WAAY,SAAQ,QAAQ;gBAC3B,OAAO,EAAE,MAAM;CAG5B;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;gBAChC,OAAO,EAAE,MAAM;CAG5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,gBAAgB,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;AAElG;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE;CAKhG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAUtF;AAID,iHAAiH;AACjH,qBAAa,eAAgB,SAAQ,QAAQ;CAAG;AAEhD,eAAO,MAAM,UAAU;oCACE,MAAM,KAAG,MAAM;sDACG,MAAM,KAAG,MAAM;;qCAGhC,MAAM,SAAS,MAAM,KAAG,MAAM;uCAC5B,MAAM,OAAO,MAAM,KAAG,MAAM;8CACrB,MAAM,KAAG,MAAM;0CAEnB,MAAM,KAAG,MAAM;;;;qCAIpB,MAAM,UAAU,MAAM,EAAE,KAAG,MAAM;CACjD,CAAC;AAEX;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAEhF"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OreError {\n return err instanceof OreError;\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * Thrown when an internal invariant fails — e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'` — synchronous setup() threw\n * - `'async-setup'` — async setup() promise rejected\n * - `'mounted'` — an onMounted callback threw\n * - `'form-reset'` — an onFormReset callback threw\n */\nexport type OreErrorPhase = 'async-setup' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n */\nexport function reportRuntimeError(error: OreLifecycleError, element: HTMLElement): void {\n logError(`<${error.component}> setup error (phase: ${error.phase}):`, error.cause);\n\n element.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\n/** Thrown by `waitFor` and `waitForEvent` in the testing sub-path when a condition is not met within the timeout. */\nexport class OreTimeoutError extends OreError {}\n\nexport const ORE_ERRORS = {\n defineDuplicate: (tag: string): string => `define('${tag}') called twice — custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invalidDynamicTagName: (tagName: string): string =>\n `html\\`...\\`: dynamic tag name \"${tagName}\" is not a valid HTML element name`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n mismatchedDynamicCloseTag: 'html`...`: dynamic closing tag has no matching dynamic opening tag',\n propInvalidReflect: 'Structured props cannot use reflect:true — use prop.json() with reflect:false',\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold — e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first — `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"kCAKA,IAAa,EAAb,MAAa,UAAiB,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAA+B,CACvC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAiC,CAAS,CACxC,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAOa,EAAb,cAAsC,CAAS,CAC7C,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAea,EAAb,cAAuC,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAM,EAAS,CAAE,MAAO,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAY,EAAQ,UACzB,KAAK,MAAQ,EAAQ,KACvB,CACF,EAKA,SAAgB,EAAmB,EAA0B,EAA4B,CACvF,EAAS,IAAI,EAAM,UAAU,wBAAwB,EAAM,MAAM,IAAK,EAAM,KAAK,EAEjF,EAAQ,cACN,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQ,CACV,CAAC,CACH,CACF,CAKA,IAAa,EAAb,cAAqC,CAAS,CAAC,EAElC,EAAa,CACxB,gBAAkB,GAAwB,WAAW,EAAI,qDACzD,kCAAoC,GAClC,+BAA+B,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAwB,GACtB,kCAAkC,EAAQ,oCAC5C,kBAAoB,GAA4B,uBAAuB,IACvE,sBAAuB,wDACvB,0BAA2B,qEAC3B,mBAAoB,gFACpB,kBAAmB,EAAa,IAA6B,0BAA0B,EAAI,MAAM,EAAO,KAAK;CAAI,GACnH,EAYA,SAAgB,EAAU,EAAoB,EAAoC,CAChF,GAAI,CAAC,EAAW,MAAM,IAAI,EAAiB,EAAW,kBAAkB,CAAO,CAAC,CAClF"}
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["import { error as logError } from './_dev';\n\n// ─── Structured error types ───────────────────────────────────────────────────\n\n/** Base class for all Ore errors. Use `instanceof OreError` to catch any Ore-originated error. */\nexport class OreError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is OreError {\n return err instanceof OreError;\n }\n}\n\n/** Thrown when Ore API is called incorrectly (e.g. outside setup, duplicate define, invalid prop). */\nexport class OreApiError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * Thrown when an internal invariant fails — e.g. compiled template metadata no\n * longer matching the DOM it was cloned from. Distinct from `OreApiError`: this\n * is never the caller's fault, it signals a bug in ore itself. See `invariant()`.\n */\nexport class OreInternalError extends OreError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/**\n * The phase in which a component error occurred.\n * - `'setup'` — synchronous setup() threw\n * - `'async-setup'` — async setup() promise rejected\n * - `'mounted'` — an onMounted callback threw\n * - `'form-reset'` — an onFormReset callback threw\n * - `'each-reconcile'` — `each()` failed to reconcile a list update (e.g. duplicate keys)\n */\nexport type OreErrorPhase = 'async-setup' | 'each-reconcile' | 'form-reset' | 'mounted' | 'setup';\n\n/**\n * Structured error thrown by the Ore runtime when component setup fails.\n * Provides component name and original cause for debugging.\n */\nexport class OreLifecycleError extends OreError {\n readonly component: string;\n readonly phase: OreErrorPhase;\n\n constructor(message: string, options: { cause: Error; component: string; phase: OreErrorPhase }) {\n super(message, { cause: options.cause });\n this.component = options.component;\n this.phase = options.phase;\n }\n}\n\n/**\n * Report a runtime error via the ore:error event and console.\n *\n * `target` only needs to be an `EventTarget` (not specifically an `HTMLElement`) — component\n * lifecycle errors dispatch on the host element, but non-lifecycle failures (e.g. `each()`\n * reconciliation, which has no single \"component\" to attribute the error to) dispatch on\n * whatever live DOM node is available, such as the directive's own anchor `Comment`. Either way\n * the event still bubbles and crosses shadow boundaries (`composed: true`), so a listener on\n * `document`/`window` observes every report regardless of where it originated.\n *\n * The console log (via `_dev.ts`'s `error()`) is still dev-gated like the rest of the package's\n * console diagnostics, but the `ore:error` DOM event dispatch below is **not** — it fires in\n * every build, so consumers always have a way to observe runtime failures programmatically even\n * when console output is stripped in production.\n */\nexport function reportRuntimeError(error: OreLifecycleError, target: EventTarget): void {\n logError(`<${error.component}> setup error (phase: ${error.phase}):`, error.cause);\n\n target.dispatchEvent(\n new CustomEvent('ore:error', {\n bubbles: true,\n composed: true,\n detail: error,\n }),\n );\n}\n\n// ─── Error message constants ─────────────────────────────────────────────────\n\n/** Thrown by `flush()` in the testing sub-path when pending component work doesn't settle within the timeout. */\nexport class OreTimeoutError extends OreError {}\n\nexport const ORE_ERRORS = {\n defineDuplicate: (tag: string): string => `define('${tag}') called twice — custom element already registered`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `useField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n invalidDynamicTagName: (tagName: string): string =>\n `html\\`...\\`: dynamic tag name \"${tagName}\" is not a valid HTML element name`,\n invariantViolated: (message: string): string => `invariant violated: ${message}`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called during component setup',\n mismatchedDynamicCloseTag: 'html`...`: dynamic closing tag has no matching dynamic opening tag',\n propInvalidReflect: 'Structured props cannot use reflect:true — use prop.json() with reflect:false',\n validationFailed: (tag: string, errors: string[]): string => `Validation failed for <${tag}>:\\n${errors.join('\\n')}`,\n} as const;\n\n/**\n * Assert an internal invariant that must always hold — e.g. compiled template\n * metadata staying in sync with the DOM it was cloned from. A failed invariant\n * means a bug in ore itself, never user input, so it throws `OreInternalError`\n * unconditionally (every build, never gated like `_dev.ts`'s `warn()`).\n *\n * Narrowing caveat: `asserts condition` only narrows the exact expression\n * passed in. Assign to a local `const` first — `invariant(el.parentNode, msg)`\n * does not narrow later reads of `el.parentNode`.\n */\nexport function invariant(condition: unknown, message: string): asserts condition {\n if (!condition) throw new OreInternalError(ORE_ERRORS.invariantViolated(message));\n}\n"],"mappings":"kCAKA,IAAa,EAAb,MAAa,UAAiB,KAAM,CAClC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAA+B,CACvC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAiC,CAAS,CACxC,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAOa,EAAb,cAAsC,CAAS,CAC7C,YAAY,EAAiB,CAC3B,MAAM,CAAO,CACf,CACF,EAgBa,EAAb,cAAuC,CAAS,CAC9C,UACA,MAEA,YAAY,EAAiB,EAAoE,CAC/F,MAAM,EAAS,CAAE,MAAO,EAAQ,KAAM,CAAC,EACvC,KAAK,UAAY,EAAQ,UACzB,KAAK,MAAQ,EAAQ,KACvB,CACF,EAiBA,SAAgB,EAAmB,EAA0B,EAA2B,CACtF,EAAS,IAAI,EAAM,UAAU,wBAAwB,EAAM,MAAM,IAAK,EAAM,KAAK,EAEjF,EAAO,cACL,IAAI,YAAY,YAAa,CAC3B,QAAS,GACT,SAAU,GACV,OAAQ,CACV,CAAC,CACH,CACF,CAKA,IAAa,EAAb,cAAqC,CAAS,CAAC,EAElC,EAAa,CACxB,gBAAkB,GAAwB,WAAW,EAAI,qDACzD,kCAAoC,GAClC,+BAA+B,EAAI,8BACrC,kBAAmB,+BACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAwB,GACtB,kCAAkC,EAAQ,oCAC5C,kBAAoB,GAA4B,uBAAuB,IACvE,sBAAuB,wDACvB,0BAA2B,qEAC3B,mBAAoB,gFACpB,kBAAmB,EAAa,IAA6B,0BAA0B,EAAI,MAAM,EAAO,KAAK;CAAI,GACnH,EAYA,SAAgB,EAAU,EAAoB,EAAoC,CAChF,GAAI,CAAC,EAAW,MAAM,IAAI,EAAiB,EAAW,kBAAkB,CAAO,CAAC,CAClF"}
@@ -1,2 +1,2 @@
1
- const e=require("./utils/dom.cjs"),t=require("./runtime.cjs"),n=require("./utils/aria.cjs");let r=require("@vielzeug/ripple");var i=(n,r)=>{let i=r?.target??t.getHost(),o=[];if(n.attr)for(let[e,t]of Object.entries(n.attr)){let n=s(i,a(e),t);n&&o.push(n)}if(n.class&&o.push(u(i,n.class)),n.style)for(let[e,t]of Object.entries(n.style)){let n=l(i,e,t);n&&o.push(n)}if(n.on){let{target:t,...a}=r??{};for(let t of Object.keys(n.on)){let r=n.on[t];r&&o.push(e.listen(i,t,r,a))}}let c=()=>{for(let e of o)e()};return t.tryRegisterCleanup(c),c},a=n.normalizeHostAttrKey,o=(e,n)=>{if(typeof e==`function`)return t.watchEffect(()=>n(e()));if((0,r.isReactive)(e))return t.watchEffect(()=>n(e.value));n(e)};function s(t,n,r){return o(r,r=>e.setAttr(t,n,r))}var c=/[;{}]/g;function l(t,n,r){let i=(n.startsWith(`--`)?n:e.toKebab(n)).replace(c,``);if(!i)return;let a=!1;return o(r,e=>{e!=null&&e!==``?(a=!0,t.style.setProperty(i,String(e).replace(c,``))):a&&t.style.removeProperty(i)})}function u(e,n){let i=typeof n==`function`?n:()=>{let e={};for(let[t,i]of Object.entries(n))e[t]=typeof i==`function`?i():(0,r.isReactive)(i)?i.value:!!i;return e},a=new Set;return t.watchEffect(()=>{let t=new Set;for(let[n,r]of Object.entries(i()))r&&(t.add(n),a.has(n)||e.classList.add(n));for(let n of a)t.has(n)||e.classList.remove(n);a=t})}exports.bind=i;
1
+ const e=require("./utils/dom.cjs"),t=require("./runtime.cjs"),n=require("./utils/aria.cjs");let r=require("@vielzeug/ripple");var i=(r,i)=>{let o=i?.target??t.getHost(),u=[];if(r.attr)for(let[e,t]of Object.entries(r.attr)){let n=s(o,a(e),t);n&&u.push(n)}if(r.aria)for(let[e,t]of Object.entries(r.aria)){let r=s(o,n.normalizeAriaKey(e),t);r&&u.push(r)}if(r.class&&u.push(l(o,r.class)),r.style)for(let[e,t]of Object.entries(r.style)){let n=c(o,e,t);n&&u.push(n)}if(r.on){let{target:t,...n}=i??{};for(let t of Object.keys(r.on)){let i=r.on[t];i&&u.push(e.listen(o,t,i,n))}}let d=()=>{for(let e of u)e()};return t.tryRegisterCleanup(d),d},a=n.normalizeHostAttrKey,o=(e,n)=>{if(typeof e==`function`)return t.watchEffect(()=>n(e()));if((0,r.isReactive)(e))return t.watchEffect(()=>n(e.value));n(e)};function s(t,n,r){return o(r,r=>e.setAttr(t,n,r))}function c(t,n,r){let i=e.sanitizeCssToken(n.startsWith(`--`)?n:e.toKebab(n));if(!i)return;let a=!1;return o(r,n=>{n!=null&&n!==``?(a=!0,t.style.setProperty(i,e.sanitizeCssToken(String(n)))):a&&t.style.removeProperty(i)})}function l(n,r){let i=typeof r==`function`?r:()=>{let t={};for(let[n,i]of Object.entries(r))t[n]=e.resolveMaybeReactive(i);return t},a=new Set;return t.watchEffect(()=>{let e=new Set;for(let[t,r]of Object.entries(i()))r&&(e.add(t),a.has(t)||n.classList.add(t));for(let t of a)e.has(t)||n.classList.remove(t);a=e})}exports.bind=i;
2
2
  //# sourceMappingURL=host-bind.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"host-bind.cjs","names":[],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API — reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeHostAttrKey } from './utils/aria';\nimport { listen, setAttr, toKebab } from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => string | number | boolean | null | undefined)\n | Readable<string | number | boolean | null | undefined>\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = Readable<boolean> | (() => boolean) | boolean;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n attr?: ReflectConfig;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\nexport type HostBindFn = (config: HostBindConfig, options?: BindOptions) => () => void;\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind: HostBindFn = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | void => {\n if (typeof value === 'function') {\n return watchEffect(() => updater(value()));\n }\n\n if (isReactive(value)) {\n return watchEffect(() => updater(value.value));\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nconst UNSAFE_CSS_CHARS = /[;{}]/g;\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n const cssName = (name.startsWith('--') ? name : toKebab(name)).replace(UNSAFE_CSS_CHARS, '');\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n if (v != null && v !== '') {\n owned = true;\n host.style.setProperty(cssName, String(v).replace(UNSAFE_CSS_CHARS, ''));\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => {\n const result: Record<string, boolean> = {};\n\n for (const [cls, entry] of Object.entries(value)) {\n result[cls] = typeof entry === 'function' ? entry() : isReactive(entry) ? entry.value : Boolean(entry);\n }\n\n return result;\n };\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"8HA0DA,IAAa,GAAoB,EAAwB,IAAwC,CAC/F,IAAM,EAAM,GAAS,QAAsC,EAAA,QAAQ,EAC7D,EAA+B,CAAC,EAEtC,GAAI,EAAO,KACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,IAAI,EAAG,CAEtD,IAAM,EAAU,EAAe,EADlB,EAAW,CACW,EAAM,CAAK,EAE1C,GAAS,EAAU,KAAK,CAAO,CACrC,CAOF,GAJI,EAAO,OACT,EAAU,KAAK,EAAc,EAAI,EAAO,KAAK,CAAC,EAG5C,EAAO,MACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,KAAK,EAAG,CACvD,IAAM,EAAU,EAAW,EAAI,EAAK,CAAK,EAErC,GAAS,EAAU,KAAK,CAAO,CACrC,CAGF,GAAI,EAAO,GAAI,CACb,GAAM,CAAE,OAAQ,EAAI,GAAG,GAAoB,GAAW,CAAC,EAEvD,IAAK,IAAM,KAAS,OAAO,KAAK,EAAO,EAAE,EAAoC,CAC3E,IAAM,EAAW,EAAO,GAAG,GAEtB,GAEL,EAAU,KAAK,EAAA,OAAO,EAAI,EAAiB,EAA2B,CAAe,CAAC,CACxF,CACF,CAEA,IAAM,MAAsB,CAC1B,IAAK,IAAM,KAAW,EAAW,EAAQ,CAC3C,EAIA,OAFA,EAAA,mBAAmB,CAAO,EAEnB,CACT,EAEM,EAAa,EAAA,qBAEb,GACJ,EACA,IACwB,CACxB,GAAI,OAAO,GAAU,WACnB,OAAO,EAAA,gBAAkB,EAAQ,EAAM,CAAC,CAAC,EAG3C,IAAA,EAAA,EAAA,WAAA,CAAe,CAAK,EAClB,OAAO,EAAA,gBAAkB,EAAQ,EAAM,KAAK,CAAC,EAG/C,EAAQ,CAAK,CACf,EAEA,SAAS,EAAe,EAAmB,EAAc,EAA8C,CACrG,OAAO,EAAqB,EAAQ,GAAS,EAAA,QAAQ,EAAM,EAAM,CAAI,CAAC,CACxE,CAEA,IAAM,EAAmB,SAEzB,SAAS,EAAW,EAAmB,EAAc,EAA8C,CACjG,IAAM,GAAW,EAAK,WAAW,IAAI,EAAI,EAAO,EAAA,QAAQ,CAAI,EAAA,CAAG,QAAQ,EAAkB,EAAE,EAE3F,GAAI,CAAC,EAAS,OAEd,IAAI,EAAQ,GAQZ,OAAO,EAAqB,EAPV,GAA0D,CACtE,GAAK,MAAQ,IAAM,IACrB,EAAQ,GACR,EAAK,MAAM,YAAY,EAAS,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAkB,EAAE,CAAC,GAC9D,GAAO,EAAK,MAAM,eAAe,CAAO,CACrD,CAE2C,CAC7C,CAEA,SAAS,EACP,EACA,EACY,CACZ,IAAM,EACJ,OAAO,GAAU,WACb,MAC+B,CAC7B,IAAM,EAAkC,CAAC,EAEzC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAK,EAC7C,EAAO,GAAO,OAAO,GAAU,WAAa,EAAM,GAAA,EAAA,EAAA,WAAA,CAAe,CAAK,EAAI,EAAM,MAAQ,EAAQ,EAGlG,OAAO,CACT,EAEF,EAAO,IAAI,IAkBf,OAhBY,EAAA,gBAAkB,CAC5B,IAAM,EAAO,IAAI,IAEjB,IAAK,GAAM,CAAC,EAAK,KAAW,OAAO,QAAQ,EAAO,CAAC,EAC5C,IAEL,EAAK,IAAI,CAAG,EAEP,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,IAAI,CAAG,GAE5C,IAAK,IAAM,KAAO,EACX,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,OAAO,CAAG,EAE/C,EAAO,CACT,CAEO,CACT"}
1
+ {"version":3,"file":"host-bind.cjs","names":[],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API — reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeAriaKey, normalizeHostAttrKey } from './utils/aria';\nimport { listen, resolveMaybeReactive, sanitizeCssToken, setAttr, toKebab } from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => string | number | boolean | null | undefined)\n | Readable<string | number | boolean | null | undefined>\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = Readable<boolean> | (() => boolean) | boolean;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n /**\n * ARIA attributes, keyed by bare property name (`expanded`) or fully-qualified\n * (`aria-expanded`) — both normalize to the same attribute. A separate key from `attr`\n * only so bare names can be normalized; the underlying write path is identical.\n */\n aria?: ReflectConfig;\n attr?: ReflectConfig;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\nexport type HostBindFn = (config: HostBindConfig, options?: BindOptions) => () => void;\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind: HostBindFn = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.aria) {\n for (const [key, value] of Object.entries(config.aria)) {\n const name = normalizeAriaKey(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | void => {\n if (typeof value === 'function') {\n return watchEffect(() => updater(value()));\n }\n\n if (isReactive(value)) {\n return watchEffect(() => updater(value.value));\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n const cssName = sanitizeCssToken(name.startsWith('--') ? name : toKebab(name));\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n if (v != null && v !== '') {\n owned = true;\n host.style.setProperty(cssName, sanitizeCssToken(String(v)));\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => {\n const result: Record<string, boolean> = {};\n\n for (const [cls, entry] of Object.entries(value)) {\n result[cls] = resolveMaybeReactive(entry);\n }\n\n return result;\n };\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"8HAgEA,IAAa,GAAoB,EAAwB,IAAwC,CAC/F,IAAM,EAAM,GAAS,QAAsC,EAAA,QAAQ,EAC7D,EAA+B,CAAC,EAEtC,GAAI,EAAO,KACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,IAAI,EAAG,CAEtD,IAAM,EAAU,EAAe,EADlB,EAAW,CACW,EAAM,CAAK,EAE1C,GAAS,EAAU,KAAK,CAAO,CACrC,CAGF,GAAI,EAAO,KACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,IAAI,EAAG,CAEtD,IAAM,EAAU,EAAe,EADlB,EAAA,iBAAiB,CACK,EAAM,CAAK,EAE1C,GAAS,EAAU,KAAK,CAAO,CACrC,CAOF,GAJI,EAAO,OACT,EAAU,KAAK,EAAc,EAAI,EAAO,KAAK,CAAC,EAG5C,EAAO,MACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,KAAK,EAAG,CACvD,IAAM,EAAU,EAAW,EAAI,EAAK,CAAK,EAErC,GAAS,EAAU,KAAK,CAAO,CACrC,CAGF,GAAI,EAAO,GAAI,CACb,GAAM,CAAE,OAAQ,EAAI,GAAG,GAAoB,GAAW,CAAC,EAEvD,IAAK,IAAM,KAAS,OAAO,KAAK,EAAO,EAAE,EAAoC,CAC3E,IAAM,EAAW,EAAO,GAAG,GAEtB,GAEL,EAAU,KAAK,EAAA,OAAO,EAAI,EAAiB,EAA2B,CAAe,CAAC,CACxF,CACF,CAEA,IAAM,MAAsB,CAC1B,IAAK,IAAM,KAAW,EAAW,EAAQ,CAC3C,EAIA,OAFA,EAAA,mBAAmB,CAAO,EAEnB,CACT,EAEM,EAAa,EAAA,qBAEb,GACJ,EACA,IACwB,CACxB,GAAI,OAAO,GAAU,WACnB,OAAO,EAAA,gBAAkB,EAAQ,EAAM,CAAC,CAAC,EAG3C,IAAA,EAAA,EAAA,WAAA,CAAe,CAAK,EAClB,OAAO,EAAA,gBAAkB,EAAQ,EAAM,KAAK,CAAC,EAG/C,EAAQ,CAAK,CACf,EAEA,SAAS,EAAe,EAAmB,EAAc,EAA8C,CACrG,OAAO,EAAqB,EAAQ,GAAS,EAAA,QAAQ,EAAM,EAAM,CAAI,CAAC,CACxE,CAEA,SAAS,EAAW,EAAmB,EAAc,EAA8C,CACjG,IAAM,EAAU,EAAA,iBAAiB,EAAK,WAAW,IAAI,EAAI,EAAO,EAAA,QAAQ,CAAI,CAAC,EAE7E,GAAI,CAAC,EAAS,OAEd,IAAI,EAAQ,GAQZ,OAAO,EAAqB,EAPV,GAA0D,CACtE,GAAK,MAAQ,IAAM,IACrB,EAAQ,GACR,EAAK,MAAM,YAAY,EAAS,EAAA,iBAAiB,OAAO,CAAC,CAAC,CAAC,GAClD,GAAO,EAAK,MAAM,eAAe,CAAO,CACrD,CAE2C,CAC7C,CAEA,SAAS,EACP,EACA,EACY,CACZ,IAAM,EACJ,OAAO,GAAU,WACb,MAC+B,CAC7B,IAAM,EAAkC,CAAC,EAEzC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAK,EAC7C,EAAO,GAAO,EAAA,qBAAqB,CAAK,EAG1C,OAAO,CACT,EAEF,EAAO,IAAI,IAkBf,OAhBY,EAAA,gBAAkB,CAC5B,IAAM,EAAO,IAAI,IAEjB,IAAK,GAAM,CAAC,EAAK,KAAW,OAAO,QAAQ,EAAO,CAAC,EAC5C,IAEL,EAAK,IAAI,CAAG,EAEP,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,IAAI,CAAG,GAE5C,IAAK,IAAM,KAAO,EACX,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,OAAO,CAAG,EAE/C,EAAO,CACT,CAEO,CACT"}
@@ -16,6 +16,12 @@ type HostEventListener = {
16
16
  bivarianceHack(event: Event): void;
17
17
  }['bivarianceHack'];
18
18
  export type HostBindConfig = {
19
+ /**
20
+ * ARIA attributes, keyed by bare property name (`expanded`) or fully-qualified
21
+ * (`aria-expanded`) — both normalize to the same attribute. A separate key from `attr`
22
+ * only so bare names can be normalized; the underlying write path is identical.
23
+ */
24
+ aria?: ReflectConfig;
19
25
  attr?: ReflectConfig;
20
26
  class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;
21
27
  on?: Record<string, HostEventListener | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"host-bind.d.ts","sourceRoot":"","sources":["../src/host-bind.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM7D;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACpD,QAAQ,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACtD,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAE7D,KAAK,qBAAqB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC;AAE3E,KAAK,iBAAiB,GAAG;IAAE,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,CAAC,gBAAgB,CAAC,CAAC;AAElF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAChF,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAC,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,uBAAuB,GAAG;IAClD;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,MAAM,IAAI,CAAC;AAEvF;;;;;GAKG;AACH,eAAO,MAAM,IAAI,EAAE,UA4ClB,CAAC"}
1
+ {"version":3,"file":"host-bind.d.ts","sourceRoot":"","sources":["../src/host-bind.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM7D;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACpD,QAAQ,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACtD,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAE7D,KAAK,qBAAqB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC;AAE3E,KAAK,iBAAiB,GAAG;IAAE,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,CAAC,gBAAgB,CAAC,CAAC;AAElF,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAChF,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAC,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,uBAAuB,GAAG;IAClD;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,MAAM,IAAI,CAAC;AAEvF;;;;;GAKG;AACH,eAAO,MAAM,IAAI,EAAE,UAqDlB,CAAC"}
package/dist/host-bind.js CHANGED
@@ -1,2 +1,2 @@
1
- import{listen as e,setAttr as t,toKebab as n}from"./utils/dom.js";import{getHost as r,tryRegisterCleanup as i,watchEffect as a}from"./runtime.js";import{normalizeHostAttrKey as o}from"./utils/aria.js";import{isReactive as s}from"@vielzeug/ripple";var c=(t,n)=>{let a=n?.target??r(),o=[];if(t.attr)for(let[e,n]of Object.entries(t.attr)){let t=d(a,l(e),n);t&&o.push(t)}if(t.class&&o.push(m(a,t.class)),t.style)for(let[e,n]of Object.entries(t.style)){let t=p(a,e,n);t&&o.push(t)}if(t.on){let{target:r,...i}=n??{};for(let n of Object.keys(t.on)){let r=t.on[n];r&&o.push(e(a,n,r,i))}}let s=()=>{for(let e of o)e()};return i(s),s},l=o,u=(e,t)=>{if(typeof e==`function`)return a(()=>t(e()));if(s(e))return a(()=>t(e.value));t(e)};function d(e,n,r){return u(r,r=>t(e,n,r))}var f=/[;{}]/g;function p(e,t,r){let i=(t.startsWith(`--`)?t:n(t)).replace(f,``);if(!i)return;let a=!1;return u(r,t=>{t!=null&&t!==``?(a=!0,e.style.setProperty(i,String(t).replace(f,``))):a&&e.style.removeProperty(i)})}function m(e,t){let n=typeof t==`function`?t:()=>{let e={};for(let[n,r]of Object.entries(t))e[n]=typeof r==`function`?r():s(r)?r.value:!!r;return e},r=new Set;return a(()=>{let t=new Set;for(let[i,a]of Object.entries(n()))a&&(t.add(i),r.has(i)||e.classList.add(i));for(let n of r)t.has(n)||e.classList.remove(n);r=t})}export{c as bind};
1
+ import{listen as e,resolveMaybeReactive as t,sanitizeCssToken as n,setAttr as r,toKebab as i}from"./utils/dom.js";import{getHost as a,tryRegisterCleanup as o,watchEffect as s}from"./runtime.js";import{normalizeAriaKey as c,normalizeHostAttrKey as l}from"./utils/aria.js";import{isReactive as u}from"@vielzeug/ripple";var d=(t,n)=>{let r=n?.target??a(),i=[];if(t.attr)for(let[e,n]of Object.entries(t.attr)){let t=m(r,f(e),n);t&&i.push(t)}if(t.aria)for(let[e,n]of Object.entries(t.aria)){let t=m(r,c(e),n);t&&i.push(t)}if(t.class&&i.push(g(r,t.class)),t.style)for(let[e,n]of Object.entries(t.style)){let t=h(r,e,n);t&&i.push(t)}if(t.on){let{target:a,...o}=n??{};for(let n of Object.keys(t.on)){let a=t.on[n];a&&i.push(e(r,n,a,o))}}let s=()=>{for(let e of i)e()};return o(s),s},f=l,p=(e,t)=>{if(typeof e==`function`)return s(()=>t(e()));if(u(e))return s(()=>t(e.value));t(e)};function m(e,t,n){return p(n,n=>r(e,t,n))}function h(e,t,r){let a=n(t.startsWith(`--`)?t:i(t));if(!a)return;let o=!1;return p(r,t=>{t!=null&&t!==``?(o=!0,e.style.setProperty(a,n(String(t)))):o&&e.style.removeProperty(a)})}function g(e,n){let r=typeof n==`function`?n:()=>{let e={};for(let[r,i]of Object.entries(n))e[r]=t(i);return e},i=new Set;return s(()=>{let t=new Set;for(let[n,a]of Object.entries(r()))a&&(t.add(n),i.has(n)||e.classList.add(n));for(let n of i)t.has(n)||e.classList.remove(n);i=t})}export{d as bind};
2
2
  //# sourceMappingURL=host-bind.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"host-bind.js","names":[],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API — reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeHostAttrKey } from './utils/aria';\nimport { listen, setAttr, toKebab } from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => string | number | boolean | null | undefined)\n | Readable<string | number | boolean | null | undefined>\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = Readable<boolean> | (() => boolean) | boolean;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n attr?: ReflectConfig;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\nexport type HostBindFn = (config: HostBindConfig, options?: BindOptions) => () => void;\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind: HostBindFn = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | void => {\n if (typeof value === 'function') {\n return watchEffect(() => updater(value()));\n }\n\n if (isReactive(value)) {\n return watchEffect(() => updater(value.value));\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nconst UNSAFE_CSS_CHARS = /[;{}]/g;\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n const cssName = (name.startsWith('--') ? name : toKebab(name)).replace(UNSAFE_CSS_CHARS, '');\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n if (v != null && v !== '') {\n owned = true;\n host.style.setProperty(cssName, String(v).replace(UNSAFE_CSS_CHARS, ''));\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => {\n const result: Record<string, boolean> = {};\n\n for (const [cls, entry] of Object.entries(value)) {\n result[cls] = typeof entry === 'function' ? entry() : isReactive(entry) ? entry.value : Boolean(entry);\n }\n\n return result;\n };\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"uPA0DA,IAAa,GAAoB,EAAwB,IAAwC,CAC/F,IAAM,EAAM,GAAS,QAAsC,EAAQ,EAC7D,EAA+B,CAAC,EAEtC,GAAI,EAAO,KACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,IAAI,EAAG,CAEtD,IAAM,EAAU,EAAe,EADlB,EAAW,CACW,EAAM,CAAK,EAE1C,GAAS,EAAU,KAAK,CAAO,CACrC,CAOF,GAJI,EAAO,OACT,EAAU,KAAK,EAAc,EAAI,EAAO,KAAK,CAAC,EAG5C,EAAO,MACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,KAAK,EAAG,CACvD,IAAM,EAAU,EAAW,EAAI,EAAK,CAAK,EAErC,GAAS,EAAU,KAAK,CAAO,CACrC,CAGF,GAAI,EAAO,GAAI,CACb,GAAM,CAAE,OAAQ,EAAI,GAAG,GAAoB,GAAW,CAAC,EAEvD,IAAK,IAAM,KAAS,OAAO,KAAK,EAAO,EAAE,EAAoC,CAC3E,IAAM,EAAW,EAAO,GAAG,GAEtB,GAEL,EAAU,KAAK,EAAO,EAAI,EAAiB,EAA2B,CAAe,CAAC,CACxF,CACF,CAEA,IAAM,MAAsB,CAC1B,IAAK,IAAM,KAAW,EAAW,EAAQ,CAC3C,EAIA,OAFA,EAAmB,CAAO,EAEnB,CACT,EAEM,EAAa,EAEb,GACJ,EACA,IACwB,CACxB,GAAI,OAAO,GAAU,WACnB,OAAO,MAAkB,EAAQ,EAAM,CAAC,CAAC,EAG3C,GAAI,EAAW,CAAK,EAClB,OAAO,MAAkB,EAAQ,EAAM,KAAK,CAAC,EAG/C,EAAQ,CAAK,CACf,EAEA,SAAS,EAAe,EAAmB,EAAc,EAA8C,CACrG,OAAO,EAAqB,EAAQ,GAAS,EAAQ,EAAM,EAAM,CAAI,CAAC,CACxE,CAEA,IAAM,EAAmB,SAEzB,SAAS,EAAW,EAAmB,EAAc,EAA8C,CACjG,IAAM,GAAW,EAAK,WAAW,IAAI,EAAI,EAAO,EAAQ,CAAI,EAAA,CAAG,QAAQ,EAAkB,EAAE,EAE3F,GAAI,CAAC,EAAS,OAEd,IAAI,EAAQ,GAQZ,OAAO,EAAqB,EAPV,GAA0D,CACtE,GAAK,MAAQ,IAAM,IACrB,EAAQ,GACR,EAAK,MAAM,YAAY,EAAS,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAkB,EAAE,CAAC,GAC9D,GAAO,EAAK,MAAM,eAAe,CAAO,CACrD,CAE2C,CAC7C,CAEA,SAAS,EACP,EACA,EACY,CACZ,IAAM,EACJ,OAAO,GAAU,WACb,MAC+B,CAC7B,IAAM,EAAkC,CAAC,EAEzC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAK,EAC7C,EAAO,GAAO,OAAO,GAAU,WAAa,EAAM,EAAI,EAAW,CAAK,EAAI,EAAM,MAAQ,EAAQ,EAGlG,OAAO,CACT,EAEF,EAAO,IAAI,IAkBf,OAhBY,MAAkB,CAC5B,IAAM,EAAO,IAAI,IAEjB,IAAK,GAAM,CAAC,EAAK,KAAW,OAAO,QAAQ,EAAO,CAAC,EAC5C,IAEL,EAAK,IAAI,CAAG,EAEP,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,IAAI,CAAG,GAE5C,IAAK,IAAM,KAAO,EACX,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,OAAO,CAAG,EAE/C,EAAO,CACT,CAEO,CACT"}
1
+ {"version":3,"file":"host-bind.js","names":[],"sources":["../src/host-bind.ts"],"sourcesContent":["/**\n * Host element binding API — reactive attr, class, style, and event bindings\n * applied directly to the component's host element or any target element.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { getHost, tryRegisterCleanup, watchEffect } from './runtime';\nimport { normalizeAriaKey, normalizeHostAttrKey } from './utils/aria';\nimport { listen, resolveMaybeReactive, sanitizeCssToken, setAttr, toKebab } from './utils/dom';\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => string | number | boolean | null | undefined)\n | Readable<string | number | boolean | null | undefined>\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\ntype HostClassBindingValue = Readable<boolean> | (() => boolean) | boolean;\n// Bivariant callback allows consumers to use narrower event types.\ntype HostEventListener = { bivarianceHack(event: Event): void }['bivarianceHack'];\n\nexport type HostBindConfig = {\n /**\n * ARIA attributes, keyed by bare property name (`expanded`) or fully-qualified\n * (`aria-expanded`) — both normalize to the same attribute. A separate key from `attr`\n * only so bare names can be normalized; the underlying write path is identical.\n */\n aria?: ReflectConfig;\n attr?: ReflectConfig;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type BindOptions = AddEventListenerOptions & {\n /**\n * Target element to bind to. Defaults to the host element when called\n * via `bind()`. Pass an explicit element to bind to any other element\n * (e.g. a slotted trigger or an internally-referenced child element).\n * When a target is provided, cleanup is always auto-registered with the\n * component scope if one is active.\n */\n target?: Element;\n};\n\nexport type HostBindFn = (config: HostBindConfig, options?: BindOptions) => () => void;\n\n/**\n * Apply reactive or static bindings to an element's attributes, classes, styles,\n * and events. Defaults to the current component's host element; pass\n * `options.target` to bind to any other element (e.g. a slotted trigger, an\n * internally-referenced child).\n */\nexport const bind: HostBindFn = (config: HostBindConfig, options?: BindOptions): (() => void) => {\n const el = (options?.target as HTMLElement | undefined) ?? getHost();\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.aria) {\n for (const [key, value] of Object.entries(config.aria)) {\n const name = normalizeAriaKey(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.on) {\n const { target: _t, ...listenerOptions } = options ?? {};\n\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, listenerOptions));\n }\n }\n\n const cleanup = (): void => {\n for (const dispose of disposers) dispose();\n };\n\n tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\nconst toHostAttr = normalizeHostAttrKey;\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | void => {\n if (typeof value === 'function') {\n return watchEffect(() => updater(value()));\n }\n\n if (isReactive(value)) {\n return watchEffect(() => updater(value.value));\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n const cssName = sanitizeCssToken(name.startsWith('--') ? name : toKebab(name));\n\n if (!cssName) return;\n\n let owned = false;\n const setStyle = (v: string | number | boolean | null | undefined): void => {\n if (v != null && v !== '') {\n owned = true;\n host.style.setProperty(cssName, sanitizeCssToken(String(v)));\n } else if (owned) host.style.removeProperty(cssName);\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => {\n const result: Record<string, boolean> = {};\n\n for (const [cls, entry] of Object.entries(value)) {\n result[cls] = resolveMaybeReactive(entry);\n }\n\n return result;\n };\n\n let prev = new Set<string>();\n\n const sub = watchEffect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n prev = next;\n });\n\n return sub;\n}\n"],"mappings":"6TAgEA,IAAa,GAAoB,EAAwB,IAAwC,CAC/F,IAAM,EAAM,GAAS,QAAsC,EAAQ,EAC7D,EAA+B,CAAC,EAEtC,GAAI,EAAO,KACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,IAAI,EAAG,CAEtD,IAAM,EAAU,EAAe,EADlB,EAAW,CACW,EAAM,CAAK,EAE1C,GAAS,EAAU,KAAK,CAAO,CACrC,CAGF,GAAI,EAAO,KACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,IAAI,EAAG,CAEtD,IAAM,EAAU,EAAe,EADlB,EAAiB,CACK,EAAM,CAAK,EAE1C,GAAS,EAAU,KAAK,CAAO,CACrC,CAOF,GAJI,EAAO,OACT,EAAU,KAAK,EAAc,EAAI,EAAO,KAAK,CAAC,EAG5C,EAAO,MACT,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAO,KAAK,EAAG,CACvD,IAAM,EAAU,EAAW,EAAI,EAAK,CAAK,EAErC,GAAS,EAAU,KAAK,CAAO,CACrC,CAGF,GAAI,EAAO,GAAI,CACb,GAAM,CAAE,OAAQ,EAAI,GAAG,GAAoB,GAAW,CAAC,EAEvD,IAAK,IAAM,KAAS,OAAO,KAAK,EAAO,EAAE,EAAoC,CAC3E,IAAM,EAAW,EAAO,GAAG,GAEtB,GAEL,EAAU,KAAK,EAAO,EAAI,EAAiB,EAA2B,CAAe,CAAC,CACxF,CACF,CAEA,IAAM,MAAsB,CAC1B,IAAK,IAAM,KAAW,EAAW,EAAQ,CAC3C,EAIA,OAFA,EAAmB,CAAO,EAEnB,CACT,EAEM,EAAa,EAEb,GACJ,EACA,IACwB,CACxB,GAAI,OAAO,GAAU,WACnB,OAAO,MAAkB,EAAQ,EAAM,CAAC,CAAC,EAG3C,GAAI,EAAW,CAAK,EAClB,OAAO,MAAkB,EAAQ,EAAM,KAAK,CAAC,EAG/C,EAAQ,CAAK,CACf,EAEA,SAAS,EAAe,EAAmB,EAAc,EAA8C,CACrG,OAAO,EAAqB,EAAQ,GAAS,EAAQ,EAAM,EAAM,CAAI,CAAC,CACxE,CAEA,SAAS,EAAW,EAAmB,EAAc,EAA8C,CACjG,IAAM,EAAU,EAAiB,EAAK,WAAW,IAAI,EAAI,EAAO,EAAQ,CAAI,CAAC,EAE7E,GAAI,CAAC,EAAS,OAEd,IAAI,EAAQ,GAQZ,OAAO,EAAqB,EAPV,GAA0D,CACtE,GAAK,MAAQ,IAAM,IACrB,EAAQ,GACR,EAAK,MAAM,YAAY,EAAS,EAAiB,OAAO,CAAC,CAAC,CAAC,GAClD,GAAO,EAAK,MAAM,eAAe,CAAO,CACrD,CAE2C,CAC7C,CAEA,SAAS,EACP,EACA,EACY,CACZ,IAAM,EACJ,OAAO,GAAU,WACb,MAC+B,CAC7B,IAAM,EAAkC,CAAC,EAEzC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAK,EAC7C,EAAO,GAAO,EAAqB,CAAK,EAG1C,OAAO,CACT,EAEF,EAAO,IAAI,IAkBf,OAhBY,MAAkB,CAC5B,IAAM,EAAO,IAAI,IAEjB,IAAK,GAAM,CAAC,EAAK,KAAW,OAAO,QAAQ,EAAO,CAAC,EAC5C,IAEL,EAAK,IAAI,CAAG,EAEP,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,IAAI,CAAG,GAE5C,IAAK,IAAM,KAAO,EACX,EAAK,IAAI,CAAG,GAAG,EAAK,UAAU,OAAO,CAAG,EAE/C,EAAO,CACT,CAEO,CACT"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./types/bindings.cjs"),n=require("./runtime.cjs"),r=require("./context.cjs"),i=require("./props.cjs"),a=require("./utils/css.cjs"),o=require("./define.cjs"),s=require("./slots.cjs"),c=require("./host-bind.cjs"),l=require("./aria.cjs"),u=require("./utils/emit.cjs"),d=require("./template/instantiator.cjs");require("./template.cjs");const f=require("./utils/id.cjs");exports.OreApiError=e.OreApiError,exports.OreError=e.OreError,exports.OreInternalError=e.OreInternalError,exports.OreLifecycleError=e.OreLifecycleError,exports.OreTimeoutError=e.OreTimeoutError,exports.aria=l.aria,exports.bind=c.bind,exports.createContext=r.createContext,exports.createId=f.createId,exports.createStableId=f.createStableId,exports.css=a.css,exports.define=o.define,exports.getHost=n.getHost,exports.html=d.html,exports.inject=r.inject,exports.injectStrict=r.injectStrict,exports.onCleanup=n.onCleanup,exports.onElement=n.onElement,exports.onEvent=n.onEvent,exports.onFormReset=n.onFormReset,exports.onMounted=n.onMounted,exports.prop=i.prop,exports.provide=r.provide,exports.ref=t.ref,exports.resetIdCounter=f.resetIdCounter,exports.useEmit=u.useEmit,exports.useSlots=s.useSlots,exports.watchEffect=n.watchEffect;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./types/bindings.cjs"),n=require("./runtime.cjs"),r=require("./context.cjs"),i=require("./props.cjs"),a=require("./utils/css.cjs"),o=require("./define.cjs"),s=require("./slots.cjs"),c=require("./host-bind.cjs"),l=require("./aria.cjs"),u=require("./utils/emit.cjs"),d=require("./template/instantiator.cjs");require("./template.cjs");const f=require("./directives/classMap.cjs"),p=require("./directives/each.cjs"),m=require("./directives/model.cjs"),h=require("./directives/styleMap.cjs"),g=require("./directives/when.cjs"),_=require("./utils/id.cjs");exports.OreApiError=e.OreApiError,exports.OreError=e.OreError,exports.OreInternalError=e.OreInternalError,exports.OreLifecycleError=e.OreLifecycleError,exports.aria=l.aria,exports.bind=c.bind,exports.classMap=f.classMap,exports.createContext=r.createContext,exports.createId=_.createId,exports.createStableId=_.createStableId,exports.css=a.css,exports.define=o.define,exports.each=p.each,exports.getHost=n.getHost,exports.html=d.html,exports.inject=r.inject,exports.injectStrict=r.injectStrict,exports.model=m.model,exports.onCleanup=n.onCleanup,exports.onElement=n.onElement,exports.onEvent=n.onEvent,exports.onFormReset=n.onFormReset,exports.onMounted=n.onMounted,exports.prop=i.prop,exports.provide=r.provide,exports.ref=t.ref,exports.resetStableIdCounter=_.resetStableIdCounter,exports.styleMap=h.styleMap,exports.useEmit=u.useEmit,exports.useSlots=s.useSlots,exports.watchEffect=n.watchEffect,exports.when=g.when;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { OreApiError, OreError, type OreErrorPhase, OreInternalError, OreLifecycleError, OreTimeoutError, } from './errors';
1
+ export { OreApiError, OreError, type OreErrorPhase, OreInternalError, OreLifecycleError } from './errors';
2
2
  export { define, prop } from './define';
3
3
  export type { ComponentDefinition } from './component-types';
4
4
  export type { InferProps, PropDef, PropInputDefs, PropsDef } from './props';
@@ -9,7 +9,12 @@ export { bind, type BindOptions, type HostBindConfig, type HostBindFn, type Host
9
9
  export { getHost, onCleanup, onElement, onEvent, onFormReset, type OnFormResetCallback, onMounted, type OnMountedCallback, watchEffect, } from './runtime';
10
10
  export { useEmit, type EmitFn } from './utils/emit';
11
11
  export { html } from './template';
12
+ export { classMap } from './directives/classMap';
13
+ export { each } from './directives/each';
14
+ export { model } from './directives/model';
15
+ export { styleMap } from './directives/styleMap';
16
+ export { when } from './directives/when';
12
17
  export { css, type CSSResult } from './utils/css';
13
- export { createId, createStableId, resetIdCounter } from './utils/id';
14
- export { ref, type DirectiveResult, type HTMLResult, type Ref, type RefCallback } from './types/bindings';
18
+ export { createId, createStableId, resetStableIdCounter } from './utils/id';
19
+ export { ref, type HTMLResult, type Ref, type RefCallback } from './types/bindings';
15
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,QAAQ,EACR,KAAK,aAAa,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GAChB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5E,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE5F,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAExD,OAAO,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EACL,IAAI,EACJ,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,OAAO,EACP,SAAS,EACT,SAAS,EACT,OAAO,EACP,WAAW,EACX,KAAK,mBAAmB,EACxB,SAAS,EACT,KAAK,iBAAiB,EACtB,WAAW,GACZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,OAAO,EAAE,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEtE,OAAO,EAAE,GAAG,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE1G,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5E,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE5F,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAExD,OAAO,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EACL,IAAI,EACJ,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,OAAO,EACP,SAAS,EACT,SAAS,EACT,OAAO,EACP,WAAW,EACX,KAAK,mBAAmB,EACxB,SAAS,EACT,KAAK,iBAAiB,EACtB,WAAW,GACZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AASlC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,EAAE,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,GAAG,EAAE,KAAK,UAAU,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{OreApiError as e,OreError as t,OreInternalError as n,OreLifecycleError as r,OreTimeoutError as i}from"./errors.js";import{ref as a}from"./types/bindings.js";import{getHost as o,onCleanup as s,onElement as c,onEvent as l,onFormReset as u,onMounted as d,watchEffect as f}from"./runtime.js";import{createContext as p,inject as m,injectStrict as h,provide as g}from"./context.js";import{prop as _}from"./props.js";import{css as v}from"./utils/css.js";import{define as y}from"./define.js";import{useSlots as b}from"./slots.js";import{bind as x}from"./host-bind.js";import{aria as S}from"./aria.js";import{useEmit as C}from"./utils/emit.js";import{html as w}from"./template/instantiator.js";import"./template.js";import{createId as T,createStableId as E,resetIdCounter as D}from"./utils/id.js";export{e as OreApiError,t as OreError,n as OreInternalError,r as OreLifecycleError,i as OreTimeoutError,S as aria,x as bind,p as createContext,T as createId,E as createStableId,v as css,y as define,o as getHost,w as html,m as inject,h as injectStrict,s as onCleanup,c as onElement,l as onEvent,u as onFormReset,d as onMounted,_ as prop,g as provide,a as ref,D as resetIdCounter,C as useEmit,b as useSlots,f as watchEffect};
1
+ import{OreApiError as e,OreError as t,OreInternalError as n,OreLifecycleError as r}from"./errors.js";import{ref as i}from"./types/bindings.js";import{getHost as a,onCleanup as o,onElement as s,onEvent as c,onFormReset as l,onMounted as u,watchEffect as d}from"./runtime.js";import{createContext as f,inject as p,injectStrict as m,provide as h}from"./context.js";import{prop as g}from"./props.js";import{css as _}from"./utils/css.js";import{define as v}from"./define.js";import{useSlots as y}from"./slots.js";import{bind as b}from"./host-bind.js";import{aria as x}from"./aria.js";import{useEmit as S}from"./utils/emit.js";import{html as C}from"./template/instantiator.js";import"./template.js";import{classMap as w}from"./directives/classMap.js";import{each as T}from"./directives/each.js";import{model as E}from"./directives/model.js";import{styleMap as D}from"./directives/styleMap.js";import{when as O}from"./directives/when.js";import{createId as k,createStableId as A,resetStableIdCounter as j}from"./utils/id.js";export{e as OreApiError,t as OreError,n as OreInternalError,r as OreLifecycleError,x as aria,b as bind,w as classMap,f as createContext,k as createId,A as createStableId,_ as css,v as define,T as each,a as getHost,C as html,p as inject,m as injectStrict,E as model,o as onCleanup,s as onElement,c as onEvent,l as onFormReset,u as onMounted,g as prop,h as provide,i as ref,j as resetStableIdCounter,D as styleMap,S as useEmit,y as useSlots,d as watchEffect,O as when};