@vielzeug/craftit 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/README.md +71 -53
  2. package/dist/component.cjs +2 -0
  3. package/dist/component.cjs.map +1 -0
  4. package/dist/component.d.ts +39 -0
  5. package/dist/component.d.ts.map +1 -0
  6. package/dist/component.js +2 -0
  7. package/dist/component.js.map +1 -0
  8. package/dist/controls/a11y-control.cjs +2 -0
  9. package/dist/controls/a11y-control.cjs.map +1 -0
  10. package/dist/controls/a11y-control.d.ts +16 -0
  11. package/dist/controls/a11y-control.d.ts.map +1 -0
  12. package/dist/controls/a11y-control.js +2 -0
  13. package/dist/controls/a11y-control.js.map +1 -0
  14. package/dist/controls/checkable-control.cjs +2 -0
  15. package/dist/controls/checkable-control.cjs.map +1 -0
  16. package/dist/controls/checkable-control.d.ts +15 -0
  17. package/dist/controls/checkable-control.d.ts.map +1 -0
  18. package/dist/controls/checkable-control.js +2 -0
  19. package/dist/controls/checkable-control.js.map +1 -0
  20. package/dist/controls/field-control.cjs +2 -0
  21. package/dist/controls/field-control.cjs.map +1 -0
  22. package/dist/controls/field-control.d.ts +156 -0
  23. package/dist/controls/field-control.d.ts.map +1 -0
  24. package/dist/controls/field-control.js +2 -0
  25. package/dist/controls/field-control.js.map +1 -0
  26. package/dist/controls/index.d.ts +10 -0
  27. package/dist/controls/index.d.ts.map +1 -0
  28. package/dist/controls/internal/control-state.cjs +2 -0
  29. package/dist/controls/internal/control-state.cjs.map +1 -0
  30. package/dist/controls/internal/control-state.d.ts +19 -0
  31. package/dist/controls/internal/control-state.d.ts.map +1 -0
  32. package/dist/controls/internal/control-state.js +2 -0
  33. package/dist/controls/internal/control-state.js.map +1 -0
  34. package/dist/controls/internal/keyboard-utils.cjs +2 -0
  35. package/dist/controls/internal/keyboard-utils.cjs.map +1 -0
  36. package/dist/controls/internal/keyboard-utils.d.ts +7 -0
  37. package/dist/controls/internal/keyboard-utils.d.ts.map +1 -0
  38. package/dist/controls/internal/keyboard-utils.js +2 -0
  39. package/dist/controls/internal/keyboard-utils.js.map +1 -0
  40. package/dist/controls/internal/number-utils.cjs +2 -0
  41. package/dist/controls/internal/number-utils.cjs.map +1 -0
  42. package/dist/controls/internal/number-utils.d.ts +6 -0
  43. package/dist/controls/internal/number-utils.d.ts.map +1 -0
  44. package/dist/controls/internal/number-utils.js +2 -0
  45. package/dist/controls/internal/number-utils.js.map +1 -0
  46. package/dist/controls/internal/validation-utils.cjs +2 -0
  47. package/dist/controls/internal/validation-utils.cjs.map +1 -0
  48. package/dist/controls/internal/validation-utils.d.ts +13 -0
  49. package/dist/controls/internal/validation-utils.d.ts.map +1 -0
  50. package/dist/controls/internal/validation-utils.js +2 -0
  51. package/dist/controls/internal/validation-utils.js.map +1 -0
  52. package/dist/controls/list-control.cjs +2 -0
  53. package/dist/controls/list-control.cjs.map +1 -0
  54. package/dist/controls/list-control.d.ts +21 -0
  55. package/dist/controls/list-control.d.ts.map +1 -0
  56. package/dist/controls/list-control.js +2 -0
  57. package/dist/controls/list-control.js.map +1 -0
  58. package/dist/controls/list-key-control.cjs +2 -0
  59. package/dist/controls/list-key-control.cjs.map +1 -0
  60. package/dist/controls/list-key-control.d.ts +14 -0
  61. package/dist/controls/list-key-control.d.ts.map +1 -0
  62. package/dist/controls/list-key-control.js +2 -0
  63. package/dist/controls/list-key-control.js.map +1 -0
  64. package/dist/controls/overlay-control.cjs +2 -0
  65. package/dist/controls/overlay-control.cjs.map +1 -0
  66. package/dist/controls/overlay-control.d.ts +37 -0
  67. package/dist/controls/overlay-control.d.ts.map +1 -0
  68. package/dist/controls/overlay-control.js +2 -0
  69. package/dist/controls/overlay-control.js.map +1 -0
  70. package/dist/controls/press-control.cjs +2 -0
  71. package/dist/controls/press-control.cjs.map +1 -0
  72. package/dist/controls/press-control.d.ts +12 -0
  73. package/dist/controls/press-control.d.ts.map +1 -0
  74. package/dist/controls/press-control.js +2 -0
  75. package/dist/controls/press-control.js.map +1 -0
  76. package/dist/controls/slider-control.cjs +2 -0
  77. package/dist/controls/slider-control.cjs.map +1 -0
  78. package/dist/controls/slider-control.d.ts +19 -0
  79. package/dist/controls/slider-control.d.ts.map +1 -0
  80. package/dist/controls/slider-control.js +2 -0
  81. package/dist/controls/slider-control.js.map +1 -0
  82. package/dist/controls/spinner-control.cjs +2 -0
  83. package/dist/controls/spinner-control.cjs.map +1 -0
  84. package/dist/controls/spinner-control.d.ts +18 -0
  85. package/dist/controls/spinner-control.d.ts.map +1 -0
  86. package/dist/controls/spinner-control.js +2 -0
  87. package/dist/controls/spinner-control.js.map +1 -0
  88. package/dist/controls.cjs +1 -0
  89. package/dist/controls.js +1 -0
  90. package/dist/craftit.cjs +1 -1
  91. package/dist/craftit.cjs.map +1 -1
  92. package/dist/craftit.js +1 -1
  93. package/dist/craftit.js.map +1 -1
  94. package/dist/directives/attr.cjs +1 -1
  95. package/dist/directives/attr.cjs.map +1 -1
  96. package/dist/directives/attr.d.ts +4 -6
  97. package/dist/directives/attr.d.ts.map +1 -1
  98. package/dist/directives/attr.js +1 -1
  99. package/dist/directives/attr.js.map +1 -1
  100. package/dist/directives/bind.cjs +1 -1
  101. package/dist/directives/bind.cjs.map +1 -1
  102. package/dist/directives/bind.d.ts +20 -12
  103. package/dist/directives/bind.d.ts.map +1 -1
  104. package/dist/directives/bind.js +1 -1
  105. package/dist/directives/bind.js.map +1 -1
  106. package/dist/directives/choose.cjs +1 -1
  107. package/dist/directives/choose.cjs.map +1 -1
  108. package/dist/directives/choose.d.ts +17 -12
  109. package/dist/directives/choose.d.ts.map +1 -1
  110. package/dist/directives/choose.js +1 -1
  111. package/dist/directives/choose.js.map +1 -1
  112. package/dist/directives/each.cjs +1 -1
  113. package/dist/directives/each.cjs.map +1 -1
  114. package/dist/directives/each.d.ts +19 -31
  115. package/dist/directives/each.d.ts.map +1 -1
  116. package/dist/directives/each.js +1 -1
  117. package/dist/directives/each.js.map +1 -1
  118. package/dist/directives/index.d.ts +1 -2
  119. package/dist/directives/index.d.ts.map +1 -1
  120. package/dist/directives/memo.cjs +1 -1
  121. package/dist/directives/memo.cjs.map +1 -1
  122. package/dist/directives/memo.d.ts +8 -4
  123. package/dist/directives/memo.d.ts.map +1 -1
  124. package/dist/directives/memo.js +1 -1
  125. package/dist/directives/memo.js.map +1 -1
  126. package/dist/directives/on.cjs +1 -1
  127. package/dist/directives/on.cjs.map +1 -1
  128. package/dist/directives/on.d.ts +1 -1
  129. package/dist/directives/on.d.ts.map +1 -1
  130. package/dist/directives/on.js +1 -1
  131. package/dist/directives/on.js.map +1 -1
  132. package/dist/directives/raw.cjs +1 -1
  133. package/dist/directives/raw.cjs.map +1 -1
  134. package/dist/directives/raw.d.ts +1 -1
  135. package/dist/directives/raw.d.ts.map +1 -1
  136. package/dist/directives/raw.js +1 -1
  137. package/dist/directives/raw.js.map +1 -1
  138. package/dist/directives/spread.cjs +1 -1
  139. package/dist/directives/spread.cjs.map +1 -1
  140. package/dist/directives/spread.d.ts +1 -1
  141. package/dist/directives/spread.d.ts.map +1 -1
  142. package/dist/directives/spread.js +1 -1
  143. package/dist/directives/spread.js.map +1 -1
  144. package/dist/directives/style.cjs +1 -1
  145. package/dist/directives/style.cjs.map +1 -1
  146. package/dist/directives/style.js +1 -1
  147. package/dist/directives/style.js.map +1 -1
  148. package/dist/directives/until.cjs.map +1 -1
  149. package/dist/directives/until.d.ts +1 -1
  150. package/dist/directives/until.d.ts.map +1 -1
  151. package/dist/directives/until.js.map +1 -1
  152. package/dist/directives/when.cjs +1 -1
  153. package/dist/directives/when.cjs.map +1 -1
  154. package/dist/directives/when.d.ts +11 -5
  155. package/dist/directives/when.d.ts.map +1 -1
  156. package/dist/directives/when.js +1 -1
  157. package/dist/directives/when.js.map +1 -1
  158. package/dist/directives.cjs +1 -0
  159. package/dist/directives.js +1 -0
  160. package/dist/form.cjs +2 -0
  161. package/dist/form.cjs.map +1 -0
  162. package/dist/form.d.ts +29 -0
  163. package/dist/form.d.ts.map +1 -0
  164. package/dist/form.js +2 -0
  165. package/dist/form.js.map +1 -0
  166. package/dist/host.cjs +2 -0
  167. package/dist/host.cjs.map +1 -0
  168. package/dist/host.d.ts +75 -0
  169. package/dist/host.d.ts.map +1 -0
  170. package/dist/host.js +2 -0
  171. package/dist/host.js.map +1 -0
  172. package/dist/index.cjs +1 -1
  173. package/dist/index.d.ts +8 -9
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +1 -1
  176. package/dist/internal.cjs +2 -0
  177. package/dist/internal.cjs.map +1 -0
  178. package/dist/internal.d.ts +171 -0
  179. package/dist/internal.d.ts.map +1 -0
  180. package/dist/internal.js +2 -0
  181. package/dist/internal.js.map +1 -0
  182. package/dist/observers/index.d.ts +4 -0
  183. package/dist/observers/index.d.ts.map +1 -0
  184. package/dist/observers/intersection-observe.cjs +2 -0
  185. package/dist/observers/intersection-observe.cjs.map +1 -0
  186. package/dist/observers/intersection-observe.d.ts +9 -0
  187. package/dist/observers/intersection-observe.d.ts.map +1 -0
  188. package/dist/observers/intersection-observe.js +2 -0
  189. package/dist/observers/intersection-observe.js.map +1 -0
  190. package/dist/observers/media-observe.cjs +2 -0
  191. package/dist/observers/media-observe.cjs.map +1 -0
  192. package/dist/observers/media-observe.d.ts +8 -0
  193. package/dist/observers/media-observe.d.ts.map +1 -0
  194. package/dist/observers/media-observe.js +2 -0
  195. package/dist/observers/media-observe.js.map +1 -0
  196. package/dist/observers/resize-observe.cjs +2 -0
  197. package/dist/observers/resize-observe.cjs.map +1 -0
  198. package/dist/observers/resize-observe.d.ts +11 -0
  199. package/dist/observers/resize-observe.d.ts.map +1 -0
  200. package/dist/observers/resize-observe.js +2 -0
  201. package/dist/observers/resize-observe.js.map +1 -0
  202. package/dist/observers.cjs +1 -0
  203. package/dist/observers.js +1 -0
  204. package/dist/props.cjs +2 -0
  205. package/dist/props.cjs.map +1 -0
  206. package/dist/props.d.ts +52 -0
  207. package/dist/props.d.ts.map +1 -0
  208. package/dist/props.js +2 -0
  209. package/dist/props.js.map +1 -0
  210. package/dist/registration.cjs +2 -0
  211. package/dist/registration.cjs.map +1 -0
  212. package/dist/registration.d.ts +18 -0
  213. package/dist/registration.d.ts.map +1 -0
  214. package/dist/registration.js +2 -0
  215. package/dist/registration.js.map +1 -0
  216. package/dist/runtime-bindings.cjs +2 -0
  217. package/dist/runtime-bindings.cjs.map +1 -0
  218. package/dist/runtime-bindings.d.ts.map +1 -0
  219. package/dist/runtime-bindings.js +2 -0
  220. package/dist/runtime-bindings.js.map +1 -0
  221. package/dist/runtime-core.cjs +2 -0
  222. package/dist/runtime-core.cjs.map +1 -0
  223. package/dist/runtime-core.d.ts +21 -0
  224. package/dist/runtime-core.d.ts.map +1 -0
  225. package/dist/runtime-core.js +2 -0
  226. package/dist/runtime-core.js.map +1 -0
  227. package/dist/runtime-lifecycle.cjs +2 -0
  228. package/dist/runtime-lifecycle.cjs.map +1 -0
  229. package/dist/runtime-lifecycle.d.ts +24 -0
  230. package/dist/runtime-lifecycle.d.ts.map +1 -0
  231. package/dist/runtime-lifecycle.js +2 -0
  232. package/dist/runtime-lifecycle.js.map +1 -0
  233. package/dist/runtime.cjs +2 -0
  234. package/dist/runtime.cjs.map +1 -0
  235. package/dist/runtime.d.ts +21 -0
  236. package/dist/runtime.d.ts.map +1 -0
  237. package/dist/runtime.js +2 -0
  238. package/dist/runtime.js.map +1 -0
  239. package/dist/template-bindings.cjs +2 -0
  240. package/dist/template-bindings.cjs.map +1 -0
  241. package/dist/{core/template-bindings.d.ts → template-bindings.d.ts} +4 -1
  242. package/dist/template-bindings.d.ts.map +1 -0
  243. package/dist/template-bindings.js +2 -0
  244. package/dist/template-bindings.js.map +1 -0
  245. package/dist/template-compiler.cjs +2 -0
  246. package/dist/template-compiler.cjs.map +1 -0
  247. package/dist/{core/template-compiler.d.ts → template-compiler.d.ts} +1 -2
  248. package/dist/template-compiler.d.ts.map +1 -0
  249. package/dist/template-compiler.js +2 -0
  250. package/dist/template-compiler.js.map +1 -0
  251. package/dist/template-dom.cjs +2 -0
  252. package/dist/{core/template-dom.js.map → template-dom.cjs.map} +1 -1
  253. package/dist/template-dom.d.ts.map +1 -0
  254. package/dist/template-dom.js +2 -0
  255. package/dist/template-dom.js.map +1 -0
  256. package/dist/template-html.cjs +2 -0
  257. package/dist/template-html.cjs.map +1 -0
  258. package/dist/{core/template-html.d.ts → template-html.d.ts} +1 -4
  259. package/dist/template-html.d.ts.map +1 -0
  260. package/dist/template-html.js +2 -0
  261. package/dist/template-html.js.map +1 -0
  262. package/dist/template.cjs +2 -0
  263. package/dist/template.cjs.map +1 -0
  264. package/dist/{core/template.d.ts → template.d.ts} +2 -3
  265. package/dist/template.d.ts.map +1 -0
  266. package/dist/template.js +2 -0
  267. package/dist/template.js.map +1 -0
  268. package/dist/testing/index.d.ts +2 -0
  269. package/dist/testing/index.d.ts.map +1 -0
  270. package/dist/testing/testing.cjs +2 -0
  271. package/dist/testing/testing.cjs.map +1 -0
  272. package/dist/{test/test.d.ts → testing/testing.d.ts} +8 -8
  273. package/dist/testing/testing.d.ts.map +1 -0
  274. package/dist/testing/testing.js +2 -0
  275. package/dist/testing/testing.js.map +1 -0
  276. package/dist/testing.cjs +1 -0
  277. package/dist/testing.js +1 -0
  278. package/package.json +19 -14
  279. package/dist/core/component.cjs +0 -2
  280. package/dist/core/component.cjs.map +0 -1
  281. package/dist/core/component.d.ts +0 -172
  282. package/dist/core/component.d.ts.map +0 -1
  283. package/dist/core/component.js +0 -2
  284. package/dist/core/component.js.map +0 -1
  285. package/dist/core/host.cjs +0 -2
  286. package/dist/core/host.cjs.map +0 -1
  287. package/dist/core/host.d.ts +0 -77
  288. package/dist/core/host.d.ts.map +0 -1
  289. package/dist/core/host.js +0 -2
  290. package/dist/core/host.js.map +0 -1
  291. package/dist/core/internal.cjs +0 -2
  292. package/dist/core/internal.cjs.map +0 -1
  293. package/dist/core/internal.d.ts +0 -105
  294. package/dist/core/internal.d.ts.map +0 -1
  295. package/dist/core/internal.js +0 -2
  296. package/dist/core/internal.js.map +0 -1
  297. package/dist/core/runtime-bindings.cjs +0 -2
  298. package/dist/core/runtime-bindings.cjs.map +0 -1
  299. package/dist/core/runtime-bindings.d.ts.map +0 -1
  300. package/dist/core/runtime-bindings.js +0 -2
  301. package/dist/core/runtime-bindings.js.map +0 -1
  302. package/dist/core/runtime-lifecycle.cjs +0 -2
  303. package/dist/core/runtime-lifecycle.cjs.map +0 -1
  304. package/dist/core/runtime-lifecycle.d.ts +0 -116
  305. package/dist/core/runtime-lifecycle.d.ts.map +0 -1
  306. package/dist/core/runtime-lifecycle.js +0 -2
  307. package/dist/core/runtime-lifecycle.js.map +0 -1
  308. package/dist/core/runtime.cjs +0 -1
  309. package/dist/core/runtime.d.ts +0 -3
  310. package/dist/core/runtime.d.ts.map +0 -1
  311. package/dist/core/runtime.js +0 -1
  312. package/dist/core/template-bindings.cjs +0 -2
  313. package/dist/core/template-bindings.cjs.map +0 -1
  314. package/dist/core/template-bindings.d.ts.map +0 -1
  315. package/dist/core/template-bindings.js +0 -2
  316. package/dist/core/template-bindings.js.map +0 -1
  317. package/dist/core/template-compiler.cjs +0 -2
  318. package/dist/core/template-compiler.cjs.map +0 -1
  319. package/dist/core/template-compiler.d.ts.map +0 -1
  320. package/dist/core/template-compiler.js +0 -2
  321. package/dist/core/template-compiler.js.map +0 -1
  322. package/dist/core/template-dom.cjs +0 -2
  323. package/dist/core/template-dom.cjs.map +0 -1
  324. package/dist/core/template-dom.d.ts.map +0 -1
  325. package/dist/core/template-dom.js +0 -2
  326. package/dist/core/template-html.cjs +0 -2
  327. package/dist/core/template-html.cjs.map +0 -1
  328. package/dist/core/template-html.d.ts.map +0 -1
  329. package/dist/core/template-html.js +0 -2
  330. package/dist/core/template-html.js.map +0 -1
  331. package/dist/core/template.cjs +0 -2
  332. package/dist/core/template.cjs.map +0 -1
  333. package/dist/core/template.d.ts.map +0 -1
  334. package/dist/core/template.js +0 -2
  335. package/dist/core/template.js.map +0 -1
  336. package/dist/core/utilities.cjs +0 -2
  337. package/dist/core/utilities.cjs.map +0 -1
  338. package/dist/core/utilities.d.ts +0 -68
  339. package/dist/core/utilities.d.ts.map +0 -1
  340. package/dist/core/utilities.js +0 -2
  341. package/dist/core/utilities.js.map +0 -1
  342. package/dist/directives/index.cjs +0 -1
  343. package/dist/directives/index.js +0 -1
  344. package/dist/directives/match.cjs +0 -2
  345. package/dist/directives/match.cjs.map +0 -1
  346. package/dist/directives/match.d.ts +0 -31
  347. package/dist/directives/match.d.ts.map +0 -1
  348. package/dist/directives/match.js +0 -2
  349. package/dist/directives/match.js.map +0 -1
  350. package/dist/labs/a11y.cjs +0 -2
  351. package/dist/labs/a11y.cjs.map +0 -1
  352. package/dist/labs/a11y.d.ts +0 -61
  353. package/dist/labs/a11y.d.ts.map +0 -1
  354. package/dist/labs/a11y.js +0 -2
  355. package/dist/labs/a11y.js.map +0 -1
  356. package/dist/labs/index.d.ts +0 -8
  357. package/dist/labs/index.d.ts.map +0 -1
  358. package/dist/labs/list.cjs +0 -2
  359. package/dist/labs/list.cjs.map +0 -1
  360. package/dist/labs/list.d.ts +0 -26
  361. package/dist/labs/list.d.ts.map +0 -1
  362. package/dist/labs/list.js +0 -2
  363. package/dist/labs/list.js.map +0 -1
  364. package/dist/labs/observers.cjs +0 -2
  365. package/dist/labs/observers.cjs.map +0 -1
  366. package/dist/labs/observers.d.ts +0 -42
  367. package/dist/labs/observers.d.ts.map +0 -1
  368. package/dist/labs/observers.js +0 -2
  369. package/dist/labs/observers.js.map +0 -1
  370. package/dist/labs/overlay.cjs +0 -2
  371. package/dist/labs/overlay.cjs.map +0 -1
  372. package/dist/labs/overlay.d.ts +0 -35
  373. package/dist/labs/overlay.d.ts.map +0 -1
  374. package/dist/labs/overlay.js +0 -2
  375. package/dist/labs/overlay.js.map +0 -1
  376. package/dist/labs/selectable.cjs +0 -2
  377. package/dist/labs/selectable.cjs.map +0 -1
  378. package/dist/labs/selectable.d.ts +0 -70
  379. package/dist/labs/selectable.d.ts.map +0 -1
  380. package/dist/labs/selectable.js +0 -2
  381. package/dist/labs/selectable.js.map +0 -1
  382. package/dist/labs/selection.cjs +0 -2
  383. package/dist/labs/selection.cjs.map +0 -1
  384. package/dist/labs/selection.d.ts +0 -68
  385. package/dist/labs/selection.d.ts.map +0 -1
  386. package/dist/labs/selection.js +0 -2
  387. package/dist/labs/selection.js.map +0 -1
  388. package/dist/labs.cjs +0 -1
  389. package/dist/labs.js +0 -1
  390. package/dist/test/index.d.ts +0 -2
  391. package/dist/test/index.d.ts.map +0 -1
  392. package/dist/test/test.cjs +0 -2
  393. package/dist/test/test.cjs.map +0 -1
  394. package/dist/test/test.d.ts.map +0 -1
  395. package/dist/test/test.js +0 -2
  396. package/dist/test/test.js.map +0 -1
  397. package/dist/test.cjs +0 -1
  398. package/dist/test.js +0 -1
  399. /package/dist/{core/runtime-bindings.d.ts → runtime-bindings.d.ts} +0 -0
  400. /package/dist/{core/template-dom.d.ts → template-dom.d.ts} +0 -0
@@ -1,6 +1,10 @@
1
1
  import { type ReadonlySignal } from '@vielzeug/stateit';
2
- import type { HTMLResult } from '../core/internal';
2
+ import type { HTMLResult } from '../internal';
3
3
  type Dep = unknown | ReadonlySignal<unknown>;
4
+ export type MemoOptions = {
5
+ deps?: ReadonlyArray<Dep>;
6
+ render: () => string | HTMLResult;
7
+ };
4
8
  /**
5
9
  * Memoizes a template fragment — `templateFn` is only re-called when at least
6
10
  * one entry in `deps` has changed (compared with `Object.is`).
@@ -13,11 +17,11 @@ type Dep = unknown | ReadonlySignal<unknown>;
13
17
  * import { memo } from '@vielzeug/craftit/directives';
14
18
  *
15
19
  * // Only re-renders the table when `rows` actually changes
16
- * html`${memo([rows], () => html`<big-table :data=${rows}></big-table>`)}`
20
+ * html`${memo({ deps: [rows], render: () => html`<big-table :data=${rows}></big-table>` })}`
17
21
  *
18
22
  * // Multiple deps — re-renders when either changes
19
- * html`${memo([locale, theme], () => html`<themed-chart :locale=${locale}></themed-chart>`)}`
23
+ * html`${memo({ deps: [locale, theme], render: () => html`<themed-chart :locale=${locale}></themed-chart>` })}`
20
24
  */
21
- export declare function memo(deps: ReadonlyArray<Dep>, templateFn: () => string | HTMLResult): () => string | HTMLResult;
25
+ export declare function memo(options: MemoOptions): () => string | HTMLResult;
22
26
  export {};
23
27
  //# sourceMappingURL=memo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memo.d.ts","sourceRoot":"","sources":["../../src/directives/memo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,GAAG,GAAG,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,MAAM,GAAG,UAAU,GAAG,MAAM,MAAM,GAAG,UAAU,CAkB/G"}
1
+ {"version":3,"file":"memo.d.ts","sourceRoot":"","sources":["../../src/directives/memo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,cAAc,EAAW,MAAM,mBAAmB,CAAC;AAErF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,KAAK,GAAG,GAAG,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,MAAM,GAAG,UAAU,CAAC;CACnC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,MAAM,GAAG,UAAU,CAUpE"}
@@ -1,2 +1,2 @@
1
- import{isSignal as e}from"@vielzeug/stateit";function t(t,n){let r=``,i=[],a=!1;return()=>{let o=t.map(t=>e(t)?t.value:t);return(!a||o.length!==i.length||o.some((e,t)=>!Object.is(e,i[t])))&&(r=n(),i=o,a=!0),r}}export{t as memo};
1
+ import{computed as e,isSignal as t,untrack as n}from"@vielzeug/stateit";function r(r){let i=e(()=>{for(let e of r.deps??[])t(e)&&Reflect.get(e,`value`);return n(r.render)});return()=>i.value}export{r as memo};
2
2
  //# sourceMappingURL=memo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memo.js","names":[],"sources":["../../src/directives/memo.ts"],"sourcesContent":["import { isSignal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../core/internal';\n\ntype Dep = unknown | ReadonlySignal<unknown>;\n\n/**\n * Memoizes a template fragment — `templateFn` is only re-called when at least\n * one entry in `deps` has changed (compared with `Object.is`).\n *\n * Signal values in `deps` are automatically unwrapped and tracked, so changing a\n * dep signal triggers a re-evaluation. This is useful for skipping expensive\n * sub-tree renders when only unrelated state changes.\n *\n * @example\n * import { memo } from '@vielzeug/craftit/directives';\n *\n * // Only re-renders the table when `rows` actually changes\n * html`${memo([rows], () => html`<big-table :data=${rows}></big-table>`)}`\n *\n * // Multiple deps — re-renders when either changes\n * html`${memo([locale, theme], () => html`<themed-chart :locale=${locale}></themed-chart>`)}`\n */\nexport function memo(deps: ReadonlyArray<Dep>, templateFn: () => string | HTMLResult): () => string | HTMLResult {\n let cached: string | HTMLResult = '';\n let lastDeps: unknown[] = [];\n let initialized = false;\n\n return (): string | HTMLResult => {\n const current = deps.map((d) => (isSignal(d) ? (d as ReadonlySignal<unknown>).value : d));\n const changed =\n !initialized || current.length !== lastDeps.length || current.some((v, i) => !Object.is(v, lastDeps[i]));\n\n if (changed) {\n cached = templateFn();\n lastDeps = current;\n initialized = true;\n }\n\n return cached;\n };\n}\n"],"mappings":"6CAuBA,SAAgB,EAAK,EAA0B,EAAkE,CAC/G,IAAI,EAA8B,GAC9B,EAAsB,EAAE,CACxB,EAAc,GAElB,UAAkC,CAChC,IAAM,EAAU,EAAK,IAAK,GAAO,EAAS,EAAE,CAAI,EAA8B,MAAQ,EAAG,CAUzF,OARE,CAAC,GAAe,EAAQ,SAAW,EAAS,QAAU,EAAQ,MAAM,EAAG,IAAM,CAAC,OAAO,GAAG,EAAG,EAAS,GAAG,CAAC,IAGxG,EAAS,GAAY,CACrB,EAAW,EACX,EAAc,IAGT"}
1
+ {"version":3,"file":"memo.js","names":[],"sources":["../../src/directives/memo.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, untrack } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../internal';\n\ntype Dep = unknown | ReadonlySignal<unknown>;\n\nexport type MemoOptions = {\n deps?: ReadonlyArray<Dep>;\n render: () => string | HTMLResult;\n};\n\n/**\n * Memoizes a template fragment — `templateFn` is only re-called when at least\n * one entry in `deps` has changed (compared with `Object.is`).\n *\n * Signal values in `deps` are automatically unwrapped and tracked, so changing a\n * dep signal triggers a re-evaluation. This is useful for skipping expensive\n * sub-tree renders when only unrelated state changes.\n *\n * @example\n * import { memo } from '@vielzeug/craftit/directives';\n *\n * // Only re-renders the table when `rows` actually changes\n * html`${memo({ deps: [rows], render: () => html`<big-table :data=${rows}></big-table>` })}`\n *\n * // Multiple deps — re-renders when either changes\n * html`${memo({ deps: [locale, theme], render: () => html`<themed-chart :locale=${locale}></themed-chart>` })}`\n */\nexport function memo(options: MemoOptions): () => string | HTMLResult {\n const renderSignal = computed(() => {\n for (const dep of options.deps ?? []) {\n if (isSignal(dep)) Reflect.get(dep, 'value');\n }\n\n return untrack(options.render);\n });\n\n return () => renderSignal.value;\n}\n"],"mappings":"wEA4BA,SAAgB,EAAK,EAAiD,CACpE,IAAM,EAAe,MAAe,CAClC,IAAK,IAAM,KAAO,EAAQ,MAAQ,EAAE,CAC9B,EAAS,EAAI,EAAE,QAAQ,IAAI,EAAK,QAAQ,CAG9C,OAAO,EAAQ,EAAQ,OAAO,EAC9B,CAEF,UAAa,EAAa"}
@@ -1,2 +1,2 @@
1
- const e=require(`../core/utilities.cjs`);function t(t,n,r){return{mount(i,{registerCleanup:a}){if(t===`clickOutside`){let t=i.ownerDocument??document;a(e.listen(t,`click`,e=>{e.composedPath().includes(i)||n(e)},r))}else a(e.listen(i,t,n,r))}}}exports.on=t;
1
+ const e=require(`../internal.cjs`);function t(t,n,r){return{mount(i,{registerCleanup:a}){if(t===`clickOutside`){let t=i.ownerDocument??document;a(e.listen(t,`click`,e=>{e.composedPath().includes(i)||n(e)},r))}else a(e.listen(i,t,n,r))}}}exports.on=t;
2
2
  //# sourceMappingURL=on.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"on.cjs","names":[],"sources":["../../src/directives/on.ts"],"sourcesContent":["import type { Directive } from '../core/internal';\n\nimport { listen } from '../core/utilities';\n\n/**\n * Attaches an event listener to an element as a spread directive, supporting\n * full `AddEventListenerOptions` (e.g. `passive`, `once`, `capture`).\n *\n * **Synthetic event: `'clickOutside'`**\n * When the event name is `'clickOutside'`, the listener is attached to `document`\n * and fires whenever a click occurs *outside* the host element — useful for\n * closing dropdowns, modals, and popovers.\n *\n * @example\n * import { on } from '@vielzeug/craftit/directives';\n *\n * // Passive wheel listener (not possible with @wheel= template syntax)\n * html`<div ${on('wheel', onScroll, { passive: true })}></div>`\n *\n * // Typed handler — `e` inferred as `MouseEvent`\n * html`<button ${on('click', (e) => e.clientX)}></button>`\n *\n * // Click-outside (closes a dropdown when the user clicks away)\n * html`<div ${on('clickOutside', () => open.value = false)}></div>`\n */\nexport function on(\n event: 'clickOutside',\n handler: (e: MouseEvent) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on<K extends keyof HTMLElementEventMap>(\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on(event: string, handler: (e: any) => void, options?: AddEventListenerOptions): Directive {\n return {\n mount(el, { registerCleanup }) {\n if (event === 'clickOutside') {\n const doc = el.ownerDocument ?? document;\n const docHandler = (e: Event) => {\n if (!e.composedPath().includes(el)) handler(e as MouseEvent);\n };\n\n registerCleanup(listen(doc, 'click', docHandler, options));\n } else {\n registerCleanup(listen(el, event, handler, options));\n }\n },\n };\n}\n"],"mappings":"yCAmCA,SAAgB,EAAG,EAAe,EAA2B,EAA8C,CACzG,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAC7B,GAAI,IAAU,eAAgB,CAC5B,IAAM,EAAM,EAAG,eAAiB,SAKhC,EAAgB,EAAA,OAAO,EAAK,QAJR,GAAa,CAC1B,EAAE,cAAc,CAAC,SAAS,EAAG,EAAE,EAAQ,EAAgB,EAGb,EAAQ,CAAC,MAE1D,EAAgB,EAAA,OAAO,EAAI,EAAO,EAAS,EAAQ,CAAC,EAGzD"}
1
+ {"version":3,"file":"on.cjs","names":[],"sources":["../../src/directives/on.ts"],"sourcesContent":["import type { Directive } from '../internal';\n\nimport { listen } from '../internal';\n\n/**\n * Attaches an event listener to an element as a spread directive, supporting\n * full `AddEventListenerOptions` (e.g. `passive`, `once`, `capture`).\n *\n * **Synthetic event: `'clickOutside'`**\n * When the event name is `'clickOutside'`, the listener is attached to `document`\n * and fires whenever a click occurs *outside* the host element — useful for\n * closing dropdowns, modals, and popovers.\n *\n * @example\n * import { on } from '@vielzeug/craftit/directives';\n *\n * // Passive wheel listener (not possible with @wheel= template syntax)\n * html`<div ${on('wheel', onScroll, { passive: true })}></div>`\n *\n * // Typed handler — `e` inferred as `MouseEvent`\n * html`<button ${on('click', (e) => e.clientX)}></button>`\n *\n * // Click-outside (closes a dropdown when the user clicks away)\n * html`<div ${on('clickOutside', () => open.value = false)}></div>`\n */\nexport function on(\n event: 'clickOutside',\n handler: (e: MouseEvent) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on<K extends keyof HTMLElementEventMap>(\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on(event: string, handler: (e: any) => void, options?: AddEventListenerOptions): Directive {\n return {\n mount(el, { registerCleanup }) {\n if (event === 'clickOutside') {\n const doc = el.ownerDocument ?? document;\n const docHandler = (e: Event) => {\n if (!e.composedPath().includes(el)) handler(e as MouseEvent);\n };\n\n registerCleanup(listen(doc, 'click', docHandler, options));\n } else {\n registerCleanup(listen(el, event, handler, options));\n }\n },\n };\n}\n"],"mappings":"mCAmCA,SAAgB,EAAG,EAAe,EAA2B,EAA8C,CACzG,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAC7B,GAAI,IAAU,eAAgB,CAC5B,IAAM,EAAM,EAAG,eAAiB,SAKhC,EAAgB,EAAA,OAAO,EAAK,QAJR,GAAa,CAC1B,EAAE,cAAc,CAAC,SAAS,EAAG,EAAE,EAAQ,EAAgB,EAGb,EAAQ,CAAC,MAE1D,EAAgB,EAAA,OAAO,EAAI,EAAO,EAAS,EAAQ,CAAC,EAGzD"}
@@ -1,4 +1,4 @@
1
- import type { Directive } from '../core/internal';
1
+ import type { Directive } from '../internal';
2
2
  /**
3
3
  * Attaches an event listener to an element as a spread directive, supporting
4
4
  * full `AddEventListenerOptions` (e.g. `passive`, `once`, `capture`).
@@ -1 +1 @@
1
- {"version":3,"file":"on.d.ts","sourceRoot":"","sources":["../../src/directives/on.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIlD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,EAAE,CAChB,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,EAChC,OAAO,CAAC,EAAE,uBAAuB,GAChC,SAAS,CAAC;AACb,wBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,mBAAmB,EACpD,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC5C,OAAO,CAAC,EAAE,uBAAuB,GAChC,SAAS,CAAC"}
1
+ {"version":3,"file":"on.d.ts","sourceRoot":"","sources":["../../src/directives/on.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,EAAE,CAChB,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,EAChC,OAAO,CAAC,EAAE,uBAAuB,GAChC,SAAS,CAAC;AACb,wBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,mBAAmB,EACpD,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC5C,OAAO,CAAC,EAAE,uBAAuB,GAChC,SAAS,CAAC"}
@@ -1,2 +1,2 @@
1
- import{listen as e}from"../core/utilities.js";function t(t,n,r){return{mount(i,{registerCleanup:a}){a(t===`clickOutside`?e(i.ownerDocument??document,`click`,e=>{e.composedPath().includes(i)||n(e)},r):e(i,t,n,r))}}}export{t as on};
1
+ import{listen as e}from"../internal.js";function t(t,n,r){return{mount(i,{registerCleanup:a}){a(t===`clickOutside`?e(i.ownerDocument??document,`click`,e=>{e.composedPath().includes(i)||n(e)},r):e(i,t,n,r))}}}export{t as on};
2
2
  //# sourceMappingURL=on.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"on.js","names":[],"sources":["../../src/directives/on.ts"],"sourcesContent":["import type { Directive } from '../core/internal';\n\nimport { listen } from '../core/utilities';\n\n/**\n * Attaches an event listener to an element as a spread directive, supporting\n * full `AddEventListenerOptions` (e.g. `passive`, `once`, `capture`).\n *\n * **Synthetic event: `'clickOutside'`**\n * When the event name is `'clickOutside'`, the listener is attached to `document`\n * and fires whenever a click occurs *outside* the host element — useful for\n * closing dropdowns, modals, and popovers.\n *\n * @example\n * import { on } from '@vielzeug/craftit/directives';\n *\n * // Passive wheel listener (not possible with @wheel= template syntax)\n * html`<div ${on('wheel', onScroll, { passive: true })}></div>`\n *\n * // Typed handler — `e` inferred as `MouseEvent`\n * html`<button ${on('click', (e) => e.clientX)}></button>`\n *\n * // Click-outside (closes a dropdown when the user clicks away)\n * html`<div ${on('clickOutside', () => open.value = false)}></div>`\n */\nexport function on(\n event: 'clickOutside',\n handler: (e: MouseEvent) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on<K extends keyof HTMLElementEventMap>(\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on(event: string, handler: (e: any) => void, options?: AddEventListenerOptions): Directive {\n return {\n mount(el, { registerCleanup }) {\n if (event === 'clickOutside') {\n const doc = el.ownerDocument ?? document;\n const docHandler = (e: Event) => {\n if (!e.composedPath().includes(el)) handler(e as MouseEvent);\n };\n\n registerCleanup(listen(doc, 'click', docHandler, options));\n } else {\n registerCleanup(listen(el, event, handler, options));\n }\n },\n };\n}\n"],"mappings":"8CAmCA,SAAgB,EAAG,EAAe,EAA2B,EAA8C,CACzG,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAO3B,EANE,IAAU,eAMI,EALJ,EAAG,eAAiB,SAKJ,QAJR,GAAa,CAC1B,EAAE,cAAc,CAAC,SAAS,EAAG,EAAE,EAAQ,EAAgB,EAGb,EAAQ,CAEzC,EAAO,EAAI,EAAO,EAAS,EAAQ,CAAC,EAGzD"}
1
+ {"version":3,"file":"on.js","names":[],"sources":["../../src/directives/on.ts"],"sourcesContent":["import type { Directive } from '../internal';\n\nimport { listen } from '../internal';\n\n/**\n * Attaches an event listener to an element as a spread directive, supporting\n * full `AddEventListenerOptions` (e.g. `passive`, `once`, `capture`).\n *\n * **Synthetic event: `'clickOutside'`**\n * When the event name is `'clickOutside'`, the listener is attached to `document`\n * and fires whenever a click occurs *outside* the host element — useful for\n * closing dropdowns, modals, and popovers.\n *\n * @example\n * import { on } from '@vielzeug/craftit/directives';\n *\n * // Passive wheel listener (not possible with @wheel= template syntax)\n * html`<div ${on('wheel', onScroll, { passive: true })}></div>`\n *\n * // Typed handler — `e` inferred as `MouseEvent`\n * html`<button ${on('click', (e) => e.clientX)}></button>`\n *\n * // Click-outside (closes a dropdown when the user clicks away)\n * html`<div ${on('clickOutside', () => open.value = false)}></div>`\n */\nexport function on(\n event: 'clickOutside',\n handler: (e: MouseEvent) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on<K extends keyof HTMLElementEventMap>(\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Directive;\nexport function on(event: string, handler: (e: any) => void, options?: AddEventListenerOptions): Directive {\n return {\n mount(el, { registerCleanup }) {\n if (event === 'clickOutside') {\n const doc = el.ownerDocument ?? document;\n const docHandler = (e: Event) => {\n if (!e.composedPath().includes(el)) handler(e as MouseEvent);\n };\n\n registerCleanup(listen(doc, 'click', docHandler, options));\n } else {\n registerCleanup(listen(el, event, handler, options));\n }\n },\n };\n}\n"],"mappings":"wCAmCA,SAAgB,EAAG,EAAe,EAA2B,EAA8C,CACzG,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAO3B,EANE,IAAU,eAMI,EALJ,EAAG,eAAiB,SAKJ,QAJR,GAAa,CAC1B,EAAE,cAAc,CAAC,SAAS,EAAG,EAAE,EAAQ,EAAgB,EAGb,EAAQ,CAEzC,EAAO,EAAI,EAAO,EAAS,EAAQ,CAAC,EAGzD"}
@@ -1,2 +1,2 @@
1
- const e=require(`../core/internal.cjs`);let t=require(`@vielzeug/stateit`);function n(n){return(0,t.isSignal)(n)?(0,t.computed)(()=>e.htmlResult(n.value)):typeof n==`function`?(0,t.computed)(()=>e.htmlResult(n())):e.htmlResult(n)}exports.raw=n;
1
+ const e=require(`../internal.cjs`);let t=require(`@vielzeug/stateit`);function n(n){return(0,t.isSignal)(n)?(0,t.computed)(()=>e.htmlResult(n.value)):typeof n==`function`?(0,t.computed)(()=>e.htmlResult(n())):e.htmlResult(n)}exports.raw=n;
2
2
  //# sourceMappingURL=raw.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"raw.cjs","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { htmlResult, type HTMLResult } from '../core/internal';\n\n/**\n * Renders a trusted HTML string without escaping.\n * **Only use with content you control** — passing user-supplied strings\n * directly is an XSS risk.\n *\n * Supports static strings, writable Signals, and getter functions.\n * When reactive, the DOM is updated in-place whenever the value changes.\n *\n * @example\n * import { raw } from '@vielzeug/craftit/directives';\n *\n * // Static\n * html`<div>${raw('<strong>bold</strong>')}</div>`\n *\n * // Reactive signal\n * const content = signal('<em>hello</em>');\n * html`<div>${raw(content)}</div>`\n *\n * // Getter\n * html`<div>${raw(() => sanitize(props.body.value))}</div>`\n */\nexport function raw(\n value: string | Signal<string> | ReadonlySignal<string> | (() => string),\n): HTMLResult | ReadonlySignal<HTMLResult> {\n if (isSignal(value)) {\n return computed(() => htmlResult((value as ReadonlySignal<string>).value));\n }\n\n if (typeof value === 'function') {\n return computed(() => htmlResult((value as () => string)()));\n }\n\n return htmlResult(value);\n}\n"],"mappings":"2EAyBA,SAAgB,EACd,EACyC,CASzC,OARA,EAAA,EAAA,UAAa,EAAM,EACjB,EAAA,EAAA,cAAsB,EAAA,WAAY,EAAiC,MAAM,CAAC,CAGxE,OAAO,GAAU,YACnB,EAAA,EAAA,cAAsB,EAAA,WAAY,GAAwB,CAAC,CAAC,CAGvD,EAAA,WAAW,EAAM"}
1
+ {"version":3,"file":"raw.cjs","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { htmlResult, type HTMLResult } from '../internal';\n\n/**\n * Renders a trusted HTML string without escaping.\n * **Only use with content you control** — passing user-supplied strings\n * directly is an XSS risk.\n *\n * Supports static strings, writable Signals, and getter functions.\n * When reactive, the DOM is updated in-place whenever the value changes.\n *\n * @example\n * import { raw } from '@vielzeug/craftit/directives';\n *\n * // Static\n * html`<div>${raw('<strong>bold</strong>')}</div>`\n *\n * // Reactive signal\n * const content = signal('<em>hello</em>');\n * html`<div>${raw(content)}</div>`\n *\n * // Getter\n * html`<div>${raw(() => sanitize(props.body.value))}</div>`\n */\nexport function raw(\n value: string | Signal<string> | ReadonlySignal<string> | (() => string),\n): HTMLResult | ReadonlySignal<HTMLResult> {\n if (isSignal(value)) {\n return computed(() => htmlResult((value as ReadonlySignal<string>).value));\n }\n\n if (typeof value === 'function') {\n return computed(() => htmlResult((value as () => string)()));\n }\n\n return htmlResult(value);\n}\n"],"mappings":"sEAyBA,SAAgB,EACd,EACyC,CASzC,OARA,EAAA,EAAA,UAAa,EAAM,EACjB,EAAA,EAAA,cAAsB,EAAA,WAAY,EAAiC,MAAM,CAAC,CAGxE,OAAO,GAAU,YACnB,EAAA,EAAA,cAAsB,EAAA,WAAY,GAAwB,CAAC,CAAC,CAGvD,EAAA,WAAW,EAAM"}
@@ -1,5 +1,5 @@
1
1
  import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
2
- import { type HTMLResult } from '../core/internal';
2
+ import { type HTMLResult } from '../internal';
3
3
  /**
4
4
  * Renders a trusted HTML string without escaping.
5
5
  * **Only use with content you control** — passing user-supplied strings
@@ -1 +1 @@
1
- {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/directives/raw.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEzF,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,GAAG,CACjB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,GACvE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAUzC"}
1
+ {"version":3,"file":"raw.d.ts","sourceRoot":"","sources":["../../src/directives/raw.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEzF,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,GAAG,CACjB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,GACvE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAUzC"}
@@ -1,2 +1,2 @@
1
- import{htmlResult as e}from"../core/internal.js";import{computed as t,isSignal as n}from"@vielzeug/stateit";function r(r){return n(r)?t(()=>e(r.value)):typeof r==`function`?t(()=>e(r())):e(r)}export{r as raw};
1
+ import{htmlResult as e}from"../internal.js";import{computed as t,isSignal as n}from"@vielzeug/stateit";function r(r){return n(r)?t(()=>e(r.value)):typeof r==`function`?t(()=>e(r())):e(r)}export{r as raw};
2
2
  //# sourceMappingURL=raw.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"raw.js","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { htmlResult, type HTMLResult } from '../core/internal';\n\n/**\n * Renders a trusted HTML string without escaping.\n * **Only use with content you control** — passing user-supplied strings\n * directly is an XSS risk.\n *\n * Supports static strings, writable Signals, and getter functions.\n * When reactive, the DOM is updated in-place whenever the value changes.\n *\n * @example\n * import { raw } from '@vielzeug/craftit/directives';\n *\n * // Static\n * html`<div>${raw('<strong>bold</strong>')}</div>`\n *\n * // Reactive signal\n * const content = signal('<em>hello</em>');\n * html`<div>${raw(content)}</div>`\n *\n * // Getter\n * html`<div>${raw(() => sanitize(props.body.value))}</div>`\n */\nexport function raw(\n value: string | Signal<string> | ReadonlySignal<string> | (() => string),\n): HTMLResult | ReadonlySignal<HTMLResult> {\n if (isSignal(value)) {\n return computed(() => htmlResult((value as ReadonlySignal<string>).value));\n }\n\n if (typeof value === 'function') {\n return computed(() => htmlResult((value as () => string)()));\n }\n\n return htmlResult(value);\n}\n"],"mappings":"4GAyBA,SAAgB,EACd,EACyC,CASzC,OARI,EAAS,EAAM,CACV,MAAe,EAAY,EAAiC,MAAM,CAAC,CAGxE,OAAO,GAAU,WACZ,MAAe,EAAY,GAAwB,CAAC,CAAC,CAGvD,EAAW,EAAM"}
1
+ {"version":3,"file":"raw.js","names":[],"sources":["../../src/directives/raw.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { htmlResult, type HTMLResult } from '../internal';\n\n/**\n * Renders a trusted HTML string without escaping.\n * **Only use with content you control** — passing user-supplied strings\n * directly is an XSS risk.\n *\n * Supports static strings, writable Signals, and getter functions.\n * When reactive, the DOM is updated in-place whenever the value changes.\n *\n * @example\n * import { raw } from '@vielzeug/craftit/directives';\n *\n * // Static\n * html`<div>${raw('<strong>bold</strong>')}</div>`\n *\n * // Reactive signal\n * const content = signal('<em>hello</em>');\n * html`<div>${raw(content)}</div>`\n *\n * // Getter\n * html`<div>${raw(() => sanitize(props.body.value))}</div>`\n */\nexport function raw(\n value: string | Signal<string> | ReadonlySignal<string> | (() => string),\n): HTMLResult | ReadonlySignal<HTMLResult> {\n if (isSignal(value)) {\n return computed(() => htmlResult((value as ReadonlySignal<string>).value));\n }\n\n if (typeof value === 'function') {\n return computed(() => htmlResult((value as () => string)()));\n }\n\n return htmlResult(value);\n}\n"],"mappings":"uGAyBA,SAAgB,EACd,EACyC,CASzC,OARI,EAAS,EAAM,CACV,MAAe,EAAY,EAAiC,MAAM,CAAC,CAGxE,OAAO,GAAU,WACZ,MAAe,EAAY,GAAwB,CAAC,CAAC,CAGvD,EAAW,EAAM"}
@@ -1,2 +1,2 @@
1
- require(`../core/internal.cjs`);const e=require(`../core/utilities.cjs`),t=require(`../core/runtime-bindings.cjs`);let n=require(`@vielzeug/stateit`);var r=(e,t,r)=>e?(r((0,n.effect)(()=>{t(e.value)})),!0):!1,i=(t,n,r,i)=>n.startsWith(`@`)?(typeof r==`function`&&i(e.listen(t,n.slice(1),r)),!0):!1,a=(e,n,i,a)=>{if(!n.startsWith(`.`))return!1;let o=n.slice(1),s=t.hasWritableValueSetter(i)?i:void 0;return r(t.toReactiveBindingSource(i),t=>e[o]=t,a)||(e[o]=i),t.bindPropertyModel(e,o,s,a),!0},o=(e,n,i,a)=>{if(!n.startsWith(`?`))return!1;let o=n.slice(1);return r(t.toReactiveBindingSource(i),t=>e.toggleAttribute(o,!!t),a)||e.toggleAttribute(o,!!i),!0},s=(n,i,a,o)=>{r(t.toReactiveBindingSource(a),t=>e.setAttr(n,i,t),o)||e.setAttr(n,i,a)},c=(e,t,n,r)=>{n!==void 0&&(i(e,t,n,r)||a(e,t,n,r)||o(e,t,n,r)||s(e,t,n,r))};function l(e){return{mount(t,{registerCleanup:n}){for(let[r,i]of Object.entries(e))c(t,r,i,n)}}}exports.spread=l;
1
+ const e=require(`../internal.cjs`),t=require(`../runtime-bindings.cjs`);let n=require(`@vielzeug/stateit`);var r=(e,t,r)=>e?(r((0,n.effect)(()=>{t(e.value)})),!0):!1,i=(t,n,r,i)=>n.startsWith(`@`)?(typeof r==`function`&&i(e.listen(t,n.slice(1),r)),!0):!1,a=(e,n,i,a)=>{if(!n.startsWith(`.`))return!1;let o=n.slice(1),s=t.hasWritableValueSetter(i)?i:void 0;return r(t.toReactiveBindingSource(i),t=>e[o]=t,a)||(e[o]=i),t.bindPropertyModel(e,o,s,a),!0},o=(e,n,i,a)=>{if(!n.startsWith(`?`))return!1;let o=n.slice(1);return r(t.toReactiveBindingSource(i),t=>e.toggleAttribute(o,!!t),a)||e.toggleAttribute(o,!!i),!0},s=(n,i,a,o)=>{r(t.toReactiveBindingSource(a),t=>e.setAttr(n,i,t),o)||e.setAttr(n,i,a)},c=(e,t,n,r)=>{n!==void 0&&(i(e,t,n,r)||a(e,t,n,r)||o(e,t,n,r)||s(e,t,n,r))};function l(e){return{mount(t,{registerCleanup:n}){for(let[r,i]of Object.entries(e))c(t,r,i,n)}}}exports.spread=l;
2
2
  //# sourceMappingURL=spread.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"spread.cjs","names":[],"sources":["../../src/directives/spread.ts"],"sourcesContent":["import { effect, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { type Directive } from '../core/internal';\nimport { bindPropertyModel, hasWritableValueSetter, toReactiveBindingSource } from '../core/runtime-bindings';\nimport { listen, setAttr } from '../core/utilities';\n\nexport type SpreadValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ReadonlySignal<string | number | boolean | null | undefined>\n | (() => string | number | boolean | null | undefined)\n | ((event: Event) => void);\n\ntype RegisterCleanup = (fn: () => void) => void;\n\nconst applyReactiveValue = (\n source: ReadonlySignal<unknown> | undefined,\n apply: (value: unknown) => void,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!source) return false;\n\n registerCleanup(\n effect(() => {\n apply(source.value);\n }),\n );\n\n return true;\n};\n\nconst applyEventEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('@')) return false;\n\n if (typeof rawValue === 'function') {\n registerCleanup(listen(el, rawKey.slice(1), rawValue as (event: Event) => void));\n }\n\n return true;\n};\n\nconst applyPropertyEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('.')) return false;\n\n const key = rawKey.slice(1);\n const writableModel = hasWritableValueSetter(rawValue) ? rawValue : undefined;\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => ((el as any)[key] = value), registerCleanup)) {\n (el as any)[key] = rawValue;\n }\n\n bindPropertyModel(el, key, writableModel, registerCleanup);\n\n return true;\n};\n\nconst applyBooleanAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('?')) return false;\n\n const key = rawKey.slice(1);\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => el.toggleAttribute(key, Boolean(value)), registerCleanup)) {\n el.toggleAttribute(key, Boolean(rawValue));\n }\n\n return true;\n};\n\nconst applyAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): void => {\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => setAttr(el, rawKey, value), registerCleanup)) {\n setAttr(el, rawKey, rawValue);\n }\n};\n\nconst applyEntry = (el: HTMLElement, rawKey: string, rawValue: SpreadValue, registerCleanup: RegisterCleanup): void => {\n if (rawValue === undefined) return;\n\n if (applyEventEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyPropertyEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyBooleanAttributeEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n applyAttributeEntry(el, rawKey, rawValue, registerCleanup);\n};\n\n/**\n * Unified spread directive for attributes, properties, and events.\n *\n * Key prefixes:\n * - `name` -> attribute\n * - `?name` -> boolean attribute\n * - `.name` -> DOM property\n * - `@name` -> event listener\n */\nexport function spread(map: Record<string, SpreadValue>): Directive {\n return {\n mount(el, { registerCleanup }) {\n for (const [key, value] of Object.entries(map)) {\n applyEntry(el, key, value, registerCleanup);\n }\n },\n };\n}\n"],"mappings":"sJAkBA,IAAM,GACJ,EACA,EACA,IAEK,GAEL,GAAA,EAAA,EAAA,YACe,CACX,EAAM,EAAO,MAAM,EACnB,CACH,CAEM,IARa,GAWhB,GACJ,EACA,EACA,EACA,IAEK,EAAO,WAAW,IAAI,EAEvB,OAAO,GAAa,YACtB,EAAgB,EAAA,OAAO,EAAI,EAAO,MAAM,EAAE,CAAE,EAAmC,CAAC,CAG3E,IAN6B,GAShC,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CACrB,EAAgB,EAAA,uBAAuB,EAAS,CAAG,EAAW,IAAA,GASpE,OANK,EAFU,EAAA,wBAAwB,EAAS,CAEf,GAAW,EAAY,GAAO,EAAQ,EAAgB,GACpF,EAAW,GAAO,GAGrB,EAAA,kBAAkB,EAAI,EAAK,EAAe,EAAgB,CAEnD,IAGH,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CAO3B,OAJK,EAFU,EAAA,wBAAwB,EAAS,CAEf,GAAU,EAAG,gBAAgB,EAAK,EAAQ,EAAO,CAAE,EAAgB,EAClG,EAAG,gBAAgB,EAAK,EAAQ,EAAU,CAGrC,IAGH,GACJ,EACA,EACA,EACA,IACS,CAGJ,EAFU,EAAA,wBAAwB,EAAS,CAEf,GAAU,EAAA,QAAQ,EAAI,EAAQ,EAAM,CAAE,EAAgB,EACrF,EAAA,QAAQ,EAAI,EAAQ,EAAS,EAI3B,GAAc,EAAiB,EAAgB,EAAuB,IAA2C,CACjH,IAAa,IAAA,KAEb,EAAgB,EAAI,EAAQ,EAAU,EAAgB,EAEtD,EAAmB,EAAI,EAAQ,EAAU,EAAgB,EAEzD,EAA2B,EAAI,EAAQ,EAAU,EAAgB,EAErE,EAAoB,EAAI,EAAQ,EAAU,EAAgB,GAY5D,SAAgB,EAAO,EAA6C,CAClE,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAC7B,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAI,CAC5C,EAAW,EAAI,EAAK,EAAO,EAAgB,EAGhD"}
1
+ {"version":3,"file":"spread.cjs","names":[],"sources":["../../src/directives/spread.ts"],"sourcesContent":["import { effect, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { type Directive, listen, setAttr } from '../internal';\nimport { bindPropertyModel, hasWritableValueSetter, toReactiveBindingSource } from '../runtime-bindings';\n\nexport type SpreadValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ReadonlySignal<string | number | boolean | null | undefined>\n | (() => string | number | boolean | null | undefined)\n | ((event: Event) => void);\n\ntype RegisterCleanup = (fn: () => void) => void;\n\nconst applyReactiveValue = (\n source: ReadonlySignal<unknown> | undefined,\n apply: (value: unknown) => void,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!source) return false;\n\n registerCleanup(\n effect(() => {\n apply(source.value);\n }),\n );\n\n return true;\n};\n\nconst applyEventEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('@')) return false;\n\n if (typeof rawValue === 'function') {\n registerCleanup(listen(el, rawKey.slice(1), rawValue as (event: Event) => void));\n }\n\n return true;\n};\n\nconst applyPropertyEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('.')) return false;\n\n const key = rawKey.slice(1);\n const writableModel = hasWritableValueSetter(rawValue) ? rawValue : undefined;\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => ((el as any)[key] = value), registerCleanup)) {\n (el as any)[key] = rawValue;\n }\n\n bindPropertyModel(el, key, writableModel, registerCleanup);\n\n return true;\n};\n\nconst applyBooleanAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('?')) return false;\n\n const key = rawKey.slice(1);\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => el.toggleAttribute(key, Boolean(value)), registerCleanup)) {\n el.toggleAttribute(key, Boolean(rawValue));\n }\n\n return true;\n};\n\nconst applyAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): void => {\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => setAttr(el, rawKey, value), registerCleanup)) {\n setAttr(el, rawKey, rawValue);\n }\n};\n\nconst applyEntry = (el: HTMLElement, rawKey: string, rawValue: SpreadValue, registerCleanup: RegisterCleanup): void => {\n if (rawValue === undefined) return;\n\n if (applyEventEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyPropertyEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyBooleanAttributeEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n applyAttributeEntry(el, rawKey, rawValue, registerCleanup);\n};\n\n/**\n * Unified spread directive for attributes, properties, and events.\n *\n * Key prefixes:\n * - `name` -> attribute\n * - `?name` -> boolean attribute\n * - `.name` -> DOM property\n * - `@name` -> event listener\n */\nexport function spread(map: Record<string, SpreadValue>): Directive {\n return {\n mount(el, { registerCleanup }) {\n for (const [key, value] of Object.entries(map)) {\n applyEntry(el, key, value, registerCleanup);\n }\n },\n };\n}\n"],"mappings":"2GAiBA,IAAM,GACJ,EACA,EACA,IAEK,GAEL,GAAA,EAAA,EAAA,YACe,CACX,EAAM,EAAO,MAAM,EACnB,CACH,CAEM,IARa,GAWhB,GACJ,EACA,EACA,EACA,IAEK,EAAO,WAAW,IAAI,EAEvB,OAAO,GAAa,YACtB,EAAgB,EAAA,OAAO,EAAI,EAAO,MAAM,EAAE,CAAE,EAAmC,CAAC,CAG3E,IAN6B,GAShC,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CACrB,EAAgB,EAAA,uBAAuB,EAAS,CAAG,EAAW,IAAA,GASpE,OANK,EAFU,EAAA,wBAAwB,EAAS,CAEf,GAAW,EAAY,GAAO,EAAQ,EAAgB,GACpF,EAAW,GAAO,GAGrB,EAAA,kBAAkB,EAAI,EAAK,EAAe,EAAgB,CAEnD,IAGH,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CAO3B,OAJK,EAFU,EAAA,wBAAwB,EAAS,CAEf,GAAU,EAAG,gBAAgB,EAAK,EAAQ,EAAO,CAAE,EAAgB,EAClG,EAAG,gBAAgB,EAAK,EAAQ,EAAU,CAGrC,IAGH,GACJ,EACA,EACA,EACA,IACS,CAGJ,EAFU,EAAA,wBAAwB,EAAS,CAEf,GAAU,EAAA,QAAQ,EAAI,EAAQ,EAAM,CAAE,EAAgB,EACrF,EAAA,QAAQ,EAAI,EAAQ,EAAS,EAI3B,GAAc,EAAiB,EAAgB,EAAuB,IAA2C,CACjH,IAAa,IAAA,KAEb,EAAgB,EAAI,EAAQ,EAAU,EAAgB,EAEtD,EAAmB,EAAI,EAAQ,EAAU,EAAgB,EAEzD,EAA2B,EAAI,EAAQ,EAAU,EAAgB,EAErE,EAAoB,EAAI,EAAQ,EAAU,EAAgB,GAY5D,SAAgB,EAAO,EAA6C,CAClE,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAC7B,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAI,CAC5C,EAAW,EAAI,EAAK,EAAO,EAAgB,EAGhD"}
@@ -1,5 +1,5 @@
1
1
  import { type ReadonlySignal } from '@vielzeug/stateit';
2
- import { type Directive } from '../core/internal';
2
+ import { type Directive } from '../internal';
3
3
  export type SpreadValue = string | number | boolean | null | undefined | ReadonlySignal<string | number | boolean | null | undefined> | (() => string | number | boolean | null | undefined) | ((event: Event) => void);
4
4
  /**
5
5
  * Unified spread directive for attributes, properties, and events.
@@ -1 +1 @@
1
- {"version":3,"file":"spread.d.ts","sourceRoot":"","sources":["../../src/directives/spread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIlD,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,cAAc,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GAC5D,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACpD,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;AAmG7B;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,CAQlE"}
1
+ {"version":3,"file":"spread.d.ts","sourceRoot":"","sources":["../../src/directives/spread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,aAAa,CAAC;AAG9D,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,cAAc,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GAC5D,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACpD,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;AAmG7B;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,CAQlE"}
@@ -1,2 +1,2 @@
1
- import"../core/internal.js";import{listen as e,setAttr as t}from"../core/utilities.js";import{bindPropertyModel as n,hasWritableValueSetter as r,toReactiveBindingSource as i}from"../core/runtime-bindings.js";import{effect as a}from"@vielzeug/stateit";var o=(e,t,n)=>e?(n(a(()=>{t(e.value)})),!0):!1,s=(t,n,r,i)=>n.startsWith(`@`)?(typeof r==`function`&&i(e(t,n.slice(1),r)),!0):!1,c=(e,t,a,s)=>{if(!t.startsWith(`.`))return!1;let c=t.slice(1),l=r(a)?a:void 0;return o(i(a),t=>e[c]=t,s)||(e[c]=a),n(e,c,l,s),!0},l=(e,t,n,r)=>{if(!t.startsWith(`?`))return!1;let a=t.slice(1);return o(i(n),t=>e.toggleAttribute(a,!!t),r)||e.toggleAttribute(a,!!n),!0},u=(e,n,r,a)=>{o(i(r),r=>t(e,n,r),a)||t(e,n,r)},d=(e,t,n,r)=>{n!==void 0&&(s(e,t,n,r)||c(e,t,n,r)||l(e,t,n,r)||u(e,t,n,r))};function f(e){return{mount(t,{registerCleanup:n}){for(let[r,i]of Object.entries(e))d(t,r,i,n)}}}export{f as spread};
1
+ import{listen as e,setAttr as t}from"../internal.js";import{bindPropertyModel as n,hasWritableValueSetter as r,toReactiveBindingSource as i}from"../runtime-bindings.js";import{effect as a}from"@vielzeug/stateit";var o=(e,t,n)=>e?(n(a(()=>{t(e.value)})),!0):!1,s=(t,n,r,i)=>n.startsWith(`@`)?(typeof r==`function`&&i(e(t,n.slice(1),r)),!0):!1,c=(e,t,a,s)=>{if(!t.startsWith(`.`))return!1;let c=t.slice(1),l=r(a)?a:void 0;return o(i(a),t=>e[c]=t,s)||(e[c]=a),n(e,c,l,s),!0},l=(e,t,n,r)=>{if(!t.startsWith(`?`))return!1;let a=t.slice(1);return o(i(n),t=>e.toggleAttribute(a,!!t),r)||e.toggleAttribute(a,!!n),!0},u=(e,n,r,a)=>{o(i(r),r=>t(e,n,r),a)||t(e,n,r)},d=(e,t,n,r)=>{n!==void 0&&(s(e,t,n,r)||c(e,t,n,r)||l(e,t,n,r)||u(e,t,n,r))};function f(e){return{mount(t,{registerCleanup:n}){for(let[r,i]of Object.entries(e))d(t,r,i,n)}}}export{f as spread};
2
2
  //# sourceMappingURL=spread.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spread.js","names":[],"sources":["../../src/directives/spread.ts"],"sourcesContent":["import { effect, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { type Directive } from '../core/internal';\nimport { bindPropertyModel, hasWritableValueSetter, toReactiveBindingSource } from '../core/runtime-bindings';\nimport { listen, setAttr } from '../core/utilities';\n\nexport type SpreadValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ReadonlySignal<string | number | boolean | null | undefined>\n | (() => string | number | boolean | null | undefined)\n | ((event: Event) => void);\n\ntype RegisterCleanup = (fn: () => void) => void;\n\nconst applyReactiveValue = (\n source: ReadonlySignal<unknown> | undefined,\n apply: (value: unknown) => void,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!source) return false;\n\n registerCleanup(\n effect(() => {\n apply(source.value);\n }),\n );\n\n return true;\n};\n\nconst applyEventEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('@')) return false;\n\n if (typeof rawValue === 'function') {\n registerCleanup(listen(el, rawKey.slice(1), rawValue as (event: Event) => void));\n }\n\n return true;\n};\n\nconst applyPropertyEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('.')) return false;\n\n const key = rawKey.slice(1);\n const writableModel = hasWritableValueSetter(rawValue) ? rawValue : undefined;\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => ((el as any)[key] = value), registerCleanup)) {\n (el as any)[key] = rawValue;\n }\n\n bindPropertyModel(el, key, writableModel, registerCleanup);\n\n return true;\n};\n\nconst applyBooleanAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('?')) return false;\n\n const key = rawKey.slice(1);\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => el.toggleAttribute(key, Boolean(value)), registerCleanup)) {\n el.toggleAttribute(key, Boolean(rawValue));\n }\n\n return true;\n};\n\nconst applyAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): void => {\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => setAttr(el, rawKey, value), registerCleanup)) {\n setAttr(el, rawKey, rawValue);\n }\n};\n\nconst applyEntry = (el: HTMLElement, rawKey: string, rawValue: SpreadValue, registerCleanup: RegisterCleanup): void => {\n if (rawValue === undefined) return;\n\n if (applyEventEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyPropertyEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyBooleanAttributeEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n applyAttributeEntry(el, rawKey, rawValue, registerCleanup);\n};\n\n/**\n * Unified spread directive for attributes, properties, and events.\n *\n * Key prefixes:\n * - `name` -> attribute\n * - `?name` -> boolean attribute\n * - `.name` -> DOM property\n * - `@name` -> event listener\n */\nexport function spread(map: Record<string, SpreadValue>): Directive {\n return {\n mount(el, { registerCleanup }) {\n for (const [key, value] of Object.entries(map)) {\n applyEntry(el, key, value, registerCleanup);\n }\n },\n };\n}\n"],"mappings":"2PAkBA,IAAM,GACJ,EACA,EACA,IAEK,GAEL,EACE,MAAa,CACX,EAAM,EAAO,MAAM,EACnB,CACH,CAEM,IARa,GAWhB,GACJ,EACA,EACA,EACA,IAEK,EAAO,WAAW,IAAI,EAEvB,OAAO,GAAa,YACtB,EAAgB,EAAO,EAAI,EAAO,MAAM,EAAE,CAAE,EAAmC,CAAC,CAG3E,IAN6B,GAShC,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CACrB,EAAgB,EAAuB,EAAS,CAAG,EAAW,IAAA,GASpE,OANK,EAFU,EAAwB,EAAS,CAEf,GAAW,EAAY,GAAO,EAAQ,EAAgB,GACpF,EAAW,GAAO,GAGrB,EAAkB,EAAI,EAAK,EAAe,EAAgB,CAEnD,IAGH,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CAO3B,OAJK,EAFU,EAAwB,EAAS,CAEf,GAAU,EAAG,gBAAgB,EAAK,EAAQ,EAAO,CAAE,EAAgB,EAClG,EAAG,gBAAgB,EAAK,EAAQ,EAAU,CAGrC,IAGH,GACJ,EACA,EACA,EACA,IACS,CAGJ,EAFU,EAAwB,EAAS,CAEf,GAAU,EAAQ,EAAI,EAAQ,EAAM,CAAE,EAAgB,EACrF,EAAQ,EAAI,EAAQ,EAAS,EAI3B,GAAc,EAAiB,EAAgB,EAAuB,IAA2C,CACjH,IAAa,IAAA,KAEb,EAAgB,EAAI,EAAQ,EAAU,EAAgB,EAEtD,EAAmB,EAAI,EAAQ,EAAU,EAAgB,EAEzD,EAA2B,EAAI,EAAQ,EAAU,EAAgB,EAErE,EAAoB,EAAI,EAAQ,EAAU,EAAgB,GAY5D,SAAgB,EAAO,EAA6C,CAClE,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAC7B,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAI,CAC5C,EAAW,EAAI,EAAK,EAAO,EAAgB,EAGhD"}
1
+ {"version":3,"file":"spread.js","names":[],"sources":["../../src/directives/spread.ts"],"sourcesContent":["import { effect, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { type Directive, listen, setAttr } from '../internal';\nimport { bindPropertyModel, hasWritableValueSetter, toReactiveBindingSource } from '../runtime-bindings';\n\nexport type SpreadValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | ReadonlySignal<string | number | boolean | null | undefined>\n | (() => string | number | boolean | null | undefined)\n | ((event: Event) => void);\n\ntype RegisterCleanup = (fn: () => void) => void;\n\nconst applyReactiveValue = (\n source: ReadonlySignal<unknown> | undefined,\n apply: (value: unknown) => void,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!source) return false;\n\n registerCleanup(\n effect(() => {\n apply(source.value);\n }),\n );\n\n return true;\n};\n\nconst applyEventEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('@')) return false;\n\n if (typeof rawValue === 'function') {\n registerCleanup(listen(el, rawKey.slice(1), rawValue as (event: Event) => void));\n }\n\n return true;\n};\n\nconst applyPropertyEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('.')) return false;\n\n const key = rawKey.slice(1);\n const writableModel = hasWritableValueSetter(rawValue) ? rawValue : undefined;\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => ((el as any)[key] = value), registerCleanup)) {\n (el as any)[key] = rawValue;\n }\n\n bindPropertyModel(el, key, writableModel, registerCleanup);\n\n return true;\n};\n\nconst applyBooleanAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): boolean => {\n if (!rawKey.startsWith('?')) return false;\n\n const key = rawKey.slice(1);\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => el.toggleAttribute(key, Boolean(value)), registerCleanup)) {\n el.toggleAttribute(key, Boolean(rawValue));\n }\n\n return true;\n};\n\nconst applyAttributeEntry = (\n el: HTMLElement,\n rawKey: string,\n rawValue: SpreadValue,\n registerCleanup: RegisterCleanup,\n): void => {\n const source = toReactiveBindingSource(rawValue);\n\n if (!applyReactiveValue(source, (value) => setAttr(el, rawKey, value), registerCleanup)) {\n setAttr(el, rawKey, rawValue);\n }\n};\n\nconst applyEntry = (el: HTMLElement, rawKey: string, rawValue: SpreadValue, registerCleanup: RegisterCleanup): void => {\n if (rawValue === undefined) return;\n\n if (applyEventEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyPropertyEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n if (applyBooleanAttributeEntry(el, rawKey, rawValue, registerCleanup)) return;\n\n applyAttributeEntry(el, rawKey, rawValue, registerCleanup);\n};\n\n/**\n * Unified spread directive for attributes, properties, and events.\n *\n * Key prefixes:\n * - `name` -> attribute\n * - `?name` -> boolean attribute\n * - `.name` -> DOM property\n * - `@name` -> event listener\n */\nexport function spread(map: Record<string, SpreadValue>): Directive {\n return {\n mount(el, { registerCleanup }) {\n for (const [key, value] of Object.entries(map)) {\n applyEntry(el, key, value, registerCleanup);\n }\n },\n };\n}\n"],"mappings":"oNAiBA,IAAM,GACJ,EACA,EACA,IAEK,GAEL,EACE,MAAa,CACX,EAAM,EAAO,MAAM,EACnB,CACH,CAEM,IARa,GAWhB,GACJ,EACA,EACA,EACA,IAEK,EAAO,WAAW,IAAI,EAEvB,OAAO,GAAa,YACtB,EAAgB,EAAO,EAAI,EAAO,MAAM,EAAE,CAAE,EAAmC,CAAC,CAG3E,IAN6B,GAShC,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CACrB,EAAgB,EAAuB,EAAS,CAAG,EAAW,IAAA,GASpE,OANK,EAFU,EAAwB,EAAS,CAEf,GAAW,EAAY,GAAO,EAAQ,EAAgB,GACpF,EAAW,GAAO,GAGrB,EAAkB,EAAI,EAAK,EAAe,EAAgB,CAEnD,IAGH,GACJ,EACA,EACA,EACA,IACY,CACZ,GAAI,CAAC,EAAO,WAAW,IAAI,CAAE,MAAO,GAEpC,IAAM,EAAM,EAAO,MAAM,EAAE,CAO3B,OAJK,EAFU,EAAwB,EAAS,CAEf,GAAU,EAAG,gBAAgB,EAAK,EAAQ,EAAO,CAAE,EAAgB,EAClG,EAAG,gBAAgB,EAAK,EAAQ,EAAU,CAGrC,IAGH,GACJ,EACA,EACA,EACA,IACS,CAGJ,EAFU,EAAwB,EAAS,CAEf,GAAU,EAAQ,EAAI,EAAQ,EAAM,CAAE,EAAgB,EACrF,EAAQ,EAAI,EAAQ,EAAS,EAI3B,GAAc,EAAiB,EAAgB,EAAuB,IAA2C,CACjH,IAAa,IAAA,KAEb,EAAgB,EAAI,EAAQ,EAAU,EAAgB,EAEtD,EAAmB,EAAI,EAAQ,EAAU,EAAgB,EAEzD,EAA2B,EAAI,EAAQ,EAAU,EAAgB,EAErE,EAAoB,EAAI,EAAQ,EAAU,EAAgB,GAY5D,SAAgB,EAAO,EAA6C,CAClE,MAAO,CACL,MAAM,EAAI,CAAE,mBAAmB,CAC7B,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAI,CAC5C,EAAW,EAAI,EAAK,EAAO,EAAgB,EAGhD"}
@@ -1,2 +1,2 @@
1
- const e=require(`../core/utilities.cjs`);let t=require(`@vielzeug/stateit`);var n=new Set([`animationIterationCount`,`columnCount`,`flex`,`flexGrow`,`flexShrink`,`fontWeight`,`gridColumn`,`gridRow`,`lineHeight`,`opacity`,`order`,`orphans`,`tabSize`,`widows`,`zIndex`]),r=(e,t)=>typeof t==`number`&&!n.has(e)?`${t}px`:String(t);function i(n){let i=Object.entries(n),a=i.some(([,e])=>(0,t.isSignal)(e)||typeof e==`function`),o=()=>{let n=[];for(let[a,o]of i){let i=(0,t.isSignal)(o)?o.value:typeof o==`function`?o():o;i!=null&&i!==``&&n.push(`${e.toKebab(a)}:${r(a,i)}`)}return n.join(`;`)};return a?(0,t.computed)(o):o()}exports.style=i;
1
+ const e=require(`../internal.cjs`);let t=require(`@vielzeug/stateit`);var n=new Set([`animationIterationCount`,`columnCount`,`flex`,`flexGrow`,`flexShrink`,`fontWeight`,`gridColumn`,`gridRow`,`lineHeight`,`opacity`,`order`,`orphans`,`tabSize`,`widows`,`zIndex`]),r=(e,t)=>typeof t==`number`&&!n.has(e)?`${t}px`:String(t);function i(n){let i=Object.entries(n),a=i.some(([,e])=>(0,t.isSignal)(e)||typeof e==`function`),o=()=>{let n=[];for(let[a,o]of i){let i=(0,t.isSignal)(o)?o.value:typeof o==`function`?o():o;i!=null&&i!==``&&n.push(`${e.toKebab(a)}:${r(a,i)}`)}return n.join(`;`)};return a?(0,t.computed)(o):o()}exports.style=i;
2
2
  //# sourceMappingURL=style.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"style.cjs","names":[],"sources":["../../src/directives/style.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { toKebab } from '../core/utilities';\n\ntype StyleValue =\n | string\n | number\n | undefined\n | null\n | Signal<string | number>\n | ReadonlySignal<string | number>\n | (() => string | number | null | undefined);\n\n/** Properties that are unitless — numbers are NOT suffixed with 'px'. */\nconst UNITLESS = new Set([\n 'animationIterationCount',\n 'columnCount',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridColumn',\n 'gridRow',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'widows',\n 'zIndex',\n]);\n\nconst toCssValue = (prop: string, val: string | number): string => {\n if (typeof val === 'number' && !UNITLESS.has(prop)) return `${val}px`;\n\n return String(val);\n};\n\n/**\n * Build a dynamic inline style string from an object map of CSS properties to values.\n * Supports camelCase property names (auto-converted to kebab-case). Number values\n * automatically get a `px` suffix except for unitless properties (opacity, zIndex, etc.).\n *\n * When any value is a reactive Signal or getter function the returned value is a\n * `ReadonlySignal<string>` that updates automatically — no arrow-function wrapper needed.\n *\n * @example\n * import { style } from '@vielzeug/craftit/directives';\n *\n * // Static — returns a plain string\n * html`<div style=${style({ color: 'red', fontSize: 16 })}></div>`\n *\n * // Reactive — returns a signal\n * html`<div style=${style({ fontSize: size, color: theme })}></div>`\n */\nexport function style(map: Record<string, StyleValue>): string | ReadonlySignal<string> {\n const entries = Object.entries(map);\n const hasReactive = entries.some(([, v]) => isSignal(v) || typeof v === 'function');\n\n const build = (): string => {\n const parts: string[] = [];\n\n for (const [k, v] of entries) {\n const raw = isSignal(v)\n ? (v as ReadonlySignal<string | number>).value\n : typeof v === 'function'\n ? (v as () => string | number | null | undefined)()\n : v;\n\n if (raw != null && raw !== '') parts.push(`${toKebab(k)}:${toCssValue(k, raw as string | number)}`);\n }\n\n return parts.join(';');\n };\n\n return hasReactive ? computed(build) : build();\n}\n"],"mappings":"4EAcA,IAAM,EAAW,IAAI,IAAI,CACvB,0BACA,cACA,OACA,WACA,aACA,aACA,aACA,UACA,aACA,UACA,QACA,UACA,UACA,SACA,SACD,CAAC,CAEI,GAAc,EAAc,IAC5B,OAAO,GAAQ,UAAY,CAAC,EAAS,IAAI,EAAK,CAAS,GAAG,EAAI,IAE3D,OAAO,EAAI,CAoBpB,SAAgB,EAAM,EAAkE,CACtF,IAAM,EAAU,OAAO,QAAQ,EAAI,CAC7B,EAAc,EAAQ,MAAM,EAAG,MAAA,EAAA,EAAA,UAAgB,EAAE,EAAI,OAAO,GAAM,WAAW,CAE7E,MAAsB,CAC1B,IAAM,EAAkB,EAAE,CAE1B,IAAK,GAAM,CAAC,EAAG,KAAM,EAAS,CAC5B,IAAM,GAAA,EAAA,EAAA,UAAe,EAAE,CAClB,EAAsC,MACvC,OAAO,GAAM,WACV,GAAgD,CACjD,EAEF,GAAO,MAAQ,IAAQ,IAAI,EAAM,KAAK,GAAG,EAAA,QAAQ,EAAE,CAAC,GAAG,EAAW,EAAG,EAAuB,GAAG,CAGrG,OAAO,EAAM,KAAK,IAAI,EAGxB,OAAO,GAAA,EAAA,EAAA,UAAuB,EAAM,CAAG,GAAO"}
1
+ {"version":3,"file":"style.cjs","names":[],"sources":["../../src/directives/style.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { toKebab } from '../internal';\n\ntype StyleValue =\n | string\n | number\n | undefined\n | null\n | Signal<string | number>\n | ReadonlySignal<string | number>\n | (() => string | number | null | undefined);\n\n/** Properties that are unitless — numbers are NOT suffixed with 'px'. */\nconst UNITLESS = new Set([\n 'animationIterationCount',\n 'columnCount',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridColumn',\n 'gridRow',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'widows',\n 'zIndex',\n]);\n\nconst toCssValue = (prop: string, val: string | number): string => {\n if (typeof val === 'number' && !UNITLESS.has(prop)) return `${val}px`;\n\n return String(val);\n};\n\n/**\n * Build a dynamic inline style string from an object map of CSS properties to values.\n * Supports camelCase property names (auto-converted to kebab-case). Number values\n * automatically get a `px` suffix except for unitless properties (opacity, zIndex, etc.).\n *\n * When any value is a reactive Signal or getter function the returned value is a\n * `ReadonlySignal<string>` that updates automatically — no arrow-function wrapper needed.\n *\n * @example\n * import { style } from '@vielzeug/craftit/directives';\n *\n * // Static — returns a plain string\n * html`<div style=${style({ color: 'red', fontSize: 16 })}></div>`\n *\n * // Reactive — returns a signal\n * html`<div style=${style({ fontSize: size, color: theme })}></div>`\n */\nexport function style(map: Record<string, StyleValue>): string | ReadonlySignal<string> {\n const entries = Object.entries(map);\n const hasReactive = entries.some(([, v]) => isSignal(v) || typeof v === 'function');\n\n const build = (): string => {\n const parts: string[] = [];\n\n for (const [k, v] of entries) {\n const raw = isSignal(v)\n ? (v as ReadonlySignal<string | number>).value\n : typeof v === 'function'\n ? (v as () => string | number | null | undefined)()\n : v;\n\n if (raw != null && raw !== '') parts.push(`${toKebab(k)}:${toCssValue(k, raw as string | number)}`);\n }\n\n return parts.join(';');\n };\n\n return hasReactive ? computed(build) : build();\n}\n"],"mappings":"sEAcA,IAAM,EAAW,IAAI,IAAI,CACvB,0BACA,cACA,OACA,WACA,aACA,aACA,aACA,UACA,aACA,UACA,QACA,UACA,UACA,SACA,SACD,CAAC,CAEI,GAAc,EAAc,IAC5B,OAAO,GAAQ,UAAY,CAAC,EAAS,IAAI,EAAK,CAAS,GAAG,EAAI,IAE3D,OAAO,EAAI,CAoBpB,SAAgB,EAAM,EAAkE,CACtF,IAAM,EAAU,OAAO,QAAQ,EAAI,CAC7B,EAAc,EAAQ,MAAM,EAAG,MAAA,EAAA,EAAA,UAAgB,EAAE,EAAI,OAAO,GAAM,WAAW,CAE7E,MAAsB,CAC1B,IAAM,EAAkB,EAAE,CAE1B,IAAK,GAAM,CAAC,EAAG,KAAM,EAAS,CAC5B,IAAM,GAAA,EAAA,EAAA,UAAe,EAAE,CAClB,EAAsC,MACvC,OAAO,GAAM,WACV,GAAgD,CACjD,EAEF,GAAO,MAAQ,IAAQ,IAAI,EAAM,KAAK,GAAG,EAAA,QAAQ,EAAE,CAAC,GAAG,EAAW,EAAG,EAAuB,GAAG,CAGrG,OAAO,EAAM,KAAK,IAAI,EAGxB,OAAO,GAAA,EAAA,EAAA,UAAuB,EAAM,CAAG,GAAO"}
@@ -1,2 +1,2 @@
1
- import{toKebab as e}from"../core/utilities.js";import{computed as t,isSignal as n}from"@vielzeug/stateit";var r=new Set([`animationIterationCount`,`columnCount`,`flex`,`flexGrow`,`flexShrink`,`fontWeight`,`gridColumn`,`gridRow`,`lineHeight`,`opacity`,`order`,`orphans`,`tabSize`,`widows`,`zIndex`]),i=(e,t)=>typeof t==`number`&&!r.has(e)?`${t}px`:String(t);function a(r){let a=Object.entries(r),o=a.some(([,e])=>n(e)||typeof e==`function`),s=()=>{let t=[];for(let[r,o]of a){let a=n(o)?o.value:typeof o==`function`?o():o;a!=null&&a!==``&&t.push(`${e(r)}:${i(r,a)}`)}return t.join(`;`)};return o?t(s):s()}export{a as style};
1
+ import{toKebab as e}from"../internal.js";import{computed as t,isSignal as n}from"@vielzeug/stateit";var r=new Set([`animationIterationCount`,`columnCount`,`flex`,`flexGrow`,`flexShrink`,`fontWeight`,`gridColumn`,`gridRow`,`lineHeight`,`opacity`,`order`,`orphans`,`tabSize`,`widows`,`zIndex`]),i=(e,t)=>typeof t==`number`&&!r.has(e)?`${t}px`:String(t);function a(r){let a=Object.entries(r),o=a.some(([,e])=>n(e)||typeof e==`function`),s=()=>{let t=[];for(let[r,o]of a){let a=n(o)?o.value:typeof o==`function`?o():o;a!=null&&a!==``&&t.push(`${e(r)}:${i(r,a)}`)}return t.join(`;`)};return o?t(s):s()}export{a as style};
2
2
  //# sourceMappingURL=style.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../src/directives/style.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { toKebab } from '../core/utilities';\n\ntype StyleValue =\n | string\n | number\n | undefined\n | null\n | Signal<string | number>\n | ReadonlySignal<string | number>\n | (() => string | number | null | undefined);\n\n/** Properties that are unitless — numbers are NOT suffixed with 'px'. */\nconst UNITLESS = new Set([\n 'animationIterationCount',\n 'columnCount',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridColumn',\n 'gridRow',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'widows',\n 'zIndex',\n]);\n\nconst toCssValue = (prop: string, val: string | number): string => {\n if (typeof val === 'number' && !UNITLESS.has(prop)) return `${val}px`;\n\n return String(val);\n};\n\n/**\n * Build a dynamic inline style string from an object map of CSS properties to values.\n * Supports camelCase property names (auto-converted to kebab-case). Number values\n * automatically get a `px` suffix except for unitless properties (opacity, zIndex, etc.).\n *\n * When any value is a reactive Signal or getter function the returned value is a\n * `ReadonlySignal<string>` that updates automatically — no arrow-function wrapper needed.\n *\n * @example\n * import { style } from '@vielzeug/craftit/directives';\n *\n * // Static — returns a plain string\n * html`<div style=${style({ color: 'red', fontSize: 16 })}></div>`\n *\n * // Reactive — returns a signal\n * html`<div style=${style({ fontSize: size, color: theme })}></div>`\n */\nexport function style(map: Record<string, StyleValue>): string | ReadonlySignal<string> {\n const entries = Object.entries(map);\n const hasReactive = entries.some(([, v]) => isSignal(v) || typeof v === 'function');\n\n const build = (): string => {\n const parts: string[] = [];\n\n for (const [k, v] of entries) {\n const raw = isSignal(v)\n ? (v as ReadonlySignal<string | number>).value\n : typeof v === 'function'\n ? (v as () => string | number | null | undefined)()\n : v;\n\n if (raw != null && raw !== '') parts.push(`${toKebab(k)}:${toCssValue(k, raw as string | number)}`);\n }\n\n return parts.join(';');\n };\n\n return hasReactive ? computed(build) : build();\n}\n"],"mappings":"0GAcA,IAAM,EAAW,IAAI,IAAI,CACvB,0BACA,cACA,OACA,WACA,aACA,aACA,aACA,UACA,aACA,UACA,QACA,UACA,UACA,SACA,SACD,CAAC,CAEI,GAAc,EAAc,IAC5B,OAAO,GAAQ,UAAY,CAAC,EAAS,IAAI,EAAK,CAAS,GAAG,EAAI,IAE3D,OAAO,EAAI,CAoBpB,SAAgB,EAAM,EAAkE,CACtF,IAAM,EAAU,OAAO,QAAQ,EAAI,CAC7B,EAAc,EAAQ,MAAM,EAAG,KAAO,EAAS,EAAE,EAAI,OAAO,GAAM,WAAW,CAE7E,MAAsB,CAC1B,IAAM,EAAkB,EAAE,CAE1B,IAAK,GAAM,CAAC,EAAG,KAAM,EAAS,CAC5B,IAAM,EAAM,EAAS,EAAE,CAClB,EAAsC,MACvC,OAAO,GAAM,WACV,GAAgD,CACjD,EAEF,GAAO,MAAQ,IAAQ,IAAI,EAAM,KAAK,GAAG,EAAQ,EAAE,CAAC,GAAG,EAAW,EAAG,EAAuB,GAAG,CAGrG,OAAO,EAAM,KAAK,IAAI,EAGxB,OAAO,EAAc,EAAS,EAAM,CAAG,GAAO"}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../src/directives/style.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport { toKebab } from '../internal';\n\ntype StyleValue =\n | string\n | number\n | undefined\n | null\n | Signal<string | number>\n | ReadonlySignal<string | number>\n | (() => string | number | null | undefined);\n\n/** Properties that are unitless — numbers are NOT suffixed with 'px'. */\nconst UNITLESS = new Set([\n 'animationIterationCount',\n 'columnCount',\n 'flex',\n 'flexGrow',\n 'flexShrink',\n 'fontWeight',\n 'gridColumn',\n 'gridRow',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'widows',\n 'zIndex',\n]);\n\nconst toCssValue = (prop: string, val: string | number): string => {\n if (typeof val === 'number' && !UNITLESS.has(prop)) return `${val}px`;\n\n return String(val);\n};\n\n/**\n * Build a dynamic inline style string from an object map of CSS properties to values.\n * Supports camelCase property names (auto-converted to kebab-case). Number values\n * automatically get a `px` suffix except for unitless properties (opacity, zIndex, etc.).\n *\n * When any value is a reactive Signal or getter function the returned value is a\n * `ReadonlySignal<string>` that updates automatically — no arrow-function wrapper needed.\n *\n * @example\n * import { style } from '@vielzeug/craftit/directives';\n *\n * // Static — returns a plain string\n * html`<div style=${style({ color: 'red', fontSize: 16 })}></div>`\n *\n * // Reactive — returns a signal\n * html`<div style=${style({ fontSize: size, color: theme })}></div>`\n */\nexport function style(map: Record<string, StyleValue>): string | ReadonlySignal<string> {\n const entries = Object.entries(map);\n const hasReactive = entries.some(([, v]) => isSignal(v) || typeof v === 'function');\n\n const build = (): string => {\n const parts: string[] = [];\n\n for (const [k, v] of entries) {\n const raw = isSignal(v)\n ? (v as ReadonlySignal<string | number>).value\n : typeof v === 'function'\n ? (v as () => string | number | null | undefined)()\n : v;\n\n if (raw != null && raw !== '') parts.push(`${toKebab(k)}:${toCssValue(k, raw as string | number)}`);\n }\n\n return parts.join(';');\n };\n\n return hasReactive ? computed(build) : build();\n}\n"],"mappings":"oGAcA,IAAM,EAAW,IAAI,IAAI,CACvB,0BACA,cACA,OACA,WACA,aACA,aACA,aACA,UACA,aACA,UACA,QACA,UACA,UACA,SACA,SACD,CAAC,CAEI,GAAc,EAAc,IAC5B,OAAO,GAAQ,UAAY,CAAC,EAAS,IAAI,EAAK,CAAS,GAAG,EAAI,IAE3D,OAAO,EAAI,CAoBpB,SAAgB,EAAM,EAAkE,CACtF,IAAM,EAAU,OAAO,QAAQ,EAAI,CAC7B,EAAc,EAAQ,MAAM,EAAG,KAAO,EAAS,EAAE,EAAI,OAAO,GAAM,WAAW,CAE7E,MAAsB,CAC1B,IAAM,EAAkB,EAAE,CAE1B,IAAK,GAAM,CAAC,EAAG,KAAM,EAAS,CAC5B,IAAM,EAAM,EAAS,EAAE,CAClB,EAAsC,MACvC,OAAO,GAAM,WACV,GAAgD,CACjD,EAEF,GAAO,MAAQ,IAAQ,IAAI,EAAM,KAAK,GAAG,EAAQ,EAAE,CAAC,GAAG,EAAW,EAAG,EAAuB,GAAG,CAGrG,OAAO,EAAM,KAAK,IAAI,EAGxB,OAAO,EAAc,EAAS,EAAM,CAAG,GAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"until.cjs","names":[],"sources":["../../src/directives/until.ts"],"sourcesContent":["import { signal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../core/internal';\n\ntype State = { done: false } | { done: true; value: string | HTMLResult };\n\n/**\n * Renders `pendingFn` while a Promise is pending, then switches to the resolved\n * result. Lighter-weight alternative to `suspense()` for one-shot data loading\n * with no error/retry UI.\n *\n * Returns a reactive getter the engine tracks automatically — no manual signal\n * management needed at the call site.\n *\n * @param promise The promise to await. Should already resolve to a renderable value.\n * @param pendingFn Optional function called while the promise is pending.\n * @param onError Optional function called when the promise rejects. Receives the rejection reason.\n *\n * @example\n * import { until } from '@vielzeug/craftit/directives';\n *\n * const data = fetch('/api/user').then(r => r.json());\n *\n * html`${until(\n * data.then(u => html`<p>Hello, ${u.name}!</p>`),\n * () => html`<p>Loading…</p>`,\n * (err) => html`<p>Error: ${String(err)}</p>`,\n * )}`\n */\nexport function until(\n promise: Promise<string | HTMLResult>,\n pendingFn?: () => string | HTMLResult,\n onError?: (err: unknown) => string | HTMLResult,\n): () => string | HTMLResult {\n const state = signal<State>({ done: false });\n\n promise.then(\n (val) => {\n state.value = { done: true, value: val };\n },\n (err) => {\n if (onError) {\n state.value = { done: true, value: onError(err) };\n } else {\n state.value = { done: true, value: `Error: ${String(err)}` };\n }\n },\n );\n\n return () => (state.value.done ? state.value.value : (pendingFn?.() ?? ''));\n}\n"],"mappings":"mCA6BA,SAAgB,EACd,EACA,EACA,EAC2B,CAC3B,IAAM,GAAA,EAAA,EAAA,QAAsB,CAAE,KAAM,GAAO,CAAC,CAe5C,OAbA,EAAQ,KACL,GAAQ,CACP,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAK,EAEzC,GAAQ,CACH,EACF,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAQ,EAAI,CAAE,CAEjD,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,UAAU,OAAO,EAAI,GAAI,EAGjE,KAEa,EAAM,MAAM,KAAO,EAAM,MAAM,MAAS,KAAa,EAAI"}
1
+ {"version":3,"file":"until.cjs","names":[],"sources":["../../src/directives/until.ts"],"sourcesContent":["import { signal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../internal';\n\ntype State = { done: false } | { done: true; value: string | HTMLResult };\n\n/**\n * Renders `pendingFn` while a Promise is pending, then switches to the resolved\n * result. Lighter-weight alternative to `suspense()` for one-shot data loading\n * with no error/retry UI.\n *\n * Returns a reactive getter the engine tracks automatically — no manual signal\n * management needed at the call site.\n *\n * @param promise The promise to await. Should already resolve to a renderable value.\n * @param pendingFn Optional function called while the promise is pending.\n * @param onError Optional function called when the promise rejects. Receives the rejection reason.\n *\n * @example\n * import { until } from '@vielzeug/craftit/directives';\n *\n * const data = fetch('/api/user').then(r => r.json());\n *\n * html`${until(\n * data.then(u => html`<p>Hello, ${u.name}!</p>`),\n * () => html`<p>Loading…</p>`,\n * (err) => html`<p>Error: ${String(err)}</p>`,\n * )}`\n */\nexport function until(\n promise: Promise<string | HTMLResult>,\n pendingFn?: () => string | HTMLResult,\n onError?: (err: unknown) => string | HTMLResult,\n): () => string | HTMLResult {\n const state = signal<State>({ done: false });\n\n promise.then(\n (val) => {\n state.value = { done: true, value: val };\n },\n (err) => {\n if (onError) {\n state.value = { done: true, value: onError(err) };\n } else {\n state.value = { done: true, value: `Error: ${String(err)}` };\n }\n },\n );\n\n return () => (state.value.done ? state.value.value : (pendingFn?.() ?? ''));\n}\n"],"mappings":"mCA6BA,SAAgB,EACd,EACA,EACA,EAC2B,CAC3B,IAAM,GAAA,EAAA,EAAA,QAAsB,CAAE,KAAM,GAAO,CAAC,CAe5C,OAbA,EAAQ,KACL,GAAQ,CACP,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAK,EAEzC,GAAQ,CACH,EACF,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAQ,EAAI,CAAE,CAEjD,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,UAAU,OAAO,EAAI,GAAI,EAGjE,KAEa,EAAM,MAAM,KAAO,EAAM,MAAM,MAAS,KAAa,EAAI"}
@@ -1,4 +1,4 @@
1
- import type { HTMLResult } from '../core/internal';
1
+ import type { HTMLResult } from '../internal';
2
2
  /**
3
3
  * Renders `pendingFn` while a Promise is pending, then switches to the resolved
4
4
  * result. Lighter-weight alternative to `suspense()` for one-shot data loading
@@ -1 +1 @@
1
- {"version":3,"file":"until.d.ts","sourceRoot":"","sources":["../../src/directives/until.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC,EACrC,SAAS,CAAC,EAAE,MAAM,MAAM,GAAG,UAAU,EACrC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,UAAU,GAC9C,MAAM,MAAM,GAAG,UAAU,CAiB3B"}
1
+ {"version":3,"file":"until.d.ts","sourceRoot":"","sources":["../../src/directives/until.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC,EACrC,SAAS,CAAC,EAAE,MAAM,MAAM,GAAG,UAAU,EACrC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,UAAU,GAC9C,MAAM,MAAM,GAAG,UAAU,CAiB3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"until.js","names":[],"sources":["../../src/directives/until.ts"],"sourcesContent":["import { signal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../core/internal';\n\ntype State = { done: false } | { done: true; value: string | HTMLResult };\n\n/**\n * Renders `pendingFn` while a Promise is pending, then switches to the resolved\n * result. Lighter-weight alternative to `suspense()` for one-shot data loading\n * with no error/retry UI.\n *\n * Returns a reactive getter the engine tracks automatically — no manual signal\n * management needed at the call site.\n *\n * @param promise The promise to await. Should already resolve to a renderable value.\n * @param pendingFn Optional function called while the promise is pending.\n * @param onError Optional function called when the promise rejects. Receives the rejection reason.\n *\n * @example\n * import { until } from '@vielzeug/craftit/directives';\n *\n * const data = fetch('/api/user').then(r => r.json());\n *\n * html`${until(\n * data.then(u => html`<p>Hello, ${u.name}!</p>`),\n * () => html`<p>Loading…</p>`,\n * (err) => html`<p>Error: ${String(err)}</p>`,\n * )}`\n */\nexport function until(\n promise: Promise<string | HTMLResult>,\n pendingFn?: () => string | HTMLResult,\n onError?: (err: unknown) => string | HTMLResult,\n): () => string | HTMLResult {\n const state = signal<State>({ done: false });\n\n promise.then(\n (val) => {\n state.value = { done: true, value: val };\n },\n (err) => {\n if (onError) {\n state.value = { done: true, value: onError(err) };\n } else {\n state.value = { done: true, value: `Error: ${String(err)}` };\n }\n },\n );\n\n return () => (state.value.done ? state.value.value : (pendingFn?.() ?? ''));\n}\n"],"mappings":"2CA6BA,SAAgB,EACd,EACA,EACA,EAC2B,CAC3B,IAAM,EAAQ,EAAc,CAAE,KAAM,GAAO,CAAC,CAe5C,OAbA,EAAQ,KACL,GAAQ,CACP,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAK,EAEzC,GAAQ,CACH,EACF,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAQ,EAAI,CAAE,CAEjD,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,UAAU,OAAO,EAAI,GAAI,EAGjE,KAEa,EAAM,MAAM,KAAO,EAAM,MAAM,MAAS,KAAa,EAAI"}
1
+ {"version":3,"file":"until.js","names":[],"sources":["../../src/directives/until.ts"],"sourcesContent":["import { signal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../internal';\n\ntype State = { done: false } | { done: true; value: string | HTMLResult };\n\n/**\n * Renders `pendingFn` while a Promise is pending, then switches to the resolved\n * result. Lighter-weight alternative to `suspense()` for one-shot data loading\n * with no error/retry UI.\n *\n * Returns a reactive getter the engine tracks automatically — no manual signal\n * management needed at the call site.\n *\n * @param promise The promise to await. Should already resolve to a renderable value.\n * @param pendingFn Optional function called while the promise is pending.\n * @param onError Optional function called when the promise rejects. Receives the rejection reason.\n *\n * @example\n * import { until } from '@vielzeug/craftit/directives';\n *\n * const data = fetch('/api/user').then(r => r.json());\n *\n * html`${until(\n * data.then(u => html`<p>Hello, ${u.name}!</p>`),\n * () => html`<p>Loading…</p>`,\n * (err) => html`<p>Error: ${String(err)}</p>`,\n * )}`\n */\nexport function until(\n promise: Promise<string | HTMLResult>,\n pendingFn?: () => string | HTMLResult,\n onError?: (err: unknown) => string | HTMLResult,\n): () => string | HTMLResult {\n const state = signal<State>({ done: false });\n\n promise.then(\n (val) => {\n state.value = { done: true, value: val };\n },\n (err) => {\n if (onError) {\n state.value = { done: true, value: onError(err) };\n } else {\n state.value = { done: true, value: `Error: ${String(err)}` };\n }\n },\n );\n\n return () => (state.value.done ? state.value.value : (pendingFn?.() ?? ''));\n}\n"],"mappings":"2CA6BA,SAAgB,EACd,EACA,EACA,EAC2B,CAC3B,IAAM,EAAQ,EAAc,CAAE,KAAM,GAAO,CAAC,CAe5C,OAbA,EAAQ,KACL,GAAQ,CACP,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAK,EAEzC,GAAQ,CACH,EACF,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAQ,EAAI,CAAE,CAEjD,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,UAAU,OAAO,EAAI,GAAI,EAGjE,KAEa,EAAM,MAAM,KAAO,EAAM,MAAM,MAAS,KAAa,EAAI"}
@@ -1,2 +1,2 @@
1
- let e=require(`@vielzeug/stateit`);function t(t,n,r){if((0,e.isSignal)(t)||typeof t==`function`){let i=(0,e.isSignal)(t)?()=>t.value:t;return{render:()=>i()?n():r?.()??``}}return t?n():r?.()??``}exports.when=t;
1
+ let e=require(`@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(0,e.isSignal)(i)||typeof i==`function`?{render:s}:s()}var r=t=>(0,e.isSignal)(t)?t.value:typeof t==`function`?t():t;exports.when=n;
2
2
  //# sourceMappingURL=when.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"when.cjs","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport type { Directive, HTMLResult } from '../core/internal';\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(isLoggedIn, () => html`<user-panel>`, () => html`<login-form>`)}`\n * html`${when(() => count.value > 0, () => html`<span>${count}</span>`)}`\n */\nexport function when<V extends string | HTMLResult>(\n condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown),\n thenFn: () => V,\n elseFn?: () => V,\n): Directive;\nexport function when<V extends string | HTMLResult>(condition: unknown, thenFn: () => V, elseFn?: () => V): V | string;\nexport function when<V extends string | HTMLResult>(\n condition: unknown,\n thenFn: () => V,\n elseFn?: () => V,\n): V | string | Directive {\n if (isSignal(condition) || typeof condition === 'function') {\n const get = isSignal(condition) ? () => (condition as ReadonlySignal<unknown>).value : (condition as () => unknown);\n\n return {\n render: (): string | HTMLResult => (get() ? thenFn() : (elseFn?.() ?? '')),\n };\n }\n\n return condition ? thenFn() : (elseFn?.() ?? '');\n}\n"],"mappings":"mCAsBA,SAAgB,EACd,EACA,EACA,EACwB,CACxB,IAAA,EAAA,EAAA,UAAa,EAAU,EAAI,OAAO,GAAc,WAAY,CAC1D,IAAM,GAAA,EAAA,EAAA,UAAe,EAAU,KAAU,EAAsC,MAAS,EAExF,MAAO,CACL,WAAoC,GAAK,CAAG,GAAQ,CAAI,KAAU,EAAI,GACvE,CAGH,OAAO,EAAY,GAAQ,CAAI,KAAU,EAAI"}
1
+ {"version":3,"file":"when.cjs","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":"mCAYA,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,OANA,EAAA,EAAA,UAAa,EAAU,EAAI,OAAO,GAAc,WACvC,CACL,OAAQ,EACT,CAGI,GAAgB,CAGzB,IAAM,EAAkB,IACtB,EAAA,EAAA,UAAa,EAAU,CAAU,EAAsC,MAEnE,OAAO,GAAc,WAAoB,GAA6B,CAEnE"}
@@ -1,5 +1,11 @@
1
1
  import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
2
- import type { Directive, HTMLResult } from '../core/internal';
2
+ import type { Directive, HTMLResult } from '../internal';
3
+ type TemplateFn<V extends string | HTMLResult = string | HTMLResult> = () => V;
4
+ export type WhenOptions<V extends string | HTMLResult = string | HTMLResult> = {
5
+ condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown) | unknown;
6
+ else?: TemplateFn<V> | null;
7
+ then?: TemplateFn<V> | null;
8
+ };
3
9
  /**
4
10
  * Conditionally renders one of two templates based on a condition.
5
11
  *
@@ -9,9 +15,9 @@ import type { Directive, HTMLResult } from '../core/internal';
9
15
  * @example
10
16
  * import { when } from '@vielzeug/craftit/directives';
11
17
  *
12
- * html`${when(isLoggedIn, () => html`<user-panel>`, () => html`<login-form>`)}`
13
- * html`${when(() => count.value > 0, () => html`<span>${count}</span>`)}`
18
+ * html`${when({ condition: isLoggedIn, then: () => html`<user-panel>`, else: () => html`<login-form>` })}`
19
+ * html`${when({ condition: () => count.value > 0, then: () => html`<span>${count}</span>` })}`
14
20
  */
15
- export declare function when<V extends string | HTMLResult>(condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown), thenFn: () => V, elseFn?: () => V): Directive;
16
- export declare function when<V extends string | HTMLResult>(condition: unknown, thenFn: () => V, elseFn?: () => V): V | string;
21
+ export declare function when<V extends string | HTMLResult>(options: WhenOptions<V>): Directive | V | string;
22
+ export {};
17
23
  //# sourceMappingURL=when.d.ts.map
@@ -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,kBAAkB,CAAC;AAE9D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,UAAU,EAChD,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,EACtE,MAAM,EAAE,MAAM,CAAC,EACf,MAAM,CAAC,EAAE,MAAM,CAAC,GACf,SAAS,CAAC;AACb,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC"}
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,2 +1,2 @@
1
- import{isSignal as e}from"@vielzeug/stateit";function t(t,n,r){if(e(t)||typeof t==`function`){let i=e(t)?()=>t.value:t;return{render:()=>i()?n():r?.()??``}}return t?n():r?.()??``}export{t as when};
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};
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 '../core/internal';\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(isLoggedIn, () => html`<user-panel>`, () => html`<login-form>`)}`\n * html`${when(() => count.value > 0, () => html`<span>${count}</span>`)}`\n */\nexport function when<V extends string | HTMLResult>(\n condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown),\n thenFn: () => V,\n elseFn?: () => V,\n): Directive;\nexport function when<V extends string | HTMLResult>(condition: unknown, thenFn: () => V, elseFn?: () => V): V | string;\nexport function when<V extends string | HTMLResult>(\n condition: unknown,\n thenFn: () => V,\n elseFn?: () => V,\n): V | string | Directive {\n if (isSignal(condition) || typeof condition === 'function') {\n const get = isSignal(condition) ? () => (condition as ReadonlySignal<unknown>).value : (condition as () => unknown);\n\n return {\n render: (): string | HTMLResult => (get() ? thenFn() : (elseFn?.() ?? '')),\n };\n }\n\n return condition ? thenFn() : (elseFn?.() ?? '');\n}\n"],"mappings":"6CAsBA,SAAgB,EACd,EACA,EACA,EACwB,CACxB,GAAI,EAAS,EAAU,EAAI,OAAO,GAAc,WAAY,CAC1D,IAAM,EAAM,EAAS,EAAU,KAAU,EAAsC,MAAS,EAExF,MAAO,CACL,WAAoC,GAAK,CAAG,GAAQ,CAAI,KAAU,EAAI,GACvE,CAGH,OAAO,EAAY,GAAQ,CAAI,KAAU,EAAI"}
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"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./directives/spread.cjs`),t=require(`./directives/attr.cjs`),n=require(`./directives/bind.cjs`),r=require(`./directives/choose.cjs`),i=require(`./directives/classes.cjs`),a=require(`./directives/each.cjs`),o=require(`./directives/memo.cjs`),s=require(`./directives/on.cjs`),c=require(`./directives/raw.cjs`),l=require(`./directives/style.cjs`),u=require(`./directives/until.cjs`),d=require(`./directives/when.cjs`);exports.attrs=t.attrs,exports.bind=n.bind,exports.choose=r.choose,exports.classes=i.classes,exports.each=a.each,exports.memo=o.memo,exports.on=s.on,exports.raw=c.raw,exports.spread=e.spread,exports.style=l.style,exports.until=u.until,exports.when=d.when;
@@ -0,0 +1 @@
1
+ import{spread as e}from"./directives/spread.js";import{attrs as t}from"./directives/attr.js";import{bind as n}from"./directives/bind.js";import{choose as r}from"./directives/choose.js";import{classes as i}from"./directives/classes.js";import{each as a}from"./directives/each.js";import{memo as o}from"./directives/memo.js";import{on as s}from"./directives/on.js";import{raw as c}from"./directives/raw.js";import{style as l}from"./directives/style.js";import{until as u}from"./directives/until.js";import{when as d}from"./directives/when.js";export{t as attrs,n as bind,r as choose,i as classes,a as each,o as memo,s as on,c as raw,e as spread,l as style,u as until,d as when};
package/dist/form.cjs ADDED
@@ -0,0 +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;
2
+ //# sourceMappingURL=form.cjs.map
@@ -0,0 +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"}
package/dist/form.d.ts ADDED
@@ -0,0 +1,29 @@
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
+ };
16
+ export type FormFieldOptions<T = unknown> = {
17
+ disabled?: Signal<boolean> | ReadonlySignal<boolean> | ComputedSignal<boolean>;
18
+ toFormValue?: (value: T) => File | FormData | string | null;
19
+ value: Signal<T> | ReadonlySignal<T>;
20
+ };
21
+ export type FormFieldHandle = {
22
+ checkValidity: () => boolean;
23
+ readonly internals: ElementInternals;
24
+ reportValidity: () => boolean;
25
+ setCustomValidity: (message: string) => void;
26
+ setValidity: ElementInternals['setValidity'];
27
+ };
28
+ export declare const defineField: <T = unknown>(options: FormFieldOptions<T>, callbacks?: FormFieldCallbacks) => FormFieldHandle;
29
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +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"}
package/dist/form.js ADDED
@@ -0,0 +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};
2
+ //# sourceMappingURL=form.js.map
@@ -0,0 +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"}
package/dist/host.cjs ADDED
@@ -0,0 +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;
2
+ //# sourceMappingURL=host.cjs.map