@vielzeug/craftit 2.1.0 → 3.0.3

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 (325) hide show
  1. package/README.md +58 -124
  2. package/dist/controls/a11y-control.cjs +1 -1
  3. package/dist/controls/a11y-control.cjs.map +1 -1
  4. package/dist/controls/a11y-control.d.ts +1 -1
  5. package/dist/controls/a11y-control.d.ts.map +1 -1
  6. package/dist/controls/a11y-control.js +1 -1
  7. package/dist/controls/a11y-control.js.map +1 -1
  8. package/dist/controls/checkable-control.cjs +1 -1
  9. package/dist/controls/checkable-control.cjs.map +1 -1
  10. package/dist/controls/checkable-control.d.ts +7 -7
  11. package/dist/controls/checkable-control.d.ts.map +1 -1
  12. package/dist/controls/checkable-control.js +1 -1
  13. package/dist/controls/checkable-control.js.map +1 -1
  14. package/dist/controls/choice-field-control.cjs +2 -0
  15. package/dist/controls/choice-field-control.cjs.map +1 -0
  16. package/dist/controls/choice-field-control.d.ts +3 -0
  17. package/dist/controls/choice-field-control.d.ts.map +1 -0
  18. package/dist/controls/choice-field-control.js +2 -0
  19. package/dist/controls/choice-field-control.js.map +1 -0
  20. package/dist/controls/field-control.cjs +1 -1
  21. package/dist/controls/field-control.cjs.map +1 -1
  22. package/dist/controls/field-control.d.ts +28 -73
  23. package/dist/controls/field-control.d.ts.map +1 -1
  24. package/dist/controls/field-control.js +1 -1
  25. package/dist/controls/field-control.js.map +1 -1
  26. package/dist/controls/index.d.ts +11 -9
  27. package/dist/controls/index.d.ts.map +1 -1
  28. package/dist/controls/internal/control-state.cjs +1 -1
  29. package/dist/controls/internal/control-state.cjs.map +1 -1
  30. package/dist/controls/internal/control-state.d.ts +6 -4
  31. package/dist/controls/internal/control-state.d.ts.map +1 -1
  32. package/dist/controls/internal/control-state.js +1 -1
  33. package/dist/controls/internal/control-state.js.map +1 -1
  34. package/dist/controls/internal/keyboard-utils.cjs.map +1 -1
  35. package/dist/controls/internal/keyboard-utils.js.map +1 -1
  36. package/dist/controls/internal/number-utils.cjs.map +1 -1
  37. package/dist/controls/internal/number-utils.js.map +1 -1
  38. package/dist/controls/internal/validation-utils.cjs.map +1 -1
  39. package/dist/controls/internal/validation-utils.js.map +1 -1
  40. package/dist/controls/list-control.cjs +1 -1
  41. package/dist/controls/list-control.cjs.map +1 -1
  42. package/dist/controls/list-control.d.ts +10 -8
  43. package/dist/controls/list-control.d.ts.map +1 -1
  44. package/dist/controls/list-control.js +1 -1
  45. package/dist/controls/list-control.js.map +1 -1
  46. package/dist/controls/overlay-control.cjs +1 -1
  47. package/dist/controls/overlay-control.cjs.map +1 -1
  48. package/dist/controls/overlay-control.d.ts +17 -14
  49. package/dist/controls/overlay-control.d.ts.map +1 -1
  50. package/dist/controls/overlay-control.js +1 -1
  51. package/dist/controls/overlay-control.js.map +1 -1
  52. package/dist/controls/popup-list-control.cjs +2 -0
  53. package/dist/controls/popup-list-control.cjs.map +1 -0
  54. package/dist/controls/popup-list-control.d.ts +160 -0
  55. package/dist/controls/popup-list-control.d.ts.map +1 -0
  56. package/dist/controls/popup-list-control.js +2 -0
  57. package/dist/controls/popup-list-control.js.map +1 -0
  58. package/dist/controls/press-control.cjs.map +1 -1
  59. package/dist/controls/press-control.js.map +1 -1
  60. package/dist/controls/slider-control.cjs.map +1 -1
  61. package/dist/controls/slider-control.js.map +1 -1
  62. package/dist/controls/spinner-control.cjs.map +1 -1
  63. package/dist/controls/spinner-control.js.map +1 -1
  64. package/dist/controls/swipe-control.cjs +2 -0
  65. package/dist/controls/swipe-control.cjs.map +1 -0
  66. package/dist/controls/swipe-control.d.ts +32 -0
  67. package/dist/controls/swipe-control.d.ts.map +1 -0
  68. package/dist/controls/swipe-control.js +2 -0
  69. package/dist/controls/swipe-control.js.map +1 -0
  70. package/dist/controls/text-field-control.cjs +2 -0
  71. package/dist/controls/text-field-control.cjs.map +1 -0
  72. package/dist/controls/text-field-control.d.ts +3 -0
  73. package/dist/controls/text-field-control.d.ts.map +1 -0
  74. package/dist/controls/text-field-control.js +2 -0
  75. package/dist/controls/text-field-control.js.map +1 -0
  76. package/dist/controls.cjs +1 -1
  77. package/dist/controls.js +1 -1
  78. package/dist/craftit.cjs +1 -1
  79. package/dist/craftit.cjs.map +1 -1
  80. package/dist/craftit.js +1 -1
  81. package/dist/craftit.js.map +1 -1
  82. package/dist/directives/classMap.cjs +2 -0
  83. package/dist/directives/classMap.cjs.map +1 -0
  84. package/dist/directives/classMap.d.ts +19 -0
  85. package/dist/directives/classMap.d.ts.map +1 -0
  86. package/dist/directives/classMap.js +2 -0
  87. package/dist/directives/classMap.js.map +1 -0
  88. package/dist/directives/each.cjs +1 -1
  89. package/dist/directives/each.cjs.map +1 -1
  90. package/dist/directives/each.d.ts +5 -30
  91. package/dist/directives/each.d.ts.map +1 -1
  92. package/dist/directives/each.js +1 -1
  93. package/dist/directives/each.js.map +1 -1
  94. package/dist/directives/guard.cjs +2 -0
  95. package/dist/directives/guard.cjs.map +1 -0
  96. package/dist/directives/guard.d.ts +10 -0
  97. package/dist/directives/guard.d.ts.map +1 -0
  98. package/dist/directives/guard.js +2 -0
  99. package/dist/directives/guard.js.map +1 -0
  100. package/dist/directives/live.cjs +2 -0
  101. package/dist/directives/live.cjs.map +1 -0
  102. package/dist/directives/live.d.ts +23 -0
  103. package/dist/directives/live.d.ts.map +1 -0
  104. package/dist/directives/live.js +2 -0
  105. package/dist/directives/live.js.map +1 -0
  106. package/dist/directives/raw.cjs +1 -1
  107. package/dist/directives/raw.cjs.map +1 -1
  108. package/dist/directives/raw.d.ts +3 -5
  109. package/dist/directives/raw.d.ts.map +1 -1
  110. package/dist/directives/raw.js +1 -1
  111. package/dist/directives/raw.js.map +1 -1
  112. package/dist/directives/resource.cjs +2 -0
  113. package/dist/directives/resource.cjs.map +1 -0
  114. package/dist/directives/resource.d.ts +32 -0
  115. package/dist/directives/resource.d.ts.map +1 -0
  116. package/dist/directives/resource.js +2 -0
  117. package/dist/directives/resource.js.map +1 -0
  118. package/dist/directives/styleMap.cjs +2 -0
  119. package/dist/directives/styleMap.cjs.map +1 -0
  120. package/dist/directives/styleMap.d.ts +11 -0
  121. package/dist/directives/styleMap.d.ts.map +1 -0
  122. package/dist/directives/styleMap.js +2 -0
  123. package/dist/directives/styleMap.js.map +1 -0
  124. package/dist/directives/when.cjs +1 -1
  125. package/dist/directives/when.cjs.map +1 -1
  126. package/dist/directives/when.d.ts +6 -19
  127. package/dist/directives/when.d.ts.map +1 -1
  128. package/dist/directives/when.js +1 -1
  129. package/dist/directives/when.js.map +1 -1
  130. package/dist/errors.cjs +2 -0
  131. package/dist/errors.cjs.map +1 -0
  132. package/dist/errors.d.ts +12 -0
  133. package/dist/errors.d.ts.map +1 -0
  134. package/dist/errors.js +2 -0
  135. package/dist/errors.js.map +1 -0
  136. package/dist/form.cjs +1 -1
  137. package/dist/form.cjs.map +1 -1
  138. package/dist/form.d.ts +3 -17
  139. package/dist/form.d.ts.map +1 -1
  140. package/dist/form.js +1 -1
  141. package/dist/form.js.map +1 -1
  142. package/dist/host.cjs +1 -1
  143. package/dist/host.cjs.map +1 -1
  144. package/dist/host.d.ts +40 -37
  145. package/dist/host.d.ts.map +1 -1
  146. package/dist/host.js +1 -1
  147. package/dist/host.js.map +1 -1
  148. package/dist/index.cjs +1 -1
  149. package/dist/index.d.ts +16 -8
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +1 -1
  152. package/dist/internal.cjs +1 -1
  153. package/dist/internal.cjs.map +1 -1
  154. package/dist/internal.d.ts +60 -120
  155. package/dist/internal.d.ts.map +1 -1
  156. package/dist/internal.js +1 -1
  157. package/dist/internal.js.map +1 -1
  158. package/dist/observers/index.d.ts +1 -0
  159. package/dist/observers/index.d.ts.map +1 -1
  160. package/dist/observers/intersection-observe.cjs +1 -1
  161. package/dist/observers/intersection-observe.cjs.map +1 -1
  162. package/dist/observers/intersection-observe.d.ts +1 -1
  163. package/dist/observers/intersection-observe.js +1 -1
  164. package/dist/observers/intersection-observe.js.map +1 -1
  165. package/dist/observers/media-observe.cjs +1 -1
  166. package/dist/observers/media-observe.cjs.map +1 -1
  167. package/dist/observers/media-observe.d.ts +1 -1
  168. package/dist/observers/media-observe.js +1 -1
  169. package/dist/observers/media-observe.js.map +1 -1
  170. package/dist/observers/mutation-observe.cjs +2 -0
  171. package/dist/observers/mutation-observe.cjs.map +1 -0
  172. package/dist/observers/mutation-observe.d.ts +10 -0
  173. package/dist/observers/mutation-observe.d.ts.map +1 -0
  174. package/dist/observers/mutation-observe.js +2 -0
  175. package/dist/observers/mutation-observe.js.map +1 -0
  176. package/dist/observers/resize-observe.cjs +1 -1
  177. package/dist/observers/resize-observe.cjs.map +1 -1
  178. package/dist/observers/resize-observe.d.ts +1 -1
  179. package/dist/observers/resize-observe.js +1 -1
  180. package/dist/observers/resize-observe.js.map +1 -1
  181. package/dist/observers.cjs +1 -1
  182. package/dist/observers.js +1 -1
  183. package/dist/props.cjs +1 -1
  184. package/dist/props.cjs.map +1 -1
  185. package/dist/props.d.ts +18 -31
  186. package/dist/props.d.ts.map +1 -1
  187. package/dist/props.js +1 -1
  188. package/dist/props.js.map +1 -1
  189. package/dist/registration.cjs +1 -1
  190. package/dist/registration.cjs.map +1 -1
  191. package/dist/registration.d.ts +27 -7
  192. package/dist/registration.d.ts.map +1 -1
  193. package/dist/registration.js +1 -1
  194. package/dist/registration.js.map +1 -1
  195. package/dist/runtime.cjs +1 -1
  196. package/dist/runtime.cjs.map +1 -1
  197. package/dist/runtime.d.ts +29 -17
  198. package/dist/runtime.d.ts.map +1 -1
  199. package/dist/runtime.js +1 -1
  200. package/dist/runtime.js.map +1 -1
  201. package/dist/template-bindings.cjs +1 -1
  202. package/dist/template-bindings.cjs.map +1 -1
  203. package/dist/template-bindings.d.ts +10 -47
  204. package/dist/template-bindings.d.ts.map +1 -1
  205. package/dist/template-bindings.js +1 -1
  206. package/dist/template-bindings.js.map +1 -1
  207. package/dist/template-compiler.cjs +1 -1
  208. package/dist/template-compiler.cjs.map +1 -1
  209. package/dist/template-compiler.d.ts +1 -21
  210. package/dist/template-compiler.d.ts.map +1 -1
  211. package/dist/template-compiler.js +1 -1
  212. package/dist/template-compiler.js.map +1 -1
  213. package/dist/testing/testing.cjs +1 -1
  214. package/dist/testing/testing.cjs.map +1 -1
  215. package/dist/testing/testing.d.ts +12 -5
  216. package/dist/testing/testing.d.ts.map +1 -1
  217. package/dist/testing/testing.js +1 -1
  218. package/dist/testing/testing.js.map +1 -1
  219. package/package.json +6 -12
  220. package/dist/component.cjs +0 -2
  221. package/dist/component.cjs.map +0 -1
  222. package/dist/component.d.ts +0 -39
  223. package/dist/component.d.ts.map +0 -1
  224. package/dist/component.js +0 -2
  225. package/dist/component.js.map +0 -1
  226. package/dist/controls/list-key-control.cjs +0 -2
  227. package/dist/controls/list-key-control.cjs.map +0 -1
  228. package/dist/controls/list-key-control.d.ts +0 -14
  229. package/dist/controls/list-key-control.d.ts.map +0 -1
  230. package/dist/controls/list-key-control.js +0 -2
  231. package/dist/controls/list-key-control.js.map +0 -1
  232. package/dist/directives/attr.cjs +0 -2
  233. package/dist/directives/attr.cjs.map +0 -1
  234. package/dist/directives/attr.d.ts +0 -12
  235. package/dist/directives/attr.d.ts.map +0 -1
  236. package/dist/directives/attr.js +0 -2
  237. package/dist/directives/attr.js.map +0 -1
  238. package/dist/directives/bind.cjs +0 -2
  239. package/dist/directives/bind.cjs.map +0 -1
  240. package/dist/directives/bind.d.ts +0 -38
  241. package/dist/directives/bind.d.ts.map +0 -1
  242. package/dist/directives/bind.js +0 -2
  243. package/dist/directives/bind.js.map +0 -1
  244. package/dist/directives/choose.cjs +0 -2
  245. package/dist/directives/choose.cjs.map +0 -1
  246. package/dist/directives/choose.d.ts +0 -39
  247. package/dist/directives/choose.d.ts.map +0 -1
  248. package/dist/directives/choose.js +0 -2
  249. package/dist/directives/choose.js.map +0 -1
  250. package/dist/directives/classes.cjs +0 -2
  251. package/dist/directives/classes.cjs.map +0 -1
  252. package/dist/directives/classes.d.ts +0 -20
  253. package/dist/directives/classes.d.ts.map +0 -1
  254. package/dist/directives/classes.js +0 -2
  255. package/dist/directives/classes.js.map +0 -1
  256. package/dist/directives/index.d.ts +0 -13
  257. package/dist/directives/index.d.ts.map +0 -1
  258. package/dist/directives/memo.cjs +0 -2
  259. package/dist/directives/memo.cjs.map +0 -1
  260. package/dist/directives/memo.d.ts +0 -27
  261. package/dist/directives/memo.d.ts.map +0 -1
  262. package/dist/directives/memo.js +0 -2
  263. package/dist/directives/memo.js.map +0 -1
  264. package/dist/directives/on.cjs +0 -2
  265. package/dist/directives/on.cjs.map +0 -1
  266. package/dist/directives/on.d.ts +0 -25
  267. package/dist/directives/on.d.ts.map +0 -1
  268. package/dist/directives/on.js +0 -2
  269. package/dist/directives/on.js.map +0 -1
  270. package/dist/directives/spread.cjs +0 -2
  271. package/dist/directives/spread.cjs.map +0 -1
  272. package/dist/directives/spread.d.ts +0 -14
  273. package/dist/directives/spread.d.ts.map +0 -1
  274. package/dist/directives/spread.js +0 -2
  275. package/dist/directives/spread.js.map +0 -1
  276. package/dist/directives/style.cjs +0 -2
  277. package/dist/directives/style.cjs.map +0 -1
  278. package/dist/directives/style.d.ts +0 -22
  279. package/dist/directives/style.d.ts.map +0 -1
  280. package/dist/directives/style.js +0 -2
  281. package/dist/directives/style.js.map +0 -1
  282. package/dist/directives/until.cjs +0 -2
  283. package/dist/directives/until.cjs.map +0 -1
  284. package/dist/directives/until.d.ts +0 -26
  285. package/dist/directives/until.d.ts.map +0 -1
  286. package/dist/directives/until.js +0 -2
  287. package/dist/directives/until.js.map +0 -1
  288. package/dist/directives.cjs +0 -1
  289. package/dist/directives.js +0 -1
  290. package/dist/runtime-bindings.cjs +0 -2
  291. package/dist/runtime-bindings.cjs.map +0 -1
  292. package/dist/runtime-bindings.d.ts +0 -6
  293. package/dist/runtime-bindings.d.ts.map +0 -1
  294. package/dist/runtime-bindings.js +0 -2
  295. package/dist/runtime-bindings.js.map +0 -1
  296. package/dist/runtime-core.cjs +0 -2
  297. package/dist/runtime-core.cjs.map +0 -1
  298. package/dist/runtime-core.d.ts +0 -21
  299. package/dist/runtime-core.d.ts.map +0 -1
  300. package/dist/runtime-core.js +0 -2
  301. package/dist/runtime-core.js.map +0 -1
  302. package/dist/runtime-lifecycle.cjs +0 -2
  303. package/dist/runtime-lifecycle.cjs.map +0 -1
  304. package/dist/runtime-lifecycle.d.ts +0 -24
  305. package/dist/runtime-lifecycle.d.ts.map +0 -1
  306. package/dist/runtime-lifecycle.js +0 -2
  307. package/dist/runtime-lifecycle.js.map +0 -1
  308. package/dist/template-dom.cjs +0 -2
  309. package/dist/template-dom.cjs.map +0 -1
  310. package/dist/template-dom.d.ts +0 -13
  311. package/dist/template-dom.d.ts.map +0 -1
  312. package/dist/template-dom.js +0 -2
  313. package/dist/template-dom.js.map +0 -1
  314. package/dist/template-html.cjs +0 -2
  315. package/dist/template-html.cjs.map +0 -1
  316. package/dist/template-html.d.ts +0 -23
  317. package/dist/template-html.d.ts.map +0 -1
  318. package/dist/template-html.js +0 -2
  319. package/dist/template-html.js.map +0 -1
  320. package/dist/template.cjs +0 -2
  321. package/dist/template.cjs.map +0 -1
  322. package/dist/template.d.ts +0 -10
  323. package/dist/template.d.ts.map +0 -1
  324. package/dist/template.js +0 -2
  325. package/dist/template.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzD,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,IAAI,MAAM,CAAC,CAAC;AAE/E,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,IAAI;IAC7E,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC;IACjF,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC7B,CAAC;AAYF;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,MAAM,CAenG"}
1
+ {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;AAE1D,KAAK,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AAU1C;;GAEG;AACH,wBAAgB,IAAI,CAClB,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,cAAc,EAC5B,KAAK,CAAC,EAAE,MAAM,cAAc,GAC3B,cAAc,CAAC,cAAc,CAAC,CAMhC"}
@@ -1,2 +1,2 @@
1
- import{isSignal as e}from"@vielzeug/stateit";var t=e=>{if(e.then!==void 0&&e.then!==null&&typeof e.then!=`function`)throw Error(`[craftit:when] options.then must be a function when provided.`);if(e.else!==void 0&&e.else!==null&&typeof e.else!=`function`)throw Error(`[craftit:when] options.else must be a function when provided.`)};function n(n){t(n);let{condition:i}=n,{else:a,then:o}=n,s=()=>r(i)?o?.()??``:a?.()??``;return e(i)||typeof i==`function`?{render:s}:s()}var r=t=>e(t)?t.value:typeof t==`function`?t():t;export{n as when};
1
+ import{computed as e,isSignal as t}from"@vielzeug/stateit";var n=e=>typeof e==`function`?e():t(e)?e.value:e;function r(t,r,i){return e(()=>n(t)?r():i?i():``)}export{r as when};
2
2
  //# sourceMappingURL=when.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport type { Directive, HTMLResult } from '../internal';\n\ntype TemplateFn<V extends string | HTMLResult = string | HTMLResult> = () => V;\n\nexport type WhenOptions<V extends string | HTMLResult = string | HTMLResult> = {\n condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown) | unknown;\n else?: TemplateFn<V> | null;\n then?: TemplateFn<V> | null;\n};\n\nconst validateWhenOptions = <V extends string | HTMLResult>(options: WhenOptions<V>): void => {\n if (options.then !== undefined && options.then !== null && typeof options.then !== 'function') {\n throw new Error('[craftit:when] options.then must be a function when provided.');\n }\n\n if (options.else !== undefined && options.else !== null && typeof options.else !== 'function') {\n throw new Error('[craftit:when] options.else must be a function when provided.');\n }\n};\n\n/**\n * Conditionally renders one of two templates based on a condition.\n *\n * - **Signal or getter** — returns a reactive function the engine re-runs automatically.\n * - **Static value** — evaluated once at call time, returns the result directly.\n *\n * @example\n * import { when } from '@vielzeug/craftit/directives';\n *\n * html`${when({ condition: isLoggedIn, then: () => html`<user-panel>`, else: () => html`<login-form>` })}`\n * html`${when({ condition: () => count.value > 0, then: () => html`<span>${count}</span>` })}`\n */\nexport function when<V extends string | HTMLResult>(options: WhenOptions<V>): Directive | V | string {\n validateWhenOptions(options);\n\n const { condition } = options;\n const { else: resolvedElse, then: resolvedThen } = options;\n const renderResolved = (): V | string =>\n conditionValue(condition) ? (resolvedThen?.() ?? '') : (resolvedElse?.() ?? '');\n\n if (isSignal(condition) || typeof condition === 'function') {\n return {\n render: renderResolved,\n };\n }\n\n return renderResolved();\n}\n\nconst conditionValue = (condition: WhenOptions['condition']): unknown => {\n if (isSignal(condition)) return (condition as ReadonlySignal<unknown>).value;\n\n if (typeof condition === 'function') return (condition as () => unknown)();\n\n return condition;\n};\n"],"mappings":"6CAYA,IAAM,EAAsD,GAAkC,CAC5F,GAAI,EAAQ,OAAS,IAAA,IAAa,EAAQ,OAAS,MAAQ,OAAO,EAAQ,MAAS,WACjF,MAAU,MAAM,gEAAgE,CAGlF,GAAI,EAAQ,OAAS,IAAA,IAAa,EAAQ,OAAS,MAAQ,OAAO,EAAQ,MAAS,WACjF,MAAU,MAAM,gEAAgE,EAgBpF,SAAgB,EAAoC,EAAiD,CACnG,EAAoB,EAAQ,CAE5B,GAAM,CAAE,aAAc,EAChB,CAAE,KAAM,EAAc,KAAM,GAAiB,EAC7C,MACJ,EAAe,EAAU,CAAI,KAAgB,EAAI,GAAO,KAAgB,EAAI,GAQ9E,OANI,EAAS,EAAU,EAAI,OAAO,GAAc,WACvC,CACL,OAAQ,EACT,CAGI,GAAgB,CAGzB,IAAM,EAAkB,GAClB,EAAS,EAAU,CAAU,EAAsC,MAEnE,OAAO,GAAc,WAAoB,GAA6B,CAEnE"}
1
+ {"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../internal';\n\ntype MaybeReactive<T> = T | (() => T) | ReadonlySignal<T>;\n\ntype WhenRenderable = string | HTMLResult;\n\nconst resolve = <T>(value: MaybeReactive<T>): T => {\n if (typeof value === 'function') return (value as () => T)();\n\n if (isSignal(value)) return value.value;\n\n return value;\n};\n\n/**\n * Conditionally renders one of two branches.\n */\nexport function when(\n condition: MaybeReactive<boolean>,\n truthy: () => WhenRenderable,\n falsy?: () => WhenRenderable,\n): ReadonlySignal<WhenRenderable> {\n return computed(() => {\n if (resolve(condition)) return truthy();\n\n return falsy ? falsy() : '';\n });\n} // Note: when returns HtmlResult (not DirectiveResult)\n"],"mappings":"2DAQA,IAAM,EAAc,GACd,OAAO,GAAU,WAAoB,EAAkB,EAEvD,EAAS,CAAK,EAAU,EAAM,MAE3B,EAMT,SAAgB,EACd,EACA,EACA,EACgC,CAChC,OAAO,MACD,EAAQ,CAAS,EAAU,EAAO,EAE/B,EAAQ,EAAM,EAAI,EAC1B,CACH"}
@@ -0,0 +1,2 @@
1
+ var e={cleanupFailed:`One or more cleanup callbacks failed during dispose`,defineDuplicate:e=>`define('${e}') was called more than once`,defineFieldRequiresFormAssociated:e=>`defineField() requires define('${e}', { formAssociated: true })`,defineRequiresTag:`define() requires a non-empty tag name`,eachDuplicateKey:(e,t)=>`each() received duplicate key "${e}" at index ${t}`,injectStrictFailed:(e,t)=>`injectStrict() could not resolve key "${e}" in <${t}>`,lifecycleOutsideSetup:`Lifecycle hooks must be called synchronously during component setup`,styleReplaceFailed:`Style sheet replace failed`,unhandledComponentError:e=>`<${e}> threw an unhandled error during setup`};exports.CRAFTIT_ERRORS=e;
2
+ //# sourceMappingURL=errors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export const CRAFTIT_ERRORS = {\n cleanupFailed: 'One or more cleanup callbacks failed during dispose',\n defineDuplicate: (tag: string): string => `define('${tag}') was called more than once`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `defineField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a non-empty tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called synchronously during component setup',\n styleReplaceFailed: 'Style sheet replace failed',\n unhandledComponentError: (tag: string): string => `<${tag}> threw an unhandled error during setup`,\n} as const;\n"],"mappings":"AAAA,IAAa,EAAiB,CAC5B,cAAe,sDACf,gBAAkB,GAAwB,WAAW,EAAI,8BACzD,kCAAoC,GAClC,kCAAkC,EAAI,8BACxC,kBAAmB,yCACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAuB,sEACvB,mBAAoB,6BACpB,wBAA0B,GAAwB,IAAI,EAAI,wCAC5D"}
@@ -0,0 +1,12 @@
1
+ export declare const CRAFTIT_ERRORS: {
2
+ readonly cleanupFailed: "One or more cleanup callbacks failed during dispose";
3
+ readonly defineDuplicate: (tag: string) => string;
4
+ readonly defineFieldRequiresFormAssociated: (tag: string) => string;
5
+ readonly defineRequiresTag: "define() requires a non-empty tag name";
6
+ readonly eachDuplicateKey: (key: string, index: number) => string;
7
+ readonly injectStrictFailed: (key: string, tag: string) => string;
8
+ readonly lifecycleOutsideSetup: "Lifecycle hooks must be called synchronously during component setup";
9
+ readonly styleReplaceFailed: "Style sheet replace failed";
10
+ readonly unhandledComponentError: (tag: string) => string;
11
+ };
12
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;oCAEF,MAAM,KAAG,MAAM;sDACG,MAAM,KAAG,MAAM;;qCAGhC,MAAM,SAAS,MAAM,KAAG,MAAM;uCAC5B,MAAM,OAAO,MAAM,KAAG,MAAM;;;4CAGvB,MAAM,KAAG,MAAM;CACtC,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,2 @@
1
+ var e={cleanupFailed:`One or more cleanup callbacks failed during dispose`,defineDuplicate:e=>`define('${e}') was called more than once`,defineFieldRequiresFormAssociated:e=>`defineField() requires define('${e}', { formAssociated: true })`,defineRequiresTag:`define() requires a non-empty tag name`,eachDuplicateKey:(e,t)=>`each() received duplicate key "${e}" at index ${t}`,injectStrictFailed:(e,t)=>`injectStrict() could not resolve key "${e}" in <${t}>`,lifecycleOutsideSetup:`Lifecycle hooks must be called synchronously during component setup`,styleReplaceFailed:`Style sheet replace failed`,unhandledComponentError:e=>`<${e}> threw an unhandled error during setup`};export{e as CRAFTIT_ERRORS};
2
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export const CRAFTIT_ERRORS = {\n cleanupFailed: 'One or more cleanup callbacks failed during dispose',\n defineDuplicate: (tag: string): string => `define('${tag}') was called more than once`,\n defineFieldRequiresFormAssociated: (tag: string): string =>\n `defineField() requires define('${tag}', { formAssociated: true })`,\n defineRequiresTag: 'define() requires a non-empty tag name',\n eachDuplicateKey: (key: string, index: number): string => `each() received duplicate key \"${key}\" at index ${index}`,\n injectStrictFailed: (key: string, tag: string): string => `injectStrict() could not resolve key \"${key}\" in <${tag}>`,\n lifecycleOutsideSetup: 'Lifecycle hooks must be called synchronously during component setup',\n styleReplaceFailed: 'Style sheet replace failed',\n unhandledComponentError: (tag: string): string => `<${tag}> threw an unhandled error during setup`,\n} as const;\n"],"mappings":"AAAA,IAAa,EAAiB,CAC5B,cAAe,sDACf,gBAAkB,GAAwB,WAAW,EAAI,8BACzD,kCAAoC,GAClC,kCAAkC,EAAI,8BACxC,kBAAmB,yCACnB,kBAAmB,EAAa,IAA0B,kCAAkC,EAAI,aAAa,IAC7G,oBAAqB,EAAa,IAAwB,yCAAyC,EAAI,QAAQ,EAAI,GACnH,sBAAuB,sEACvB,mBAAoB,6BACpB,wBAA0B,GAAwB,IAAI,EAAI,wCAC5D"}
package/dist/form.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const e=require(`./runtime-core.cjs`);let t=require(`@vielzeug/stateit`);var n=new WeakMap,r=new WeakMap,i=(i,a)=>{let o=e.currentRuntime().el;if(!o.constructor.formAssociated)throw Error(`[craftit:E8] defineField() requires define(..., { formAssociated: true, ... })`);let s=r.get(o)??o.attachInternals();r.set(o,s);let c=i.toFormValue??(e=>e==null?``:String(e));(0,t.effect)(()=>{s.setFormValue(c(i.value.value))});let l=i.disabled;return l&&(0,t.effect)(()=>{l.value?s.states.add(`disabled`):s.states.delete(`disabled`)}),a&&n.set(o,{...n.get(o),...a}),{checkValidity:()=>s.checkValidity(),internals:s,reportValidity:()=>s.reportValidity(),setCustomValidity:e=>e?s.setValidity({customError:!0},e):s.setValidity({}),setValidity:s.setValidity.bind(s)}};exports.defineField=i,exports.formCallbackRegistry=n;
1
+ const e=require(`./errors.cjs`),t=require(`./runtime.cjs`);require(`@vielzeug/stateit`);var n=new WeakMap,r=r=>{let i=t.currentElementOrThrow();if(!i.constructor.formAssociated)throw Error(e.CRAFTIT_ERRORS.defineFieldRequiresFormAssociated(i.localName));let a=n.get(i)??i.attachInternals();n.set(i,a);let o=r.toFormValue??(e=>e==null?null:e instanceof File||e instanceof FormData?e:String(e));t.effect(()=>{a.setFormValue(o(r.value.value))});let s=r.disabled;if(s){let e=a.states;t.effect(()=>{s.value?e.add(`disabled`):e.delete(`disabled`)})}return{checkValidity:()=>a.checkValidity(),internals:a,reportValidity:()=>a.reportValidity(),setCustomValidity:e=>e?a.setValidity({customError:!0},e):a.setValidity({}),setValidity:a.setValidity.bind(a)}};exports.defineField=r;
2
2
  //# sourceMappingURL=form.cjs.map
package/dist/form.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"form.cjs","names":[],"sources":["../src/form.ts"],"sourcesContent":["import { type ComputedSignal, type ReadonlySignal, type Signal, effect } from '@vielzeug/stateit';\n\nimport { currentRuntime } from './runtime-core';\n\n/** @internal */\nexport const formCallbackRegistry = new WeakMap<HTMLElement, FormFieldCallbacks>();\n/** @internal */\nexport const internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n\n/**\n * Callbacks that hook into form lifecycle events. Can be passed directly to defineField\n * as a second argument to keep all form logic co-located.\n */\nexport type FormFieldCallbacks = {\n onAssociated?: (form: HTMLFormElement | null) => void;\n onDisabled?: (disabled: boolean) => void;\n onReset?: () => void;\n onStateRestore?: (state: unknown, mode: 'autocomplete' | 'restore') => void;\n};\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: Signal<boolean> | ReadonlySignal<boolean> | ComputedSignal<boolean>;\n toFormValue?: (value: T) => File | FormData | string | null;\n value: Signal<T> | ReadonlySignal<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n setCustomValidity: (message: string) => void;\n setValidity: ElementInternals['setValidity'];\n};\n\nexport const defineField = <T = unknown>(\n options: FormFieldOptions<T>,\n callbacks?: FormFieldCallbacks,\n): FormFieldHandle => {\n const rt = currentRuntime();\n const host = rt.el;\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new Error('[craftit:E8] defineField() requires define(..., { formAssociated: true, ... })');\n }\n\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n\n const toFormValue = options.toFormValue ?? ((v: T) => (v == null ? '' : String(v)));\n\n effect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n effect(() => {\n if (disabled.value) {\n internals.states.add('disabled');\n } else {\n internals.states.delete('disabled');\n }\n });\n }\n\n if (callbacks) {\n formCallbackRegistry.set(host, { ...formCallbackRegistry.get(host), ...callbacks });\n }\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n setValidity: internals.setValidity.bind(internals),\n };\n};\n"],"mappings":"yEAKA,IAAa,EAAuB,IAAI,QAE3B,EAAoB,IAAI,QA2BxB,GACX,EACA,IACoB,CAEpB,IAAM,EADK,EAAA,gBAAgB,CACX,GAGhB,GAAI,CAFS,EAAK,YAER,eACR,MAAU,MAAM,iFAAiF,CAGnG,IAAM,EAAY,EAAkB,IAAI,EAAK,EAAI,EAAK,iBAAiB,CAEvE,EAAkB,IAAI,EAAM,EAAU,CAEtC,IAAM,EAAc,EAAQ,cAAiB,GAAU,GAAK,KAAO,GAAK,OAAO,EAAE,GAEjF,EAAA,EAAA,YAAa,CACX,EAAU,aAAa,EAAY,EAAQ,MAAM,MAAM,CAAC,EACxD,CAEF,IAAM,EAAW,EAAQ,SAqBzB,OAnBI,IACF,EAAA,EAAA,YAAa,CACP,EAAS,MACX,EAAU,OAAO,IAAI,WAAW,CAEhC,EAAU,OAAO,OAAO,WAAW,EAErC,CAGA,GACF,EAAqB,IAAI,EAAM,CAAE,GAAG,EAAqB,IAAI,EAAK,CAAE,GAAG,EAAW,CAAC,CAQ9E,CACL,kBAN0B,EAAU,eAAe,CAOnD,YACA,mBAP2B,EAAU,gBAAgB,CAQrD,kBAPyB,GACzB,EAAU,EAAU,YAAY,CAAE,YAAa,GAAM,CAAE,EAAQ,CAAG,EAAU,YAAY,EAAE,CAAC,CAO3F,YAAa,EAAU,YAAY,KAAK,EAAU,CACnD"}
1
+ {"version":3,"file":"form.cjs","names":[],"sources":["../src/form.ts"],"sourcesContent":["import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { currentElementOrThrow, effect } from './runtime';\n\n/** @internal */\nconst internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: ReadonlySignal<boolean>;\n toFormValue?: (value: T) => File | FormData | string | null;\n value: Signal<T> | ReadonlySignal<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n setCustomValidity: (message: string) => void;\n setValidity: ElementInternals['setValidity'];\n};\n\nexport const defineField = <T = unknown>(options: FormFieldOptions<T>): FormFieldHandle => {\n const host = currentElementOrThrow();\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new Error(CRAFTIT_ERRORS.defineFieldRequiresFormAssociated(host.localName));\n }\n\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n\n const toFormValue =\n options.toFormValue ??\n ((v: T): File | FormData | string | null => {\n if (v == null) return null;\n\n if (v instanceof File || v instanceof FormData) return v;\n\n return String(v);\n });\n\n effect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n const states = internals.states as CustomStateSet;\n\n effect(() => {\n if (disabled.value) states.add('disabled');\n else states.delete('disabled');\n });\n }\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n setValidity: internals.setValidity.bind(internals),\n };\n};\n"],"mappings":"wFAMA,IAAM,EAAoB,IAAI,QAgBjB,EAA4B,GAAkD,CACzF,IAAM,EAAO,EAAA,sBAAsB,EAGnC,GAAI,CAFS,EAAK,YAER,eACR,MAAU,MAAM,EAAA,eAAe,kCAAkC,EAAK,SAAS,CAAC,EAGlF,IAAM,EAAY,EAAkB,IAAI,CAAI,GAAK,EAAK,gBAAgB,EAEtE,EAAkB,IAAI,EAAM,CAAS,EAErC,IAAM,EACJ,EAAQ,cACN,GACI,GAAK,KAAa,KAElB,aAAa,MAAQ,aAAa,SAAiB,EAEhD,OAAO,CAAC,GAGnB,EAAA,WAAa,CACX,EAAU,aAAa,EAAY,EAAQ,MAAM,KAAK,CAAC,CACzD,CAAC,EAED,IAAM,EAAW,EAAQ,SAEzB,GAAI,EAAU,CACZ,IAAM,EAAS,EAAU,OAEzB,EAAA,WAAa,CACP,EAAS,MAAO,EAAO,IAAI,UAAU,EACpC,EAAO,OAAO,UAAU,CAC/B,CAAC,CACH,CAOA,MAAO,CACL,kBAN0B,EAAU,cAAc,EAOlD,YACA,mBAP2B,EAAU,eAAe,EAQpD,kBAPyB,GACzB,EAAU,EAAU,YAAY,CAAE,YAAa,EAAK,EAAG,CAAO,EAAI,EAAU,YAAY,CAAC,CAAC,EAO1F,YAAa,EAAU,YAAY,KAAK,CAAS,CACnD,CACF"}
package/dist/form.d.ts CHANGED
@@ -1,20 +1,6 @@
1
- import { type ComputedSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';
2
- /** @internal */
3
- export declare const formCallbackRegistry: WeakMap<HTMLElement, FormFieldCallbacks>;
4
- /** @internal */
5
- export declare const internalsRegistry: WeakMap<HTMLElement, ElementInternals>;
6
- /**
7
- * Callbacks that hook into form lifecycle events. Can be passed directly to defineField
8
- * as a second argument to keep all form logic co-located.
9
- */
10
- export type FormFieldCallbacks = {
11
- onAssociated?: (form: HTMLFormElement | null) => void;
12
- onDisabled?: (disabled: boolean) => void;
13
- onReset?: () => void;
14
- onStateRestore?: (state: unknown, mode: 'autocomplete' | 'restore') => void;
15
- };
1
+ import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
16
2
  export type FormFieldOptions<T = unknown> = {
17
- disabled?: Signal<boolean> | ReadonlySignal<boolean> | ComputedSignal<boolean>;
3
+ disabled?: ReadonlySignal<boolean>;
18
4
  toFormValue?: (value: T) => File | FormData | string | null;
19
5
  value: Signal<T> | ReadonlySignal<T>;
20
6
  };
@@ -25,5 +11,5 @@ export type FormFieldHandle = {
25
11
  setCustomValidity: (message: string) => void;
26
12
  setValidity: ElementInternals['setValidity'];
27
13
  };
28
- export declare const defineField: <T = unknown>(options: FormFieldOptions<T>, callbacks?: FormFieldCallbacks) => FormFieldHandle;
14
+ export declare const defineField: <T = unknown>(options: FormFieldOptions<T>) => FormFieldHandle;
29
15
  //# sourceMappingURL=form.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAU,MAAM,mBAAmB,CAAC;AAIlG,gBAAgB;AAChB,eAAO,MAAM,oBAAoB,0CAAiD,CAAC;AACnF,gBAAgB;AAChB,eAAO,MAAM,iBAAiB,wCAA+C,CAAC;AAE9E;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,CAAC;IACtD,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,GAAG,SAAS,KAAK,IAAI,CAAC;CAC7E,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAC/E,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5D,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC;IAC9B,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;CAC9C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,GAAG,OAAO,EACrC,SAAS,gBAAgB,CAAC,CAAC,CAAC,EAC5B,YAAY,kBAAkB,KAC7B,eA+CF,CAAC"}
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAQrE,MAAM,MAAM,gBAAgB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC1C,QAAQ,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5D,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,cAAc,EAAE,MAAM,OAAO,CAAC;IAC9B,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;CAC9C,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,GAAG,OAAO,EAAE,SAAS,gBAAgB,CAAC,CAAC,CAAC,KAAG,eAiDvE,CAAC"}
package/dist/form.js CHANGED
@@ -1,2 +1,2 @@
1
- import{currentRuntime as e}from"./runtime-core.js";import{effect as t}from"@vielzeug/stateit";var n=new WeakMap,r=new WeakMap,i=(i,a)=>{let o=e().el;if(!o.constructor.formAssociated)throw Error(`[craftit:E8] defineField() requires define(..., { formAssociated: true, ... })`);let s=r.get(o)??o.attachInternals();r.set(o,s);let c=i.toFormValue??(e=>e==null?``:String(e));t(()=>{s.setFormValue(c(i.value.value))});let l=i.disabled;return l&&t(()=>{l.value?s.states.add(`disabled`):s.states.delete(`disabled`)}),a&&n.set(o,{...n.get(o),...a}),{checkValidity:()=>s.checkValidity(),internals:s,reportValidity:()=>s.reportValidity(),setCustomValidity:e=>e?s.setValidity({customError:!0},e):s.setValidity({}),setValidity:s.setValidity.bind(s)}};export{i as defineField,n as formCallbackRegistry};
1
+ import{CRAFTIT_ERRORS as e}from"./errors.js";import{currentElementOrThrow as t,effect as n}from"./runtime.js";import"@vielzeug/stateit";var r=new WeakMap,i=i=>{let a=t();if(!a.constructor.formAssociated)throw Error(e.defineFieldRequiresFormAssociated(a.localName));let o=r.get(a)??a.attachInternals();r.set(a,o);let s=i.toFormValue??(e=>e==null?null:e instanceof File||e instanceof FormData?e:String(e));n(()=>{o.setFormValue(s(i.value.value))});let c=i.disabled;if(c){let e=o.states;n(()=>{c.value?e.add(`disabled`):e.delete(`disabled`)})}return{checkValidity:()=>o.checkValidity(),internals:o,reportValidity:()=>o.reportValidity(),setCustomValidity:e=>e?o.setValidity({customError:!0},e):o.setValidity({}),setValidity:o.setValidity.bind(o)}};export{i as defineField};
2
2
  //# sourceMappingURL=form.js.map
package/dist/form.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","names":[],"sources":["../src/form.ts"],"sourcesContent":["import { type ComputedSignal, type ReadonlySignal, type Signal, effect } from '@vielzeug/stateit';\n\nimport { currentRuntime } from './runtime-core';\n\n/** @internal */\nexport const formCallbackRegistry = new WeakMap<HTMLElement, FormFieldCallbacks>();\n/** @internal */\nexport const internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n\n/**\n * Callbacks that hook into form lifecycle events. Can be passed directly to defineField\n * as a second argument to keep all form logic co-located.\n */\nexport type FormFieldCallbacks = {\n onAssociated?: (form: HTMLFormElement | null) => void;\n onDisabled?: (disabled: boolean) => void;\n onReset?: () => void;\n onStateRestore?: (state: unknown, mode: 'autocomplete' | 'restore') => void;\n};\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: Signal<boolean> | ReadonlySignal<boolean> | ComputedSignal<boolean>;\n toFormValue?: (value: T) => File | FormData | string | null;\n value: Signal<T> | ReadonlySignal<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n setCustomValidity: (message: string) => void;\n setValidity: ElementInternals['setValidity'];\n};\n\nexport const defineField = <T = unknown>(\n options: FormFieldOptions<T>,\n callbacks?: FormFieldCallbacks,\n): FormFieldHandle => {\n const rt = currentRuntime();\n const host = rt.el;\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new Error('[craftit:E8] defineField() requires define(..., { formAssociated: true, ... })');\n }\n\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n\n const toFormValue = options.toFormValue ?? ((v: T) => (v == null ? '' : String(v)));\n\n effect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n effect(() => {\n if (disabled.value) {\n internals.states.add('disabled');\n } else {\n internals.states.delete('disabled');\n }\n });\n }\n\n if (callbacks) {\n formCallbackRegistry.set(host, { ...formCallbackRegistry.get(host), ...callbacks });\n }\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n setValidity: internals.setValidity.bind(internals),\n };\n};\n"],"mappings":"8FAKA,IAAa,EAAuB,IAAI,QAE3B,EAAoB,IAAI,QA2BxB,GACX,EACA,IACoB,CAEpB,IAAM,EADK,GAAgB,CACX,GAGhB,GAAI,CAFS,EAAK,YAER,eACR,MAAU,MAAM,iFAAiF,CAGnG,IAAM,EAAY,EAAkB,IAAI,EAAK,EAAI,EAAK,iBAAiB,CAEvE,EAAkB,IAAI,EAAM,EAAU,CAEtC,IAAM,EAAc,EAAQ,cAAiB,GAAU,GAAK,KAAO,GAAK,OAAO,EAAE,EAEjF,MAAa,CACX,EAAU,aAAa,EAAY,EAAQ,MAAM,MAAM,CAAC,EACxD,CAEF,IAAM,EAAW,EAAQ,SAqBzB,OAnBI,GACF,MAAa,CACP,EAAS,MACX,EAAU,OAAO,IAAI,WAAW,CAEhC,EAAU,OAAO,OAAO,WAAW,EAErC,CAGA,GACF,EAAqB,IAAI,EAAM,CAAE,GAAG,EAAqB,IAAI,EAAK,CAAE,GAAG,EAAW,CAAC,CAQ9E,CACL,kBAN0B,EAAU,eAAe,CAOnD,YACA,mBAP2B,EAAU,gBAAgB,CAQrD,kBAPyB,GACzB,EAAU,EAAU,YAAY,CAAE,YAAa,GAAM,CAAE,EAAQ,CAAG,EAAU,YAAY,EAAE,CAAC,CAO3F,YAAa,EAAU,YAAY,KAAK,EAAU,CACnD"}
1
+ {"version":3,"file":"form.js","names":[],"sources":["../src/form.ts"],"sourcesContent":["import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { currentElementOrThrow, effect } from './runtime';\n\n/** @internal */\nconst internalsRegistry = new WeakMap<HTMLElement, ElementInternals>();\n\nexport type FormFieldOptions<T = unknown> = {\n disabled?: ReadonlySignal<boolean>;\n toFormValue?: (value: T) => File | FormData | string | null;\n value: Signal<T> | ReadonlySignal<T>;\n};\n\nexport type FormFieldHandle = {\n checkValidity: () => boolean;\n readonly internals: ElementInternals;\n reportValidity: () => boolean;\n setCustomValidity: (message: string) => void;\n setValidity: ElementInternals['setValidity'];\n};\n\nexport const defineField = <T = unknown>(options: FormFieldOptions<T>): FormFieldHandle => {\n const host = currentElementOrThrow();\n const ctor = host.constructor as typeof HTMLElement & { formAssociated?: boolean };\n\n if (!ctor.formAssociated) {\n throw new Error(CRAFTIT_ERRORS.defineFieldRequiresFormAssociated(host.localName));\n }\n\n const internals = internalsRegistry.get(host) ?? host.attachInternals();\n\n internalsRegistry.set(host, internals);\n\n const toFormValue =\n options.toFormValue ??\n ((v: T): File | FormData | string | null => {\n if (v == null) return null;\n\n if (v instanceof File || v instanceof FormData) return v;\n\n return String(v);\n });\n\n effect(() => {\n internals.setFormValue(toFormValue(options.value.value));\n });\n\n const disabled = options.disabled;\n\n if (disabled) {\n const states = internals.states as CustomStateSet;\n\n effect(() => {\n if (disabled.value) states.add('disabled');\n else states.delete('disabled');\n });\n }\n\n const checkValidity = () => internals.checkValidity();\n const reportValidity = () => internals.reportValidity();\n const setCustomValidity = (message: string) =>\n message ? internals.setValidity({ customError: true }, message) : internals.setValidity({});\n\n return {\n checkValidity,\n internals,\n reportValidity,\n setCustomValidity,\n setValidity: internals.setValidity.bind(internals),\n };\n};\n"],"mappings":"wIAMA,IAAM,EAAoB,IAAI,QAgBjB,EAA4B,GAAkD,CACzF,IAAM,EAAO,EAAsB,EAGnC,GAAI,CAFS,EAAK,YAER,eACR,MAAU,MAAM,EAAe,kCAAkC,EAAK,SAAS,CAAC,EAGlF,IAAM,EAAY,EAAkB,IAAI,CAAI,GAAK,EAAK,gBAAgB,EAEtE,EAAkB,IAAI,EAAM,CAAS,EAErC,IAAM,EACJ,EAAQ,cACN,GACI,GAAK,KAAa,KAElB,aAAa,MAAQ,aAAa,SAAiB,EAEhD,OAAO,CAAC,GAGnB,MAAa,CACX,EAAU,aAAa,EAAY,EAAQ,MAAM,KAAK,CAAC,CACzD,CAAC,EAED,IAAM,EAAW,EAAQ,SAEzB,GAAI,EAAU,CACZ,IAAM,EAAS,EAAU,OAEzB,MAAa,CACP,EAAS,MAAO,EAAO,IAAI,UAAU,EACpC,EAAO,OAAO,UAAU,CAC/B,CAAC,CACH,CAOA,MAAO,CACL,kBAN0B,EAAU,cAAc,EAOlD,YACA,mBAP2B,EAAU,eAAe,EAQpD,kBAPyB,GACzB,EAAU,EAAU,YAAY,CAAE,YAAa,EAAK,EAAG,CAAO,EAAI,EAAU,YAAY,CAAC,CAAC,EAO1F,YAAa,EAAU,YAAY,KAAK,CAAS,CACnD,CACF"}
package/dist/host.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const e=require(`./runtime-core.cjs`),t=require(`./runtime-lifecycle.cjs`),n=require(`./internal.cjs`);let r=require(`@vielzeug/stateit`);var i=new WeakMap,a=(t,n)=>{let r=e.currentRuntime().el;i.has(r)||i.set(r,new Map),i.get(r).set(t,n)};function o(t,...n){let r=e.currentRuntime().el;for(;r;){if(r instanceof HTMLElement){let e=i.get(r)?.get(t);if(e!==void 0)return e}let e=r.getRootNode();r=r.parentElement??(e instanceof ShadowRoot?e.host:null)}return n.length>0?n[0]:void 0}function s(e){return Symbol(e)}var c=(e,n,r)=>{e&&t.onMount(()=>{t.effect(()=>{let t=n;for(let n of r){let r=e[n]?.value;r!==void 0&&(t[n].value=r)}})})},l=(e,n)=>{let r=!1;t.effect(()=>{let t=!!n.contextDisabled?.value;t&&!r?(e.setAttribute(`disabled`,``),r=!0):!t&&r&&!n.ownDisabled?.value&&(e.removeAttribute(`disabled`),r=!1);let i=n.contextSize?.value,a=!!n.ownSize?.value;i&&!a?e.setAttribute(`size`,i):a||e.removeAttribute(`size`);let o=n.contextVariant?.value,s=!!n.ownVariant?.value;o&&!s?e.setAttribute(`variant`,o):s||e.removeAttribute(`variant`)})},u=`default`,d=e=>!e||e===u?u:e,f=new WeakMap,p=()=>{let n=e.currentRuntime().el,i=f.get(n);if(i)return i;let a=new Map,o=new Map,s=new Map,c=new Map,l=!1,p=e=>{let t=d(e),n=a.get(t);return n||(n=(0,r.signal)(!1),a.set(t,n)),n},m=e=>{let t=d(e),n=o.get(t);return n||(n=(0,r.signal)([]),o.set(t,n)),n},h=e=>{let t=d(e),n=s.get(t),r=[];if(n)for(let e of n)r.push(...e.assignedElements({flatten:!0}));m(t).value=r,p(t).value=r.length>0},g=e=>{if(c.has(e))return;let t=d(e.getAttribute(`name`)),n=s.get(t)??new Set;n.add(e),s.set(t,n);let r=()=>h(t);e.addEventListener(`slotchange`,r),c.set(e,()=>{if(e.removeEventListener(`slotchange`,r),c.delete(e),l)return;let n=s.get(t);n&&(n.delete(e),n.size===0&&s.delete(t),h(t))}),h(t)},_=e=>{c.get(e)?.()};p(u),m(u),n.shadowRoot?.querySelectorAll(`slot`).forEach(e=>g(e));let v=new MutationObserver(e=>{for(let t of e)t.addedNodes.forEach(e=>{if(e instanceof HTMLSlotElement){g(e);return}e instanceof Element&&e.querySelectorAll(`slot`).forEach(e=>g(e))}),t.removedNodes.forEach(e=>{if(e instanceof HTMLSlotElement){_(e);return}e instanceof Element&&e.querySelectorAll(`slot`).forEach(e=>_(e))})});n.shadowRoot&&v.observe(n.shadowRoot,{childList:!0,subtree:!0}),t.onCleanup(()=>{l=!0,v.disconnect();for(let e of[...c.values()])e();c.clear(),s.clear()});let y={elements:e=>m(d(e)),has:e=>p(d(e))};return f.set(n,y),y},m=()=>{let r=e.currentRuntime().el;return{bind:(e,i,a)=>{let o=[],s=typeof e==`string`?{[e]:i}:e,c=typeof e==`string`&&e===`on`?a:i;if(`attr`in s)for(let[e,t]of Object.entries(s.attr)){let n=h(r,e.startsWith(`aria-`)||e===`role`?e:e.startsWith(`aria`)?`aria-${e.slice(4).toLowerCase()}`:e,t);n&&o.push(n)}if(`class`in s&&o.push(g(r,s.class)),`on`in s)for(let e of Object.keys(s.on)){let t=s.on[e];t&&o.push(n.listen(r,e,t,c))}let l=()=>{for(;o.length>0;)o.pop()?.()};return t.onCleanup(l),l},el:r,shadowRoot:r.shadowRoot}};function h(e,r,i){if(typeof i==`function`)return t.effect(()=>n.setAttr(e,r,i()));n.setAttr(e,r,i)}function g(e,n){let r=new Set;return t.effect(()=>{let t=new Set(Object.entries(n()).filter(([,e])=>e).map(([e])=>e));for(let n of r)t.has(n)||e.classList.remove(n);for(let n of t)r.has(n)||e.classList.add(n);r=t})}exports.bridgeContextAttributes=l,exports.createContext=s,exports.createHost=m,exports.createSlots=p,exports.inject=o,exports.provide=a,exports.syncContextProps=c;
1
+ const e=require(`./errors.cjs`),t=require(`./runtime.cjs`),n=require(`./internal.cjs`);let r=require(`@vielzeug/stateit`);var i=new WeakMap,a=(e,n)=>{let r=t.currentElementOrThrow();i.has(r)||i.set(r,new Map),i.get(r).set(e,n)};function o(e,...n){let r=t.currentElementOrThrow();for(;r;){if(r instanceof HTMLElement){let t=i.get(r)?.get(e);if(t!==void 0)return t}let t=r.getRootNode();r=r.parentElement??(t instanceof ShadowRoot?t.host:null)}return n.length>0?n[0]:void 0}var s=n=>{let r=o(n);if(r!==void 0)return r;let i=t.currentElementOrThrow();throw Error(e.CRAFTIT_ERRORS.injectStrictFailed(String(n),i.localName))};function c(e){return Symbol(e)}var l=e=>e===`role`||e.startsWith(`aria-`)?e:e.startsWith(`aria`)?`aria-${e.slice(4).toLowerCase()}`:`aria-${e}`,u=e=>e===`role`||e.startsWith(`aria-`)?e:e.startsWith(`aria`)?`aria-${e.slice(4).toLowerCase()}`:e,d=(e,t,n)=>{if(n==null||n===!1){e.removeAttribute(t);return}e.setAttribute(t,n===!0?`true`:String(n))},f=(e,n,i={})=>{let{autoCleanup:a=!0}=i,o=[];for(let[t,i]of Object.entries(n)){let n=l(t);if(typeof i==`function`){let t=i;o.push((0,r.effect)(()=>{d(e,n,t())}));continue}d(e,n,i)}let s=()=>{for(;o.length>0;)o.pop()?.()};return a&&t.tryRegisterCleanup(s),s},p=`default`,m=e=>e||p,h=()=>{let e=t.currentElementOrThrow(),n=new Map,i=new Map,a=new Map,o=e=>{let t=n.get(e);return t||(t={elements:(0,r.signal)([]),presence:(0,r.signal)(!1)},n.set(e,t)),t},s=(e,t)=>{if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0},c=e=>{let t=m(e),n=i.get(t),r=[];if(n)for(let e of n)r.push(...e.assignedElements({flatten:!0}));let a=o(t);s(a.elements.value,r)||(a.elements.value=r);let c=r.length>0;a.presence.value!==c&&(a.presence.value=c)},l=e=>{if(a.has(e))return;let t=m(e.getAttribute(`name`)),n=i.get(t)??new Set;n.add(e),i.set(t,n);let r=()=>c(t);e.addEventListener(`slotchange`,r),a.set(e,()=>{e.removeEventListener(`slotchange`,r)}),c(t)},u=()=>{e.shadowRoot?.querySelectorAll(`slot`).forEach(e=>l(e))},d=()=>{for(let e of i.keys())c(e)};return u(),t.onMounted(()=>{u(),d()}),t.onCleanup(()=>{for(let e of a.values())e();a.clear(),i.clear()}),{elements:e=>o(m(e)).elements,has:e=>o(m(e)).presence}},g=()=>{let e=t.currentElementOrThrow();return{bind:(r,i)=>{let a=[];if(r.attr)for(let[t,n]of Object.entries(r.attr)){let r=v(e,u(t),n);r&&a.push(r)}if(r.class&&a.push(b(e,r.class)),r.prop)for(let[t,n]of Object.entries(r.prop)){let{get:r,set:i}=n;Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:r,...i?{set:i}:{}}),a.push(()=>{let n=Object.getOwnPropertyDescriptor(e,t);!n||n.get!==r||n.set!==i||delete e[t]})}if(r.on)for(let t of Object.keys(r.on)){let o=r.on[t];o&&a.push(n.listen(e,t,o,i))}if(r.style)for(let[t,n]of Object.entries(r.style)){let r=y(e,t,n);r&&a.push(r)}let o=()=>{for(;a.length>0;)a.pop()?.()};return t.onCleanup(o),o},el:e}},_=(e,n)=>{if(typeof e==`function`)return t.effect(()=>n(e()));if((0,r.isSignal)(e))return t.effect(()=>n(e.value));n(e)};function v(e,t,r){return _(r,r=>n.setAttr(e,t,r))}function y(e,t,r){let i=t.startsWith(`--`)?t:n.toKebab(t),a=!1;return _(r,t=>{t!=null&&t!==``?(a=!0,e.style.setProperty(i,String(t))):a&&e.style.removeProperty(i)})}function b(e,n){let i=typeof n==`function`?n:()=>{let e={};for(let[t,i]of Object.entries(n))e[t]=typeof i==`function`?i():(0,r.isSignal)(i)?i.value:!!i;return e},a=new Set;return t.effect(()=>{let t=new Set;for(let[n,r]of Object.entries(i()))r&&(t.add(n),a.has(n)||e.classList.add(n));for(let n of a)t.has(n)||e.classList.remove(n);a=t})}exports.createContext=c,exports.createHost=g,exports.createSlots=h,exports.inject=o,exports.injectStrict=s,exports.provide=a,exports.syncAria=f;
2
2
  //# sourceMappingURL=host.cjs.map
package/dist/host.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"host.cjs","names":[],"sources":["../src/host.ts"],"sourcesContent":["/**\n * Host utilities — component context injection, slot observation, and attribute/class reflection.\n *\n * - Context API (provide, inject, createContext, syncContextProps)\n * - Slot observation and detection (setup slots)\n * - Host element binding (reflect) for attributes, classes, and host listeners\n */\n\nimport { type ReadonlySignal, type Signal, signal } from '@vielzeug/stateit';\n\nimport { listen, setAttr } from './internal';\nimport { currentRuntime } from './runtime-core';\nimport { effect, onCleanup, onMount, type HostEventListeners } from './runtime-lifecycle';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// CONTEXT API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown> | string | symbol, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __craftit_injection_key?: T;\n};\n\nexport const provide = <T>(key: InjectionKey<T> | string | symbol, value: T): void => {\n const el = currentRuntime().el;\n\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(key, value);\n};\n\nexport function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, ...rest: [T?]): T | undefined {\n let node: Node | null = currentRuntime().el;\n\n while (node) {\n if (node instanceof HTMLElement) {\n const v = contextRegistry.get(node)?.get(key);\n\n if (v !== undefined) return v as T;\n }\n\n const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return rest.length > 0 ? rest[0] : undefined;\n}\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n\n/**\n * Reactively inherits prop values from a context object provided by an ancestor component.\n * For each key, when the context value is not `undefined`, it is written into the matching prop signal.\n * The effect is automatically cleaned up when the component unmounts.\n *\n * Deferred to `onMount` so context values win over HTML attribute values set on the child.\n *\n * @example\n * syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);\n */\nexport const syncContextProps = <\n K extends string,\n Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>,\n Props extends Record<K, Signal<unknown>>,\n>(\n ctx: Ctx | undefined,\n props: Props,\n keys: K[],\n): void => {\n if (!ctx) return;\n\n onMount(() => {\n effect(() => {\n const target = props as Record<K, Signal<unknown>>;\n\n for (const k of keys) {\n const v = ctx[k]?.value;\n\n if (v !== undefined) target[k].value = v;\n }\n });\n });\n};\n\nexport type HostContextAttributeBridge = {\n contextDisabled?: ReadonlySignal<boolean | undefined>;\n contextSize?: ReadonlySignal<string | undefined>;\n contextVariant?: ReadonlySignal<string | undefined>;\n ownDisabled?: ReadonlySignal<boolean | undefined>;\n ownSize?: ReadonlySignal<string | undefined>;\n ownVariant?: ReadonlySignal<string | undefined>;\n};\n\nexport const bridgeContextAttributes = (host: HTMLElement, options: HostContextAttributeBridge): void => {\n let contextDisabledActive = false;\n\n effect(() => {\n const contextDisabled = Boolean(options.contextDisabled?.value);\n\n if (contextDisabled && !contextDisabledActive) {\n host.setAttribute('disabled', '');\n contextDisabledActive = true;\n } else if (!contextDisabled && contextDisabledActive && !options.ownDisabled?.value) {\n host.removeAttribute('disabled');\n contextDisabledActive = false;\n }\n\n const contextSize = options.contextSize?.value;\n const hasOwnSize = Boolean(options.ownSize?.value);\n\n if (contextSize && !hasOwnSize) host.setAttribute('size', contextSize);\n else if (!hasOwnSize) host.removeAttribute('size');\n\n const contextVariant = options.contextVariant?.value;\n const hasOwnVariant = Boolean(options.ownVariant?.value);\n\n if (contextVariant && !hasOwnVariant) host.setAttribute('variant', contextVariant);\n else if (!hasOwnVariant) host.removeAttribute('variant');\n });\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SLOTS API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SLOT_DEFAULT = 'default';\nconst normalizeSlotName = (slotName: string | null | undefined): string => {\n if (!slotName || slotName === SLOT_DEFAULT) return SLOT_DEFAULT;\n\n return slotName;\n};\n\nconst slotsRegistry = new WeakMap<HTMLElement, ComponentSlots>();\n\nexport type ComponentSlots = {\n elements: (name?: string) => ReadonlySignal<Element[]>;\n has: (name?: string) => ReadonlySignal<boolean>;\n};\n\n/**\n * Creates first-class slot signals for setup context.\n *\n * - `slots.has(name?)`: whether a slot has assigned elements\n * - `slots.elements(name?)`: assigned elements for a slot (flattened)\n */\nexport const createSlots = (): ComponentSlots => {\n const host = currentRuntime().el;\n const cached = slotsRegistry.get(host);\n\n if (cached) return cached;\n\n const presenceSignals = new Map<string, Signal<boolean>>();\n const elementSignals = new Map<string, Signal<Element[]>>();\n const slotNodesByName = new Map<string, Set<HTMLSlotElement>>();\n const slotCleanupMap = new Map<HTMLSlotElement, () => void>();\n let isDisposing = false;\n\n const ensurePresenceSignal = (name: string): Signal<boolean> => {\n const normalized = normalizeSlotName(name);\n let s = presenceSignals.get(normalized);\n\n if (!s) {\n s = signal(false);\n presenceSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const ensureElementSignal = (name: string): Signal<Element[]> => {\n const normalized = normalizeSlotName(name);\n let s = elementSignals.get(normalized);\n\n if (!s) {\n s = signal<Element[]>([]);\n elementSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const recomputeSlot = (name: string): void => {\n const normalized = normalizeSlotName(name);\n const slotsForName = slotNodesByName.get(normalized);\n const assigned: Element[] = [];\n\n if (slotsForName) {\n for (const slotEl of slotsForName) {\n assigned.push(...slotEl.assignedElements({ flatten: true }));\n }\n }\n\n ensureElementSignal(normalized).value = assigned;\n ensurePresenceSignal(normalized).value = assigned.length > 0;\n };\n\n const bindSlot = (slotEl: HTMLSlotElement): void => {\n if (slotCleanupMap.has(slotEl)) return;\n\n const name = normalizeSlotName(slotEl.getAttribute('name'));\n const setForName = slotNodesByName.get(name) ?? new Set<HTMLSlotElement>();\n\n setForName.add(slotEl);\n slotNodesByName.set(name, setForName);\n\n const onChange = () => recomputeSlot(name);\n\n slotEl.addEventListener('slotchange', onChange);\n\n const cleanup = () => {\n slotEl.removeEventListener('slotchange', onChange);\n slotCleanupMap.delete(slotEl);\n\n if (isDisposing) return;\n\n const currentSet = slotNodesByName.get(name);\n\n if (!currentSet) return;\n\n currentSet.delete(slotEl);\n\n if (currentSet.size === 0) {\n slotNodesByName.delete(name);\n }\n\n recomputeSlot(name);\n };\n\n slotCleanupMap.set(slotEl, cleanup);\n\n recomputeSlot(name);\n };\n\n const unbindSlot = (slotEl: HTMLSlotElement): void => {\n slotCleanupMap.get(slotEl)?.();\n };\n\n const bindAllSlots = (): void => {\n host.shadowRoot?.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n };\n\n ensurePresenceSignal(SLOT_DEFAULT);\n ensureElementSignal(SLOT_DEFAULT);\n\n bindAllSlots();\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n mutation.addedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n bindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n }\n });\n\n mutation.removedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n unbindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => unbindSlot(slotEl));\n }\n });\n }\n });\n\n if (host.shadowRoot) {\n observer.observe(host.shadowRoot, { childList: true, subtree: true });\n }\n\n onCleanup(() => {\n isDisposing = true;\n observer.disconnect();\n\n for (const cleanup of [...slotCleanupMap.values()]) cleanup();\n\n slotCleanupMap.clear();\n slotNodesByName.clear();\n });\n\n const slots: ComponentSlots = {\n elements: (name?: string) => ensureElementSignal(normalizeSlotName(name)),\n has: (name?: string) => ensurePresenceSignal(normalizeSlotName(name)),\n };\n\n slotsRegistry.set(host, slots);\n\n return slots;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REFLECT API (HOST ATTRIBUTE/EVENT/CLASS BINDING)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => Record<string, boolean>)\n | (() => string | number | boolean | null | undefined)\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\nexport type HostBindConfig<CustomEvents extends Record<string, unknown> = Record<string, never>> =\n | { attr: ReflectConfig }\n | { class: () => Record<string, boolean> }\n | { on: HostEventListeners<CustomEvents> };\n\nexport type HostBindTarget = 'attr' | 'class' | 'on';\n\nexport type ComponentHost = {\n bind: {\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n config: HostBindConfig<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'attr',\n config: ReflectConfig,\n ): () => void;\n (target: 'class', getter: () => Record<string, boolean>): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'on',\n hostEvents: HostEventListeners<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n };\n el: HTMLElement;\n shadowRoot: ShadowRoot;\n};\n\nexport const createHost = (): ComponentHost => {\n const el = currentRuntime().el;\n\n return {\n bind: (\n targetOrConfig: HostBindTarget | HostBindConfig,\n configOrOptions?: ReflectConfig | (() => Record<string, boolean>) | HostEventListeners | AddEventListenerOptions,\n maybeOptions?: AddEventListenerOptions,\n ) => {\n const disposers: Array<() => void> = [];\n\n const config =\n typeof targetOrConfig === 'string'\n ? ({ [targetOrConfig]: configOrOptions } as HostBindConfig)\n : (targetOrConfig as HostBindConfig);\n const options =\n typeof targetOrConfig === 'string' && targetOrConfig === 'on'\n ? (maybeOptions as AddEventListenerOptions | undefined)\n : (configOrOptions as AddEventListenerOptions | undefined);\n\n if ('attr' in config) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name =\n key.startsWith('aria-') || key === 'role'\n ? key\n : key.startsWith('aria')\n ? `aria-${key.slice(4).toLowerCase()}`\n : key;\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if ('class' in config) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if ('on' in config) {\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, options));\n }\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n onCleanup(cleanup);\n\n return cleanup;\n },\n el,\n shadowRoot: el.shadowRoot as ShadowRoot,\n };\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n if (typeof value === 'function') {\n return effect(() => setAttr(host, name, (value as () => HostBindingValue)()));\n } else {\n setAttr(host, name, value);\n }\n}\n\nfunction applyClassMap(host: HTMLElement, getter: () => Record<string, boolean>): () => void {\n let prev = new Set<string>();\n\n return effect(() => {\n const next = new Set(\n Object.entries(getter())\n .filter(([, active]) => active)\n .map(([cls]) => cls),\n );\n\n for (const cls of prev) if (!next.has(cls)) host.classList.remove(cls);\n for (const cls of next) if (!prev.has(cls)) host.classList.add(cls);\n\n prev = next;\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"host.cjs","names":[],"sources":["../src/host.ts"],"sourcesContent":["/**\n * Host utilities — component context injection, slot observation, and attribute/class reflection.\n *\n * - Context API (provide, inject, createContext)\n * - Slot observation and detection (setup slots)\n * - Host element binding (reflect) for attributes, classes, and host listeners\n */\n\nimport { effect as rawEffect, type ReadonlySignal, type Signal, isSignal, signal } from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { listen, setAttr, toKebab } from './internal';\nimport { currentElementOrThrow, effect, onCleanup, onMounted, tryRegisterCleanup } from './runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// CONTEXT API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown>, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __craftit_injection_key?: T;\n};\n\nexport const provide = <T>(key: InjectionKey<T>, value: T): void => {\n const el = currentElementOrThrow();\n\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(key, value);\n};\n\nexport function inject<T>(key: InjectionKey<T>): T | undefined;\nexport function inject<T>(key: InjectionKey<T>, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T>, ...rest: [T?]): T | undefined {\n let node: Node | null = currentElementOrThrow();\n\n while (node) {\n if (node instanceof HTMLElement) {\n const v = contextRegistry.get(node)?.get(key);\n\n if (v !== undefined) return v as T;\n }\n\n const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return rest.length > 0 ? rest[0] : undefined;\n}\n\nexport const injectStrict = <T>(key: InjectionKey<T>): T => {\n const resolved = inject<T>(key);\n\n if (resolved !== undefined) return resolved;\n\n const host = currentElementOrThrow();\n\n throw new Error(CRAFTIT_ERRORS.injectStrictFailed(String(key), host.localName));\n};\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ARIA SYNC\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AriaValue = string | number | boolean | null | undefined | (() => string | number | boolean | null | undefined);\n\ntype AriaConfig = Record<string, AriaValue>;\n\ntype SyncAriaOptions = {\n autoCleanup?: boolean;\n};\n\nconst toAriaAttr = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : `aria-${key}`;\n};\n\nconst toHostAttr = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : key;\n};\n\nconst setA11yAttr = (target: Element, key: string, value: string | number | boolean | null | undefined): void => {\n if (value == null || value === false) {\n target.removeAttribute(key);\n\n return;\n }\n\n target.setAttribute(key, value === true ? 'true' : String(value));\n};\n\n/**\n * Reactively syncs ARIA attributes to a target element.\n * Static values are set immediately; getter functions are tracked as effects.\n * Returns a cleanup function that removes all reactive bindings.\n *\n * @example\n * syncAria(element, {\n * role: 'button',\n * expanded: () => isOpen.value,\n * disabled: () => isDisabled.value,\n * });\n */\nexport const syncAria = (target: Element, config: AriaConfig, options: SyncAriaOptions = {}): (() => void) => {\n const { autoCleanup = true } = options;\n const disposers: Array<() => void> = [];\n\n for (const [rawKey, rawValue] of Object.entries(config)) {\n const key = toAriaAttr(rawKey);\n\n if (typeof rawValue === 'function') {\n const getter = rawValue as () => string | number | boolean | null | undefined;\n\n disposers.push(\n rawEffect(() => {\n setA11yAttr(target, key, getter());\n }),\n );\n\n continue;\n }\n\n setA11yAttr(target, key, rawValue as string | number | boolean | null | undefined);\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n if (autoCleanup) tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SLOTS API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SLOT_DEFAULT = 'default';\nconst normalizeSlotName = (slotName: string | null | undefined): string => slotName || SLOT_DEFAULT;\n\nexport type ComponentSlots = {\n elements: (name?: string) => ReadonlySignal<Element[]>;\n has: (name?: string) => ReadonlySignal<boolean>;\n};\n\n/**\n * Creates first-class slot signals for setup context.\n *\n * - `slots.has(name?)`: whether a slot has assigned elements\n * - `slots.elements(name?)`: assigned elements for a slot (flattened)\n */\nexport const createSlots = (): ComponentSlots => {\n const host = currentElementOrThrow();\n\n type SlotEntry = {\n elements: Signal<Element[]>;\n presence: Signal<boolean>;\n };\n\n const slotSignals = new Map<string, SlotEntry>();\n const slotNodesByName = new Map<string, Set<HTMLSlotElement>>();\n const slotCleanupMap = new Map<HTMLSlotElement, () => void>();\n\n const ensureSlotEntry = (normalizedName: string): SlotEntry => {\n let entry = slotSignals.get(normalizedName);\n\n if (!entry) {\n entry = {\n elements: signal<Element[]>([]),\n presence: signal(false),\n };\n slotSignals.set(normalizedName, entry);\n }\n\n return entry;\n };\n\n const areElementsEqual = (prev: Element[], next: Element[]): boolean => {\n if (prev.length !== next.length) return false;\n\n for (let i = 0; i < prev.length; i++) {\n if (prev[i] !== next[i]) return false;\n }\n\n return true;\n };\n\n const recomputeSlot = (name: string): void => {\n const normalized = normalizeSlotName(name);\n const slotsForName = slotNodesByName.get(normalized);\n const assigned: Element[] = [];\n\n if (slotsForName) {\n for (const slotEl of slotsForName) {\n assigned.push(...slotEl.assignedElements({ flatten: true }));\n }\n }\n\n const entry = ensureSlotEntry(normalized);\n\n if (!areElementsEqual(entry.elements.value, assigned)) entry.elements.value = assigned;\n\n const hasElements = assigned.length > 0;\n\n if (entry.presence.value !== hasElements) entry.presence.value = hasElements;\n };\n\n const bindSlot = (slotEl: HTMLSlotElement): void => {\n if (slotCleanupMap.has(slotEl)) return;\n\n const name = normalizeSlotName(slotEl.getAttribute('name'));\n const setForName = slotNodesByName.get(name) ?? new Set<HTMLSlotElement>();\n\n setForName.add(slotEl);\n slotNodesByName.set(name, setForName);\n\n const onChange = () => recomputeSlot(name);\n\n slotEl.addEventListener('slotchange', onChange);\n\n slotCleanupMap.set(slotEl, () => {\n slotEl.removeEventListener('slotchange', onChange);\n });\n\n recomputeSlot(name);\n };\n\n const bindAllSlots = (): void => {\n host.shadowRoot?.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n };\n\n const recomputeAllSlots = (): void => {\n for (const name of slotNodesByName.keys()) {\n recomputeSlot(name);\n }\n };\n\n // setup() runs before the template is rendered, so bind once now (if any slots\n // already exist) and schedule another pass after first render.\n bindAllSlots();\n onMounted(() => {\n bindAllSlots();\n recomputeAllSlots();\n });\n\n onCleanup(() => {\n for (const cleanup of slotCleanupMap.values()) cleanup();\n\n slotCleanupMap.clear();\n slotNodesByName.clear();\n });\n\n return {\n elements: (name?: string) => ensureSlotEntry(normalizeSlotName(name)).elements,\n has: (name?: string) => ensureSlotEntry(normalizeSlotName(name)).presence,\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REFLECT API (HOST ATTRIBUTE/EVENT/CLASS BINDING)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => string | number | boolean | null | undefined)\n | ReadonlySignal<string | number | boolean | null | undefined>\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\n/**\n * Describes a reactive property accessor binding on the host element.\n * The getter is called lazily; the optional setter is used when external code\n * assigns `element.propName = value`.\n */\nexport type HostPropDescriptor<T = unknown> = {\n get: () => T;\n set?: (value: T) => void;\n};\n\ntype HostClassBindingValue = ReadonlySignal<boolean> | (() => boolean) | boolean;\ntype HostEventListener = (event: any) => void;\n\nexport type HostBindConfig = {\n attr?: ReflectConfig;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n prop?: Record<string, HostPropDescriptor>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type ComponentHost = {\n bind: (config: HostBindConfig, options?: AddEventListenerOptions) => () => void;\n el: HTMLElement;\n};\n\nexport const createHost = (): ComponentHost => {\n const el = currentElementOrThrow();\n\n const bind = (config: HostBindConfig, options?: AddEventListenerOptions): (() => void) => {\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.prop) {\n for (const [key, descriptor] of Object.entries(config.prop)) {\n const { get, set } = descriptor;\n\n Object.defineProperty(el, key, {\n configurable: true,\n enumerable: true,\n get,\n ...(set ? { set } : {}),\n });\n\n disposers.push(() => {\n const descriptor = Object.getOwnPropertyDescriptor(el, key);\n\n if (!descriptor || descriptor.get !== get || descriptor.set !== set) return;\n\n delete (el as unknown as Record<string, unknown>)[key];\n });\n }\n }\n\n if (config.on) {\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, options));\n }\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n onCleanup(cleanup);\n\n return cleanup;\n };\n\n return {\n bind,\n el,\n };\n};\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | void => {\n if (typeof value === 'function') {\n return effect(() => updater(value()));\n }\n\n if (isSignal(value)) {\n return effect(() => updater(value.value));\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n // Normalize camelCase property names to kebab-case for CSS setProperty.\n // CSS custom properties (--foo) are already kebab-case, so leave them as-is.\n const cssName = name.startsWith('--') ? name : toKebab(name);\n\n // Track whether this binding has ever written a value to the inline style.\n // This prevents removeProperty() from wiping an external inline style that\n // the component never set (e.g. user-authored style=\"grid-area: main;\").\n let owned = false;\n\n const setStyle = (v: any) => {\n if (v != null && v !== '') {\n owned = true;\n host.style.setProperty(cssName, String(v));\n } else if (owned) {\n host.style.removeProperty(cssName);\n }\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => {\n const result: Record<string, boolean> = {};\n\n for (const [cls, entry] of Object.entries(value)) {\n result[cls] = typeof entry === 'function' ? entry() : isSignal(entry) ? entry.value : Boolean(entry);\n }\n\n return result;\n };\n\n let prev = new Set<string>();\n\n return effect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n\n prev = next;\n });\n}\n"],"mappings":"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"}
package/dist/host.d.ts CHANGED
@@ -1,39 +1,37 @@
1
1
  /**
2
2
  * Host utilities — component context injection, slot observation, and attribute/class reflection.
3
3
  *
4
- * - Context API (provide, inject, createContext, syncContextProps)
4
+ * - Context API (provide, inject, createContext)
5
5
  * - Slot observation and detection (setup slots)
6
6
  * - Host element binding (reflect) for attributes, classes, and host listeners
7
7
  */
8
- import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
9
- import { type HostEventListeners } from './runtime-lifecycle';
8
+ import { type ReadonlySignal } from '@vielzeug/stateit';
10
9
  export type InjectionKey<T> = symbol & {
11
10
  readonly __craftit_injection_key?: T;
12
11
  };
13
- export declare const provide: <T>(key: InjectionKey<T> | string | symbol, value: T) => void;
14
- export declare function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;
15
- export declare function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;
12
+ export declare const provide: <T>(key: InjectionKey<T>, value: T) => void;
13
+ export declare function inject<T>(key: InjectionKey<T>): T | undefined;
14
+ export declare function inject<T>(key: InjectionKey<T>, fallback: T): T;
15
+ export declare const injectStrict: <T>(key: InjectionKey<T>) => T;
16
16
  export declare function createContext<T>(description?: string): InjectionKey<T>;
17
+ type AriaValue = string | number | boolean | null | undefined | (() => string | number | boolean | null | undefined);
18
+ type AriaConfig = Record<string, AriaValue>;
19
+ type SyncAriaOptions = {
20
+ autoCleanup?: boolean;
21
+ };
17
22
  /**
18
- * Reactively inherits prop values from a context object provided by an ancestor component.
19
- * For each key, when the context value is not `undefined`, it is written into the matching prop signal.
20
- * The effect is automatically cleaned up when the component unmounts.
21
- *
22
- * Deferred to `onMount` so context values win over HTML attribute values set on the child.
23
+ * Reactively syncs ARIA attributes to a target element.
24
+ * Static values are set immediately; getter functions are tracked as effects.
25
+ * Returns a cleanup function that removes all reactive bindings.
23
26
  *
24
27
  * @example
25
- * syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);
28
+ * syncAria(element, {
29
+ * role: 'button',
30
+ * expanded: () => isOpen.value,
31
+ * disabled: () => isDisabled.value,
32
+ * });
26
33
  */
27
- export declare const syncContextProps: <K extends string, Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>, Props extends Record<K, Signal<unknown>>>(ctx: Ctx | undefined, props: Props, keys: K[]) => void;
28
- export type HostContextAttributeBridge = {
29
- contextDisabled?: ReadonlySignal<boolean | undefined>;
30
- contextSize?: ReadonlySignal<string | undefined>;
31
- contextVariant?: ReadonlySignal<string | undefined>;
32
- ownDisabled?: ReadonlySignal<boolean | undefined>;
33
- ownSize?: ReadonlySignal<string | undefined>;
34
- ownVariant?: ReadonlySignal<string | undefined>;
35
- };
36
- export declare const bridgeContextAttributes: (host: HTMLElement, options: HostContextAttributeBridge) => void;
34
+ export declare const syncAria: (target: Element, config: AriaConfig, options?: SyncAriaOptions) => (() => void);
37
35
  export type ComponentSlots = {
38
36
  elements: (name?: string) => ReadonlySignal<Element[]>;
39
37
  has: (name?: string) => ReadonlySignal<boolean>;
@@ -48,28 +46,33 @@ export declare const createSlots: () => ComponentSlots;
48
46
  /**
49
47
  * Describes a reactive or static host binding value.
50
48
  */
51
- export type HostBindingValue = (() => Record<string, boolean>) | (() => string | number | boolean | null | undefined) | string | number | boolean | null | undefined;
49
+ export type HostBindingValue = (() => string | number | boolean | null | undefined) | ReadonlySignal<string | number | boolean | null | undefined> | string | number | boolean | null | undefined;
52
50
  /**
53
51
  * Configuration for host attribute bindings.
54
52
  */
55
53
  export type ReflectConfig = Record<string, HostBindingValue>;
56
- export type HostBindConfig<CustomEvents extends Record<string, unknown> = Record<string, never>> = {
57
- attr: ReflectConfig;
58
- } | {
59
- class: () => Record<string, boolean>;
60
- } | {
61
- on: HostEventListeners<CustomEvents>;
54
+ /**
55
+ * Describes a reactive property accessor binding on the host element.
56
+ * The getter is called lazily; the optional setter is used when external code
57
+ * assigns `element.propName = value`.
58
+ */
59
+ export type HostPropDescriptor<T = unknown> = {
60
+ get: () => T;
61
+ set?: (value: T) => void;
62
+ };
63
+ type HostClassBindingValue = ReadonlySignal<boolean> | (() => boolean) | boolean;
64
+ type HostEventListener = (event: any) => void;
65
+ export type HostBindConfig = {
66
+ attr?: ReflectConfig;
67
+ class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;
68
+ on?: Record<string, HostEventListener | undefined>;
69
+ prop?: Record<string, HostPropDescriptor>;
70
+ style?: Record<string, HostBindingValue>;
62
71
  };
63
- export type HostBindTarget = 'attr' | 'class' | 'on';
64
72
  export type ComponentHost = {
65
- bind: {
66
- <CustomEvents extends Record<string, unknown> = Record<string, never>>(config: HostBindConfig<CustomEvents>, options?: AddEventListenerOptions): () => void;
67
- <CustomEvents extends Record<string, unknown> = Record<string, never>>(target: 'attr', config: ReflectConfig): () => void;
68
- (target: 'class', getter: () => Record<string, boolean>): () => void;
69
- <CustomEvents extends Record<string, unknown> = Record<string, never>>(target: 'on', hostEvents: HostEventListeners<CustomEvents>, options?: AddEventListenerOptions): () => void;
70
- };
73
+ bind: (config: HostBindConfig, options?: AddEventListenerOptions) => () => void;
71
74
  el: HTMLElement;
72
- shadowRoot: ShadowRoot;
73
75
  };
74
76
  export declare const createHost: () => ComponentHost;
77
+ export {};
75
78
  //# sourceMappingURL=host.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
package/dist/host.js CHANGED
@@ -1,2 +1,2 @@
1
- import{currentRuntime as e}from"./runtime-core.js";import{effect as t,onCleanup as n,onMount as r}from"./runtime-lifecycle.js";import{listen as i,setAttr as a}from"./internal.js";import{signal as o}from"@vielzeug/stateit";var s=new WeakMap,c=(t,n)=>{let r=e().el;s.has(r)||s.set(r,new Map),s.get(r).set(t,n)};function l(t,...n){let r=e().el;for(;r;){if(r instanceof HTMLElement){let e=s.get(r)?.get(t);if(e!==void 0)return e}let e=r.getRootNode();r=r.parentElement??(e instanceof ShadowRoot?e.host:null)}return n.length>0?n[0]:void 0}function u(e){return Symbol(e)}var d=(e,n,i)=>{e&&r(()=>{t(()=>{let t=n;for(let n of i){let r=e[n]?.value;r!==void 0&&(t[n].value=r)}})})},f=(e,n)=>{let r=!1;t(()=>{let t=!!n.contextDisabled?.value;t&&!r?(e.setAttribute(`disabled`,``),r=!0):!t&&r&&!n.ownDisabled?.value&&(e.removeAttribute(`disabled`),r=!1);let i=n.contextSize?.value,a=!!n.ownSize?.value;i&&!a?e.setAttribute(`size`,i):a||e.removeAttribute(`size`);let o=n.contextVariant?.value,s=!!n.ownVariant?.value;o&&!s?e.setAttribute(`variant`,o):s||e.removeAttribute(`variant`)})},p=`default`,m=e=>!e||e===p?p:e,h=new WeakMap,g=()=>{let t=e().el,r=h.get(t);if(r)return r;let i=new Map,a=new Map,s=new Map,c=new Map,l=!1,u=e=>{let t=m(e),n=i.get(t);return n||(n=o(!1),i.set(t,n)),n},d=e=>{let t=m(e),n=a.get(t);return n||(n=o([]),a.set(t,n)),n},f=e=>{let t=m(e),n=s.get(t),r=[];if(n)for(let e of n)r.push(...e.assignedElements({flatten:!0}));d(t).value=r,u(t).value=r.length>0},g=e=>{if(c.has(e))return;let t=m(e.getAttribute(`name`)),n=s.get(t)??new Set;n.add(e),s.set(t,n);let r=()=>f(t);e.addEventListener(`slotchange`,r),c.set(e,()=>{if(e.removeEventListener(`slotchange`,r),c.delete(e),l)return;let n=s.get(t);n&&(n.delete(e),n.size===0&&s.delete(t),f(t))}),f(t)},_=e=>{c.get(e)?.()};u(p),d(p),t.shadowRoot?.querySelectorAll(`slot`).forEach(e=>g(e));let v=new MutationObserver(e=>{for(let t of e)t.addedNodes.forEach(e=>{if(e instanceof HTMLSlotElement){g(e);return}e instanceof Element&&e.querySelectorAll(`slot`).forEach(e=>g(e))}),t.removedNodes.forEach(e=>{if(e instanceof HTMLSlotElement){_(e);return}e instanceof Element&&e.querySelectorAll(`slot`).forEach(e=>_(e))})});t.shadowRoot&&v.observe(t.shadowRoot,{childList:!0,subtree:!0}),n(()=>{l=!0,v.disconnect();for(let e of[...c.values()])e();c.clear(),s.clear()});let y={elements:e=>d(m(e)),has:e=>u(m(e))};return h.set(t,y),y},_=()=>{let t=e().el;return{bind:(e,r,a)=>{let o=[],s=typeof e==`string`?{[e]:r}:e,c=typeof e==`string`&&e===`on`?a:r;if(`attr`in s)for(let[e,n]of Object.entries(s.attr)){let r=v(t,e.startsWith(`aria-`)||e===`role`?e:e.startsWith(`aria`)?`aria-${e.slice(4).toLowerCase()}`:e,n);r&&o.push(r)}if(`class`in s&&o.push(y(t,s.class)),`on`in s)for(let e of Object.keys(s.on)){let n=s.on[e];n&&o.push(i(t,e,n,c))}let l=()=>{for(;o.length>0;)o.pop()?.()};return n(l),l},el:t,shadowRoot:t.shadowRoot}};function v(e,n,r){if(typeof r==`function`)return t(()=>a(e,n,r()));a(e,n,r)}function y(e,n){let r=new Set;return t(()=>{let t=new Set(Object.entries(n()).filter(([,e])=>e).map(([e])=>e));for(let n of r)t.has(n)||e.classList.remove(n);for(let n of t)r.has(n)||e.classList.add(n);r=t})}export{f as bridgeContextAttributes,u as createContext,_ as createHost,g as createSlots,l as inject,c as provide,d as syncContextProps};
1
+ import{CRAFTIT_ERRORS as e}from"./errors.js";import{currentElementOrThrow as t,effect as n,onCleanup as r,onMounted as i,tryRegisterCleanup as a}from"./runtime.js";import{listen as o,setAttr as s,toKebab as c}from"./internal.js";import{effect as l,isSignal as u,signal as d}from"@vielzeug/stateit";var f=new WeakMap,p=(e,n)=>{let r=t();f.has(r)||f.set(r,new Map),f.get(r).set(e,n)};function m(e,...n){let r=t();for(;r;){if(r instanceof HTMLElement){let t=f.get(r)?.get(e);if(t!==void 0)return t}let t=r.getRootNode();r=r.parentElement??(t instanceof ShadowRoot?t.host:null)}return n.length>0?n[0]:void 0}var h=n=>{let r=m(n);if(r!==void 0)return r;let i=t();throw Error(e.injectStrictFailed(String(n),i.localName))};function g(e){return Symbol(e)}var _=e=>e===`role`||e.startsWith(`aria-`)?e:e.startsWith(`aria`)?`aria-${e.slice(4).toLowerCase()}`:`aria-${e}`,v=e=>e===`role`||e.startsWith(`aria-`)?e:e.startsWith(`aria`)?`aria-${e.slice(4).toLowerCase()}`:e,y=(e,t,n)=>{if(n==null||n===!1){e.removeAttribute(t);return}e.setAttribute(t,n===!0?`true`:String(n))},b=(e,t,n={})=>{let{autoCleanup:r=!0}=n,i=[];for(let[n,r]of Object.entries(t)){let t=_(n);if(typeof r==`function`){let n=r;i.push(l(()=>{y(e,t,n())}));continue}y(e,t,r)}let o=()=>{for(;i.length>0;)i.pop()?.()};return r&&a(o),o},x=`default`,S=e=>e||x,C=()=>{let e=t(),n=new Map,a=new Map,o=new Map,s=e=>{let t=n.get(e);return t||(t={elements:d([]),presence:d(!1)},n.set(e,t)),t},c=(e,t)=>{if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0},l=e=>{let t=S(e),n=a.get(t),r=[];if(n)for(let e of n)r.push(...e.assignedElements({flatten:!0}));let i=s(t);c(i.elements.value,r)||(i.elements.value=r);let o=r.length>0;i.presence.value!==o&&(i.presence.value=o)},u=e=>{if(o.has(e))return;let t=S(e.getAttribute(`name`)),n=a.get(t)??new Set;n.add(e),a.set(t,n);let r=()=>l(t);e.addEventListener(`slotchange`,r),o.set(e,()=>{e.removeEventListener(`slotchange`,r)}),l(t)},f=()=>{e.shadowRoot?.querySelectorAll(`slot`).forEach(e=>u(e))},p=()=>{for(let e of a.keys())l(e)};return f(),i(()=>{f(),p()}),r(()=>{for(let e of o.values())e();o.clear(),a.clear()}),{elements:e=>s(S(e)).elements,has:e=>s(S(e)).presence}},w=()=>{let e=t();return{bind:(t,n)=>{let i=[];if(t.attr)for(let[n,r]of Object.entries(t.attr)){let t=E(e,v(n),r);t&&i.push(t)}if(t.class&&i.push(O(e,t.class)),t.prop)for(let[n,r]of Object.entries(t.prop)){let{get:t,set:a}=r;Object.defineProperty(e,n,{configurable:!0,enumerable:!0,get:t,...a?{set:a}:{}}),i.push(()=>{let r=Object.getOwnPropertyDescriptor(e,n);!r||r.get!==t||r.set!==a||delete e[n]})}if(t.on)for(let r of Object.keys(t.on)){let a=t.on[r];a&&i.push(o(e,r,a,n))}if(t.style)for(let[n,r]of Object.entries(t.style)){let t=D(e,n,r);t&&i.push(t)}let a=()=>{for(;i.length>0;)i.pop()?.()};return r(a),a},el:e}},T=(e,t)=>{if(typeof e==`function`)return n(()=>t(e()));if(u(e))return n(()=>t(e.value));t(e)};function E(e,t,n){return T(n,n=>s(e,t,n))}function D(e,t,n){let r=t.startsWith(`--`)?t:c(t),i=!1;return T(n,t=>{t!=null&&t!==``?(i=!0,e.style.setProperty(r,String(t))):i&&e.style.removeProperty(r)})}function O(e,t){let r=typeof t==`function`?t:()=>{let e={};for(let[n,r]of Object.entries(t))e[n]=typeof r==`function`?r():u(r)?r.value:!!r;return e},i=new Set;return n(()=>{let t=new Set;for(let[n,a]of Object.entries(r()))a&&(t.add(n),i.has(n)||e.classList.add(n));for(let n of i)t.has(n)||e.classList.remove(n);i=t})}export{g as createContext,w as createHost,C as createSlots,m as inject,h as injectStrict,p as provide,b as syncAria};
2
2
  //# sourceMappingURL=host.js.map
package/dist/host.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","names":[],"sources":["../src/host.ts"],"sourcesContent":["/**\n * Host utilities — component context injection, slot observation, and attribute/class reflection.\n *\n * - Context API (provide, inject, createContext, syncContextProps)\n * - Slot observation and detection (setup slots)\n * - Host element binding (reflect) for attributes, classes, and host listeners\n */\n\nimport { type ReadonlySignal, type Signal, signal } from '@vielzeug/stateit';\n\nimport { listen, setAttr } from './internal';\nimport { currentRuntime } from './runtime-core';\nimport { effect, onCleanup, onMount, type HostEventListeners } from './runtime-lifecycle';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// CONTEXT API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown> | string | symbol, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __craftit_injection_key?: T;\n};\n\nexport const provide = <T>(key: InjectionKey<T> | string | symbol, value: T): void => {\n const el = currentRuntime().el;\n\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(key, value);\n};\n\nexport function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, ...rest: [T?]): T | undefined {\n let node: Node | null = currentRuntime().el;\n\n while (node) {\n if (node instanceof HTMLElement) {\n const v = contextRegistry.get(node)?.get(key);\n\n if (v !== undefined) return v as T;\n }\n\n const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return rest.length > 0 ? rest[0] : undefined;\n}\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n\n/**\n * Reactively inherits prop values from a context object provided by an ancestor component.\n * For each key, when the context value is not `undefined`, it is written into the matching prop signal.\n * The effect is automatically cleaned up when the component unmounts.\n *\n * Deferred to `onMount` so context values win over HTML attribute values set on the child.\n *\n * @example\n * syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);\n */\nexport const syncContextProps = <\n K extends string,\n Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>,\n Props extends Record<K, Signal<unknown>>,\n>(\n ctx: Ctx | undefined,\n props: Props,\n keys: K[],\n): void => {\n if (!ctx) return;\n\n onMount(() => {\n effect(() => {\n const target = props as Record<K, Signal<unknown>>;\n\n for (const k of keys) {\n const v = ctx[k]?.value;\n\n if (v !== undefined) target[k].value = v;\n }\n });\n });\n};\n\nexport type HostContextAttributeBridge = {\n contextDisabled?: ReadonlySignal<boolean | undefined>;\n contextSize?: ReadonlySignal<string | undefined>;\n contextVariant?: ReadonlySignal<string | undefined>;\n ownDisabled?: ReadonlySignal<boolean | undefined>;\n ownSize?: ReadonlySignal<string | undefined>;\n ownVariant?: ReadonlySignal<string | undefined>;\n};\n\nexport const bridgeContextAttributes = (host: HTMLElement, options: HostContextAttributeBridge): void => {\n let contextDisabledActive = false;\n\n effect(() => {\n const contextDisabled = Boolean(options.contextDisabled?.value);\n\n if (contextDisabled && !contextDisabledActive) {\n host.setAttribute('disabled', '');\n contextDisabledActive = true;\n } else if (!contextDisabled && contextDisabledActive && !options.ownDisabled?.value) {\n host.removeAttribute('disabled');\n contextDisabledActive = false;\n }\n\n const contextSize = options.contextSize?.value;\n const hasOwnSize = Boolean(options.ownSize?.value);\n\n if (contextSize && !hasOwnSize) host.setAttribute('size', contextSize);\n else if (!hasOwnSize) host.removeAttribute('size');\n\n const contextVariant = options.contextVariant?.value;\n const hasOwnVariant = Boolean(options.ownVariant?.value);\n\n if (contextVariant && !hasOwnVariant) host.setAttribute('variant', contextVariant);\n else if (!hasOwnVariant) host.removeAttribute('variant');\n });\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SLOTS API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SLOT_DEFAULT = 'default';\nconst normalizeSlotName = (slotName: string | null | undefined): string => {\n if (!slotName || slotName === SLOT_DEFAULT) return SLOT_DEFAULT;\n\n return slotName;\n};\n\nconst slotsRegistry = new WeakMap<HTMLElement, ComponentSlots>();\n\nexport type ComponentSlots = {\n elements: (name?: string) => ReadonlySignal<Element[]>;\n has: (name?: string) => ReadonlySignal<boolean>;\n};\n\n/**\n * Creates first-class slot signals for setup context.\n *\n * - `slots.has(name?)`: whether a slot has assigned elements\n * - `slots.elements(name?)`: assigned elements for a slot (flattened)\n */\nexport const createSlots = (): ComponentSlots => {\n const host = currentRuntime().el;\n const cached = slotsRegistry.get(host);\n\n if (cached) return cached;\n\n const presenceSignals = new Map<string, Signal<boolean>>();\n const elementSignals = new Map<string, Signal<Element[]>>();\n const slotNodesByName = new Map<string, Set<HTMLSlotElement>>();\n const slotCleanupMap = new Map<HTMLSlotElement, () => void>();\n let isDisposing = false;\n\n const ensurePresenceSignal = (name: string): Signal<boolean> => {\n const normalized = normalizeSlotName(name);\n let s = presenceSignals.get(normalized);\n\n if (!s) {\n s = signal(false);\n presenceSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const ensureElementSignal = (name: string): Signal<Element[]> => {\n const normalized = normalizeSlotName(name);\n let s = elementSignals.get(normalized);\n\n if (!s) {\n s = signal<Element[]>([]);\n elementSignals.set(normalized, s);\n }\n\n return s;\n };\n\n const recomputeSlot = (name: string): void => {\n const normalized = normalizeSlotName(name);\n const slotsForName = slotNodesByName.get(normalized);\n const assigned: Element[] = [];\n\n if (slotsForName) {\n for (const slotEl of slotsForName) {\n assigned.push(...slotEl.assignedElements({ flatten: true }));\n }\n }\n\n ensureElementSignal(normalized).value = assigned;\n ensurePresenceSignal(normalized).value = assigned.length > 0;\n };\n\n const bindSlot = (slotEl: HTMLSlotElement): void => {\n if (slotCleanupMap.has(slotEl)) return;\n\n const name = normalizeSlotName(slotEl.getAttribute('name'));\n const setForName = slotNodesByName.get(name) ?? new Set<HTMLSlotElement>();\n\n setForName.add(slotEl);\n slotNodesByName.set(name, setForName);\n\n const onChange = () => recomputeSlot(name);\n\n slotEl.addEventListener('slotchange', onChange);\n\n const cleanup = () => {\n slotEl.removeEventListener('slotchange', onChange);\n slotCleanupMap.delete(slotEl);\n\n if (isDisposing) return;\n\n const currentSet = slotNodesByName.get(name);\n\n if (!currentSet) return;\n\n currentSet.delete(slotEl);\n\n if (currentSet.size === 0) {\n slotNodesByName.delete(name);\n }\n\n recomputeSlot(name);\n };\n\n slotCleanupMap.set(slotEl, cleanup);\n\n recomputeSlot(name);\n };\n\n const unbindSlot = (slotEl: HTMLSlotElement): void => {\n slotCleanupMap.get(slotEl)?.();\n };\n\n const bindAllSlots = (): void => {\n host.shadowRoot?.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n };\n\n ensurePresenceSignal(SLOT_DEFAULT);\n ensureElementSignal(SLOT_DEFAULT);\n\n bindAllSlots();\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n mutation.addedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n bindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n }\n });\n\n mutation.removedNodes.forEach((node) => {\n if (node instanceof HTMLSlotElement) {\n unbindSlot(node);\n\n return;\n }\n\n if (node instanceof Element) {\n node.querySelectorAll('slot').forEach((slotEl) => unbindSlot(slotEl));\n }\n });\n }\n });\n\n if (host.shadowRoot) {\n observer.observe(host.shadowRoot, { childList: true, subtree: true });\n }\n\n onCleanup(() => {\n isDisposing = true;\n observer.disconnect();\n\n for (const cleanup of [...slotCleanupMap.values()]) cleanup();\n\n slotCleanupMap.clear();\n slotNodesByName.clear();\n });\n\n const slots: ComponentSlots = {\n elements: (name?: string) => ensureElementSignal(normalizeSlotName(name)),\n has: (name?: string) => ensurePresenceSignal(normalizeSlotName(name)),\n };\n\n slotsRegistry.set(host, slots);\n\n return slots;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REFLECT API (HOST ATTRIBUTE/EVENT/CLASS BINDING)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => Record<string, boolean>)\n | (() => string | number | boolean | null | undefined)\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\nexport type HostBindConfig<CustomEvents extends Record<string, unknown> = Record<string, never>> =\n | { attr: ReflectConfig }\n | { class: () => Record<string, boolean> }\n | { on: HostEventListeners<CustomEvents> };\n\nexport type HostBindTarget = 'attr' | 'class' | 'on';\n\nexport type ComponentHost = {\n bind: {\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n config: HostBindConfig<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'attr',\n config: ReflectConfig,\n ): () => void;\n (target: 'class', getter: () => Record<string, boolean>): () => void;\n <CustomEvents extends Record<string, unknown> = Record<string, never>>(\n target: 'on',\n hostEvents: HostEventListeners<CustomEvents>,\n options?: AddEventListenerOptions,\n ): () => void;\n };\n el: HTMLElement;\n shadowRoot: ShadowRoot;\n};\n\nexport const createHost = (): ComponentHost => {\n const el = currentRuntime().el;\n\n return {\n bind: (\n targetOrConfig: HostBindTarget | HostBindConfig,\n configOrOptions?: ReflectConfig | (() => Record<string, boolean>) | HostEventListeners | AddEventListenerOptions,\n maybeOptions?: AddEventListenerOptions,\n ) => {\n const disposers: Array<() => void> = [];\n\n const config =\n typeof targetOrConfig === 'string'\n ? ({ [targetOrConfig]: configOrOptions } as HostBindConfig)\n : (targetOrConfig as HostBindConfig);\n const options =\n typeof targetOrConfig === 'string' && targetOrConfig === 'on'\n ? (maybeOptions as AddEventListenerOptions | undefined)\n : (configOrOptions as AddEventListenerOptions | undefined);\n\n if ('attr' in config) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name =\n key.startsWith('aria-') || key === 'role'\n ? key\n : key.startsWith('aria')\n ? `aria-${key.slice(4).toLowerCase()}`\n : key;\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if ('class' in config) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if ('on' in config) {\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, options));\n }\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n onCleanup(cleanup);\n\n return cleanup;\n },\n el,\n shadowRoot: el.shadowRoot as ShadowRoot,\n };\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n if (typeof value === 'function') {\n return effect(() => setAttr(host, name, (value as () => HostBindingValue)()));\n } else {\n setAttr(host, name, value);\n }\n}\n\nfunction applyClassMap(host: HTMLElement, getter: () => Record<string, boolean>): () => void {\n let prev = new Set<string>();\n\n return effect(() => {\n const next = new Set(\n Object.entries(getter())\n .filter(([, active]) => active)\n .map(([cls]) => cls),\n );\n\n for (const cls of prev) if (!next.has(cls)) host.classList.remove(cls);\n for (const cls of next) if (!prev.has(cls)) host.classList.add(cls);\n\n prev = next;\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"host.js","names":[],"sources":["../src/host.ts"],"sourcesContent":["/**\n * Host utilities — component context injection, slot observation, and attribute/class reflection.\n *\n * - Context API (provide, inject, createContext)\n * - Slot observation and detection (setup slots)\n * - Host element binding (reflect) for attributes, classes, and host listeners\n */\n\nimport { effect as rawEffect, type ReadonlySignal, type Signal, isSignal, signal } from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { listen, setAttr, toKebab } from './internal';\nimport { currentElementOrThrow, effect, onCleanup, onMounted, tryRegisterCleanup } from './runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// CONTEXT API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown>, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __craftit_injection_key?: T;\n};\n\nexport const provide = <T>(key: InjectionKey<T>, value: T): void => {\n const el = currentElementOrThrow();\n\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(key, value);\n};\n\nexport function inject<T>(key: InjectionKey<T>): T | undefined;\nexport function inject<T>(key: InjectionKey<T>, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T>, ...rest: [T?]): T | undefined {\n let node: Node | null = currentElementOrThrow();\n\n while (node) {\n if (node instanceof HTMLElement) {\n const v = contextRegistry.get(node)?.get(key);\n\n if (v !== undefined) return v as T;\n }\n\n const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return rest.length > 0 ? rest[0] : undefined;\n}\n\nexport const injectStrict = <T>(key: InjectionKey<T>): T => {\n const resolved = inject<T>(key);\n\n if (resolved !== undefined) return resolved;\n\n const host = currentElementOrThrow();\n\n throw new Error(CRAFTIT_ERRORS.injectStrictFailed(String(key), host.localName));\n};\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ARIA SYNC\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AriaValue = string | number | boolean | null | undefined | (() => string | number | boolean | null | undefined);\n\ntype AriaConfig = Record<string, AriaValue>;\n\ntype SyncAriaOptions = {\n autoCleanup?: boolean;\n};\n\nconst toAriaAttr = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : `aria-${key}`;\n};\n\nconst toHostAttr = (key: string): string => {\n if (key === 'role' || key.startsWith('aria-')) return key;\n\n return key.startsWith('aria') ? `aria-${key.slice(4).toLowerCase()}` : key;\n};\n\nconst setA11yAttr = (target: Element, key: string, value: string | number | boolean | null | undefined): void => {\n if (value == null || value === false) {\n target.removeAttribute(key);\n\n return;\n }\n\n target.setAttribute(key, value === true ? 'true' : String(value));\n};\n\n/**\n * Reactively syncs ARIA attributes to a target element.\n * Static values are set immediately; getter functions are tracked as effects.\n * Returns a cleanup function that removes all reactive bindings.\n *\n * @example\n * syncAria(element, {\n * role: 'button',\n * expanded: () => isOpen.value,\n * disabled: () => isDisabled.value,\n * });\n */\nexport const syncAria = (target: Element, config: AriaConfig, options: SyncAriaOptions = {}): (() => void) => {\n const { autoCleanup = true } = options;\n const disposers: Array<() => void> = [];\n\n for (const [rawKey, rawValue] of Object.entries(config)) {\n const key = toAriaAttr(rawKey);\n\n if (typeof rawValue === 'function') {\n const getter = rawValue as () => string | number | boolean | null | undefined;\n\n disposers.push(\n rawEffect(() => {\n setA11yAttr(target, key, getter());\n }),\n );\n\n continue;\n }\n\n setA11yAttr(target, key, rawValue as string | number | boolean | null | undefined);\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n if (autoCleanup) tryRegisterCleanup(cleanup);\n\n return cleanup;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SLOTS API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst SLOT_DEFAULT = 'default';\nconst normalizeSlotName = (slotName: string | null | undefined): string => slotName || SLOT_DEFAULT;\n\nexport type ComponentSlots = {\n elements: (name?: string) => ReadonlySignal<Element[]>;\n has: (name?: string) => ReadonlySignal<boolean>;\n};\n\n/**\n * Creates first-class slot signals for setup context.\n *\n * - `slots.has(name?)`: whether a slot has assigned elements\n * - `slots.elements(name?)`: assigned elements for a slot (flattened)\n */\nexport const createSlots = (): ComponentSlots => {\n const host = currentElementOrThrow();\n\n type SlotEntry = {\n elements: Signal<Element[]>;\n presence: Signal<boolean>;\n };\n\n const slotSignals = new Map<string, SlotEntry>();\n const slotNodesByName = new Map<string, Set<HTMLSlotElement>>();\n const slotCleanupMap = new Map<HTMLSlotElement, () => void>();\n\n const ensureSlotEntry = (normalizedName: string): SlotEntry => {\n let entry = slotSignals.get(normalizedName);\n\n if (!entry) {\n entry = {\n elements: signal<Element[]>([]),\n presence: signal(false),\n };\n slotSignals.set(normalizedName, entry);\n }\n\n return entry;\n };\n\n const areElementsEqual = (prev: Element[], next: Element[]): boolean => {\n if (prev.length !== next.length) return false;\n\n for (let i = 0; i < prev.length; i++) {\n if (prev[i] !== next[i]) return false;\n }\n\n return true;\n };\n\n const recomputeSlot = (name: string): void => {\n const normalized = normalizeSlotName(name);\n const slotsForName = slotNodesByName.get(normalized);\n const assigned: Element[] = [];\n\n if (slotsForName) {\n for (const slotEl of slotsForName) {\n assigned.push(...slotEl.assignedElements({ flatten: true }));\n }\n }\n\n const entry = ensureSlotEntry(normalized);\n\n if (!areElementsEqual(entry.elements.value, assigned)) entry.elements.value = assigned;\n\n const hasElements = assigned.length > 0;\n\n if (entry.presence.value !== hasElements) entry.presence.value = hasElements;\n };\n\n const bindSlot = (slotEl: HTMLSlotElement): void => {\n if (slotCleanupMap.has(slotEl)) return;\n\n const name = normalizeSlotName(slotEl.getAttribute('name'));\n const setForName = slotNodesByName.get(name) ?? new Set<HTMLSlotElement>();\n\n setForName.add(slotEl);\n slotNodesByName.set(name, setForName);\n\n const onChange = () => recomputeSlot(name);\n\n slotEl.addEventListener('slotchange', onChange);\n\n slotCleanupMap.set(slotEl, () => {\n slotEl.removeEventListener('slotchange', onChange);\n });\n\n recomputeSlot(name);\n };\n\n const bindAllSlots = (): void => {\n host.shadowRoot?.querySelectorAll('slot').forEach((slotEl) => bindSlot(slotEl));\n };\n\n const recomputeAllSlots = (): void => {\n for (const name of slotNodesByName.keys()) {\n recomputeSlot(name);\n }\n };\n\n // setup() runs before the template is rendered, so bind once now (if any slots\n // already exist) and schedule another pass after first render.\n bindAllSlots();\n onMounted(() => {\n bindAllSlots();\n recomputeAllSlots();\n });\n\n onCleanup(() => {\n for (const cleanup of slotCleanupMap.values()) cleanup();\n\n slotCleanupMap.clear();\n slotNodesByName.clear();\n });\n\n return {\n elements: (name?: string) => ensureSlotEntry(normalizeSlotName(name)).elements,\n has: (name?: string) => ensureSlotEntry(normalizeSlotName(name)).presence,\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REFLECT API (HOST ATTRIBUTE/EVENT/CLASS BINDING)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Describes a reactive or static host binding value.\n */\nexport type HostBindingValue =\n | (() => string | number | boolean | null | undefined)\n | ReadonlySignal<string | number | boolean | null | undefined>\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for host attribute bindings.\n */\nexport type ReflectConfig = Record<string, HostBindingValue>;\n\n/**\n * Describes a reactive property accessor binding on the host element.\n * The getter is called lazily; the optional setter is used when external code\n * assigns `element.propName = value`.\n */\nexport type HostPropDescriptor<T = unknown> = {\n get: () => T;\n set?: (value: T) => void;\n};\n\ntype HostClassBindingValue = ReadonlySignal<boolean> | (() => boolean) | boolean;\ntype HostEventListener = (event: any) => void;\n\nexport type HostBindConfig = {\n attr?: ReflectConfig;\n class?: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>;\n on?: Record<string, HostEventListener | undefined>;\n prop?: Record<string, HostPropDescriptor>;\n style?: Record<string, HostBindingValue>;\n};\n\nexport type ComponentHost = {\n bind: (config: HostBindConfig, options?: AddEventListenerOptions) => () => void;\n el: HTMLElement;\n};\n\nexport const createHost = (): ComponentHost => {\n const el = currentElementOrThrow();\n\n const bind = (config: HostBindConfig, options?: AddEventListenerOptions): (() => void) => {\n const disposers: Array<() => void> = [];\n\n if (config.attr) {\n for (const [key, value] of Object.entries(config.attr)) {\n const name = toHostAttr(key);\n const dispose = applyAttribute(el, name, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n if (config.class) {\n disposers.push(applyClassMap(el, config.class));\n }\n\n if (config.prop) {\n for (const [key, descriptor] of Object.entries(config.prop)) {\n const { get, set } = descriptor;\n\n Object.defineProperty(el, key, {\n configurable: true,\n enumerable: true,\n get,\n ...(set ? { set } : {}),\n });\n\n disposers.push(() => {\n const descriptor = Object.getOwnPropertyDescriptor(el, key);\n\n if (!descriptor || descriptor.get !== get || descriptor.set !== set) return;\n\n delete (el as unknown as Record<string, unknown>)[key];\n });\n }\n }\n\n if (config.on) {\n for (const event of Object.keys(config.on) as Array<keyof typeof config.on>) {\n const listener = config.on[event];\n\n if (!listener) continue;\n\n disposers.push(listen(el, event as string, listener as EventListener, options));\n }\n }\n\n if (config.style) {\n for (const [key, value] of Object.entries(config.style)) {\n const dispose = applyStyle(el, key, value);\n\n if (dispose) disposers.push(dispose);\n }\n }\n\n const cleanup = () => {\n while (disposers.length > 0) disposers.pop()?.();\n };\n\n onCleanup(cleanup);\n\n return cleanup;\n };\n\n return {\n bind,\n el,\n };\n};\n\nconst applyReactiveBinding = (\n value: HostBindingValue,\n updater: (next: string | number | boolean | null | undefined) => void,\n): (() => void) | void => {\n if (typeof value === 'function') {\n return effect(() => updater(value()));\n }\n\n if (isSignal(value)) {\n return effect(() => updater(value.value));\n }\n\n updater(value);\n};\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n return applyReactiveBinding(value, (next) => setAttr(host, name, next));\n}\n\nfunction applyStyle(host: HTMLElement, name: string, value: HostBindingValue): (() => void) | void {\n // Normalize camelCase property names to kebab-case for CSS setProperty.\n // CSS custom properties (--foo) are already kebab-case, so leave them as-is.\n const cssName = name.startsWith('--') ? name : toKebab(name);\n\n // Track whether this binding has ever written a value to the inline style.\n // This prevents removeProperty() from wiping an external inline style that\n // the component never set (e.g. user-authored style=\"grid-area: main;\").\n let owned = false;\n\n const setStyle = (v: any) => {\n if (v != null && v !== '') {\n owned = true;\n host.style.setProperty(cssName, String(v));\n } else if (owned) {\n host.style.removeProperty(cssName);\n }\n };\n\n return applyReactiveBinding(value, setStyle);\n}\n\nfunction applyClassMap(\n host: HTMLElement,\n value: (() => Record<string, boolean>) | Record<string, HostClassBindingValue>,\n): () => void {\n const getMap =\n typeof value === 'function'\n ? value\n : (): Record<string, boolean> => {\n const result: Record<string, boolean> = {};\n\n for (const [cls, entry] of Object.entries(value)) {\n result[cls] = typeof entry === 'function' ? entry() : isSignal(entry) ? entry.value : Boolean(entry);\n }\n\n return result;\n };\n\n let prev = new Set<string>();\n\n return effect(() => {\n const next = new Set<string>();\n\n for (const [cls, active] of Object.entries(getMap())) {\n if (!active) continue;\n\n next.add(cls);\n\n if (!prev.has(cls)) host.classList.add(cls);\n }\n\n for (const cls of prev) {\n if (!next.has(cls)) host.classList.remove(cls);\n }\n\n prev = next;\n });\n}\n"],"mappings":"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"}