@vielzeug/ore 1.2.3 → 2.0.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 (318) hide show
  1. package/README.md +11 -8
  2. package/dist/_component-class.cjs +2 -0
  3. package/dist/_component-class.cjs.map +1 -0
  4. package/dist/_component-class.d.ts +2 -0
  5. package/dist/_component-class.d.ts.map +1 -0
  6. package/dist/_component-class.js +2 -0
  7. package/dist/_component-class.js.map +1 -0
  8. package/dist/_dev.cjs +1 -1
  9. package/dist/_dev.cjs.map +1 -1
  10. package/dist/_dev.js +1 -1
  11. package/dist/_dev.js.map +1 -1
  12. package/dist/base-element.cjs +1 -1
  13. package/dist/base-element.cjs.map +1 -1
  14. package/dist/base-element.d.ts +9 -15
  15. package/dist/base-element.d.ts.map +1 -1
  16. package/dist/base-element.js +1 -1
  17. package/dist/base-element.js.map +1 -1
  18. package/dist/component-types.d.ts +3 -14
  19. package/dist/component-types.d.ts.map +1 -1
  20. package/dist/context.cjs +1 -1
  21. package/dist/context.cjs.map +1 -1
  22. package/dist/context.d.ts +13 -0
  23. package/dist/context.d.ts.map +1 -1
  24. package/dist/context.js +1 -1
  25. package/dist/context.js.map +1 -1
  26. package/dist/define.cjs +1 -1
  27. package/dist/define.cjs.map +1 -1
  28. package/dist/define.d.ts +6 -5
  29. package/dist/define.d.ts.map +1 -1
  30. package/dist/define.js +1 -1
  31. package/dist/define.js.map +1 -1
  32. package/dist/directives/classMap.cjs +1 -1
  33. package/dist/directives/classMap.cjs.map +1 -1
  34. package/dist/directives/classMap.d.ts.map +1 -1
  35. package/dist/directives/classMap.js +1 -1
  36. package/dist/directives/classMap.js.map +1 -1
  37. package/dist/directives/each.cjs +1 -1
  38. package/dist/directives/each.cjs.map +1 -1
  39. package/dist/directives/each.d.ts +9 -2
  40. package/dist/directives/each.d.ts.map +1 -1
  41. package/dist/directives/each.js +1 -1
  42. package/dist/directives/each.js.map +1 -1
  43. package/dist/directives/live.cjs +1 -1
  44. package/dist/directives/live.cjs.map +1 -1
  45. package/dist/directives/live.d.ts +10 -12
  46. package/dist/directives/live.d.ts.map +1 -1
  47. package/dist/directives/live.js +1 -1
  48. package/dist/directives/live.js.map +1 -1
  49. package/dist/directives/styleMap.cjs +1 -1
  50. package/dist/directives/styleMap.cjs.map +1 -1
  51. package/dist/directives/styleMap.d.ts +1 -1
  52. package/dist/directives/styleMap.d.ts.map +1 -1
  53. package/dist/directives/styleMap.js +1 -1
  54. package/dist/directives/styleMap.js.map +1 -1
  55. package/dist/directives/unsafe-html.cjs +2 -0
  56. package/dist/directives/unsafe-html.cjs.map +1 -0
  57. package/dist/directives/unsafe-html.d.ts +14 -0
  58. package/dist/directives/unsafe-html.d.ts.map +1 -0
  59. package/dist/directives/unsafe-html.js +2 -0
  60. package/dist/directives/unsafe-html.js.map +1 -0
  61. package/dist/directives/when.cjs +1 -1
  62. package/dist/directives/when.cjs.map +1 -1
  63. package/dist/directives/when.d.ts +1 -1
  64. package/dist/directives/when.d.ts.map +1 -1
  65. package/dist/directives/when.js +1 -1
  66. package/dist/directives/when.js.map +1 -1
  67. package/dist/errors.cjs +2 -2
  68. package/dist/errors.cjs.map +1 -1
  69. package/dist/errors.d.ts +21 -6
  70. package/dist/errors.d.ts.map +1 -1
  71. package/dist/errors.js +2 -2
  72. package/dist/errors.js.map +1 -1
  73. package/dist/forms/field.cjs +1 -1
  74. package/dist/forms/field.cjs.map +1 -1
  75. package/dist/forms/field.d.ts +5 -1
  76. package/dist/forms/field.d.ts.map +1 -1
  77. package/dist/forms/field.js +1 -1
  78. package/dist/forms/field.js.map +1 -1
  79. package/dist/host-bind.cjs +1 -1
  80. package/dist/host-bind.cjs.map +1 -1
  81. package/dist/host-bind.d.ts +6 -0
  82. package/dist/host-bind.d.ts.map +1 -1
  83. package/dist/host-bind.js +1 -1
  84. package/dist/host-bind.js.map +1 -1
  85. package/dist/index.cjs +1 -1
  86. package/dist/index.d.ts +15 -5
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +1 -1
  89. package/dist/observers/intersection-observe.cjs +1 -1
  90. package/dist/observers/intersection-observe.cjs.map +1 -1
  91. package/dist/observers/intersection-observe.d.ts.map +1 -1
  92. package/dist/observers/intersection-observe.js +1 -1
  93. package/dist/observers/intersection-observe.js.map +1 -1
  94. package/dist/observers/media-observe.cjs +1 -1
  95. package/dist/observers/media-observe.cjs.map +1 -1
  96. package/dist/observers/media-observe.d.ts.map +1 -1
  97. package/dist/observers/media-observe.js +1 -1
  98. package/dist/observers/media-observe.js.map +1 -1
  99. package/dist/observers/mutation-observe.cjs +1 -1
  100. package/dist/observers/mutation-observe.cjs.map +1 -1
  101. package/dist/observers/mutation-observe.d.ts.map +1 -1
  102. package/dist/observers/mutation-observe.js +1 -1
  103. package/dist/observers/mutation-observe.js.map +1 -1
  104. package/dist/observers/resize-observe.cjs +1 -1
  105. package/dist/observers/resize-observe.cjs.map +1 -1
  106. package/dist/observers/resize-observe.d.ts.map +1 -1
  107. package/dist/observers/resize-observe.js +1 -1
  108. package/dist/observers/resize-observe.js.map +1 -1
  109. package/dist/ore.cjs +2 -2
  110. package/dist/ore.cjs.map +1 -1
  111. package/dist/ore.iife.js +2 -2
  112. package/dist/ore.iife.js.map +1 -1
  113. package/dist/ore.js +2 -2
  114. package/dist/ore.js.map +1 -1
  115. package/dist/props.cjs +1 -1
  116. package/dist/props.cjs.map +1 -1
  117. package/dist/props.d.ts +1 -6
  118. package/dist/props.d.ts.map +1 -1
  119. package/dist/props.js +1 -1
  120. package/dist/props.js.map +1 -1
  121. package/dist/runtime.cjs +1 -1
  122. package/dist/runtime.cjs.map +1 -1
  123. package/dist/runtime.d.ts +7 -10
  124. package/dist/runtime.d.ts.map +1 -1
  125. package/dist/runtime.js +1 -1
  126. package/dist/runtime.js.map +1 -1
  127. package/dist/slots.cjs +1 -1
  128. package/dist/slots.cjs.map +1 -1
  129. package/dist/slots.d.ts.map +1 -1
  130. package/dist/slots.js +1 -1
  131. package/dist/slots.js.map +1 -1
  132. package/dist/template/binding-types.cjs +1 -0
  133. package/dist/template/binding-types.d.ts +59 -0
  134. package/dist/template/binding-types.d.ts.map +1 -0
  135. package/dist/template/binding-types.js +1 -0
  136. package/dist/template/bindings.cjs +1 -1
  137. package/dist/template/bindings.cjs.map +1 -1
  138. package/dist/template/bindings.d.ts +18 -3
  139. package/dist/template/bindings.d.ts.map +1 -1
  140. package/dist/template/bindings.js +1 -1
  141. package/dist/template/bindings.js.map +1 -1
  142. package/dist/template/compiler.cjs +1 -1
  143. package/dist/template/compiler.cjs.map +1 -1
  144. package/dist/template/compiler.d.ts +0 -4
  145. package/dist/template/compiler.d.ts.map +1 -1
  146. package/dist/template/compiler.js +1 -1
  147. package/dist/template/compiler.js.map +1 -1
  148. package/dist/template/instantiator.cjs +1 -1
  149. package/dist/template/instantiator.cjs.map +1 -1
  150. package/dist/template/instantiator.d.ts +6 -1
  151. package/dist/template/instantiator.d.ts.map +1 -1
  152. package/dist/template/instantiator.js +1 -1
  153. package/dist/template/instantiator.js.map +1 -1
  154. package/dist/template/result.cjs +2 -0
  155. package/dist/template/result.cjs.map +1 -0
  156. package/dist/template/result.d.ts +42 -0
  157. package/dist/template/result.d.ts.map +1 -0
  158. package/dist/template/result.js +2 -0
  159. package/dist/template/result.js.map +1 -0
  160. package/dist/testing/flush.cjs +1 -1
  161. package/dist/testing/flush.cjs.map +1 -1
  162. package/dist/testing/flush.d.ts +30 -26
  163. package/dist/testing/flush.d.ts.map +1 -1
  164. package/dist/testing/flush.js +1 -1
  165. package/dist/testing/flush.js.map +1 -1
  166. package/dist/testing/form-internals-polyfill.cjs +1 -1
  167. package/dist/testing/form-internals-polyfill.cjs.map +1 -1
  168. package/dist/testing/form-internals-polyfill.d.ts +9 -7
  169. package/dist/testing/form-internals-polyfill.d.ts.map +1 -1
  170. package/dist/testing/form-internals-polyfill.js +1 -1
  171. package/dist/testing/form-internals-polyfill.js.map +1 -1
  172. package/dist/testing/index.d.ts +35 -1
  173. package/dist/testing/index.d.ts.map +1 -1
  174. package/dist/testing/mount.cjs +1 -1
  175. package/dist/testing/mount.cjs.map +1 -1
  176. package/dist/testing/mount.d.ts +10 -19
  177. package/dist/testing/mount.d.ts.map +1 -1
  178. package/dist/testing/mount.js +1 -1
  179. package/dist/testing/mount.js.map +1 -1
  180. package/dist/testing/render-hook.cjs +1 -1
  181. package/dist/testing/render-hook.cjs.map +1 -1
  182. package/dist/testing/render-hook.js +1 -1
  183. package/dist/testing/render-hook.js.map +1 -1
  184. package/dist/testing/reset.cjs +2 -0
  185. package/dist/testing/reset.cjs.map +1 -0
  186. package/dist/testing/reset.d.ts +12 -0
  187. package/dist/testing/reset.d.ts.map +1 -0
  188. package/dist/testing/reset.js +2 -0
  189. package/dist/testing/reset.js.map +1 -0
  190. package/dist/testing.cjs +2 -1
  191. package/dist/testing.cjs.map +1 -0
  192. package/dist/testing.js +2 -1
  193. package/dist/testing.js.map +1 -0
  194. package/dist/utils/aria.cjs.map +1 -1
  195. package/dist/utils/aria.d.ts +1 -1
  196. package/dist/utils/aria.js.map +1 -1
  197. package/dist/utils/brand.cjs +2 -0
  198. package/dist/utils/brand.cjs.map +1 -0
  199. package/dist/utils/brand.d.ts +16 -0
  200. package/dist/utils/brand.d.ts.map +1 -0
  201. package/dist/utils/brand.js +2 -0
  202. package/dist/utils/brand.js.map +1 -0
  203. package/dist/utils/css.cjs +1 -1
  204. package/dist/utils/css.cjs.map +1 -1
  205. package/dist/utils/css.d.ts.map +1 -1
  206. package/dist/utils/css.js +1 -1
  207. package/dist/utils/css.js.map +1 -1
  208. package/dist/utils/dom.cjs +1 -1
  209. package/dist/utils/dom.cjs.map +1 -1
  210. package/dist/utils/dom.d.ts +34 -0
  211. package/dist/utils/dom.d.ts.map +1 -1
  212. package/dist/utils/dom.js +1 -1
  213. package/dist/utils/dom.js.map +1 -1
  214. package/dist/utils/emit.cjs.map +1 -1
  215. package/dist/utils/emit.d.ts +10 -3
  216. package/dist/utils/emit.d.ts.map +1 -1
  217. package/dist/utils/emit.js.map +1 -1
  218. package/dist/utils/id.cjs +1 -1
  219. package/dist/utils/id.cjs.map +1 -1
  220. package/dist/utils/id.d.ts +11 -2
  221. package/dist/utils/id.d.ts.map +1 -1
  222. package/dist/utils/id.js +1 -1
  223. package/dist/utils/id.js.map +1 -1
  224. package/package.json +15 -30
  225. package/dist/aria.cjs +0 -2
  226. package/dist/aria.cjs.map +0 -1
  227. package/dist/aria.d.ts +0 -20
  228. package/dist/aria.d.ts.map +0 -1
  229. package/dist/aria.js +0 -2
  230. package/dist/aria.js.map +0 -1
  231. package/dist/devtools.cjs +0 -2
  232. package/dist/devtools.cjs.map +0 -1
  233. package/dist/devtools.d.ts +0 -32
  234. package/dist/devtools.d.ts.map +0 -1
  235. package/dist/devtools.js +0 -2
  236. package/dist/devtools.js.map +0 -1
  237. package/dist/directives/index.d.ts +0 -8
  238. package/dist/directives/index.d.ts.map +0 -1
  239. package/dist/directives/model.cjs +0 -2
  240. package/dist/directives/model.cjs.map +0 -1
  241. package/dist/directives/model.d.ts +0 -28
  242. package/dist/directives/model.d.ts.map +0 -1
  243. package/dist/directives/model.js +0 -2
  244. package/dist/directives/model.js.map +0 -1
  245. package/dist/directives/raw.cjs +0 -2
  246. package/dist/directives/raw.cjs.map +0 -1
  247. package/dist/directives/raw.d.ts +0 -16
  248. package/dist/directives/raw.d.ts.map +0 -1
  249. package/dist/directives/raw.js +0 -2
  250. package/dist/directives/raw.js.map +0 -1
  251. package/dist/directives.cjs +0 -1
  252. package/dist/directives.js +0 -1
  253. package/dist/forms/context.cjs +0 -2
  254. package/dist/forms/context.cjs.map +0 -1
  255. package/dist/forms/context.d.ts +0 -56
  256. package/dist/forms/context.d.ts.map +0 -1
  257. package/dist/forms/context.js +0 -2
  258. package/dist/forms/context.js.map +0 -1
  259. package/dist/forms/index.d.ts +0 -11
  260. package/dist/forms/index.d.ts.map +0 -1
  261. package/dist/forms.cjs +0 -1
  262. package/dist/forms.js +0 -1
  263. package/dist/observers/index.d.ts +0 -5
  264. package/dist/observers/index.d.ts.map +0 -1
  265. package/dist/observers.cjs +0 -1
  266. package/dist/observers.js +0 -1
  267. package/dist/template.cjs +0 -1
  268. package/dist/template.d.ts +0 -4
  269. package/dist/template.d.ts.map +0 -1
  270. package/dist/template.js +0 -1
  271. package/dist/testing/events.cjs +0 -2
  272. package/dist/testing/events.cjs.map +0 -1
  273. package/dist/testing/events.d.ts +0 -37
  274. package/dist/testing/events.d.ts.map +0 -1
  275. package/dist/testing/events.js +0 -2
  276. package/dist/testing/events.js.map +0 -1
  277. package/dist/testing/interactions.cjs +0 -2
  278. package/dist/testing/interactions.cjs.map +0 -1
  279. package/dist/testing/interactions.d.ts +0 -27
  280. package/dist/testing/interactions.d.ts.map +0 -1
  281. package/dist/testing/interactions.js +0 -2
  282. package/dist/testing/interactions.js.map +0 -1
  283. package/dist/testing/query.cjs +0 -2
  284. package/dist/testing/query.cjs.map +0 -1
  285. package/dist/testing/query.d.ts +0 -24
  286. package/dist/testing/query.d.ts.map +0 -1
  287. package/dist/testing/query.js +0 -2
  288. package/dist/testing/query.js.map +0 -1
  289. package/dist/testing/testing.cjs +0 -2
  290. package/dist/testing/testing.cjs.map +0 -1
  291. package/dist/testing/testing.d.ts +0 -32
  292. package/dist/testing/testing.d.ts.map +0 -1
  293. package/dist/testing/testing.js +0 -2
  294. package/dist/testing/testing.js.map +0 -1
  295. package/dist/testing/wait.cjs +0 -2
  296. package/dist/testing/wait.cjs.map +0 -1
  297. package/dist/testing/wait.d.ts +0 -35
  298. package/dist/testing/wait.d.ts.map +0 -1
  299. package/dist/testing/wait.js +0 -2
  300. package/dist/testing/wait.js.map +0 -1
  301. package/dist/types/bindings.cjs +0 -2
  302. package/dist/types/bindings.cjs.map +0 -1
  303. package/dist/types/bindings.d.ts +0 -125
  304. package/dist/types/bindings.d.ts.map +0 -1
  305. package/dist/types/bindings.js +0 -2
  306. package/dist/types/bindings.js.map +0 -1
  307. package/dist/types.cjs +0 -2
  308. package/dist/types.cjs.map +0 -1
  309. package/dist/types.d.ts +0 -19
  310. package/dist/types.d.ts.map +0 -1
  311. package/dist/types.js +0 -2
  312. package/dist/types.js.map +0 -1
  313. package/dist/utils/event-modifiers.cjs +0 -2
  314. package/dist/utils/event-modifiers.cjs.map +0 -1
  315. package/dist/utils/event-modifiers.d.ts +0 -11
  316. package/dist/utils/event-modifiers.d.ts.map +0 -1
  317. package/dist/utils/event-modifiers.js +0 -2
  318. package/dist/utils/event-modifiers.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"dom.cjs","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { warn } from '../_dev';\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) return () => {};\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"+BAMA,IAAa,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAC1B,EAAA,KACE,yBAAyB,EAAK,oEAAoE,EAAK,MAAM,CAAC,EAAE,yBAClH,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAC1B,EAAA,KACE,iMACF,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAChE,EAAA,KACE,8CAA8C,EAAK,6DACrD,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAAI,UAAa,CAAC,EAEvB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
1
+ {"version":3,"file":"dom.cjs","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS } from '../errors';\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive\n * signal — the one shared three-way branch used by `classMap`/`styleMap`/`bind()`.\n */\nexport const resolveMaybeReactive = <T>(value: T | Readable<T> | (() => T)): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\" — a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `unsafeHtml()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping — this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes — read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Sanitize untrusted content, then use unsafeHtml() if HTML injection is required.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) {\n warn(ORE_ERRORS.listenNullTarget(name));\n\n return () => {};\n }\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"0FAaA,IAAa,EAA2B,GACtC,OAAO,GAAU,WAAc,EAAkB,GAAA,EAAI,EAAA,WAAA,CAAW,CAAK,EAAI,EAAM,MAAQ,EAO5E,EAAmB,SAEnB,EAAoB,GAA0B,EAAM,QAAQ,EAAkB,EAAE,EAEhF,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EAuBa,MAA+C,CAC1D,IAAI,EAAgB,CAAC,EACjB,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACN,EAAO,CAAQ,EACf,EAAY,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAO,CACT,EACA,gBAAgB,EAAI,CAClB,EAAS,KAAK,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQ,CACV,CACF,CACF,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAExB,GAAyB,EAAzB,EAAkG,EAAK,MAAM,CAAC,EAA9G,EAEF,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAI1B,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAE9D,GAA8C,EAA9C,EAEF,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAGH,OAFK,EAAA,WAAW,iBAAiB,CAAI,MAExB,CAAC,EAGhB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
@@ -1,8 +1,42 @@
1
1
  /**
2
2
  * Low-level DOM utilities used throughout the runtime and binding layers.
3
3
  */
4
+ import { type Readable } from '@vielzeug/ripple';
5
+ /**
6
+ * Resolves a value that may be a plain value, a getter function, or a reactive
7
+ * signal — the one shared three-way branch used by `classMap`/`styleMap`/`bind()`.
8
+ */
9
+ export declare const resolveMaybeReactive: <T>(value: T | Readable<T> | (() => T)) => T;
10
+ /**
11
+ * Characters that can break out of a CSS declaration in an inline style value or property name.
12
+ * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not
13
+ * inline style values, and signal an injection attempt there.
14
+ */
15
+ export declare const UNSAFE_CSS_CHARS: RegExp;
16
+ export declare const sanitizeCssToken: (value: string) => string;
4
17
  export declare const runAll: (fns: (() => void)[]) => void;
5
18
  export declare const removeNodes: (nodes: Node[]) => void;
19
+ /**
20
+ * Tracks "whatever is currently rendered in one spot" — a list of live DOM nodes plus the
21
+ * cleanup functions that were registered while mounting them. `clear()` tears both down and
22
+ * resets to empty, ready for the next render.
23
+ *
24
+ * Every directive/binding that swaps its rendered content when a reactive source changes
25
+ * (`when()`, `unsafeHtml()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this
26
+ * bookkeeping — this is the one shared implementation instead of four independently-maintained
27
+ * `currentNodes`/`currentCleanups` variable pairs.
28
+ */
29
+ export type ReplaceableSlot = {
30
+ /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */
31
+ clear(): void;
32
+ /** Currently tracked nodes — read after mounting to know what's live. */
33
+ readonly nodes: Node[];
34
+ /** Pass as the `registerCleanup` callback to whatever mounts the next render. */
35
+ registerCleanup(fn: () => void): void;
36
+ /** Replace the tracked node list (call once mounting the next render is complete). */
37
+ setNodes(nodes: Node[]): void;
38
+ };
39
+ export declare const createReplaceableSlot: () => ReplaceableSlot;
6
40
  export declare const setAttr: (el: Element, name: string, val: unknown) => void;
7
41
  export declare const listen: (el: EventTarget | null | undefined, name: string, handler: EventListener, options?: AddEventListenerOptions) => (() => void);
8
42
  export declare const toKebab: (str: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,eAAO,MAAM,MAAM,GAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,IAAI,EAAE,KAAG,IAI3C,CAAC;AAiCF,eAAO,MAAM,OAAO,GAAI,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,OAAO,KAAG,IAuCjE,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,IAAI,WAAW,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,MAAM,EACZ,SAAS,aAAa,EACtB,UAAU,uBAAuB,KAChC,CAAC,MAAM,IAAI,CAQb,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAA6D,CAAC;AAEpG,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACW,CAAC"}
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK7D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAG,CACiB,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAW,CAAC;AAEzC,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,MAA6C,CAAC;AAE/F,eAAO,MAAM,MAAM,GAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,IAAI,EAAE,KAAG,IAI3C,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,gGAAgG;IAChG,KAAK,IAAI,IAAI,CAAC;IACd,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACvB,iFAAiF;IACjF,eAAe,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACtC,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,eAqBxC,CAAC;AAiCF,eAAO,MAAM,OAAO,GAAI,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,OAAO,KAAG,IAuCjE,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,IAAI,WAAW,GAAG,IAAI,GAAG,SAAS,EAClC,MAAM,MAAM,EACZ,SAAS,aAAa,EACtB,UAAU,uBAAuB,KAChC,CAAC,MAAM,IAAI,CAYb,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAA6D,CAAC;AAEpG,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MACW,CAAC"}
package/dist/utils/dom.js CHANGED
@@ -1,2 +1,2 @@
1
- import{warn as e}from"../_dev.js";var t=e=>{for(let t=e.length-1;t>=0;t--)e[t]()},n=e=>{for(let t of e)t.remove()},r=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),i=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,a=(t,n,a)=>{let o=n.toLowerCase();if(/^on[a-z]/i.test(n)){e(`Blocked setAttribute("${n}", ...) — inline event handler attributes are not supported. Use @${n.slice(2)} binding syntax instead.`),t.removeAttribute(n);return}if(o===`srcdoc`){e(`Blocked setAttribute("srcdoc", ...) — "srcdoc" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`),t.removeAttribute(n);return}if(a==null||a===!1){t.removeAttribute(n);return}let s=a===!0?`true`:String(a);if(r.has(o)&&i.test(s)){e(`Blocked dangerous URL scheme in attribute "${n}". Only safe URLs are permitted in URL-accepting attributes.`),t.removeAttribute(n);return}t.setAttribute(n,s)},o=(e,t,n,r)=>{if(!e)return()=>{};let i=n;return e.addEventListener(t,i,r),()=>e.removeEventListener(t,i,r)},s=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),c=e=>Array.isArray(e)||typeof e==`object`&&!!e;export{c as isStructuredValue,o as listen,n as removeNodes,t as runAll,a as setAttr,s as toKebab};
1
+ import"../_dev.js";import{ORE_ERRORS as e}from"../errors.js";import{isReactive as t}from"@vielzeug/ripple";var n=e=>typeof e==`function`?e():t(e)?e.value:e,r=/[;{}]/g,i=e=>e.replace(r,``),a=e=>{for(let t=e.length-1;t>=0;t--)e[t]()},o=e=>{for(let t of e)t.remove()},s=()=>{let e=[],t=[];return{clear(){a(t),o(e),t=[],e=[]},get nodes(){return e},registerCleanup(e){t.push(e)},setNodes(t){e=t}}},c=new Set([`action`,`cite`,`codebase`,`data`,`formaction`,`href`,`manifest`,`ping`,`poster`,`src`,`xlink:href`]),l=/^\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\/(?:html|svg\+xml)|application\/(?:xhtml|xml)))/i,u=(e,t,n)=>{let r=t.toLowerCase();if(/^on[a-z]/i.test(t)){`${t}${t.slice(2)}`,e.removeAttribute(t);return}if(r===`srcdoc`){e.removeAttribute(t);return}if(n==null||n===!1){e.removeAttribute(t);return}let i=n===!0?`true`:String(n);if(c.has(r)&&l.test(i)){`${t}`,e.removeAttribute(t);return}e.setAttribute(t,i)},d=(t,n,r,i)=>{if(!t)return e.listenNullTarget(n),()=>{};let a=r;return t.addEventListener(n,a,i),()=>t.removeEventListener(n,a,i)},f=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),p=e=>Array.isArray(e)||typeof e==`object`&&!!e;export{r as UNSAFE_CSS_CHARS,s as createReplaceableSlot,p as isStructuredValue,d as listen,o as removeNodes,n as resolveMaybeReactive,a as runAll,i as sanitizeCssToken,u as setAttr,f as toKebab};
2
2
  //# sourceMappingURL=dom.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dom.js","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { warn } from '../_dev';\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Use raw() with a registered sanitizer if you need to inject trusted HTML.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) return () => {};\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"kCAMA,IAAa,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAC1B,EACE,yBAAyB,EAAK,oEAAoE,EAAK,MAAM,CAAC,EAAE,yBAClH,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAC1B,EACE,iMACF,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAChE,EACE,8CAA8C,EAAK,6DACrD,EACA,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAAI,UAAa,CAAC,EAEvB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
1
+ {"version":3,"file":"dom.js","names":[],"sources":["../../src/utils/dom.ts"],"sourcesContent":["/**\n * Low-level DOM utilities used throughout the runtime and binding layers.\n */\n\nimport { isReactive, type Readable } from '@vielzeug/ripple';\n\nimport { warn } from '../_dev';\nimport { ORE_ERRORS } from '../errors';\n\n/**\n * Resolves a value that may be a plain value, a getter function, or a reactive\n * signal — the one shared three-way branch used by `classMap`/`styleMap`/`bind()`.\n */\nexport const resolveMaybeReactive = <T>(value: T | Readable<T> | (() => T)): T =>\n typeof value === 'function' ? (value as () => T)() : isReactive(value) ? value.value : value;\n\n/**\n * Characters that can break out of a CSS declaration in an inline style value or property name.\n * Semicolons end the current declaration; braces are meaningful in stylesheet rules but not\n * inline style values, and signal an injection attempt there.\n */\nexport const UNSAFE_CSS_CHARS = /[;{}]/g;\n\nexport const sanitizeCssToken = (value: string): string => value.replace(UNSAFE_CSS_CHARS, '');\n\nexport const runAll = (fns: (() => void)[]): void => {\n for (let i = fns.length - 1; i >= 0; i--) fns[i]!();\n};\n\nexport const removeNodes = (nodes: Node[]): void => {\n for (const node of nodes) {\n (node as ChildNode).remove();\n }\n};\n\n/**\n * Tracks \"whatever is currently rendered in one spot\" — a list of live DOM nodes plus the\n * cleanup functions that were registered while mounting them. `clear()` tears both down and\n * resets to empty, ready for the next render.\n *\n * Every directive/binding that swaps its rendered content when a reactive source changes\n * (`when()`, `unsafeHtml()`, `each()`'s empty-list fallback, `applyHtmlBinding()`) needs exactly this\n * bookkeeping — this is the one shared implementation instead of four independently-maintained\n * `currentNodes`/`currentCleanups` variable pairs.\n */\nexport type ReplaceableSlot = {\n /** Tears down every registered cleanup and removes every tracked node, then resets to empty. */\n clear(): void;\n /** Currently tracked nodes — read after mounting to know what's live. */\n readonly nodes: Node[];\n /** Pass as the `registerCleanup` callback to whatever mounts the next render. */\n registerCleanup(fn: () => void): void;\n /** Replace the tracked node list (call once mounting the next render is complete). */\n setNodes(nodes: Node[]): void;\n};\n\nexport const createReplaceableSlot = (): ReplaceableSlot => {\n let nodes: Node[] = [];\n let cleanups: (() => void)[] = [];\n\n return {\n clear() {\n runAll(cleanups);\n removeNodes(nodes);\n cleanups = [];\n nodes = [];\n },\n get nodes() {\n return nodes;\n },\n registerCleanup(fn) {\n cleanups.push(fn);\n },\n setNodes(next) {\n nodes = next;\n },\n };\n};\n\n/**\n * HTML attributes that accept URLs. Values bound to these attributes are\n * checked for dangerous schemes before being set.\n *\n * `srcdoc` is deliberately excluded: it holds raw HTML (not a URL), so scheme\n * checking doesn't apply — it's blocked unconditionally below, alongside `on*`.\n */\nconst URL_ATTRS = new Set([\n 'action',\n 'cite',\n 'codebase',\n 'data',\n 'formaction',\n 'href',\n 'manifest',\n 'ping',\n 'poster',\n 'src',\n 'xlink:href',\n]);\n\n/**\n * Schemes that execute JavaScript or can embed arbitrary HTML. Blocked\n * unconditionally in URL-accepting attributes.\n * Covers: javascript:, vbscript:, blob:, and data: variants that carry HTML/XML\n * or script-capable SVG. Plain data: image URIs (e.g. data:image/png) are\n * intentionally allowed.\n */\nconst DANGEROUS_SCHEME_RE =\n /^\\s*(?:(?:javascript|vbscript|blob):|data:(?:[^,]*\\/(?:html|svg\\+xml)|application\\/(?:xhtml|xml)))/i;\n\nexport const setAttr = (el: Element, name: string, val: unknown): void => {\n const lowerName = name.toLowerCase();\n\n if (/^on[a-z]/i.test(name)) {\n warn(\n `Blocked setAttribute(\"${name}\", ...) — inline event handler attributes are not supported. Use @${name.slice(2)} binding syntax instead.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (lowerName === 'srcdoc') {\n warn(\n `Blocked setAttribute(\"srcdoc\", ...) — \"srcdoc\" holds raw HTML, not a URL, and is not supported via attribute binding. Sanitize untrusted content, then use unsafeHtml() if HTML injection is required.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n if (val == null || val === false) {\n el.removeAttribute(name);\n\n return;\n }\n\n const strVal = val === true ? 'true' : String(val);\n\n if (URL_ATTRS.has(lowerName) && DANGEROUS_SCHEME_RE.test(strVal)) {\n warn(\n `Blocked dangerous URL scheme in attribute \"${name}\". Only safe URLs are permitted in URL-accepting attributes.`,\n );\n el.removeAttribute(name);\n\n return;\n }\n\n el.setAttribute(name, strVal);\n};\n\nexport const listen = (\n el: EventTarget | null | undefined,\n name: string,\n handler: EventListener,\n options?: AddEventListenerOptions,\n): (() => void) => {\n if (!el) {\n warn(ORE_ERRORS.listenNullTarget(name));\n\n return () => {};\n }\n\n const listener: EventListener = handler;\n\n el.addEventListener(name, listener, options);\n\n return () => el.removeEventListener(name, listener, options);\n};\n\nexport const toKebab = (str: string): string => str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n\nexport const isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n"],"mappings":"2GAaA,IAAa,EAA2B,GACtC,OAAO,GAAU,WAAc,EAAkB,EAAI,EAAW,CAAK,EAAI,EAAM,MAAQ,EAO5E,EAAmB,SAEnB,EAAoB,GAA0B,EAAM,QAAQ,EAAkB,EAAE,EAEhF,EAAU,GAA8B,CACnD,IAAK,IAAI,EAAI,EAAI,OAAS,EAAG,GAAK,EAAG,IAAK,EAAI,EAAE,CAAE,CACpD,EAEa,EAAe,GAAwB,CAClD,IAAK,IAAM,KAAQ,EACjB,EAAoB,OAAO,CAE/B,EAuBa,MAA+C,CAC1D,IAAI,EAAgB,CAAC,EACjB,EAA2B,CAAC,EAEhC,MAAO,CACL,OAAQ,CACN,EAAO,CAAQ,EACf,EAAY,CAAK,EACjB,EAAW,CAAC,EACZ,EAAQ,CAAC,CACX,EACA,IAAI,OAAQ,CACV,OAAO,CACT,EACA,gBAAgB,EAAI,CAClB,EAAS,KAAK,CAAE,CAClB,EACA,SAAS,EAAM,CACb,EAAQ,CACV,CACF,CACF,EASM,EAAY,IAAI,IAAI,CACxB,SACA,OACA,WACA,OACA,aACA,OACA,WACA,OACA,SACA,MACA,YACF,CAAC,EASK,EACJ,sGAEW,GAAW,EAAa,EAAc,IAAuB,CACxE,IAAM,EAAY,EAAK,YAAY,EAEnC,GAAI,YAAY,KAAK,CAAI,EAAG,CAExB,GAAyB,EAAzB,EAAkG,EAAK,MAAM,CAAC,EAA9G,EAEF,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,IAAc,SAAU,CAI1B,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,GAAI,GAAO,MAAQ,IAAQ,GAAO,CAChC,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,IAAM,EAAS,IAAQ,GAAO,OAAS,OAAO,CAAG,EAEjD,GAAI,EAAU,IAAI,CAAS,GAAK,EAAoB,KAAK,CAAM,EAAG,CAE9D,GAA8C,EAA9C,EAEF,EAAG,gBAAgB,CAAI,EAEvB,MACF,CAEA,EAAG,aAAa,EAAM,CAAM,CAC9B,EAEa,GACX,EACA,EACA,EACA,IACiB,CACjB,GAAI,CAAC,EAGH,OAFK,EAAW,iBAAiB,CAAI,MAExB,CAAC,EAGhB,IAAM,EAA0B,EAIhC,OAFA,EAAG,iBAAiB,EAAM,EAAU,CAAO,MAE9B,EAAG,oBAAoB,EAAM,EAAU,CAAO,CAC7D,EAEa,EAAW,GAAwB,EAAI,QAAQ,SAAW,GAAM,IAAI,EAAE,YAAY,GAAG,EAErF,EAAqB,GAChC,MAAM,QAAQ,CAAK,GAAM,OAAO,GAAU,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"emit.cjs","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\ntype StrictEmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): boolean;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;\n};\n\ntype LooseEmitFn = (event: string, detail?: unknown) => boolean;\n\nexport type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseEmitFn;\n\nconst DEFAULT_FIRE_OPTIONS = { bubbles: true, cancelable: true, composed: false };\n\n/**\n * Returns a typed `emit()` function bound to the current component's host element.\n * Call once during `setup()` — the `Emits` type parameter maps event names to\n * their `detail` payload type.\n *\n * Every event is dispatched `cancelable: true`, and `emit()` returns `dispatchEvent`'s\n * own boolean result — `false` when a listener called `preventDefault()`. Components\n * that need to know whether a listener cancelled an event (e.g. to skip a default\n * action) read this return value directly instead of hand-rolling `dispatchEvent`.\n *\n * @example\n * ```ts\n * type Events = { close: undefined; change: { value: string } };\n *\n * setup(props) {\n * const emit = useEmit<Events>();\n * emit('close');\n *\n * const notCancelled = emit('change', { value: 'ok' });\n * if (notCancelled) props.value.value = 'ok';\n * }\n * ```\n */\nexport const useEmit = <T extends Record<string, unknown> = Record<string, never>>(): EmitFn<T> => {\n const host = getHost();\n\n return ((event: keyof T, ...rest: unknown[]) => {\n const customEventInit = rest.length > 0 ? { ...DEFAULT_FIRE_OPTIONS, detail: rest[0] } : DEFAULT_FIRE_OPTIONS;\n\n return host.dispatchEvent(new CustomEvent<unknown>(String(event), customEventInit));\n }) as EmitFn<T>;\n};\n"],"mappings":"kCAoBA,IAAM,EAAuB,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,EAAM,EAyBnE,MAAsF,CACjG,IAAM,EAAO,EAAA,QAAQ,EAErB,QAAS,EAAgB,GAAG,IAAoB,CAC9C,IAAM,EAAkB,EAAK,OAAS,EAAI,CAAE,GAAG,EAAsB,OAAQ,EAAK,EAAG,EAAI,EAEzF,OAAO,EAAK,cAAc,IAAI,YAAqB,OAAO,CAAK,EAAG,CAAe,CAAC,CACpF,EACF"}
1
+ {"version":3,"file":"emit.cjs","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\n/**\n * Typed emit function: only declared event names type-check, and `detail` is\n * required exactly when its payload type is non-void. Dynamic event names must\n * be cast at the call site — an intentional speed bump, not a silent escape.\n */\nexport type EmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): boolean;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;\n};\n\nconst DEFAULT_FIRE_OPTIONS = { bubbles: true, cancelable: true, composed: false };\n\n/**\n * Returns a typed `emit()` function bound to the current component's host element.\n * Call once during `setup()` — the `Emits` type parameter maps event names to\n * their `detail` payload type.\n *\n * Every event is dispatched `cancelable: true`, and `emit()` returns `dispatchEvent`'s\n * own boolean result — `false` when a listener called `preventDefault()`. Components\n * that need to know whether a listener cancelled an event (e.g. to skip a default\n * action) read this return value directly instead of hand-rolling `dispatchEvent`.\n *\n * Events do **not** cross the shadow boundary by default (`composed: false`) — a\n * listener outside the component's shadow root will not observe them. Dispatch a\n * `CustomEvent` with `composed: true` by hand if an event must escape the shadow root.\n *\n * @example\n * ```ts\n * type Events = { close: undefined; change: { value: string } };\n *\n * setup(props) {\n * const emit = useEmit<Events>();\n * emit('close');\n *\n * const notCancelled = emit('change', { value: 'ok' });\n * if (notCancelled) props.value.value = 'ok';\n * }\n * ```\n */\nexport const useEmit = <T extends Record<string, unknown> = Record<string, never>>(): EmitFn<T> => {\n const host = getHost();\n\n return ((event: keyof T, ...rest: unknown[]) => {\n const customEventInit = rest.length > 0 ? { ...DEFAULT_FIRE_OPTIONS, detail: rest[0] } : DEFAULT_FIRE_OPTIONS;\n\n return host.dispatchEvent(new CustomEvent<unknown>(String(event), customEventInit));\n }) as EmitFn<T>;\n};\n"],"mappings":"kCAqBA,IAAM,EAAuB,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,EAAM,EA6BnE,MAAsF,CACjG,IAAM,EAAO,EAAA,QAAQ,EAErB,QAAS,EAAgB,GAAG,IAAoB,CAC9C,IAAM,EAAkB,EAAK,OAAS,EAAI,CAAE,GAAG,EAAsB,OAAQ,EAAK,EAAG,EAAI,EAEzF,OAAO,EAAK,cAAc,IAAI,YAAqB,OAAO,CAAK,EAAG,CAAe,CAAC,CACpF,EACF"}
@@ -5,12 +5,15 @@ type NoDetail = void | undefined | never;
5
5
  type KeysWithoutDetail<T extends Record<string, unknown>> = {
6
6
  [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;
7
7
  }[keyof T];
8
- type StrictEmitFn<T extends Record<string, unknown>> = {
8
+ /**
9
+ * Typed emit function: only declared event names type-check, and `detail` is
10
+ * required exactly when its payload type is non-void. Dynamic event names must
11
+ * be cast at the call site — an intentional speed bump, not a silent escape.
12
+ */
13
+ export type EmitFn<T extends Record<string, unknown>> = {
9
14
  <K extends KeysWithoutDetail<T>>(event: K): boolean;
10
15
  <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;
11
16
  };
12
- type LooseEmitFn = (event: string, detail?: unknown) => boolean;
13
- export type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseEmitFn;
14
17
  /**
15
18
  * Returns a typed `emit()` function bound to the current component's host element.
16
19
  * Call once during `setup()` — the `Emits` type parameter maps event names to
@@ -21,6 +24,10 @@ export type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseE
21
24
  * that need to know whether a listener cancelled an event (e.g. to skip a default
22
25
  * action) read this return value directly instead of hand-rolling `dispatchEvent`.
23
26
  *
27
+ * Events do **not** cross the shadow boundary by default (`composed: false`) — a
28
+ * listener outside the component's shadow root will not observe them. Dispatch a
29
+ * `CustomEvent` with `composed: true` by hand if an event must escape the shadow root.
30
+ *
24
31
  * @example
25
32
  * ```ts
26
33
  * type Events = { close: undefined; change: { value: string } };
@@ -1 +1 @@
1
- {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/utils/emit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,KAAK,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AACzC,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;KACzD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK;CACtD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACrD,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACpD,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACrF,CAAC;AAEF,KAAK,WAAW,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;AAEhE,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;AAItF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAK,MAAM,CAAC,CAAC,CAQ7F,CAAC"}
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/utils/emit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,KAAK,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC;AACzC,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;KACzD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK;CACtD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX;;;;GAIG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACtD,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACpD,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACrF,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAK,MAAM,CAAC,CAAC,CAQ7F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"emit.js","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\ntype StrictEmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): boolean;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;\n};\n\ntype LooseEmitFn = (event: string, detail?: unknown) => boolean;\n\nexport type EmitFn<T extends Record<string, unknown>> = StrictEmitFn<T> & LooseEmitFn;\n\nconst DEFAULT_FIRE_OPTIONS = { bubbles: true, cancelable: true, composed: false };\n\n/**\n * Returns a typed `emit()` function bound to the current component's host element.\n * Call once during `setup()` — the `Emits` type parameter maps event names to\n * their `detail` payload type.\n *\n * Every event is dispatched `cancelable: true`, and `emit()` returns `dispatchEvent`'s\n * own boolean result — `false` when a listener called `preventDefault()`. Components\n * that need to know whether a listener cancelled an event (e.g. to skip a default\n * action) read this return value directly instead of hand-rolling `dispatchEvent`.\n *\n * @example\n * ```ts\n * type Events = { close: undefined; change: { value: string } };\n *\n * setup(props) {\n * const emit = useEmit<Events>();\n * emit('close');\n *\n * const notCancelled = emit('change', { value: 'ok' });\n * if (notCancelled) props.value.value = 'ok';\n * }\n * ```\n */\nexport const useEmit = <T extends Record<string, unknown> = Record<string, never>>(): EmitFn<T> => {\n const host = getHost();\n\n return ((event: keyof T, ...rest: unknown[]) => {\n const customEventInit = rest.length > 0 ? { ...DEFAULT_FIRE_OPTIONS, detail: rest[0] } : DEFAULT_FIRE_OPTIONS;\n\n return host.dispatchEvent(new CustomEvent<unknown>(String(event), customEventInit));\n }) as EmitFn<T>;\n};\n"],"mappings":"wCAoBA,IAAM,EAAuB,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,EAAM,EAyBnE,MAAsF,CACjG,IAAM,EAAO,EAAQ,EAErB,QAAS,EAAgB,GAAG,IAAoB,CAC9C,IAAM,EAAkB,EAAK,OAAS,EAAI,CAAE,GAAG,EAAsB,OAAQ,EAAK,EAAG,EAAI,EAEzF,OAAO,EAAK,cAAc,IAAI,YAAqB,OAAO,CAAK,EAAG,CAAe,CAAC,CACpF,EACF"}
1
+ {"version":3,"file":"emit.js","names":[],"sources":["../../src/utils/emit.ts"],"sourcesContent":["/**\n * Type-safe custom event emission for components.\n */\n\nimport { getHost } from '../runtime';\n\ntype NoDetail = void | undefined | never;\ntype KeysWithoutDetail<T extends Record<string, unknown>> = {\n [P in keyof T]: [T[P]] extends [NoDetail] ? P : never;\n}[keyof T];\n\n/**\n * Typed emit function: only declared event names type-check, and `detail` is\n * required exactly when its payload type is non-void. Dynamic event names must\n * be cast at the call site — an intentional speed bump, not a silent escape.\n */\nexport type EmitFn<T extends Record<string, unknown>> = {\n <K extends KeysWithoutDetail<T>>(event: K): boolean;\n <K extends Exclude<keyof T, KeysWithoutDetail<T>>>(event: K, detail: T[K]): boolean;\n};\n\nconst DEFAULT_FIRE_OPTIONS = { bubbles: true, cancelable: true, composed: false };\n\n/**\n * Returns a typed `emit()` function bound to the current component's host element.\n * Call once during `setup()` — the `Emits` type parameter maps event names to\n * their `detail` payload type.\n *\n * Every event is dispatched `cancelable: true`, and `emit()` returns `dispatchEvent`'s\n * own boolean result — `false` when a listener called `preventDefault()`. Components\n * that need to know whether a listener cancelled an event (e.g. to skip a default\n * action) read this return value directly instead of hand-rolling `dispatchEvent`.\n *\n * Events do **not** cross the shadow boundary by default (`composed: false`) — a\n * listener outside the component's shadow root will not observe them. Dispatch a\n * `CustomEvent` with `composed: true` by hand if an event must escape the shadow root.\n *\n * @example\n * ```ts\n * type Events = { close: undefined; change: { value: string } };\n *\n * setup(props) {\n * const emit = useEmit<Events>();\n * emit('close');\n *\n * const notCancelled = emit('change', { value: 'ok' });\n * if (notCancelled) props.value.value = 'ok';\n * }\n * ```\n */\nexport const useEmit = <T extends Record<string, unknown> = Record<string, never>>(): EmitFn<T> => {\n const host = getHost();\n\n return ((event: keyof T, ...rest: unknown[]) => {\n const customEventInit = rest.length > 0 ? { ...DEFAULT_FIRE_OPTIONS, detail: rest[0] } : DEFAULT_FIRE_OPTIONS;\n\n return host.dispatchEvent(new CustomEvent<unknown>(String(event), customEventInit));\n }) as EmitFn<T>;\n};\n"],"mappings":"wCAqBA,IAAM,EAAuB,CAAE,QAAS,GAAM,WAAY,GAAM,SAAU,EAAM,EA6BnE,MAAsF,CACjG,IAAM,EAAO,EAAQ,EAErB,QAAS,EAAgB,GAAG,IAAoB,CAC9C,IAAM,EAAkB,EAAK,OAAS,EAAI,CAAE,GAAG,EAAsB,OAAQ,EAAK,EAAG,EAAI,EAEzF,OAAO,EAAK,cAAc,IAAI,YAAqB,OAAO,CAAK,EAAG,CAAe,CAAC,CACpF,EACF"}
package/dist/utils/id.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};exports._resetIdCounter=r,exports.createId=i,exports.createStableId=a,exports.resetIdCounter=o;
1
+ var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};exports._resetIdCounter=r,exports.createId=i,exports.createStableId=a,exports.resetStableIdCounter=o;
2
2
  //# sourceMappingURL=id.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"id.cjs","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the stable ID counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n */\nexport const resetIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAEa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAMlE,MAA6B,CACxC,EAAiB,CACnB"}
1
+ {"version":3,"file":"id.cjs","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\n/**\n * Generates a monotonically-increasing, unique-within-this-process ID with an optional prefix.\n * No public reset — this is for uniqueness, not cross-test determinism; use `createStableId()`\n * (and `resetStableIdCounter()`) when a test needs IDs to restart from the same value each run.\n */\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the `createStableId()` counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n *\n * Named to match `createStableId()` precisely — `createId()` has no public reset (it's meant\n * for non-deterministic, monotonically-unique IDs; nothing in the package relies on it\n * restarting from a fixed value across tests).\n */\nexport const resetStableIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAOa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAUlE,MAAmC,CAC9C,EAAiB,CACnB"}
@@ -3,6 +3,11 @@
3
3
  * Template binding no longer uses this for marker IDs — binding targets are resolved
4
4
  * via path navigation on cloned template nodes.
5
5
  */
6
+ /**
7
+ * Generates a monotonically-increasing, unique-within-this-process ID with an optional prefix.
8
+ * No public reset — this is for uniqueness, not cross-test determinism; use `createStableId()`
9
+ * (and `resetStableIdCounter()`) when a test needs IDs to restart from the same value each run.
10
+ */
6
11
  export declare const createId: (prefix?: string) => string;
7
12
  /**
8
13
  * Generates a stable, unique ID with an optional semantic prefix.
@@ -11,8 +16,12 @@ export declare const createId: (prefix?: string) => string;
11
16
  */
12
17
  export declare const createStableId: (prefix?: string) => string;
13
18
  /**
14
- * Resets the stable ID counter to 0. Use in test `beforeEach` hooks when you need
19
+ * Resets the `createStableId()` counter to 0. Use in test `beforeEach` hooks when you need
15
20
  * deterministic IDs across test runs.
21
+ *
22
+ * Named to match `createStableId()` precisely — `createId()` has no public reset (it's meant
23
+ * for non-deterministic, monotonically-unique IDs; nothing in the package relies on it
24
+ * restarting from a fixed value across tests).
16
25
  */
17
- export declare const resetIdCounter: () => void;
26
+ export declare const resetStableIdCounter: () => void;
18
27
  //# sourceMappingURL=id.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,eAAO,MAAM,QAAQ,GAAI,eAAa,KAAG,MAAqC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,eAAa,KAAG,MAAgD,CAAC;AAEhG;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,IAEjC,CAAC"}
1
+ {"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../../src/utils/id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,eAAa,KAAG,MAAqC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,eAAa,KAAG,MAAgD,CAAC;AAEhG;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,QAAO,IAEvC,CAAC"}
package/dist/utils/id.js CHANGED
@@ -1,2 +1,2 @@
1
- var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};export{r as _resetIdCounter,i as createId,a as createStableId,o as resetIdCounter};
1
+ var e=0,t=0,n=Math.random().toString(36).slice(2,6),r=()=>{e=0,t=0},i=(t=`id`)=>`${t}-${++e}`,a=(e=`id`)=>`${e}-${n}${++t}`,o=()=>{t=0};export{r as _resetIdCounter,i as createId,a as createStableId,o as resetStableIdCounter};
2
2
  //# sourceMappingURL=id.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"id.js","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the stable ID counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n */\nexport const resetIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAEa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAMlE,MAA6B,CACxC,EAAiB,CACnB"}
1
+ {"version":3,"file":"id.js","names":[],"sources":["../../src/utils/id.ts"],"sourcesContent":["/**\n * Unique ID generation for runtime use (component IDs, label associations, etc.).\n * Template binding no longer uses this for marker IDs — binding targets are resolved\n * via path navigation on cloned template nodes.\n */\n\nlet _idCounter = 0;\nlet _stableCounter = 0;\nconst _tag = Math.random().toString(36).slice(2, 6);\n\n/** @internal Resets both ID counters. Called by testing cleanup(). */\nexport const _resetIdCounter = (): void => {\n _idCounter = 0;\n _stableCounter = 0;\n};\n\n/**\n * Generates a monotonically-increasing, unique-within-this-process ID with an optional prefix.\n * No public reset — this is for uniqueness, not cross-test determinism; use `createStableId()`\n * (and `resetStableIdCounter()`) when a test needs IDs to restart from the same value each run.\n */\nexport const createId = (prefix = 'id'): string => `${prefix}-${++_idCounter}`;\n\n/**\n * Generates a stable, unique ID with an optional semantic prefix.\n * Includes a short random tag to prevent collisions across multiple app instances.\n * Format: `${prefix}-${tag}${counter}` — e.g. `field-a3k21`.\n */\nexport const createStableId = (prefix = 'id'): string => `${prefix}-${_tag}${++_stableCounter}`;\n\n/**\n * Resets the `createStableId()` counter to 0. Use in test `beforeEach` hooks when you need\n * deterministic IDs across test runs.\n *\n * Named to match `createStableId()` precisely — `createId()` has no public reset (it's meant\n * for non-deterministic, monotonically-unique IDs; nothing in the package relies on it\n * restarting from a fixed value across tests).\n */\nexport const resetStableIdCounter = (): void => {\n _stableCounter = 0;\n};\n"],"mappings":"AAMA,IAAI,EAAa,EACb,EAAiB,EACf,EAAO,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,CAAC,EAGrC,MAA8B,CACzC,EAAa,EACb,EAAiB,CACnB,EAOa,GAAY,EAAS,OAAiB,GAAG,EAAO,GAAG,EAAE,IAOrD,GAAkB,EAAS,OAAiB,GAAG,EAAO,GAAG,IAAO,EAAE,IAUlE,MAAmC,CAC9C,EAAiB,CACnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/ore",
3
- "version": "1.2.3",
3
+ "version": "2.0.0",
4
4
  "description": "Custom element authoring primitives — reactive templates, signals, slots, and automatic lifecycle management",
5
5
  "type": "module",
6
6
  "files": [
@@ -16,30 +16,6 @@
16
16
  "import": "./dist/index.js",
17
17
  "require": "./dist/index.cjs"
18
18
  },
19
- "./devtools": {
20
- "source": "./src/devtools.ts",
21
- "types": "./dist/devtools.d.ts",
22
- "import": "./dist/devtools.js",
23
- "require": "./dist/devtools.cjs"
24
- },
25
- "./directives": {
26
- "source": "./src/directives/index.ts",
27
- "types": "./dist/directives/index.d.ts",
28
- "import": "./dist/directives.js",
29
- "require": "./dist/directives.cjs"
30
- },
31
- "./forms": {
32
- "source": "./src/forms/index.ts",
33
- "types": "./dist/forms/index.d.ts",
34
- "import": "./dist/forms.js",
35
- "require": "./dist/forms.cjs"
36
- },
37
- "./observers": {
38
- "source": "./src/observers/index.ts",
39
- "types": "./dist/observers/index.d.ts",
40
- "import": "./dist/observers.js",
41
- "require": "./dist/observers.cjs"
42
- },
43
19
  "./testing": {
44
20
  "source": "./src/testing/index.ts",
45
21
  "types": "./dist/testing/index.d.ts",
@@ -55,6 +31,7 @@
55
31
  "prepublishOnly": "pnpm run build",
56
32
  "preview": "vite preview",
57
33
  "test": "vitest",
34
+ "test:types": "tsc -p tsconfig.json --noEmit",
58
35
  "build:bundle": "vite build --config vite.bundle.config.ts"
59
36
  },
60
37
  "publishConfig": {
@@ -64,15 +41,23 @@
64
41
  "engines": {
65
42
  "node": ">=22"
66
43
  },
67
- "dependencies": {
68
- "@vielzeug/ripple": "1.2.3"
44
+ "peerDependencies": {
45
+ "@vielzeug/assay": "^2.0.0",
46
+ "@vielzeug/ripple": "^2.0.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "@vielzeug/assay": {
50
+ "optional": true
51
+ }
69
52
  },
70
53
  "devDependencies": {
71
- "@types/node": "^26.1.0",
54
+ "@types/node": "^26.1.2",
55
+ "@vielzeug/assay": "2.0.0",
56
+ "@vielzeug/ripple": "2.0.0",
72
57
  "axe-core": "^4.12.1",
73
- "jsdom": "^29.1.1",
58
+ "jsdom": "^30.0.1",
74
59
  "typescript": "^6.0.3",
75
- "vite": "^8.1.3",
60
+ "vite": "^8.2.0",
76
61
  "vitest": "^4.1.10"
77
62
  }
78
63
  }
package/dist/aria.cjs DELETED
@@ -1,2 +0,0 @@
1
- const e=require("./utils/aria.cjs"),t=require("./host-bind.cjs");var n=(n,r)=>{let i={};for(let[t,n]of Object.entries(r))i[e.normalizeAriaKey(t)]=n;return t.bind({attr:i},{target:n})};exports.aria=n;
2
- //# sourceMappingURL=aria.cjs.map
package/dist/aria.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"aria.cjs","names":[],"sources":["../src/aria.ts"],"sourcesContent":["/**\n * Reactive ARIA attribute sync.\n *\n * `aria()` is a thin wrapper over `bind({ attr })` — the two used to carry\n * independent copies of the same \"static | getter | signal → attribute write\"\n * logic, which had already drifted (this file's writes bypassed the\n * `on*`/dangerous-URL-scheme hardening that `setAttr()` gives every other\n * attribute write in the package). `aria()` now exists purely to normalize\n * bare ARIA property names (`expanded` → `aria-expanded`) before delegating —\n * for attributes that are already fully-qualified, `bind({ attr }, { target })`\n * is equivalent.\n */\n\nimport { bind, type HostBindingValue } from './host-bind';\nimport { normalizeAriaKey } from './utils/aria';\n\nexport type AriaConfig = Record<string, HostBindingValue>;\n\n/**\n * Reactively sync ARIA attributes on any element, auto-cleanup on component\n * disconnect. Returns a cleanup function that removes all reactive bindings.\n */\nexport const aria = (target: Element, config: AriaConfig): (() => void) => {\n const attr: Record<string, HostBindingValue> = {};\n\n for (const [key, value] of Object.entries(config)) attr[normalizeAriaKey(key)] = value;\n\n return bind({ attr }, { target });\n};\n"],"mappings":"iEAsBA,IAAa,GAAQ,EAAiB,IAAqC,CACzE,IAAM,EAAyC,CAAC,EAEhD,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EAAG,EAAK,EAAA,iBAAiB,CAAG,GAAK,EAEjF,OAAO,EAAA,KAAK,CAAE,MAAK,EAAG,CAAE,QAAO,CAAC,CAClC"}
package/dist/aria.d.ts DELETED
@@ -1,20 +0,0 @@
1
- /**
2
- * Reactive ARIA attribute sync.
3
- *
4
- * `aria()` is a thin wrapper over `bind({ attr })` — the two used to carry
5
- * independent copies of the same "static | getter | signal → attribute write"
6
- * logic, which had already drifted (this file's writes bypassed the
7
- * `on*`/dangerous-URL-scheme hardening that `setAttr()` gives every other
8
- * attribute write in the package). `aria()` now exists purely to normalize
9
- * bare ARIA property names (`expanded` → `aria-expanded`) before delegating —
10
- * for attributes that are already fully-qualified, `bind({ attr }, { target })`
11
- * is equivalent.
12
- */
13
- import { type HostBindingValue } from './host-bind';
14
- export type AriaConfig = Record<string, HostBindingValue>;
15
- /**
16
- * Reactively sync ARIA attributes on any element, auto-cleanup on component
17
- * disconnect. Returns a cleanup function that removes all reactive bindings.
18
- */
19
- export declare const aria: (target: Element, config: AriaConfig) => (() => void);
20
- //# sourceMappingURL=aria.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"aria.d.ts","sourceRoot":"","sources":["../src/aria.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAQ,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,IAAI,GAAI,QAAQ,OAAO,EAAE,QAAQ,UAAU,KAAG,CAAC,MAAM,IAAI,CAMrE,CAAC"}
package/dist/aria.js DELETED
@@ -1,2 +0,0 @@
1
- import{normalizeAriaKey as e}from"./utils/aria.js";import{bind as t}from"./host-bind.js";var n=(n,r)=>{let i={};for(let[t,n]of Object.entries(r))i[e(t)]=n;return t({attr:i},{target:n})};export{n as aria};
2
- //# sourceMappingURL=aria.js.map
package/dist/aria.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"aria.js","names":[],"sources":["../src/aria.ts"],"sourcesContent":["/**\n * Reactive ARIA attribute sync.\n *\n * `aria()` is a thin wrapper over `bind({ attr })` — the two used to carry\n * independent copies of the same \"static | getter | signal → attribute write\"\n * logic, which had already drifted (this file's writes bypassed the\n * `on*`/dangerous-URL-scheme hardening that `setAttr()` gives every other\n * attribute write in the package). `aria()` now exists purely to normalize\n * bare ARIA property names (`expanded` → `aria-expanded`) before delegating —\n * for attributes that are already fully-qualified, `bind({ attr }, { target })`\n * is equivalent.\n */\n\nimport { bind, type HostBindingValue } from './host-bind';\nimport { normalizeAriaKey } from './utils/aria';\n\nexport type AriaConfig = Record<string, HostBindingValue>;\n\n/**\n * Reactively sync ARIA attributes on any element, auto-cleanup on component\n * disconnect. Returns a cleanup function that removes all reactive bindings.\n */\nexport const aria = (target: Element, config: AriaConfig): (() => void) => {\n const attr: Record<string, HostBindingValue> = {};\n\n for (const [key, value] of Object.entries(config)) attr[normalizeAriaKey(key)] = value;\n\n return bind({ attr }, { target });\n};\n"],"mappings":"yFAsBA,IAAa,GAAQ,EAAiB,IAAqC,CACzE,IAAM,EAAyC,CAAC,EAEhD,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EAAG,EAAK,EAAiB,CAAG,GAAK,EAEjF,OAAO,EAAK,CAAE,MAAK,EAAG,CAAE,QAAO,CAAC,CAClC"}
package/dist/devtools.cjs DELETED
@@ -1,2 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./testing/flush.cjs");async function t(t){return e.flush({...t,logger:console.debug})}exports.debugFlush=t;
2
- //# sourceMappingURL=devtools.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"devtools.cjs","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/ore — debug utilities for component update visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n * ```\n */\n\nimport type { FlushOptions } from './testing/flush';\n\nimport { flush } from './testing/flush';\n\n/**\n * Flushes pending reactive updates with debug logging pre-wired to `console.debug`.\n *\n * Equivalent to `flush({ ...options, logger: console.debug })` but imported from a\n * dedicated sub-path so the `console.debug` reference is tree-shaken from production\n * bundles when this sub-path is not imported.\n *\n * Logs each turn and timing phase to `console.debug` so you can diagnose\n * unexpected update order or timing issues.\n *\n * @example\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n *\n * // in a test\n * await debugFlush();\n * // [flush] starting with maxTurns=5\n * // [flush] microtask turn 1/5\n * // ...\n * ```\n */\nexport async function debugFlush(options?: Omit<FlushOptions, 'logger'>): Promise<void> {\n return flush({ ...options, logger: console.debug });\n}\n"],"mappings":"0GAkCA,eAAsB,EAAW,EAAuD,CACtF,OAAO,EAAA,MAAM,CAAE,GAAG,EAAS,OAAQ,QAAQ,KAAM,CAAC,CACpD"}
@@ -1,32 +0,0 @@
1
- /**
2
- * @vielzeug/ore — debug utilities for component update visualisation.
3
- *
4
- * Import from the dedicated sub-path so it is tree-shaken from production bundles:
5
- * ```ts
6
- * import { debugFlush } from '@vielzeug/ore/devtools';
7
- * ```
8
- */
9
- import type { FlushOptions } from './testing/flush';
10
- /**
11
- * Flushes pending reactive updates with debug logging pre-wired to `console.debug`.
12
- *
13
- * Equivalent to `flush({ ...options, logger: console.debug })` but imported from a
14
- * dedicated sub-path so the `console.debug` reference is tree-shaken from production
15
- * bundles when this sub-path is not imported.
16
- *
17
- * Logs each turn and timing phase to `console.debug` so you can diagnose
18
- * unexpected update order or timing issues.
19
- *
20
- * @example
21
- * ```ts
22
- * import { debugFlush } from '@vielzeug/ore/devtools';
23
- *
24
- * // in a test
25
- * await debugFlush();
26
- * // [flush] starting with maxTurns=5
27
- * // [flush] microtask turn 1/5
28
- * // ...
29
- * ```
30
- */
31
- export declare function debugFlush(options?: Omit<FlushOptions, 'logger'>): Promise<void>;
32
- //# sourceMappingURL=devtools.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF"}
package/dist/devtools.js DELETED
@@ -1,2 +0,0 @@
1
- import{flush as e}from"./testing/flush.js";async function t(t){return e({...t,logger:console.debug})}export{t as debugFlush};
2
- //# sourceMappingURL=devtools.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"devtools.js","names":[],"sources":["../src/devtools.ts"],"sourcesContent":["/**\n * @vielzeug/ore — debug utilities for component update visualisation.\n *\n * Import from the dedicated sub-path so it is tree-shaken from production bundles:\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n * ```\n */\n\nimport type { FlushOptions } from './testing/flush';\n\nimport { flush } from './testing/flush';\n\n/**\n * Flushes pending reactive updates with debug logging pre-wired to `console.debug`.\n *\n * Equivalent to `flush({ ...options, logger: console.debug })` but imported from a\n * dedicated sub-path so the `console.debug` reference is tree-shaken from production\n * bundles when this sub-path is not imported.\n *\n * Logs each turn and timing phase to `console.debug` so you can diagnose\n * unexpected update order or timing issues.\n *\n * @example\n * ```ts\n * import { debugFlush } from '@vielzeug/ore/devtools';\n *\n * // in a test\n * await debugFlush();\n * // [flush] starting with maxTurns=5\n * // [flush] microtask turn 1/5\n * // ...\n * ```\n */\nexport async function debugFlush(options?: Omit<FlushOptions, 'logger'>): Promise<void> {\n return flush({ ...options, logger: console.debug });\n}\n"],"mappings":"2CAkCA,eAAsB,EAAW,EAAuD,CACtF,OAAO,EAAM,CAAE,GAAG,EAAS,OAAQ,QAAQ,KAAM,CAAC,CACpD"}
@@ -1,8 +0,0 @@
1
- export { classMap } from './classMap';
2
- export { each } from './each';
3
- export { live, type LiveSignal } from './live';
4
- export { model } from './model';
5
- export { raw, setRawSanitizer } from './raw';
6
- export { styleMap } from './styleMap';
7
- export { when } from './when';
8
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/directives/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC"}
@@ -1,2 +0,0 @@
1
- const e=require("../types/bindings.cjs"),t=require("../utils/dom.cjs");let n=require("@vielzeug/ripple");function r(r){return e.createSpreadObject((e,i)=>{let a=e,o=a.type===`checkbox`,s=a.type===`number`||a.type===`range`,c=e instanceof HTMLSelectElement,l=c&&e.multiple,u=(0,n.effect)(()=>{let t=r.value;if(l){let n=Array.isArray(t)?t:[],r=e;for(let e of r.options)e.selected=n.includes(e.value)}else o?a.checked=!!t:e.value=t==null?``:String(t)});i(()=>u.dispose()),i(t.listen(e,c?`change`:`input`,e=>{let t=e.target;if(l){let t=e.target;r.value=Array.from(t.selectedOptions).map(e=>e.value)}else o?r.value=t.checked:s?r.value=t.value===``?0:Number(t.value):r.value=t.value}))})}exports.model=r;
2
- //# sourceMappingURL=model.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"model.cjs","names":[],"sources":["../../src/directives/model.ts"],"sourcesContent":["import { effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { createSpreadObject, type SpreadObject } from '../types/bindings';\nimport { listen } from '../utils/dom';\n\n/**\n * Two-way binding spread for form inputs.\n * Syncs the signal value to the element's DOM value and back.\n *\n * Supports `type=\"text\"` (default), `type=\"number\"`, `type=\"range\"`,\n * `type=\"checkbox\"`, `<select>` (single-select), and\n * `<select multiple>` (multi-select, `Signal<string[]>`).\n *\n * @example\n * ```ts\n * const name = signal('');\n * html`<input type=\"text\" ${model(name)} />`\n *\n * const count = signal(0);\n * html`<input type=\"number\" ${model(count)} />`\n *\n * const checked = signal(false);\n * html`<input type=\"checkbox\" ${model(checked)} />`\n *\n * const selected = signal<string[]>([]);\n * html`<select multiple ${model(selected)}><option value=\"a\">A</option></select>`\n * ```\n */\nexport function model<T extends string | number | boolean | null>(source: Signal<T>): SpreadObject;\nexport function model(source: Signal<string[]>): SpreadObject;\nexport function model<T extends string | number | boolean | null | string[]>(source: Signal<T>): SpreadObject {\n return createSpreadObject((el, registerCleanup) => {\n const input = el as HTMLInputElement;\n const isCheckbox = input.type === 'checkbox';\n const isNumeric = input.type === 'number' || input.type === 'range';\n const isSelect = el instanceof HTMLSelectElement;\n const isMultiSelect = isSelect && (el as HTMLSelectElement).multiple;\n\n // Signal → DOM\n const sub = rawEffect(() => {\n const v = source.value;\n\n if (isMultiSelect) {\n const selected = Array.isArray(v) ? (v as string[]) : [];\n const selectEl = el as HTMLSelectElement;\n\n for (const opt of selectEl.options) {\n opt.selected = selected.includes(opt.value);\n }\n } else if (isCheckbox) {\n input.checked = Boolean(v);\n } else {\n (el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement).value =\n v == null ? '' : String(v as string | number | boolean | null);\n }\n });\n\n registerCleanup(() => sub.dispose());\n\n // DOM → Signal\n // <select> fires 'change'; text/number/range/textarea/checkbox fire 'input'.\n const eventName = isSelect ? 'change' : 'input';\n\n registerCleanup(\n listen(el, eventName, (e: Event) => {\n const target = e.target as HTMLInputElement;\n\n if (isMultiSelect) {\n const selectEl = e.target as HTMLSelectElement;\n const values = Array.from(selectEl.selectedOptions).map((opt) => opt.value);\n\n (source as Signal<string[]>).value = values;\n } else if (isCheckbox) {\n source.value = target.checked as T;\n } else if (isNumeric) {\n source.value = (target.value === '' ? 0 : Number(target.value)) as T;\n } else {\n source.value = target.value as T;\n }\n }),\n );\n });\n}\n"],"mappings":"yGA8BA,SAAgB,EAA6D,EAAiC,CAC5G,OAAO,EAAA,oBAAoB,EAAI,IAAoB,CACjD,IAAM,EAAQ,EACR,EAAa,EAAM,OAAS,WAC5B,EAAY,EAAM,OAAS,UAAY,EAAM,OAAS,QACtD,EAAW,aAAc,kBACzB,EAAgB,GAAa,EAAyB,SAGtD,GAAA,EAAA,EAAA,OAAA,KAAsB,CAC1B,IAAM,EAAI,EAAO,MAEjB,GAAI,EAAe,CACjB,IAAM,EAAW,MAAM,QAAQ,CAAC,EAAK,EAAiB,CAAC,EACjD,EAAW,EAEjB,IAAK,IAAM,KAAO,EAAS,QACzB,EAAI,SAAW,EAAS,SAAS,EAAI,KAAK,CAE9C,MAAW,EACT,EAAM,QAAU,EAAQ,EAExB,EAAmE,MACjE,GAAK,KAAO,GAAK,OAAO,CAAqC,CAEnE,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EAMnC,EACE,EAAA,OAAO,EAHS,EAAW,SAAW,QAGf,GAAa,CAClC,IAAM,EAAS,EAAE,OAEjB,GAAI,EAAe,CACjB,IAAM,EAAW,EAAE,OAGnB,EAA6B,MAFd,MAAM,KAAK,EAAS,eAAe,CAAC,CAAC,IAAK,GAAQ,EAAI,KAEhC,CACvC,MAAW,EACT,EAAO,MAAQ,EAAO,QACb,EACT,EAAO,MAAS,EAAO,QAAU,GAAK,EAAI,OAAO,EAAO,KAAK,EAE7D,EAAO,MAAQ,EAAO,KAE1B,CAAC,CACH,CACF,CAAC,CACH"}
@@ -1,28 +0,0 @@
1
- import { type Signal } from '@vielzeug/ripple';
2
- import { type SpreadObject } from '../types/bindings';
3
- /**
4
- * Two-way binding spread for form inputs.
5
- * Syncs the signal value to the element's DOM value and back.
6
- *
7
- * Supports `type="text"` (default), `type="number"`, `type="range"`,
8
- * `type="checkbox"`, `<select>` (single-select), and
9
- * `<select multiple>` (multi-select, `Signal<string[]>`).
10
- *
11
- * @example
12
- * ```ts
13
- * const name = signal('');
14
- * html`<input type="text" ${model(name)} />`
15
- *
16
- * const count = signal(0);
17
- * html`<input type="number" ${model(count)} />`
18
- *
19
- * const checked = signal(false);
20
- * html`<input type="checkbox" ${model(checked)} />`
21
- *
22
- * const selected = signal<string[]>([]);
23
- * html`<select multiple ${model(selected)}><option value="a">A</option></select>`
24
- * ```
25
- */
26
- export declare function model<T extends string | number | boolean | null>(source: Signal<T>): SpreadObject;
27
- export declare function model(source: Signal<string[]>): SpreadObject;
28
- //# sourceMappingURL=model.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/directives/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEpE,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG1E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC;AACnG,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,YAAY,CAAC"}
@@ -1,2 +0,0 @@
1
- import{createSpreadObject as e}from"../types/bindings.js";import{listen as t}from"../utils/dom.js";import{effect as n}from"@vielzeug/ripple";function r(r){return e((e,i)=>{let a=e,o=a.type===`checkbox`,s=a.type===`number`||a.type===`range`,c=e instanceof HTMLSelectElement,l=c&&e.multiple,u=n(()=>{let t=r.value;if(l){let n=Array.isArray(t)?t:[],r=e;for(let e of r.options)e.selected=n.includes(e.value)}else o?a.checked=!!t:e.value=t==null?``:String(t)});i(()=>u.dispose()),i(t(e,c?`change`:`input`,e=>{let t=e.target;if(l){let t=e.target;r.value=Array.from(t.selectedOptions).map(e=>e.value)}else o?r.value=t.checked:s?r.value=t.value===``?0:Number(t.value):r.value=t.value}))})}export{r as model};
2
- //# sourceMappingURL=model.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"model.js","names":[],"sources":["../../src/directives/model.ts"],"sourcesContent":["import { effect as rawEffect, type Signal } from '@vielzeug/ripple';\n\nimport { createSpreadObject, type SpreadObject } from '../types/bindings';\nimport { listen } from '../utils/dom';\n\n/**\n * Two-way binding spread for form inputs.\n * Syncs the signal value to the element's DOM value and back.\n *\n * Supports `type=\"text\"` (default), `type=\"number\"`, `type=\"range\"`,\n * `type=\"checkbox\"`, `<select>` (single-select), and\n * `<select multiple>` (multi-select, `Signal<string[]>`).\n *\n * @example\n * ```ts\n * const name = signal('');\n * html`<input type=\"text\" ${model(name)} />`\n *\n * const count = signal(0);\n * html`<input type=\"number\" ${model(count)} />`\n *\n * const checked = signal(false);\n * html`<input type=\"checkbox\" ${model(checked)} />`\n *\n * const selected = signal<string[]>([]);\n * html`<select multiple ${model(selected)}><option value=\"a\">A</option></select>`\n * ```\n */\nexport function model<T extends string | number | boolean | null>(source: Signal<T>): SpreadObject;\nexport function model(source: Signal<string[]>): SpreadObject;\nexport function model<T extends string | number | boolean | null | string[]>(source: Signal<T>): SpreadObject {\n return createSpreadObject((el, registerCleanup) => {\n const input = el as HTMLInputElement;\n const isCheckbox = input.type === 'checkbox';\n const isNumeric = input.type === 'number' || input.type === 'range';\n const isSelect = el instanceof HTMLSelectElement;\n const isMultiSelect = isSelect && (el as HTMLSelectElement).multiple;\n\n // Signal → DOM\n const sub = rawEffect(() => {\n const v = source.value;\n\n if (isMultiSelect) {\n const selected = Array.isArray(v) ? (v as string[]) : [];\n const selectEl = el as HTMLSelectElement;\n\n for (const opt of selectEl.options) {\n opt.selected = selected.includes(opt.value);\n }\n } else if (isCheckbox) {\n input.checked = Boolean(v);\n } else {\n (el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement).value =\n v == null ? '' : String(v as string | number | boolean | null);\n }\n });\n\n registerCleanup(() => sub.dispose());\n\n // DOM → Signal\n // <select> fires 'change'; text/number/range/textarea/checkbox fire 'input'.\n const eventName = isSelect ? 'change' : 'input';\n\n registerCleanup(\n listen(el, eventName, (e: Event) => {\n const target = e.target as HTMLInputElement;\n\n if (isMultiSelect) {\n const selectEl = e.target as HTMLSelectElement;\n const values = Array.from(selectEl.selectedOptions).map((opt) => opt.value);\n\n (source as Signal<string[]>).value = values;\n } else if (isCheckbox) {\n source.value = target.checked as T;\n } else if (isNumeric) {\n source.value = (target.value === '' ? 0 : Number(target.value)) as T;\n } else {\n source.value = target.value as T;\n }\n }),\n );\n });\n}\n"],"mappings":"6IA8BA,SAAgB,EAA6D,EAAiC,CAC5G,OAAO,GAAoB,EAAI,IAAoB,CACjD,IAAM,EAAQ,EACR,EAAa,EAAM,OAAS,WAC5B,EAAY,EAAM,OAAS,UAAY,EAAM,OAAS,QACtD,EAAW,aAAc,kBACzB,EAAgB,GAAa,EAAyB,SAGtD,EAAM,MAAgB,CAC1B,IAAM,EAAI,EAAO,MAEjB,GAAI,EAAe,CACjB,IAAM,EAAW,MAAM,QAAQ,CAAC,EAAK,EAAiB,CAAC,EACjD,EAAW,EAEjB,IAAK,IAAM,KAAO,EAAS,QACzB,EAAI,SAAW,EAAS,SAAS,EAAI,KAAK,CAE9C,MAAW,EACT,EAAM,QAAU,EAAQ,EAExB,EAAmE,MACjE,GAAK,KAAO,GAAK,OAAO,CAAqC,CAEnE,CAAC,EAED,MAAsB,EAAI,QAAQ,CAAC,EAMnC,EACE,EAAO,EAHS,EAAW,SAAW,QAGf,GAAa,CAClC,IAAM,EAAS,EAAE,OAEjB,GAAI,EAAe,CACjB,IAAM,EAAW,EAAE,OAGnB,EAA6B,MAFd,MAAM,KAAK,EAAS,eAAe,CAAC,CAAC,IAAK,GAAQ,EAAI,KAEhC,CACvC,MAAW,EACT,EAAO,MAAQ,EAAO,QACb,EACT,EAAO,MAAS,EAAO,QAAU,GAAK,EAAI,OAAO,EAAO,KAAK,EAE7D,EAAO,MAAQ,EAAO,KAE1B,CAAC,CACH,CACF,CAAC,CACH"}
@@ -1,2 +0,0 @@
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;
2
- //# sourceMappingURL=raw.cjs.map
@@ -1 +0,0 @@
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,16 +0,0 @@
1
- import { type Readable, type Signal } from '@vielzeug/ripple';
2
- import { type DirectiveResult } from '../types/bindings';
3
- type RawSanitizer = (html: string) => string;
4
- export declare const setRawSanitizer: (fn: RawSanitizer | null) => void;
5
- /**
6
- * Renders a trusted HTML string without escaping as a DirectiveResult.
7
- * Only use with content you control — passing user-supplied strings
8
- * directly is an XSS risk. Register a sanitizer with setRawSanitizer()
9
- * to add a runtime safety net.
10
- *
11
- * Supports static strings, signals, and getter functions `() => string`.
12
- * When reactive, the DOM is updated in-place whenever the value changes.
13
- */
14
- export declare function raw(value: (() => string) | string | Signal<string> | Readable<string>): DirectiveResult;
15
- export {};
16
- //# sourceMappingURL=raw.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/directives/raw.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAIzG,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGhF,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAK7C,eAAO,MAAM,eAAe,GAAI,IAAI,YAAY,GAAG,IAAI,KAAG,IAIzD,CAAC;AAmCF;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAuCvG"}
@@ -1,2 +0,0 @@
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};
2
- //# sourceMappingURL=raw.js.map
@@ -1 +0,0 @@
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"}