@vielzeug/craftit 2.0.1 → 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 -107
  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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","names":[],"sources":["../../src/testing/testing.ts"],"sourcesContent":["/**\n * Testing utilities for Craftit components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n */\n\nimport { define, type ComponentDefinition } from '../component';\nimport { _resetIdCounter } from '../internal';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface Fixture<T extends HTMLElement = HTMLElement> {\n /** The component element */\n element: T;\n /** The component's shadow root */\n readonly shadow: ShadowRoot;\n /** Query a single element within shadow root */\n query<E extends Element = Element>(selector: string): E | null;\n /** Query all elements within shadow root */\n queryAll<E extends Element = Element>(selector: string): E[];\n /** Query the first element whose trimmed text content matches */\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n /** Query all elements whose trimmed text content matches */\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n /** Query a single element by its `data-testid` attribute */\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n /** Query all elements by their `data-testid` attribute */\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n /** Set an attribute (boolean `false` removes it) then flush */\n attr(name: string, value: string | number | boolean): Promise<void>;\n /** Set multiple attributes then flush */\n attrs(record: Record<string, string | number | boolean>): Promise<void>;\n /** Wait for all reactive updates and animation frames */\n flush(): Promise<void>;\n /** Run a callback then flush — the standard way to trigger and assert a reactive update */\n act(fn: () => unknown): Promise<void>;\n /** Remove the component from the DOM */\n destroy(): void;\n}\n\n/** Scoped query helpers for any DOM element — see {@link within} */\nexport interface QueryScope {\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n}\n\nexport interface MountOptions {\n /** Properties assigned directly onto the element */\n props?: Record<string, unknown>;\n /** HTML attributes to set on the element */\n attrs?: Record<string, string | number | boolean>;\n /** Inner HTML for slot content */\n html?: string;\n /** Parent container (default: document.body) */\n container?: HTMLElement;\n /** Extra component options when passing an inline setup function */\n componentOptions?: Omit<ComponentDefinition<any, any>, 'setup'>;\n}\n\ntype TestComponentOptions<\n Props extends Record<string, unknown> = Record<string, never>,\n Events extends Record<string, unknown> = Record<string, unknown>,\n> = Omit<ComponentDefinition<Props, Events>, 'setup'> & Pick<ComponentDefinition<Props, Events>, 'setup'>;\n\nexport interface WaitOptions {\n /** Maximum wait time in ms (default: 1000) */\n timeout?: number;\n /** Polling interval in ms (default: 50) */\n interval?: number;\n /** Message included in timeout error */\n message?: string;\n}\n\n// ─── Test environment state ───────────────────────────────────────────────────\n\nconst _mountedElements: HTMLElement[] = [];\nlet _componentTagCounter = 0;\n\n/**\n * Resets global test counters used for deterministic IDs/markers.\n * @internal\n */\nexport const _resetCounters = (): void => {\n _resetIdCounter();\n};\n\n// ─── Core ────────────────────────────────────────────────────────────────────\n\n/**\n * Flush pending reactive updates.\n * Drains several microtask turns, then yields one animation frame and\n * one final microtask pass for rAF-scheduled work.\n */\nexport async function flush(): Promise<void> {\n const drainMicrotasks = async (turns: number): Promise<void> => {\n for (let i = 0; i < turns; i++) {\n await Promise.resolve();\n await new Promise<void>((resolve) => queueMicrotask(resolve));\n }\n };\n\n await drainMicrotasks(12);\n\n await new Promise<void>((resolve) =>\n typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(() => resolve()) : resolve(),\n );\n\n await drainMicrotasks(2);\n}\n\n/**\n * Register auto-cleanup after each test. Call once in your test setup file.\n *\n * @example\n * // vitest.setup.ts\n * import { afterEach } from 'vitest';\n * import { install } from '@vielzeug/craftit/testing';\n * install(afterEach);\n */\nexport function install(afterEachHook: (fn: () => void) => void): void {\n afterEachHook(cleanup);\n}\n\nfunction applyAttr(element: Element, name: string, value: string | number | boolean): void {\n if (value === false) element.removeAttribute(name);\n else element.setAttribute(name, value === true ? '' : String(value));\n}\n\nconst toError = (value: unknown): Error => {\n return value instanceof Error ? value : new Error(String(value));\n};\n\nconst withWindowErrorCapture = async <T>(action: () => Promise<T>): Promise<T> => {\n if (typeof window === 'undefined') return action();\n\n let captured: Error | null = null;\n const onError = (event: ErrorEvent) => {\n captured = toError(event.error ?? event.message);\n event.preventDefault();\n };\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n captured = toError(event.reason);\n event.preventDefault();\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n\n try {\n const result = await action();\n\n if (captured) throw captured;\n\n return result;\n } finally {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n }\n};\n\n/**\n * Mount a component into the DOM and return a test fixture.\n *\n * Accepts a registered tag name, an inline setup function, or a component\n * options object. Setup functions are auto-registered with generated tag names.\n *\n * @example — inline setup function\n * const { query } = await mount(() => {\n * const count = signal(0);\n * return html`<button @click=${() => count.value++}>${count}</button>`;\n * });\n *\n * @example — registered tag name\n * const { query } = await mount('my-counter');\n */\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: string,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: TestComponentOptions['setup'],\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: TestComponentOptions<any, any>,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: string | TestComponentOptions['setup'] | TestComponentOptions<any, any>,\n options: MountOptions = {},\n): Promise<Fixture<T>> {\n const { attrs = {}, componentOptions, container = document.body, html, props = {} } = options;\n\n let tagName: string;\n let inlineDefinition: TestComponentOptions<any, any> | undefined;\n\n if (typeof tagOrSetupOrOptions === 'string') {\n tagName = tagOrSetupOrOptions;\n } else if (typeof tagOrSetupOrOptions === 'function') {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = {\n ...(componentOptions ?? {}),\n setup: tagOrSetupOrOptions as TestComponentOptions<any, any>['setup'],\n };\n } else {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = tagOrSetupOrOptions;\n }\n\n if (inlineDefinition) {\n define(tagName, inlineDefinition as TestComponentOptions<any, any>);\n }\n\n const element = document.createElement(tagName) as T;\n\n if (html) element.innerHTML = html;\n\n if (Object.keys(props).length) Object.assign(element, props);\n\n for (const [name, value] of Object.entries(attrs)) applyAttr(element, name, value);\n\n await withWindowErrorCapture(async () => {\n container.appendChild(element);\n _mountedElements.push(element);\n await flush();\n });\n\n return {\n async act(fn) {\n await fn();\n await flush();\n },\n\n async attr(name, value) {\n applyAttr(element, name, value);\n await flush();\n },\n\n async attrs(record) {\n for (const [name, value] of Object.entries(record)) applyAttr(element, name, value);\n await flush();\n },\n\n destroy() {\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n },\n element,\n\n flush,\n\n query<E extends Element = Element>(selector: string): E | null {\n return element.shadowRoot?.querySelector<E>(selector) ?? null;\n },\n\n queryAll<E extends Element = Element>(selector: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(selector) ?? []);\n },\n\n queryAllByTestId<E extends Element = Element>(testId: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(`[data-testid=\"${testId}\"]`) ?? []);\n },\n\n queryAllByText<E extends Element = Element>(text: string, selector = '*'): E[] {\n return queryAllByText<E>(element.shadowRoot!, text, selector);\n },\n\n queryByTestId<E extends Element = Element>(testId: string): E | null {\n return element.shadowRoot?.querySelector<E>(`[data-testid=\"${testId}\"]`) ?? null;\n },\n\n queryByText<E extends Element = Element>(text: string, selector = '*'): E | null {\n return queryByText<E>(element.shadowRoot!, text, selector);\n },\n\n get shadow(): ShadowRoot {\n return element.shadowRoot!;\n },\n };\n}\n\n// ─── Scoped queries ───────────────────────────────────────────────────────────\n\nfunction queryByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E | null {\n for (const el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n}\n\nfunction queryAllByText<E extends Element = Element>(root: Element | ShadowRoot, text: string, selector: string): E[] {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n}\n\n/**\n * Create query helpers scoped to any element — useful for slotted/light DOM content.\n *\n * @example\n * const panel = fixture.query('.panel')!;\n * const { query } = within(panel);\n * expect(query('.title')?.textContent).toBe('Hello');\n */\nexport function within(element: Element): QueryScope {\n return {\n query: <E extends Element = Element>(selector: string) => element.querySelector<E>(selector),\n queryAll: <E extends Element = Element>(selector: string) => Array.from(element.querySelectorAll<E>(selector)),\n queryAllByTestId: <E extends Element = Element>(testId: string) =>\n Array.from(element.querySelectorAll<E>(`[data-testid=\"${testId}\"]`)),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(element, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) =>\n element.querySelector<E>(`[data-testid=\"${testId}\"]`),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(element, text, selector),\n };\n}\n\n// ─── Events ──────────────────────────────────────────────────────────────────\n\nconst createPointerEvent = (type: string, init: PointerEventInit = {}): Event => {\n if (typeof PointerEvent !== 'undefined') {\n return new PointerEvent(type, init);\n }\n\n return new MouseEvent(type, init);\n};\n\n/**\n * Fire low-level DOM events synchronously.\n *\n * @example\n * fire.click(button);\n * fire.keyDown(input, { key: 'Enter' });\n * fire.custom(el, 'value-change', 42);\n */\nexport const fire = {\n blur: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('blur', { bubbles: true, ...opts })),\n change: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('change', { bubbles: true, ...opts })),\n click: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, ...opts })),\n custom<D = unknown>(el: Element, name: string, detail?: D, opts?: Omit<CustomEventInit<D>, 'detail'>): void {\n el.dispatchEvent(new CustomEvent<D>(name, { bubbles: true, cancelable: true, detail, ...opts }));\n },\n focus: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('focus', { bubbles: true, ...opts })),\n input: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('input', { bubbles: true, ...opts })),\n keyDown: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...opts })),\n keyUp: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...opts })),\n pointerDown: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerdown', { bubbles: true, cancelable: true, ...opts })),\n pointerEnter: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerenter', { bubbles: false, ...opts })),\n pointerLeave: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerleave', { bubbles: false, ...opts })),\n pointerUp: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerup', { bubbles: true, cancelable: true, ...opts })),\n submit: (el: Element, opts?: EventInit) =>\n el.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true, ...opts })),\n} as const;\n\n// ─── User interactions ────────────────────────────────────────────────────────\n\nconst tick = (): Promise<void> => flush();\n\n/**\n * Higher-level async user interactions that mirror real browser behavior.\n *\n * @example\n * await user.type(input, 'hello');\n * await user.fill(input, 'replacement'); // clear then type\n * await user.click(button);\n * await user.press(input, 'Enter');\n */\nexport const user = {\n async clear(el: HTMLInputElement | HTMLTextAreaElement): Promise<void> {\n el.focus();\n el.value = '';\n fire.input(el);\n fire.change(el);\n await tick();\n },\n async click(el: Element, opts?: PointerEventInit): Promise<void> {\n fire.pointerEnter(el, opts);\n fire.click(el, opts);\n await tick();\n },\n\n async dblClick(el: Element): Promise<void> {\n for (let i = 0; i < 2; i++) {\n fire.pointerDown(el);\n fire.pointerUp(el);\n fire.click(el);\n }\n el.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }));\n await tick();\n },\n\n /** Clear existing value and type new text (select-all-and-replace semantics) */\n async fill(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n el.value = '';\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async hover(el: Element): Promise<void> {\n fire.pointerEnter(el);\n await tick();\n },\n\n /** Dispatch keydown + keyup for a single key */\n async press(el: Element, key: string, opts?: KeyboardEventInit): Promise<void> {\n fire.keyDown(el, { key, ...opts });\n fire.keyUp(el, { key, ...opts });\n await tick();\n },\n\n async select(el: HTMLSelectElement, value: string | string[]): Promise<void> {\n const values = Array.isArray(value) ? value : [value];\n\n for (const opt of el.options) opt.selected = values.includes(opt.value);\n fire.change(el);\n await tick();\n },\n\n /** Type text character-by-character, appending to any existing value */\n async type(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async unhover(el: Element): Promise<void> {\n fire.pointerLeave(el);\n await tick();\n },\n} as const;\n\n// ─── Waiting ─────────────────────────────────────────────────────────────────\n\n/**\n * Poll until a callback returns truthy (or void) without throwing.\n * Supports both boolean conditions and `expect()` assertions.\n *\n * - Returns truthy → success\n * - Returns `undefined` (e.g. bare `expect()` call) → success\n * - Returns falsy value → retry\n * - Throws → retry, re-throw original error on timeout\n *\n * @example\n * await waitFor(() => query('.status')?.textContent === 'loaded');\n * await waitFor(() => expect(count).toBe(3));\n */\nexport async function waitFor(\n fn: () => unknown,\n { interval = 50, message, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n const attempt = async (): Promise<boolean> => {\n try {\n const result = await fn();\n\n return result === undefined || !!result;\n } catch (e) {\n lastError = e;\n\n return false;\n }\n };\n\n while (Date.now() < deadline) {\n if (await attempt()) return;\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n if (await attempt()) return;\n\n const base = message ?? `waitFor timed out after ${timeout}ms`;\n\n if (lastError instanceof Error) {\n lastError.message = `${base}\\n${lastError.message}`;\n throw lastError;\n }\n\n throw new Error(lastError != null ? `${base}\\nCause: ${lastError}` : base);\n}\n\n/**\n * Resolve when the target element emits the given event.\n *\n * @example\n * const promise = waitForEvent(el, 'change');\n * fire.click(trigger);\n * const event = await promise;\n */\nexport function waitForEvent<T extends Event = Event>(element: Element, name: string, timeout = 1000): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`waitForEvent: \"${name}\" timed out after ${timeout}ms`)), timeout);\n\n element.addEventListener(\n name,\n (e) => {\n clearTimeout(timer);\n resolve(e as T);\n },\n { once: true },\n );\n });\n}\n\n// ─── Stubs & cleanup ─────────────────────────────────────────────────────────\n\n/**\n * Register a stub custom element (no-op if already defined).\n *\n * @example\n * mock('child-button', '<slot></slot>');\n */\nexport function mock(tagName: string, template = ''): void {\n if (!customElements.get(tagName)) {\n customElements.define(\n tagName,\n class extends HTMLElement {\n connectedCallback() {\n this.innerHTML = template;\n }\n },\n );\n }\n}\n\n/**\n * Remove all elements mounted via `mount()`.\n * Call in `afterEach` to keep tests isolated.\n *\n * @example\n * afterEach(() => cleanup());\n */\nexport function cleanup(): void {\n for (const el of _mountedElements) el.remove();\n _mountedElements.length = 0;\n}\n"],"mappings":"0FA+EA,IAAM,EAAkC,EAAE,CACtC,EAAuB,EAMd,MAA6B,CACxC,GAAiB,EAUnB,eAAsB,GAAuB,CAC3C,IAAM,EAAkB,KAAO,IAAiC,CAC9D,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,IACzB,MAAM,QAAQ,SAAS,CACvB,MAAM,IAAI,QAAe,GAAY,eAAe,EAAQ,CAAC,EAIjE,MAAM,EAAgB,GAAG,CAEzB,MAAM,IAAI,QAAe,GACvB,OAAO,sBAA0B,IAAc,0BAA4B,GAAS,CAAC,CAAG,GAAS,CAClG,CAED,MAAM,EAAgB,EAAE,CAY1B,SAAgB,EAAQ,EAA+C,CACrE,EAAc,EAAQ,CAGxB,SAAS,EAAU,EAAkB,EAAc,EAAwC,CACrF,IAAU,GAAO,EAAQ,gBAAgB,EAAK,CAC7C,EAAQ,aAAa,EAAM,IAAU,GAAO,GAAK,OAAO,EAAM,CAAC,CAGtE,IAAM,EAAW,GACR,aAAiB,MAAQ,EAAY,MAAM,OAAO,EAAM,CAAC,CAG5D,EAAyB,KAAU,IAAyC,CAChF,GAAI,OAAO,OAAW,IAAa,OAAO,GAAQ,CAElD,IAAI,EAAyB,KACvB,EAAW,GAAsB,CACrC,EAAW,EAAQ,EAAM,OAAS,EAAM,QAAQ,CAChD,EAAM,gBAAgB,EAElB,EAAwB,GAAiC,CAC7D,EAAW,EAAQ,EAAM,OAAO,CAChC,EAAM,gBAAgB,EAGxB,OAAO,iBAAiB,QAAS,EAAQ,CACzC,OAAO,iBAAiB,qBAAsB,EAAqB,CAEnE,GAAI,CACF,IAAM,EAAS,MAAM,GAAQ,CAE7B,GAAI,EAAU,MAAM,EAEpB,OAAO,SACC,CACR,OAAO,oBAAoB,QAAS,EAAQ,CAC5C,OAAO,oBAAoB,qBAAsB,EAAqB,GA+B1E,eAAsB,EACpB,EACA,EAAwB,EAAE,CACL,CACrB,GAAM,CAAE,QAAQ,EAAE,CAAE,mBAAkB,YAAY,SAAS,KAAM,OAAM,QAAQ,EAAE,EAAK,EAElF,EACA,EAEA,OAAO,GAAwB,SACjC,EAAU,EACD,OAAO,GAAwB,YACxC,EAAU,SAAS,EAAE,IACrB,EAAmB,CACjB,GAAI,GAAoB,EAAE,CAC1B,MAAO,EACR,GAED,EAAU,SAAS,EAAE,IACrB,EAAmB,GAGjB,GACF,EAAO,EAAS,EAAmD,CAGrE,IAAM,EAAU,SAAS,cAAc,EAAQ,CAE3C,IAAM,EAAQ,UAAY,GAE1B,OAAO,KAAK,EAAM,CAAC,QAAQ,OAAO,OAAO,EAAS,EAAM,CAE5D,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,EAAM,CAAE,EAAU,EAAS,EAAM,EAAM,CAQlF,OANA,MAAM,EAAuB,SAAY,CACvC,EAAU,YAAY,EAAQ,CAC9B,EAAiB,KAAK,EAAQ,CAC9B,MAAM,GAAO,EACb,CAEK,CACL,MAAM,IAAI,EAAI,CACZ,MAAM,GAAI,CACV,MAAM,GAAO,EAGf,MAAM,KAAK,EAAM,EAAO,CACtB,EAAU,EAAS,EAAM,EAAM,CAC/B,MAAM,GAAO,EAGf,MAAM,MAAM,EAAQ,CAClB,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,EAAO,CAAE,EAAU,EAAS,EAAM,EAAM,CACnF,MAAM,GAAO,EAGf,SAAU,CACR,EAAQ,QAAQ,CAEhB,IAAM,EAAI,EAAiB,QAAQ,EAAQ,CAEvC,IAAM,IAAI,EAAiB,OAAO,EAAG,EAAE,EAE7C,UAEA,QAEA,MAAmC,EAA4B,CAC7D,OAAO,EAAQ,YAAY,cAAiB,EAAS,EAAI,MAG3D,SAAsC,EAAuB,CAC3D,OAAO,MAAM,KAAK,EAAQ,YAAY,iBAAoB,EAAS,EAAI,EAAE,CAAC,EAG5E,iBAA8C,EAAqB,CACjE,OAAO,MAAM,KAAK,EAAQ,YAAY,iBAAoB,iBAAiB,EAAO,IAAI,EAAI,EAAE,CAAC,EAG/F,eAA4C,EAAc,EAAW,IAAU,CAC7E,OAAO,EAAkB,EAAQ,WAAa,EAAM,EAAS,EAG/D,cAA2C,EAA0B,CACnE,OAAO,EAAQ,YAAY,cAAiB,iBAAiB,EAAO,IAAI,EAAI,MAG9E,YAAyC,EAAc,EAAW,IAAe,CAC/E,OAAO,EAAe,EAAQ,WAAa,EAAM,EAAS,EAG5D,IAAI,QAAqB,CACvB,OAAO,EAAQ,YAElB,CAKH,SAAS,EACP,EACA,EACA,EACU,CACV,IAAK,IAAM,KAAM,EAAK,iBAAoB,EAAS,CACjD,GAAI,EAAG,aAAa,MAAM,GAAK,EAAM,OAAO,EAG9C,OAAO,KAGT,SAAS,EAA4C,EAA4B,EAAc,EAAuB,CACpH,OAAO,MAAM,KAAK,EAAK,iBAAoB,EAAS,CAAC,CAAC,OAAQ,GAAO,EAAG,aAAa,MAAM,GAAK,EAAK,CAWvG,SAAgB,EAAO,EAA8B,CACnD,MAAO,CACL,MAAqC,GAAqB,EAAQ,cAAiB,EAAS,CAC5F,SAAwC,GAAqB,MAAM,KAAK,EAAQ,iBAAoB,EAAS,CAAC,CAC9G,iBAAgD,GAC9C,MAAM,KAAK,EAAQ,iBAAoB,iBAAiB,EAAO,IAAI,CAAC,CACtE,gBAA8C,EAAc,EAAW,MACrE,EAAkB,EAAS,EAAM,EAAS,CAC5C,cAA6C,GAC3C,EAAQ,cAAiB,iBAAiB,EAAO,IAAI,CACvD,aAA2C,EAAc,EAAW,MAAQ,EAAe,EAAS,EAAM,EAAS,CACpH,CAKH,IAAM,GAAsB,EAAc,EAAyB,EAAE,GAC/D,OAAO,aAAiB,IACnB,IAAI,aAAa,EAAM,EAAK,CAG9B,IAAI,WAAW,EAAM,EAAK,CAWtB,EAAO,CAClB,MAAO,EAAa,IAA0B,EAAG,cAAc,IAAI,WAAW,OAAQ,CAAE,QAAS,GAAM,GAAG,EAAM,CAAC,CAAC,CAClH,QAAS,EAAa,IAAqB,EAAG,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,GAAM,GAAG,EAAM,CAAC,CAAC,CAC5G,OAAQ,EAAa,IACnB,EAAG,cAAc,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,EAAM,CAAC,CAAC,CACzF,OAAoB,EAAa,EAAc,EAAY,EAAiD,CAC1G,EAAG,cAAc,IAAI,YAAe,EAAM,CAAE,QAAS,GAAM,WAAY,GAAM,SAAQ,GAAG,EAAM,CAAC,CAAC,EAElG,OAAQ,EAAa,IAA0B,EAAG,cAAc,IAAI,WAAW,QAAS,CAAE,QAAS,GAAM,GAAG,EAAM,CAAC,CAAC,CACpH,OAAQ,EAAa,IAAqB,EAAG,cAAc,IAAI,MAAM,QAAS,CAAE,QAAS,GAAM,GAAG,EAAM,CAAC,CAAC,CAC1G,SAAU,EAAa,IACrB,EAAG,cAAc,IAAI,cAAc,UAAW,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,EAAM,CAAC,CAAC,CAC9F,OAAQ,EAAa,IACnB,EAAG,cAAc,IAAI,cAAc,QAAS,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,EAAM,CAAC,CAAC,CAC5F,aAAc,EAAa,IACzB,EAAG,cAAc,EAAmB,cAAe,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,EAAM,CAAC,CAAC,CACnG,cAAe,EAAa,IAC1B,EAAG,cAAc,EAAmB,eAAgB,CAAE,QAAS,GAAO,GAAG,EAAM,CAAC,CAAC,CACnF,cAAe,EAAa,IAC1B,EAAG,cAAc,EAAmB,eAAgB,CAAE,QAAS,GAAO,GAAG,EAAM,CAAC,CAAC,CACnF,WAAY,EAAa,IACvB,EAAG,cAAc,EAAmB,YAAa,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,EAAM,CAAC,CAAC,CACjG,QAAS,EAAa,IACpB,EAAG,cAAc,IAAI,MAAM,SAAU,CAAE,QAAS,GAAM,WAAY,GAAM,GAAG,EAAM,CAAC,CAAC,CACtF,CAIK,MAA4B,GAAO,CAW5B,EAAO,CAClB,MAAM,MAAM,EAA2D,CACrE,EAAG,OAAO,CACV,EAAG,MAAQ,GACX,EAAK,MAAM,EAAG,CACd,EAAK,OAAO,EAAG,CACf,MAAM,GAAM,EAEd,MAAM,MAAM,EAAa,EAAwC,CAC/D,EAAK,aAAa,EAAI,EAAK,CAC3B,EAAK,MAAM,EAAI,EAAK,CACpB,MAAM,GAAM,EAGd,MAAM,SAAS,EAA4B,CACzC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,IACrB,EAAK,YAAY,EAAG,CACpB,EAAK,UAAU,EAAG,CAClB,EAAK,MAAM,EAAG,CAEhB,EAAG,cAAc,IAAI,WAAW,WAAY,CAAE,QAAS,GAAM,WAAY,GAAM,CAAC,CAAC,CACjF,MAAM,GAAM,EAId,MAAM,KAAK,EAA4C,EAA6B,CAClF,EAAG,OAAO,CACV,EAAG,MAAQ,GACX,IAAK,IAAM,KAAQ,EACjB,EAAG,OAAS,EACZ,EAAK,MAAM,EAAG,CACd,EAAK,QAAQ,EAAI,CAAE,IAAK,EAAM,CAAC,CAC/B,EAAK,MAAM,EAAI,CAAE,IAAK,EAAM,CAAC,CAC7B,MAAM,GAAM,CAEd,EAAK,OAAO,EAAG,EAGjB,MAAM,MAAM,EAA4B,CACtC,EAAK,aAAa,EAAG,CACrB,MAAM,GAAM,EAId,MAAM,MAAM,EAAa,EAAa,EAAyC,CAC7E,EAAK,QAAQ,EAAI,CAAE,MAAK,GAAG,EAAM,CAAC,CAClC,EAAK,MAAM,EAAI,CAAE,MAAK,GAAG,EAAM,CAAC,CAChC,MAAM,GAAM,EAGd,MAAM,OAAO,EAAuB,EAAyC,CAC3E,IAAM,EAAS,MAAM,QAAQ,EAAM,CAAG,EAAQ,CAAC,EAAM,CAErD,IAAK,IAAM,KAAO,EAAG,QAAS,EAAI,SAAW,EAAO,SAAS,EAAI,MAAM,CACvE,EAAK,OAAO,EAAG,CACf,MAAM,GAAM,EAId,MAAM,KAAK,EAA4C,EAA6B,CAClF,EAAG,OAAO,CACV,IAAK,IAAM,KAAQ,EACjB,EAAG,OAAS,EACZ,EAAK,MAAM,EAAG,CACd,EAAK,QAAQ,EAAI,CAAE,IAAK,EAAM,CAAC,CAC/B,EAAK,MAAM,EAAI,CAAE,IAAK,EAAM,CAAC,CAC7B,MAAM,GAAM,CAEd,EAAK,OAAO,EAAG,EAGjB,MAAM,QAAQ,EAA4B,CACxC,EAAK,aAAa,EAAG,CACrB,MAAM,GAAM,EAEf,CAiBD,eAAsB,EACpB,EACA,CAAE,WAAW,GAAI,UAAS,UAAU,KAAsB,EAAE,CAC7C,CACf,IAAM,EAAW,KAAK,KAAK,CAAG,EAC1B,EAEE,EAAU,SAA8B,CAC5C,GAAI,CACF,IAAM,EAAS,MAAM,GAAI,CAEzB,OAAO,IAAW,IAAA,IAAa,CAAC,CAAC,QAC1B,EAAG,CAGV,MAFA,GAAY,EAEL,KAIX,KAAO,KAAK,KAAK,CAAG,GAAU,CAC5B,GAAI,MAAM,GAAS,CAAE,OAErB,MAAM,IAAI,QAAS,GAAM,WAAW,EAAG,EAAS,CAAC,CAGnD,GAAI,MAAM,GAAS,CAAE,OAErB,IAAM,EAAO,GAAW,2BAA2B,EAAQ,IAO3D,MALI,aAAqB,OACvB,EAAU,QAAU,GAAG,EAAK,IAAI,EAAU,UACpC,GAGE,MAAM,GAAa,KAAwC,EAAjC,GAAG,EAAK,WAAW,IAAmB,CAW5E,SAAgB,EAAsC,EAAkB,EAAc,EAAU,IAAkB,CAChH,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,IAAM,EAAQ,eAAiB,EAAW,MAAM,kBAAkB,EAAK,oBAAoB,EAAQ,IAAI,CAAC,CAAE,EAAQ,CAElH,EAAQ,iBACN,EACC,GAAM,CACL,aAAa,EAAM,CACnB,EAAQ,EAAO,EAEjB,CAAE,KAAM,GAAM,CACf,EACD,CAWJ,SAAgB,EAAK,EAAiB,EAAW,GAAU,CACpD,eAAe,IAAI,EAAQ,EAC9B,eAAe,OACb,EACA,cAAc,WAAY,CACxB,mBAAoB,CAClB,KAAK,UAAY,IAGtB,CAWL,SAAgB,GAAgB,CAC9B,IAAK,IAAM,KAAM,EAAkB,EAAG,QAAQ,CAC9C,EAAiB,OAAS"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./testing/testing.cjs`);exports._resetCounters=e._resetCounters,exports.cleanup=e.cleanup,exports.fire=e.fire,exports.flush=e.flush,exports.install=e.install,exports.mock=e.mock,exports.mount=e.mount,exports.user=e.user,exports.waitFor=e.waitFor,exports.waitForEvent=e.waitForEvent,exports.within=e.within;
@@ -0,0 +1 @@
1
+ import{_resetCounters as e,cleanup as t,fire as n,flush as r,install as i,mock as a,mount as o,user as s,waitFor as c,waitForEvent as l,within as u}from"./testing/testing.js";export{e as _resetCounters,t as cleanup,n as fire,r as flush,i as install,a as mock,o as mount,s as user,c as waitFor,l as waitForEvent,u as within};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vielzeug/craftit",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -15,11 +15,17 @@
15
15
  "import": "./dist/index.js",
16
16
  "require": "./dist/index.cjs"
17
17
  },
18
- "./labs": {
19
- "source": "./src/labs/index.ts",
20
- "types": "./dist/labs/index.d.ts",
21
- "import": "./dist/labs.js",
22
- "require": "./dist/labs.cjs"
18
+ "./controls": {
19
+ "source": "./src/controls/index.ts",
20
+ "types": "./dist/controls/index.d.ts",
21
+ "import": "./dist/controls.js",
22
+ "require": "./dist/controls.cjs"
23
+ },
24
+ "./observers": {
25
+ "source": "./src/observers/index.ts",
26
+ "types": "./dist/observers/index.d.ts",
27
+ "import": "./dist/observers.js",
28
+ "require": "./dist/observers.cjs"
23
29
  },
24
30
  "./directives": {
25
31
  "source": "./src/directives/index.ts",
@@ -27,11 +33,11 @@
27
33
  "import": "./dist/directives/index.js",
28
34
  "require": "./dist/directives/index.cjs"
29
35
  },
30
- "./test": {
31
- "source": "./src/test/index.ts",
32
- "types": "./dist/test/index.d.ts",
33
- "import": "./dist/test.js",
34
- "require": "./dist/test.cjs"
36
+ "./testing": {
37
+ "source": "./src/testing/index.ts",
38
+ "types": "./dist/testing/index.d.ts",
39
+ "import": "./dist/testing.js",
40
+ "require": "./dist/testing.cjs"
35
41
  }
36
42
  },
37
43
  "scripts": {
@@ -55,9 +61,8 @@
55
61
  "devDependencies": {
56
62
  "@types/node": "^25.5.0",
57
63
  "jsdom": "^29.0.1",
58
- "terser": "^5.46.1",
59
64
  "typescript": "~6.0.2",
60
- "vite": "^8.0.2",
61
- "vitest": "^4.1.1"
65
+ "vite": "^8.0.3",
66
+ "vitest": "^4.1.2"
62
67
  }
63
68
  }
@@ -1,2 +0,0 @@
1
- const e=require(`./internal.cjs`),t=require(`./runtime-lifecycle.cjs`),n=require(`./utilities.cjs`),r=require(`./host.cjs`),i=require(`./template-dom.cjs`);require(`./template-bindings.cjs`),require(`./template-html.cjs`);const a=require(`./template.cjs`);let o=require(`@vielzeug/stateit`);var s=new WeakMap,c=new WeakMap,l=(e,n)=>{let r=t.currentRuntime().el;if(!r.constructor.formAssociated)throw Error(`[craftit:E8] defineField() requires defineComponent({ formAssociated: true })`);let i=c.get(r)??r.attachInternals();c.set(r,i);let a=e.toFormValue??(e=>e==null?``:String(e));return(0,o.effect)(()=>{i.setFormValue(a(e.value.value))}),e.disabled&&(0,o.effect)(()=>{e.disabled.value?i.states.add(`disabled`):i.states.delete(`disabled`)}),n&&s.set(r,{...s.get(r),...n}),{checkValidity:()=>i.checkValidity(),internals:i,reportValidity:()=>i.reportValidity(),setCustomValidity:e=>e?i.setValidity({customError:!0},e):i.setValidity({}),setValidity:i.setValidity.bind(i)}},u=new Set([`default`,`omit`,`parse`,`reflect`,`type`]),d=e=>typeof e!=`object`||!e||!(`default`in e)?!1:Object.keys(e).every(e=>u.has(e)),f=new WeakMap,p=(e,r,i)=>{let a=t.currentRuntime(),s=a.el;f.has(s)||f.set(s,new Map);let c=i?.parse??(e=>i?.type===Boolean?e===``||e===`true`:typeof r==`boolean`?e!==null&&e!==`false`:e==null?r:i?.type===Number||typeof r==`number`?Number(e):e),l=(0,o.signal)(r),u=Object.prototype.hasOwnProperty.call(s,e),d=u?s[e]:void 0,p={parse:c,reflect:i?.reflect??!0,signal:l};if(u?(delete s[e],l.value=d):s.hasAttribute(e)&&(l.value=c(s.getAttribute(e))),f.get(s).set(e,p),Object.defineProperty(s,e,{configurable:!0,enumerable:!0,get:()=>l.value,set:e=>{l.value=e}}),i?.reflect??!0){let t=i?.omit??!1;a.onMount.push(()=>{a.cleanups.push((0,o.effect)(()=>{let r=l.value;r==null||r===!1||t&&r===``?s.removeAttribute(e):n.setAttr(s,e,r)}))})}return l};function m(e){let t={};for(let[r,i]of Object.entries(e)){let e=d(i)?i:{default:i},a={reflect:!(typeof e.default==`object`&&e.default!==null||Array.isArray(e.default)),...e};t[r]=p(n.toKebab(r),e.default,a)}return t}var h=(e,t)=>({...t,default:e}),g=class extends HTMLElement{static _setup;static _options;static formAssociated=!1;static observedAttributes=[];shadow;_keyedStates=new Map;_mountFns=[];_template=null;_appliedHtmlBindings=new Set;_setupDone=!1;_runtime;constructor(){super();let e=this.constructor._options;this.shadow=this.attachShadow({mode:`open`,...e?.shadow}),this._runtime={cleanups:[],el:this,errorHandlers:[],onMount:[],styles:e?.styles}}connectedCallback(){this._setupDone||this._runSetup(),this._init()}attributeChangedCallback(e,t,n){if(t===n)return;let r=f.get(this)?.get(e);if(!r)return;let i=r.parse(n);Object.is(r.signal.peek(),i)||(r.signal.value=i)}disconnectedCallback(){n.runAll(this._runtime.cleanups),this._runtime.cleanups=[],this._runtime.onMount=this._mountFns.slice(),this._appliedHtmlBindings.clear(),this._keyedStates.clear()}formAssociatedCallback(e){s.get(this)?.onAssociated?.(e)}formDisabledCallback(e){s.get(this)?.onDisabled?.(e)}formResetCallback(){s.get(this)?.onReset?.()}formStateRestoreCallback(e,t){s.get(this)?.onStateRestore?.(e,t)}_handleError(e){if(this._runtime.errorHandlers.length>0)for(let t of this._runtime.errorHandlers)t(e);else console.error(`[craftit:E3] <${this.localName}>`,e)}_runSetup(){this._setupDone=!0,t.runtimeStack.push(this._runtime);try{let{host:e}=this.constructor._options??{};if(e)for(let[t,n]of Object.entries(e))typeof n==`boolean`?n?this.setAttribute(t,``):this.removeAttribute(t):this.setAttribute(t,String(n));let t=this.constructor._setup({host:this,shadow:this.shadow});(typeof t==`string`||typeof t==`object`&&t&&`__html`in t)&&(this._template=t)}catch(e){this._handleError(e)}finally{t.runtimeStack.pop()}}_init(){let{styles:r}=this._runtime;if(r?.length&&(this.shadow.adoptedStyleSheets=r.map(n.loadStylesheet)),this._template){let t=typeof this._template==`string`?e.htmlResult(this._template):this._template;if(this.shadow.replaceChildren(i.parseHTML(t.__html)),t.__bindings.length){let e=e=>this._runtime.cleanups.push(e);a.applyBindingsInContainer(this.shadow,t.__bindings,e,{onHtml:t=>{this._appliedHtmlBindings.has(t.uid)||(this._appliedHtmlBindings.add(t.uid),a.applyHtmlBinding(this.shadow,t,e,this._keyedStates))}})}}queueMicrotask(()=>{t.runtimeStack.push(this._runtime);try{let e=this._runtime.onMount;this._mountFns=e.slice();for(let t of e){let e=t();typeof e==`function`&&this._runtime.cleanups.push(e)}}catch(e){this._handleError(e)}finally{t.runtimeStack.pop(),this._runtime.onMount=[]}})}};function _(e,t,n={}){if(!e)throw Error(`[craftit:E4] registerComponent(tag, ...) requires a tag name`);if(customElements.get(e))throw Error(`[craftit:E9] custom element already defined: ${e}`);class r extends g{static _setup=t;static _options=n;static formAssociated=n.formAssociated??!1;static observedAttributes=n.observedAttrs??[]}return customElements.define(e,r),e}function v(e){let{formAssociated:t,host:i,props:a,setup:o,shadow:s,styles:c,tag:l}=e;return _(l,e=>{let t=a?m(a):{},i=n.createEmitFn(),s=r.createSlots();return o({emit:i,host:e.host,props:t,reflect:t=>r.reflect(e.host,t),shadow:e.shadow,slots:s})},{formAssociated:t,host:i,observedAttrs:a?Object.keys(a).map(n.toKebab):[],shadow:s,styles:c})}exports.defineComponent=v,exports.defineField=l,exports.prop=p,exports.propRegistry=f,exports.typed=h;
2
- //# sourceMappingURL=component.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"component.cjs","names":[],"sources":["../../src/core/component.ts"],"sourcesContent":["/**\n * Component authoring API — define, props, lifecycle, and form field functionality.\n *\n * - defineComponent: Main API for building typed custom elements\n * - prop/typed/createProps: Reactive property definitions\n * - defineField: Form field integration\n */\n\nimport {\n type CleanupFn,\n type ComputedSignal,\n type ReadonlySignal,\n type Signal,\n signal,\n effect,\n} from '@vielzeug/stateit';\n\nimport { createSlots, type Slots, type ReflectConfig } from './host';\nimport { reflect } from './host';\nimport { type HTMLResult, htmlResult } from './internal';\nimport { currentRuntime, runtimeStack } from './runtime-lifecycle';\nimport { applyBindingsInContainer, applyHtmlBinding } from './template';\nimport { type RegisterCleanup } from './template-bindings';\nimport { parseHTML } from './template-dom';\nimport { type KeyedNode } from './template-html';\nimport { createEmitFn, type EmitFn, setAttr, toKebab, runAll, loadStylesheet, type CSSResult } from './utilities';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FORM FIELD API\n// ─────────────────────────────────────────────────────────────────────────────\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 {@link 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 defineComponent({ 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 if (options.disabled) {\n effect(() => {\n if (options.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\n// ─────────────────────────────────────────────────────────────────────────────\n// PROP SYSTEM\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype PropType<T> = T extends string\n ? StringConstructor\n : T extends number\n ? NumberConstructor\n : T extends boolean\n ? BooleanConstructor\n : T extends unknown[]\n ? ArrayConstructor\n : ObjectConstructor;\n\nexport type PropOptions<T> = {\n /** When `true`, removes the host attribute instead of setting it to `\"\"` when the value is an empty string. */\n omit?: boolean;\n parse?: (value: string | null) => T;\n reflect?: boolean;\n type?: PropType<T>;\n};\n\nexport type PropDef<T> = PropOptions<T> & { default: T };\nexport type PropInputDefs = Record<string, unknown | PropDef<unknown>>;\n\ntype PropMeta<T = unknown> = {\n parse: (value: string | null) => T;\n reflect: boolean;\n signal: Signal<T>;\n};\n\nconst PROP_DEF_KEYS = new Set(['default', 'omit', 'parse', 'reflect', 'type']);\nconst isPropDef = (value: unknown): value is PropDef<unknown> => {\n if (typeof value !== 'object' || value === null || !('default' in value)) return false;\n\n return Object.keys(value).every((key) => PROP_DEF_KEYS.has(key));\n};\n\nexport const propRegistry = new WeakMap<object, Map<string, PropMeta<unknown>>>();\n\nexport const prop = <T>(name: string, defaultValue: T, options?: PropOptions<T>): Signal<T> => {\n const rt = currentRuntime();\n const el = rt.el;\n\n if (!propRegistry.has(el)) propRegistry.set(el, new Map());\n\n const parse =\n options?.parse ??\n ((v: string | null): T => {\n // Explicit Boolean type: string values 'true' / '' → boolean\n if (options?.type === Boolean) return (v === '' || v === 'true') as T;\n\n // Boolean default: treat absent or explicit \"false\" as false, anything else as true.\n // This handles frameworks (e.g. Vue) that set the attribute to the string \"false\"\n // when a reactive binding evaluates to false, rather than removing the attribute.\n if (typeof defaultValue === 'boolean') return (v !== null && v !== 'false') as T;\n\n if (v == null) return defaultValue;\n\n // Numeric — inferred from an explicit type option or default value type\n if (options?.type === Number || typeof defaultValue === 'number') return Number(v) as T;\n\n return v as unknown as T;\n });\n const s = signal<T>(defaultValue);\n const hasPreUpgradeProperty = Object.prototype.hasOwnProperty.call(el, name);\n const preUpgradeValue = hasPreUpgradeProperty ? (el as unknown as Record<string, unknown>)[name] : undefined;\n\n const meta = {\n parse,\n reflect: options?.reflect ?? true,\n signal: s as Signal<unknown>,\n };\n\n // Prefer pre-upgrade property values set before defineProperty() (common for\n // framework/host property bindings), then fall back to attributes.\n if (hasPreUpgradeProperty) {\n delete (el as unknown as Record<string, unknown>)[name];\n s.value = preUpgradeValue as T;\n } else if (el.hasAttribute(name)) {\n s.value = parse(el.getAttribute(name)) as T;\n }\n\n propRegistry.get(el)!.set(name, meta);\n\n Object.defineProperty(el, name, {\n configurable: true,\n enumerable: true,\n get: () => s.value,\n set: (value: T) => {\n s.value = value;\n },\n });\n\n if (options?.reflect ?? true) {\n const omit = options?.omit ?? false;\n\n rt.onMount.push(() => {\n rt.cleanups.push(\n effect(() => {\n const v = s.value;\n\n if (v == null || v === false || (omit && v === '')) {\n el.removeAttribute(name);\n } else {\n setAttr(el, name, v);\n }\n }),\n );\n });\n }\n\n return s;\n};\n\ntype InferPropValue<T> = T extends object\n ? Exclude<keyof T, keyof PropDef<unknown>> extends never\n ? T extends PropDef<infer U>\n ? U\n : T\n : T\n : T;\n\nexport type InferPropsSignals<T extends PropInputDefs> = {\n [K in keyof T]: Signal<InferPropValue<T[K]>>;\n};\n\nexport function createProps<D extends PropInputDefs>(defs: D): InferPropsSignals<D> {\n const result = {} as Record<string, Signal<unknown>>;\n\n for (const [name, def] of Object.entries(defs)) {\n const descriptor = isPropDef(def) ? (def as PropDef<unknown>) : { default: def };\n const hasStructuredDefault =\n (typeof descriptor.default === 'object' && descriptor.default !== null) || Array.isArray(descriptor.default);\n const propDef: PropOptions<unknown> = { reflect: !hasStructuredDefault, ...descriptor };\n\n result[name] = prop(toKebab(name), descriptor.default, propDef);\n }\n\n return result as InferPropsSignals<D>;\n}\n\n/**\n * Forces TypeScript to infer the prop signal type from `T` rather than the default\n * value's literal type. Use in `defineComponent({ props: ... })` when the default\n * is `undefined` or when you want an explicit union type.\n *\n * @example\n * defineComponent<ButtonProps>({\n * props: {\n * color: typed<ThemeColor | undefined>(undefined),\n * disabled: { default: false },\n * },\n * setup({ props }) {\n * return html`<button>${props.color}</button>`;\n * },\n * tag: 'x-button',\n * });\n */\nexport const typed = <T>(defaultValue: T, options?: PropOptions<T>): PropDef<T> => ({\n ...options,\n default: defaultValue,\n});\n\n// ─────────────────────────────────────────────────────────────────────────────\n// COMPONENT SETUP & REGISTRATION\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type ComponentSetupContext = {\n /** The host `HTMLElement` instance for this component. */\n host: HTMLElement;\n /** Shorthand for `host.shadowRoot` — the component's open shadow root. */\n shadow: ShadowRoot;\n};\n\nexport type ComponentRegistrationOptions = {\n /** Indicates if this should be a form-associated element */\n formAssociated?: boolean;\n /** Custom options for host element (e.g. for aria-*) */\n host?: Record<string, string | boolean | number>;\n /** @internal — list of attribute names to observe via attributeChangedCallback */\n observedAttrs?: string[];\n /** Shadow root init options (mode is always 'open') — use e.g. `{ delegatesFocus: true }` for form controls */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles applied to the shadow root. Static — set at definition time, not per-render. */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\n/**\n * Helper type to build a prop schema from a props interface type.\n * Each property maps to a PropOptions shape with a `default` value.\n */\nexport type BuildPropSchema<T> = {\n [K in keyof T]-?: PropDef<T[K]>;\n};\n\n/**\n * Unified setup context passed to `defineComponent` setup function.\n * Both Props and Events generics flow through to give full type safety.\n */\nexport type DefineComponentSetupContext<\n P extends Record<string, PropOptions<any>> = Record<string, never>,\n E extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Typed emit function — fully inferred from the Events generic */\n emit: EmitFn<E>;\n /** Host element */\n host: HTMLElement;\n /** Reactive props as signals — fully inferred from the Props generic */\n props: InferPropsSignals<P>;\n /** Reflect reactive attributes, events and classes to the host */\n reflect: (config: ReflectConfig) => void;\n /** Shadow root */\n shadow: ShadowRoot;\n /** Slots helper */\n slots: Slots<any>;\n};\n\n/**\n * Configuration object for `defineComponent()`.\n * Note: no `emits` field — declare events via the Events generic instead.\n */\nexport type DefineComponentOptions<\n PropsSchema extends Record<string, PropDef<any>> = Record<string, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Whether this element is form-associated */\n formAssociated?: boolean;\n /** Host element attributes */\n host?: Record<string, string | boolean | number>;\n /** Property definitions */\n props?: PropsSchema;\n /** Setup function — returns a template */\n setup: (ctx: DefineComponentSetupContext<PropsSchema, Emits>) => string | HTMLResult;\n /** Shadow root init options */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n /** Custom element tag name (must include a hyphen) */\n tag: string;\n};\n\n// ─── Base custom element ──────────────────────────────────────────────────────\n\ntype ComponentRuntime = {\n cleanups: CleanupFn[];\n el: HTMLElement;\n errorHandlers: Array<(err: unknown) => void>;\n onMount: Array<() => CleanupFn | undefined | void>;\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\n// Lifecycle methods (connectedCallback, attributeChangedCallback, …) are invoked\n// by the browser runtime, not TypeScript code — suppress false-positive lint warnings.\n\nclass BaseElement extends HTMLElement {\n static _setup: (ctx: ComponentSetupContext) => string | HTMLResult;\n static _options?: ComponentRegistrationOptions;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n shadow: ShadowRoot;\n private _keyedStates = new Map<string, Map<string | number, KeyedNode>>();\n private _mountFns: (() => CleanupFn | undefined | void)[] = [];\n private _template: string | HTMLResult | null = null;\n private _appliedHtmlBindings = new Set<string>();\n private _setupDone = false;\n private _runtime: ComponentRuntime;\n\n constructor() {\n super();\n\n const options = (this.constructor as typeof BaseElement)._options;\n\n this.shadow = this.attachShadow({ mode: 'open', ...options?.shadow });\n this._runtime = {\n cleanups: [],\n el: this,\n errorHandlers: [],\n onMount: [],\n styles: options?.styles,\n };\n }\n\n connectedCallback(): void {\n if (!this._setupDone) this._runSetup();\n\n this._init();\n }\n\n // Fires synchronously on observed attribute change — no MutationObserver needed.\n // observedAttributes is set at class-definition time from the prop schema.\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const meta = propRegistry.get(this)?.get(name);\n\n if (!meta) return;\n\n const parsed = meta.parse(newValue);\n\n if (!Object.is(meta.signal.peek(), parsed)) meta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n runAll(this._runtime.cleanups);\n this._runtime.cleanups = [];\n this._runtime.onMount = this._mountFns.slice(); // restore for reconnect\n this._appliedHtmlBindings.clear();\n this._keyedStates.clear();\n }\n\n formAssociatedCallback(form: HTMLFormElement | null): void {\n formCallbackRegistry.get(this)?.onAssociated?.(form);\n }\n\n formDisabledCallback(disabled: boolean): void {\n formCallbackRegistry.get(this)?.onDisabled?.(disabled);\n }\n\n formResetCallback(): void {\n formCallbackRegistry.get(this)?.onReset?.();\n }\n\n formStateRestoreCallback(state: unknown, mode: 'autocomplete' | 'restore'): void {\n formCallbackRegistry.get(this)?.onStateRestore?.(state, mode);\n }\n\n private _handleError(err: unknown): void {\n if (this._runtime.errorHandlers.length > 0) {\n for (const fn of this._runtime.errorHandlers) fn(err);\n } else {\n console.error(`[craftit:E3] <${this.localName}>`, err);\n }\n }\n\n private _runSetup(): void {\n this._setupDone = true;\n runtimeStack.push(this._runtime as any);\n\n try {\n const { host: hostOptions } = (this.constructor as typeof BaseElement)._options ?? {};\n\n if (hostOptions) {\n for (const [name, value] of Object.entries(hostOptions)) {\n if (typeof value === 'boolean') {\n if (value) {\n this.setAttribute(name, '');\n } else {\n this.removeAttribute(name);\n }\n } else {\n this.setAttribute(name, String(value));\n }\n }\n }\n\n const res = (this.constructor as typeof BaseElement)._setup({ host: this, shadow: this.shadow });\n\n if (typeof res === 'string' || (typeof res === 'object' && res !== null && '__html' in res)) {\n this._template = res as string | HTMLResult;\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n }\n }\n\n private _init(): void {\n const { styles } = this._runtime;\n\n // Apply styles synchronously before rendering to prevent FOUC.\n if (styles?.length) this.shadow.adoptedStyleSheets = styles.map(loadStylesheet);\n\n if (this._template) {\n const result: HTMLResult = typeof this._template === 'string' ? htmlResult(this._template) : this._template;\n\n this.shadow.replaceChildren(parseHTML(result.__html));\n\n if (result.__bindings.length) {\n const registerCleanup: RegisterCleanup = (fn) => this._runtime.cleanups.push(fn);\n\n applyBindingsInContainer(this.shadow, result.__bindings, registerCleanup, {\n onHtml: (b) => {\n if (!this._appliedHtmlBindings.has(b.uid)) {\n this._appliedHtmlBindings.add(b.uid);\n applyHtmlBinding(this.shadow, b, registerCleanup, this._keyedStates);\n }\n },\n });\n }\n }\n\n // Defer onMount callbacks to a microtask for deterministic timing.\n // Components that depend on layout/paint should schedule rAF inside onMount.\n queueMicrotask(() => {\n runtimeStack.push(this._runtime as any);\n\n try {\n const fns = this._runtime.onMount;\n\n this._mountFns = fns.slice(); // snapshot for reconnect\n\n for (const fn of fns) {\n const cleanup = fn();\n\n if (typeof cleanup === 'function') this._runtime.cleanups.push(cleanup);\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n this._runtime.onMount = [];\n }\n });\n }\n}\n\n// ─── Component registration ───────────────────────────────────────────────────\n\n/** @internal — use `defineComponent` instead. */\nexport function registerComponent(\n tag: string,\n setup: (ctx: ComponentSetupContext) => string | HTMLResult,\n options: ComponentRegistrationOptions = {},\n): string {\n if (!tag) throw new Error('[craftit:E4] registerComponent(tag, ...) requires a tag name');\n\n if (customElements.get(tag)) {\n throw new Error(`[craftit:E9] custom element already defined: ${tag}`);\n }\n\n class Element extends BaseElement {\n static override _setup = setup;\n static override _options = options;\n static override formAssociated = options.formAssociated ?? false;\n static override observedAttributes = options.observedAttrs ?? [];\n }\n\n customElements.define(tag, Element);\n\n return tag;\n}\n\n/**\n * Defines a custom element with a cohesive, type-safe API.\n *\n * Pass your Props and Events interfaces as generics — everything in `setup`\n * is fully typed with zero boilerplate.\n *\n * @example\n * ```ts\n * type MyProps = { checked?: boolean; disabled?: boolean };\n * type MyEvents = { change: { checked: boolean } };\n *\n * defineComponent<MyProps, MyEvents>({\n * tag: 'my-checkbox',\n * props: {\n * checked: { default: false },\n * disabled: { default: false },\n * },\n * setup({ props, emit }) {\n * // props.checked → Signal<boolean> ✅\n * // emit('change', { checked: true }) ✅\n * },\n * });\n * ```\n */\nexport function defineComponent<\n PropsType = Record<string, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n>(options: DefineComponentOptions<BuildPropSchema<PropsType>, EventsType>): string {\n const { formAssociated, host: hostOptions, props: propDefs, setup, shadow: shadowOptions, styles, tag } = options;\n\n // Derive observed attribute names from prop schema at definition time so\n // attributeChangedCallback fires correctly — no MutationObserver needed.\n const observedAttrs = propDefs ? Object.keys(propDefs).map(toKebab) : [];\n\n return registerComponent(\n tag,\n (ctx) => {\n const props = propDefs\n ? createProps(propDefs as BuildPropSchema<PropsType>)\n : ({} as InferPropsSignals<BuildPropSchema<PropsType>>);\n const emit = createEmitFn<EventsType>();\n const slots = createSlots<any>();\n\n return setup({\n emit: emit as EmitFn<EventsType>,\n host: ctx.host,\n props,\n reflect: (config: ReflectConfig) => reflect(ctx.host, config),\n shadow: ctx.shadow,\n slots,\n } as DefineComponentSetupContext<BuildPropSchema<PropsType>, EventsType>);\n },\n { formAssociated, host: hostOptions, observedAttrs, shadow: shadowOptions, styles },\n );\n}\n"],"mappings":"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"}
@@ -1,172 +0,0 @@
1
- /**
2
- * Component authoring API — define, props, lifecycle, and form field functionality.
3
- *
4
- * - defineComponent: Main API for building typed custom elements
5
- * - prop/typed/createProps: Reactive property definitions
6
- * - defineField: Form field integration
7
- */
8
- import { type ComputedSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';
9
- import { type Slots, type ReflectConfig } from './host';
10
- import { type HTMLResult } from './internal';
11
- import { type EmitFn, type CSSResult } from './utilities';
12
- /** @internal */
13
- export declare const formCallbackRegistry: WeakMap<HTMLElement, FormFieldCallbacks>;
14
- /** @internal */
15
- export declare const internalsRegistry: WeakMap<HTMLElement, ElementInternals>;
16
- /**
17
- * Callbacks that hook into form lifecycle events. Can be passed directly to {@link defineField}
18
- * as a second argument to keep all form logic co-located.
19
- */
20
- export type FormFieldCallbacks = {
21
- onAssociated?: (form: HTMLFormElement | null) => void;
22
- onDisabled?: (disabled: boolean) => void;
23
- onReset?: () => void;
24
- onStateRestore?: (state: unknown, mode: 'autocomplete' | 'restore') => void;
25
- };
26
- export type FormFieldOptions<T = unknown> = {
27
- disabled?: Signal<boolean> | ReadonlySignal<boolean> | ComputedSignal<boolean>;
28
- toFormValue?: (value: T) => File | FormData | string | null;
29
- value: Signal<T> | ReadonlySignal<T>;
30
- };
31
- export type FormFieldHandle = {
32
- checkValidity: () => boolean;
33
- readonly internals: ElementInternals;
34
- reportValidity: () => boolean;
35
- setCustomValidity: (message: string) => void;
36
- setValidity: ElementInternals['setValidity'];
37
- };
38
- export declare const defineField: <T = unknown>(options: FormFieldOptions<T>, callbacks?: FormFieldCallbacks) => FormFieldHandle;
39
- type PropType<T> = T extends string ? StringConstructor : T extends number ? NumberConstructor : T extends boolean ? BooleanConstructor : T extends unknown[] ? ArrayConstructor : ObjectConstructor;
40
- export type PropOptions<T> = {
41
- /** When `true`, removes the host attribute instead of setting it to `""` when the value is an empty string. */
42
- omit?: boolean;
43
- parse?: (value: string | null) => T;
44
- reflect?: boolean;
45
- type?: PropType<T>;
46
- };
47
- export type PropDef<T> = PropOptions<T> & {
48
- default: T;
49
- };
50
- export type PropInputDefs = Record<string, unknown | PropDef<unknown>>;
51
- type PropMeta<T = unknown> = {
52
- parse: (value: string | null) => T;
53
- reflect: boolean;
54
- signal: Signal<T>;
55
- };
56
- export declare const propRegistry: WeakMap<object, Map<string, PropMeta<unknown>>>;
57
- export declare const prop: <T>(name: string, defaultValue: T, options?: PropOptions<T>) => Signal<T>;
58
- type InferPropValue<T> = T extends object ? Exclude<keyof T, keyof PropDef<unknown>> extends never ? T extends PropDef<infer U> ? U : T : T : T;
59
- export type InferPropsSignals<T extends PropInputDefs> = {
60
- [K in keyof T]: Signal<InferPropValue<T[K]>>;
61
- };
62
- export declare function createProps<D extends PropInputDefs>(defs: D): InferPropsSignals<D>;
63
- /**
64
- * Forces TypeScript to infer the prop signal type from `T` rather than the default
65
- * value's literal type. Use in `defineComponent({ props: ... })` when the default
66
- * is `undefined` or when you want an explicit union type.
67
- *
68
- * @example
69
- * defineComponent<ButtonProps>({
70
- * props: {
71
- * color: typed<ThemeColor | undefined>(undefined),
72
- * disabled: { default: false },
73
- * },
74
- * setup({ props }) {
75
- * return html`<button>${props.color}</button>`;
76
- * },
77
- * tag: 'x-button',
78
- * });
79
- */
80
- export declare const typed: <T>(defaultValue: T, options?: PropOptions<T>) => PropDef<T>;
81
- export type ComponentSetupContext = {
82
- /** The host `HTMLElement` instance for this component. */
83
- host: HTMLElement;
84
- /** Shorthand for `host.shadowRoot` — the component's open shadow root. */
85
- shadow: ShadowRoot;
86
- };
87
- export type ComponentRegistrationOptions = {
88
- /** Indicates if this should be a form-associated element */
89
- formAssociated?: boolean;
90
- /** Custom options for host element (e.g. for aria-*) */
91
- host?: Record<string, string | boolean | number>;
92
- /** @internal — list of attribute names to observe via attributeChangedCallback */
93
- observedAttrs?: string[];
94
- /** Shadow root init options (mode is always 'open') — use e.g. `{ delegatesFocus: true }` for form controls */
95
- shadow?: Omit<ShadowRootInit, 'mode'>;
96
- /** Component styles applied to the shadow root. Static — set at definition time, not per-render. */
97
- styles?: (string | CSSStyleSheet | CSSResult)[];
98
- };
99
- /**
100
- * Helper type to build a prop schema from a props interface type.
101
- * Each property maps to a PropOptions shape with a `default` value.
102
- */
103
- export type BuildPropSchema<T> = {
104
- [K in keyof T]-?: PropDef<T[K]>;
105
- };
106
- /**
107
- * Unified setup context passed to `defineComponent` setup function.
108
- * Both Props and Events generics flow through to give full type safety.
109
- */
110
- export type DefineComponentSetupContext<P extends Record<string, PropOptions<any>> = Record<string, never>, E extends Record<string, unknown> = Record<string, never>> = {
111
- /** Typed emit function — fully inferred from the Events generic */
112
- emit: EmitFn<E>;
113
- /** Host element */
114
- host: HTMLElement;
115
- /** Reactive props as signals — fully inferred from the Props generic */
116
- props: InferPropsSignals<P>;
117
- /** Reflect reactive attributes, events and classes to the host */
118
- reflect: (config: ReflectConfig) => void;
119
- /** Shadow root */
120
- shadow: ShadowRoot;
121
- /** Slots helper */
122
- slots: Slots<any>;
123
- };
124
- /**
125
- * Configuration object for `defineComponent()`.
126
- * Note: no `emits` field — declare events via the Events generic instead.
127
- */
128
- export type DefineComponentOptions<PropsSchema extends Record<string, PropDef<any>> = Record<string, never>, Emits extends Record<string, unknown> = Record<string, never>> = {
129
- /** Whether this element is form-associated */
130
- formAssociated?: boolean;
131
- /** Host element attributes */
132
- host?: Record<string, string | boolean | number>;
133
- /** Property definitions */
134
- props?: PropsSchema;
135
- /** Setup function — returns a template */
136
- setup: (ctx: DefineComponentSetupContext<PropsSchema, Emits>) => string | HTMLResult;
137
- /** Shadow root init options */
138
- shadow?: Omit<ShadowRootInit, 'mode'>;
139
- /** Component styles */
140
- styles?: (string | CSSStyleSheet | CSSResult)[];
141
- /** Custom element tag name (must include a hyphen) */
142
- tag: string;
143
- };
144
- /** @internal — use `defineComponent` instead. */
145
- export declare function registerComponent(tag: string, setup: (ctx: ComponentSetupContext) => string | HTMLResult, options?: ComponentRegistrationOptions): string;
146
- /**
147
- * Defines a custom element with a cohesive, type-safe API.
148
- *
149
- * Pass your Props and Events interfaces as generics — everything in `setup`
150
- * is fully typed with zero boilerplate.
151
- *
152
- * @example
153
- * ```ts
154
- * type MyProps = { checked?: boolean; disabled?: boolean };
155
- * type MyEvents = { change: { checked: boolean } };
156
- *
157
- * defineComponent<MyProps, MyEvents>({
158
- * tag: 'my-checkbox',
159
- * props: {
160
- * checked: { default: false },
161
- * disabled: { default: false },
162
- * },
163
- * setup({ props, emit }) {
164
- * // props.checked → Signal<boolean> ✅
165
- * // emit('change', { checked: true }) ✅
166
- * },
167
- * });
168
- * ```
169
- */
170
- export declare function defineComponent<PropsType = Record<string, never>, EventsType extends Record<string, unknown> = Record<string, never>>(options: DefineComponentOptions<BuildPropSchema<PropsType>, EventsType>): string;
171
- export {};
172
- //# sourceMappingURL=component.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/core/component.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{htmlResult as e}from"./internal.js";import{currentRuntime as t,runtimeStack as n}from"./runtime-lifecycle.js";import{createEmitFn as r,loadStylesheet as i,runAll as a,setAttr as o,toKebab as s}from"./utilities.js";import{createSlots as c,reflect as l}from"./host.js";import{parseHTML as u}from"./template-dom.js";import"./template-bindings.js";import"./template-html.js";import{applyBindingsInContainer as d,applyHtmlBinding as f}from"./template.js";import{effect as p,signal as m}from"@vielzeug/stateit";var h=new WeakMap,g=new WeakMap,_=(e,n)=>{let r=t().el;if(!r.constructor.formAssociated)throw Error(`[craftit:E8] defineField() requires defineComponent({ formAssociated: true })`);let i=g.get(r)??r.attachInternals();g.set(r,i);let a=e.toFormValue??(e=>e==null?``:String(e));return p(()=>{i.setFormValue(a(e.value.value))}),e.disabled&&p(()=>{e.disabled.value?i.states.add(`disabled`):i.states.delete(`disabled`)}),n&&h.set(r,{...h.get(r),...n}),{checkValidity:()=>i.checkValidity(),internals:i,reportValidity:()=>i.reportValidity(),setCustomValidity:e=>e?i.setValidity({customError:!0},e):i.setValidity({}),setValidity:i.setValidity.bind(i)}},v=new Set([`default`,`omit`,`parse`,`reflect`,`type`]),y=e=>typeof e!=`object`||!e||!(`default`in e)?!1:Object.keys(e).every(e=>v.has(e)),b=new WeakMap,x=(e,n,r)=>{let i=t(),a=i.el;b.has(a)||b.set(a,new Map);let s=r?.parse??(e=>r?.type===Boolean?e===``||e===`true`:typeof n==`boolean`?e!==null&&e!==`false`:e==null?n:r?.type===Number||typeof n==`number`?Number(e):e),c=m(n),l=Object.prototype.hasOwnProperty.call(a,e),u=l?a[e]:void 0,d={parse:s,reflect:r?.reflect??!0,signal:c};if(l?(delete a[e],c.value=u):a.hasAttribute(e)&&(c.value=s(a.getAttribute(e))),b.get(a).set(e,d),Object.defineProperty(a,e,{configurable:!0,enumerable:!0,get:()=>c.value,set:e=>{c.value=e}}),r?.reflect??!0){let t=r?.omit??!1;i.onMount.push(()=>{i.cleanups.push(p(()=>{let n=c.value;n==null||n===!1||t&&n===``?a.removeAttribute(e):o(a,e,n)}))})}return c};function S(e){let t={};for(let[n,r]of Object.entries(e)){let e=y(r)?r:{default:r},i={reflect:!(typeof e.default==`object`&&e.default!==null||Array.isArray(e.default)),...e};t[n]=x(s(n),e.default,i)}return t}var C=(e,t)=>({...t,default:e}),w=class extends HTMLElement{static _setup;static _options;static formAssociated=!1;static observedAttributes=[];shadow;_keyedStates=new Map;_mountFns=[];_template=null;_appliedHtmlBindings=new Set;_setupDone=!1;_runtime;constructor(){super();let e=this.constructor._options;this.shadow=this.attachShadow({mode:`open`,...e?.shadow}),this._runtime={cleanups:[],el:this,errorHandlers:[],onMount:[],styles:e?.styles}}connectedCallback(){this._setupDone||this._runSetup(),this._init()}attributeChangedCallback(e,t,n){if(t===n)return;let r=b.get(this)?.get(e);if(!r)return;let i=r.parse(n);Object.is(r.signal.peek(),i)||(r.signal.value=i)}disconnectedCallback(){a(this._runtime.cleanups),this._runtime.cleanups=[],this._runtime.onMount=this._mountFns.slice(),this._appliedHtmlBindings.clear(),this._keyedStates.clear()}formAssociatedCallback(e){h.get(this)?.onAssociated?.(e)}formDisabledCallback(e){h.get(this)?.onDisabled?.(e)}formResetCallback(){h.get(this)?.onReset?.()}formStateRestoreCallback(e,t){h.get(this)?.onStateRestore?.(e,t)}_handleError(e){if(this._runtime.errorHandlers.length>0)for(let t of this._runtime.errorHandlers)t(e);else console.error(`[craftit:E3] <${this.localName}>`,e)}_runSetup(){this._setupDone=!0,n.push(this._runtime);try{let{host:e}=this.constructor._options??{};if(e)for(let[t,n]of Object.entries(e))typeof n==`boolean`?n?this.setAttribute(t,``):this.removeAttribute(t):this.setAttribute(t,String(n));let t=this.constructor._setup({host:this,shadow:this.shadow});(typeof t==`string`||typeof t==`object`&&t&&`__html`in t)&&(this._template=t)}catch(e){this._handleError(e)}finally{n.pop()}}_init(){let{styles:t}=this._runtime;if(t?.length&&(this.shadow.adoptedStyleSheets=t.map(i)),this._template){let t=typeof this._template==`string`?e(this._template):this._template;if(this.shadow.replaceChildren(u(t.__html)),t.__bindings.length){let e=e=>this._runtime.cleanups.push(e);d(this.shadow,t.__bindings,e,{onHtml:t=>{this._appliedHtmlBindings.has(t.uid)||(this._appliedHtmlBindings.add(t.uid),f(this.shadow,t,e,this._keyedStates))}})}}queueMicrotask(()=>{n.push(this._runtime);try{let e=this._runtime.onMount;this._mountFns=e.slice();for(let t of e){let e=t();typeof e==`function`&&this._runtime.cleanups.push(e)}}catch(e){this._handleError(e)}finally{n.pop(),this._runtime.onMount=[]}})}};function T(e,t,n={}){if(!e)throw Error(`[craftit:E4] registerComponent(tag, ...) requires a tag name`);if(customElements.get(e))throw Error(`[craftit:E9] custom element already defined: ${e}`);class r extends w{static _setup=t;static _options=n;static formAssociated=n.formAssociated??!1;static observedAttributes=n.observedAttrs??[]}return customElements.define(e,r),e}function E(e){let{formAssociated:t,host:n,props:i,setup:a,shadow:o,styles:u,tag:d}=e;return T(d,e=>{let t=i?S(i):{},n=r(),o=c();return a({emit:n,host:e.host,props:t,reflect:t=>l(e.host,t),shadow:e.shadow,slots:o})},{formAssociated:t,host:n,observedAttrs:i?Object.keys(i).map(s):[],shadow:o,styles:u})}export{E as defineComponent,_ as defineField,x as prop,b as propRegistry,C as typed};
2
- //# sourceMappingURL=component.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"component.js","names":[],"sources":["../../src/core/component.ts"],"sourcesContent":["/**\n * Component authoring API — define, props, lifecycle, and form field functionality.\n *\n * - defineComponent: Main API for building typed custom elements\n * - prop/typed/createProps: Reactive property definitions\n * - defineField: Form field integration\n */\n\nimport {\n type CleanupFn,\n type ComputedSignal,\n type ReadonlySignal,\n type Signal,\n signal,\n effect,\n} from '@vielzeug/stateit';\n\nimport { createSlots, type Slots, type ReflectConfig } from './host';\nimport { reflect } from './host';\nimport { type HTMLResult, htmlResult } from './internal';\nimport { currentRuntime, runtimeStack } from './runtime-lifecycle';\nimport { applyBindingsInContainer, applyHtmlBinding } from './template';\nimport { type RegisterCleanup } from './template-bindings';\nimport { parseHTML } from './template-dom';\nimport { type KeyedNode } from './template-html';\nimport { createEmitFn, type EmitFn, setAttr, toKebab, runAll, loadStylesheet, type CSSResult } from './utilities';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FORM FIELD API\n// ─────────────────────────────────────────────────────────────────────────────\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 {@link 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 defineComponent({ 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 if (options.disabled) {\n effect(() => {\n if (options.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\n// ─────────────────────────────────────────────────────────────────────────────\n// PROP SYSTEM\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype PropType<T> = T extends string\n ? StringConstructor\n : T extends number\n ? NumberConstructor\n : T extends boolean\n ? BooleanConstructor\n : T extends unknown[]\n ? ArrayConstructor\n : ObjectConstructor;\n\nexport type PropOptions<T> = {\n /** When `true`, removes the host attribute instead of setting it to `\"\"` when the value is an empty string. */\n omit?: boolean;\n parse?: (value: string | null) => T;\n reflect?: boolean;\n type?: PropType<T>;\n};\n\nexport type PropDef<T> = PropOptions<T> & { default: T };\nexport type PropInputDefs = Record<string, unknown | PropDef<unknown>>;\n\ntype PropMeta<T = unknown> = {\n parse: (value: string | null) => T;\n reflect: boolean;\n signal: Signal<T>;\n};\n\nconst PROP_DEF_KEYS = new Set(['default', 'omit', 'parse', 'reflect', 'type']);\nconst isPropDef = (value: unknown): value is PropDef<unknown> => {\n if (typeof value !== 'object' || value === null || !('default' in value)) return false;\n\n return Object.keys(value).every((key) => PROP_DEF_KEYS.has(key));\n};\n\nexport const propRegistry = new WeakMap<object, Map<string, PropMeta<unknown>>>();\n\nexport const prop = <T>(name: string, defaultValue: T, options?: PropOptions<T>): Signal<T> => {\n const rt = currentRuntime();\n const el = rt.el;\n\n if (!propRegistry.has(el)) propRegistry.set(el, new Map());\n\n const parse =\n options?.parse ??\n ((v: string | null): T => {\n // Explicit Boolean type: string values 'true' / '' → boolean\n if (options?.type === Boolean) return (v === '' || v === 'true') as T;\n\n // Boolean default: treat absent or explicit \"false\" as false, anything else as true.\n // This handles frameworks (e.g. Vue) that set the attribute to the string \"false\"\n // when a reactive binding evaluates to false, rather than removing the attribute.\n if (typeof defaultValue === 'boolean') return (v !== null && v !== 'false') as T;\n\n if (v == null) return defaultValue;\n\n // Numeric — inferred from an explicit type option or default value type\n if (options?.type === Number || typeof defaultValue === 'number') return Number(v) as T;\n\n return v as unknown as T;\n });\n const s = signal<T>(defaultValue);\n const hasPreUpgradeProperty = Object.prototype.hasOwnProperty.call(el, name);\n const preUpgradeValue = hasPreUpgradeProperty ? (el as unknown as Record<string, unknown>)[name] : undefined;\n\n const meta = {\n parse,\n reflect: options?.reflect ?? true,\n signal: s as Signal<unknown>,\n };\n\n // Prefer pre-upgrade property values set before defineProperty() (common for\n // framework/host property bindings), then fall back to attributes.\n if (hasPreUpgradeProperty) {\n delete (el as unknown as Record<string, unknown>)[name];\n s.value = preUpgradeValue as T;\n } else if (el.hasAttribute(name)) {\n s.value = parse(el.getAttribute(name)) as T;\n }\n\n propRegistry.get(el)!.set(name, meta);\n\n Object.defineProperty(el, name, {\n configurable: true,\n enumerable: true,\n get: () => s.value,\n set: (value: T) => {\n s.value = value;\n },\n });\n\n if (options?.reflect ?? true) {\n const omit = options?.omit ?? false;\n\n rt.onMount.push(() => {\n rt.cleanups.push(\n effect(() => {\n const v = s.value;\n\n if (v == null || v === false || (omit && v === '')) {\n el.removeAttribute(name);\n } else {\n setAttr(el, name, v);\n }\n }),\n );\n });\n }\n\n return s;\n};\n\ntype InferPropValue<T> = T extends object\n ? Exclude<keyof T, keyof PropDef<unknown>> extends never\n ? T extends PropDef<infer U>\n ? U\n : T\n : T\n : T;\n\nexport type InferPropsSignals<T extends PropInputDefs> = {\n [K in keyof T]: Signal<InferPropValue<T[K]>>;\n};\n\nexport function createProps<D extends PropInputDefs>(defs: D): InferPropsSignals<D> {\n const result = {} as Record<string, Signal<unknown>>;\n\n for (const [name, def] of Object.entries(defs)) {\n const descriptor = isPropDef(def) ? (def as PropDef<unknown>) : { default: def };\n const hasStructuredDefault =\n (typeof descriptor.default === 'object' && descriptor.default !== null) || Array.isArray(descriptor.default);\n const propDef: PropOptions<unknown> = { reflect: !hasStructuredDefault, ...descriptor };\n\n result[name] = prop(toKebab(name), descriptor.default, propDef);\n }\n\n return result as InferPropsSignals<D>;\n}\n\n/**\n * Forces TypeScript to infer the prop signal type from `T` rather than the default\n * value's literal type. Use in `defineComponent({ props: ... })` when the default\n * is `undefined` or when you want an explicit union type.\n *\n * @example\n * defineComponent<ButtonProps>({\n * props: {\n * color: typed<ThemeColor | undefined>(undefined),\n * disabled: { default: false },\n * },\n * setup({ props }) {\n * return html`<button>${props.color}</button>`;\n * },\n * tag: 'x-button',\n * });\n */\nexport const typed = <T>(defaultValue: T, options?: PropOptions<T>): PropDef<T> => ({\n ...options,\n default: defaultValue,\n});\n\n// ─────────────────────────────────────────────────────────────────────────────\n// COMPONENT SETUP & REGISTRATION\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type ComponentSetupContext = {\n /** The host `HTMLElement` instance for this component. */\n host: HTMLElement;\n /** Shorthand for `host.shadowRoot` — the component's open shadow root. */\n shadow: ShadowRoot;\n};\n\nexport type ComponentRegistrationOptions = {\n /** Indicates if this should be a form-associated element */\n formAssociated?: boolean;\n /** Custom options for host element (e.g. for aria-*) */\n host?: Record<string, string | boolean | number>;\n /** @internal — list of attribute names to observe via attributeChangedCallback */\n observedAttrs?: string[];\n /** Shadow root init options (mode is always 'open') — use e.g. `{ delegatesFocus: true }` for form controls */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles applied to the shadow root. Static — set at definition time, not per-render. */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\n/**\n * Helper type to build a prop schema from a props interface type.\n * Each property maps to a PropOptions shape with a `default` value.\n */\nexport type BuildPropSchema<T> = {\n [K in keyof T]-?: PropDef<T[K]>;\n};\n\n/**\n * Unified setup context passed to `defineComponent` setup function.\n * Both Props and Events generics flow through to give full type safety.\n */\nexport type DefineComponentSetupContext<\n P extends Record<string, PropOptions<any>> = Record<string, never>,\n E extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Typed emit function — fully inferred from the Events generic */\n emit: EmitFn<E>;\n /** Host element */\n host: HTMLElement;\n /** Reactive props as signals — fully inferred from the Props generic */\n props: InferPropsSignals<P>;\n /** Reflect reactive attributes, events and classes to the host */\n reflect: (config: ReflectConfig) => void;\n /** Shadow root */\n shadow: ShadowRoot;\n /** Slots helper */\n slots: Slots<any>;\n};\n\n/**\n * Configuration object for `defineComponent()`.\n * Note: no `emits` field — declare events via the Events generic instead.\n */\nexport type DefineComponentOptions<\n PropsSchema extends Record<string, PropDef<any>> = Record<string, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Whether this element is form-associated */\n formAssociated?: boolean;\n /** Host element attributes */\n host?: Record<string, string | boolean | number>;\n /** Property definitions */\n props?: PropsSchema;\n /** Setup function — returns a template */\n setup: (ctx: DefineComponentSetupContext<PropsSchema, Emits>) => string | HTMLResult;\n /** Shadow root init options */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component styles */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n /** Custom element tag name (must include a hyphen) */\n tag: string;\n};\n\n// ─── Base custom element ──────────────────────────────────────────────────────\n\ntype ComponentRuntime = {\n cleanups: CleanupFn[];\n el: HTMLElement;\n errorHandlers: Array<(err: unknown) => void>;\n onMount: Array<() => CleanupFn | undefined | void>;\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\n// Lifecycle methods (connectedCallback, attributeChangedCallback, …) are invoked\n// by the browser runtime, not TypeScript code — suppress false-positive lint warnings.\n\nclass BaseElement extends HTMLElement {\n static _setup: (ctx: ComponentSetupContext) => string | HTMLResult;\n static _options?: ComponentRegistrationOptions;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n shadow: ShadowRoot;\n private _keyedStates = new Map<string, Map<string | number, KeyedNode>>();\n private _mountFns: (() => CleanupFn | undefined | void)[] = [];\n private _template: string | HTMLResult | null = null;\n private _appliedHtmlBindings = new Set<string>();\n private _setupDone = false;\n private _runtime: ComponentRuntime;\n\n constructor() {\n super();\n\n const options = (this.constructor as typeof BaseElement)._options;\n\n this.shadow = this.attachShadow({ mode: 'open', ...options?.shadow });\n this._runtime = {\n cleanups: [],\n el: this,\n errorHandlers: [],\n onMount: [],\n styles: options?.styles,\n };\n }\n\n connectedCallback(): void {\n if (!this._setupDone) this._runSetup();\n\n this._init();\n }\n\n // Fires synchronously on observed attribute change — no MutationObserver needed.\n // observedAttributes is set at class-definition time from the prop schema.\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n const meta = propRegistry.get(this)?.get(name);\n\n if (!meta) return;\n\n const parsed = meta.parse(newValue);\n\n if (!Object.is(meta.signal.peek(), parsed)) meta.signal.value = parsed as never;\n }\n\n disconnectedCallback(): void {\n runAll(this._runtime.cleanups);\n this._runtime.cleanups = [];\n this._runtime.onMount = this._mountFns.slice(); // restore for reconnect\n this._appliedHtmlBindings.clear();\n this._keyedStates.clear();\n }\n\n formAssociatedCallback(form: HTMLFormElement | null): void {\n formCallbackRegistry.get(this)?.onAssociated?.(form);\n }\n\n formDisabledCallback(disabled: boolean): void {\n formCallbackRegistry.get(this)?.onDisabled?.(disabled);\n }\n\n formResetCallback(): void {\n formCallbackRegistry.get(this)?.onReset?.();\n }\n\n formStateRestoreCallback(state: unknown, mode: 'autocomplete' | 'restore'): void {\n formCallbackRegistry.get(this)?.onStateRestore?.(state, mode);\n }\n\n private _handleError(err: unknown): void {\n if (this._runtime.errorHandlers.length > 0) {\n for (const fn of this._runtime.errorHandlers) fn(err);\n } else {\n console.error(`[craftit:E3] <${this.localName}>`, err);\n }\n }\n\n private _runSetup(): void {\n this._setupDone = true;\n runtimeStack.push(this._runtime as any);\n\n try {\n const { host: hostOptions } = (this.constructor as typeof BaseElement)._options ?? {};\n\n if (hostOptions) {\n for (const [name, value] of Object.entries(hostOptions)) {\n if (typeof value === 'boolean') {\n if (value) {\n this.setAttribute(name, '');\n } else {\n this.removeAttribute(name);\n }\n } else {\n this.setAttribute(name, String(value));\n }\n }\n }\n\n const res = (this.constructor as typeof BaseElement)._setup({ host: this, shadow: this.shadow });\n\n if (typeof res === 'string' || (typeof res === 'object' && res !== null && '__html' in res)) {\n this._template = res as string | HTMLResult;\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n }\n }\n\n private _init(): void {\n const { styles } = this._runtime;\n\n // Apply styles synchronously before rendering to prevent FOUC.\n if (styles?.length) this.shadow.adoptedStyleSheets = styles.map(loadStylesheet);\n\n if (this._template) {\n const result: HTMLResult = typeof this._template === 'string' ? htmlResult(this._template) : this._template;\n\n this.shadow.replaceChildren(parseHTML(result.__html));\n\n if (result.__bindings.length) {\n const registerCleanup: RegisterCleanup = (fn) => this._runtime.cleanups.push(fn);\n\n applyBindingsInContainer(this.shadow, result.__bindings, registerCleanup, {\n onHtml: (b) => {\n if (!this._appliedHtmlBindings.has(b.uid)) {\n this._appliedHtmlBindings.add(b.uid);\n applyHtmlBinding(this.shadow, b, registerCleanup, this._keyedStates);\n }\n },\n });\n }\n }\n\n // Defer onMount callbacks to a microtask for deterministic timing.\n // Components that depend on layout/paint should schedule rAF inside onMount.\n queueMicrotask(() => {\n runtimeStack.push(this._runtime as any);\n\n try {\n const fns = this._runtime.onMount;\n\n this._mountFns = fns.slice(); // snapshot for reconnect\n\n for (const fn of fns) {\n const cleanup = fn();\n\n if (typeof cleanup === 'function') this._runtime.cleanups.push(cleanup);\n }\n } catch (err) {\n this._handleError(err);\n } finally {\n runtimeStack.pop();\n this._runtime.onMount = [];\n }\n });\n }\n}\n\n// ─── Component registration ───────────────────────────────────────────────────\n\n/** @internal — use `defineComponent` instead. */\nexport function registerComponent(\n tag: string,\n setup: (ctx: ComponentSetupContext) => string | HTMLResult,\n options: ComponentRegistrationOptions = {},\n): string {\n if (!tag) throw new Error('[craftit:E4] registerComponent(tag, ...) requires a tag name');\n\n if (customElements.get(tag)) {\n throw new Error(`[craftit:E9] custom element already defined: ${tag}`);\n }\n\n class Element extends BaseElement {\n static override _setup = setup;\n static override _options = options;\n static override formAssociated = options.formAssociated ?? false;\n static override observedAttributes = options.observedAttrs ?? [];\n }\n\n customElements.define(tag, Element);\n\n return tag;\n}\n\n/**\n * Defines a custom element with a cohesive, type-safe API.\n *\n * Pass your Props and Events interfaces as generics — everything in `setup`\n * is fully typed with zero boilerplate.\n *\n * @example\n * ```ts\n * type MyProps = { checked?: boolean; disabled?: boolean };\n * type MyEvents = { change: { checked: boolean } };\n *\n * defineComponent<MyProps, MyEvents>({\n * tag: 'my-checkbox',\n * props: {\n * checked: { default: false },\n * disabled: { default: false },\n * },\n * setup({ props, emit }) {\n * // props.checked → Signal<boolean> ✅\n * // emit('change', { checked: true }) ✅\n * },\n * });\n * ```\n */\nexport function defineComponent<\n PropsType = Record<string, never>,\n EventsType extends Record<string, unknown> = Record<string, never>,\n>(options: DefineComponentOptions<BuildPropSchema<PropsType>, EventsType>): string {\n const { formAssociated, host: hostOptions, props: propDefs, setup, shadow: shadowOptions, styles, tag } = options;\n\n // Derive observed attribute names from prop schema at definition time so\n // attributeChangedCallback fires correctly — no MutationObserver needed.\n const observedAttrs = propDefs ? Object.keys(propDefs).map(toKebab) : [];\n\n return registerComponent(\n tag,\n (ctx) => {\n const props = propDefs\n ? createProps(propDefs as BuildPropSchema<PropsType>)\n : ({} as InferPropsSignals<BuildPropSchema<PropsType>>);\n const emit = createEmitFn<EventsType>();\n const slots = createSlots<any>();\n\n return setup({\n emit: emit as EmitFn<EventsType>,\n host: ctx.host,\n props,\n reflect: (config: ReflectConfig) => reflect(ctx.host, config),\n shadow: ctx.shadow,\n slots,\n } as DefineComponentSetupContext<BuildPropSchema<PropsType>, EventsType>);\n },\n { formAssociated, host: hostOptions, observedAttrs, shadow: shadowOptions, styles },\n );\n}\n"],"mappings":"ggBAgCA,IAAa,EAAuB,IAAI,QAE3B,EAAoB,IAAI,QA2BxB,GACX,EACA,IACoB,CAEpB,IAAM,EADK,GAAgB,CACX,GAGhB,GAAI,CAFS,EAAK,YAER,eACR,MAAU,MAAM,gFAAgF,CAGlG,IAAM,EAAY,EAAkB,IAAI,EAAK,EAAI,EAAK,iBAAiB,CAEvE,EAAkB,IAAI,EAAM,EAAU,CAEtC,IAAM,EAAc,EAAQ,cAAiB,GAAU,GAAK,KAAO,GAAK,OAAO,EAAE,EAyBjF,OAvBA,MAAa,CACX,EAAU,aAAa,EAAY,EAAQ,MAAM,MAAM,CAAC,EACxD,CAEE,EAAQ,UACV,MAAa,CACP,EAAQ,SAAU,MACpB,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,EAkCG,EAAgB,IAAI,IAAI,CAAC,UAAW,OAAQ,QAAS,UAAW,OAAO,CAAC,CACxE,EAAa,GACb,OAAO,GAAU,WAAY,GAAkB,EAAE,YAAa,GAAe,GAE1E,OAAO,KAAK,EAAM,CAAC,MAAO,GAAQ,EAAc,IAAI,EAAI,CAAC,CAGrD,EAAe,IAAI,QAEnB,GAAW,EAAc,EAAiB,IAAwC,CAC7F,IAAM,EAAK,GAAgB,CACrB,EAAK,EAAG,GAET,EAAa,IAAI,EAAG,EAAE,EAAa,IAAI,EAAI,IAAI,IAAM,CAE1D,IAAM,EACJ,GAAS,QACP,GAEI,GAAS,OAAS,QAAiB,IAAM,IAAM,IAAM,OAKrD,OAAO,GAAiB,UAAmB,IAAM,MAAQ,IAAM,QAE/D,GAAK,KAAa,EAGlB,GAAS,OAAS,QAAU,OAAO,GAAiB,SAAiB,OAAO,EAAE,CAE3E,GAEL,EAAI,EAAU,EAAa,CAC3B,EAAwB,OAAO,UAAU,eAAe,KAAK,EAAI,EAAK,CACtE,EAAkB,EAAyB,EAA0C,GAAQ,IAAA,GAE7F,EAAO,CACX,QACA,QAAS,GAAS,SAAW,GAC7B,OAAQ,EACT,CAsBD,GAlBI,GACF,OAAQ,EAA0C,GAClD,EAAE,MAAQ,GACD,EAAG,aAAa,EAAK,GAC9B,EAAE,MAAQ,EAAM,EAAG,aAAa,EAAK,CAAC,EAGxC,EAAa,IAAI,EAAG,CAAE,IAAI,EAAM,EAAK,CAErC,OAAO,eAAe,EAAI,EAAM,CAC9B,aAAc,GACd,WAAY,GACZ,QAAW,EAAE,MACb,IAAM,GAAa,CACjB,EAAE,MAAQ,GAEb,CAAC,CAEE,GAAS,SAAW,GAAM,CAC5B,IAAM,EAAO,GAAS,MAAQ,GAE9B,EAAG,QAAQ,SAAW,CACpB,EAAG,SAAS,KACV,MAAa,CACX,IAAM,EAAI,EAAE,MAER,GAAK,MAAQ,IAAM,IAAU,GAAQ,IAAM,GAC7C,EAAG,gBAAgB,EAAK,CAExB,EAAQ,EAAI,EAAM,EAAE,EAEtB,CACH,EACD,CAGJ,OAAO,GAeT,SAAgB,EAAqC,EAA+B,CAClF,IAAM,EAAS,EAAE,CAEjB,IAAK,GAAM,CAAC,EAAM,KAAQ,OAAO,QAAQ,EAAK,CAAE,CAC9C,IAAM,EAAa,EAAU,EAAI,CAAI,EAA2B,CAAE,QAAS,EAAK,CAG1E,EAAgC,CAAE,QAAS,EAD9C,OAAO,EAAW,SAAY,UAAY,EAAW,UAAY,MAAS,MAAM,QAAQ,EAAW,QAAQ,EACtC,GAAG,EAAY,CAEvF,EAAO,GAAQ,EAAK,EAAQ,EAAK,CAAE,EAAW,QAAS,EAAQ,CAGjE,OAAO,EAoBT,IAAa,GAAY,EAAiB,KAA0C,CAClF,GAAG,EACH,QAAS,EACV,EA6FK,EAAN,cAA0B,WAAY,CACpC,OAAO,OACP,OAAO,SACP,OAAO,eAAiB,GACxB,OAAO,mBAA+B,EAAE,CAExC,OACA,aAAuB,IAAI,IAC3B,UAA4D,EAAE,CAC9D,UAAgD,KAChD,qBAA+B,IAAI,IACnC,WAAqB,GACrB,SAEA,aAAc,CACZ,OAAO,CAEP,IAAM,EAAW,KAAK,YAAmC,SAEzD,KAAK,OAAS,KAAK,aAAa,CAAE,KAAM,OAAQ,GAAG,GAAS,OAAQ,CAAC,CACrE,KAAK,SAAW,CACd,SAAU,EAAE,CACZ,GAAI,KACJ,cAAe,EAAE,CACjB,QAAS,EAAE,CACX,OAAQ,GAAS,OAClB,CAGH,mBAA0B,CACnB,KAAK,YAAY,KAAK,WAAW,CAEtC,KAAK,OAAO,CAKd,yBAAyB,EAAc,EAAyB,EAA+B,CAC7F,GAAI,IAAa,EAAU,OAE3B,IAAM,EAAO,EAAa,IAAI,KAAK,EAAE,IAAI,EAAK,CAE9C,GAAI,CAAC,EAAM,OAEX,IAAM,EAAS,EAAK,MAAM,EAAS,CAE9B,OAAO,GAAG,EAAK,OAAO,MAAM,CAAE,EAAO,GAAE,EAAK,OAAO,MAAQ,GAGlE,sBAA6B,CAC3B,EAAO,KAAK,SAAS,SAAS,CAC9B,KAAK,SAAS,SAAW,EAAE,CAC3B,KAAK,SAAS,QAAU,KAAK,UAAU,OAAO,CAC9C,KAAK,qBAAqB,OAAO,CACjC,KAAK,aAAa,OAAO,CAG3B,uBAAuB,EAAoC,CACzD,EAAqB,IAAI,KAAK,EAAE,eAAe,EAAK,CAGtD,qBAAqB,EAAyB,CAC5C,EAAqB,IAAI,KAAK,EAAE,aAAa,EAAS,CAGxD,mBAA0B,CACxB,EAAqB,IAAI,KAAK,EAAE,WAAW,CAG7C,yBAAyB,EAAgB,EAAwC,CAC/E,EAAqB,IAAI,KAAK,EAAE,iBAAiB,EAAO,EAAK,CAG/D,aAAqB,EAAoB,CACvC,GAAI,KAAK,SAAS,cAAc,OAAS,EACvC,IAAK,IAAM,KAAM,KAAK,SAAS,cAAe,EAAG,EAAI,MAErD,QAAQ,MAAM,iBAAiB,KAAK,UAAU,GAAI,EAAI,CAI1D,WAA0B,CACxB,KAAK,WAAa,GAClB,EAAa,KAAK,KAAK,SAAgB,CAEvC,GAAI,CACF,GAAM,CAAE,KAAM,GAAiB,KAAK,YAAmC,UAAY,EAAE,CAErF,GAAI,EACF,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,QAAQ,EAAY,CACjD,OAAO,GAAU,UACf,EACF,KAAK,aAAa,EAAM,GAAG,CAE3B,KAAK,gBAAgB,EAAK,CAG5B,KAAK,aAAa,EAAM,OAAO,EAAM,CAAC,CAK5C,IAAM,EAAO,KAAK,YAAmC,OAAO,CAAE,KAAM,KAAM,OAAQ,KAAK,OAAQ,CAAC,EAE5F,OAAO,GAAQ,UAAa,OAAO,GAAQ,UAAY,GAAgB,WAAY,KACrF,KAAK,UAAY,SAEZ,EAAK,CACZ,KAAK,aAAa,EAAI,QACd,CACR,EAAa,KAAK,EAItB,OAAsB,CACpB,GAAM,CAAE,UAAW,KAAK,SAKxB,GAFI,GAAQ,SAAQ,KAAK,OAAO,mBAAqB,EAAO,IAAI,EAAe,EAE3E,KAAK,UAAW,CAClB,IAAM,EAAqB,OAAO,KAAK,WAAc,SAAW,EAAW,KAAK,UAAU,CAAG,KAAK,UAIlG,GAFA,KAAK,OAAO,gBAAgB,EAAU,EAAO,OAAO,CAAC,CAEjD,EAAO,WAAW,OAAQ,CAC5B,IAAM,EAAoC,GAAO,KAAK,SAAS,SAAS,KAAK,EAAG,CAEhF,EAAyB,KAAK,OAAQ,EAAO,WAAY,EAAiB,CACxE,OAAS,GAAM,CACR,KAAK,qBAAqB,IAAI,EAAE,IAAI,GACvC,KAAK,qBAAqB,IAAI,EAAE,IAAI,CACpC,EAAiB,KAAK,OAAQ,EAAG,EAAiB,KAAK,aAAa,GAGzE,CAAC,EAMN,mBAAqB,CACnB,EAAa,KAAK,KAAK,SAAgB,CAEvC,GAAI,CACF,IAAM,EAAM,KAAK,SAAS,QAE1B,KAAK,UAAY,EAAI,OAAO,CAE5B,IAAK,IAAM,KAAM,EAAK,CACpB,IAAM,EAAU,GAAI,CAEhB,OAAO,GAAY,YAAY,KAAK,SAAS,SAAS,KAAK,EAAQ,QAElE,EAAK,CACZ,KAAK,aAAa,EAAI,QACd,CACR,EAAa,KAAK,CAClB,KAAK,SAAS,QAAU,EAAE,GAE5B,GAON,SAAgB,EACd,EACA,EACA,EAAwC,EAAE,CAClC,CACR,GAAI,CAAC,EAAK,MAAU,MAAM,+DAA+D,CAEzF,GAAI,eAAe,IAAI,EAAI,CACzB,MAAU,MAAM,gDAAgD,IAAM,CAGxE,MAAM,UAAgB,CAAY,CAChC,OAAgB,OAAS,EACzB,OAAgB,SAAW,EAC3B,OAAgB,eAAiB,EAAQ,gBAAkB,GAC3D,OAAgB,mBAAqB,EAAQ,eAAiB,EAAE,CAKlE,OAFA,eAAe,OAAO,EAAK,EAAQ,CAE5B,EA2BT,SAAgB,EAGd,EAAiF,CACjF,GAAM,CAAE,iBAAgB,KAAM,EAAa,MAAO,EAAU,QAAO,OAAQ,EAAe,SAAQ,OAAQ,EAM1G,OAAO,EACL,EACC,GAAQ,CACP,IAAM,EAAQ,EACV,EAAY,EAAuC,CAClD,EAAE,CACD,EAAO,GAA0B,CACjC,EAAQ,GAAkB,CAEhC,OAAO,EAAM,CACL,OACN,KAAM,EAAI,KACV,QACA,QAAU,GAA0B,EAAQ,EAAI,KAAM,EAAO,CAC7D,OAAQ,EAAI,OACZ,QACD,CAAwE,EAE3E,CAAE,iBAAgB,KAAM,EAAa,cApBjB,EAAW,OAAO,KAAK,EAAS,CAAC,IAAI,EAAQ,CAAG,EAAE,CAoBlB,OAAQ,EAAe,SAAQ,CACpF"}
@@ -1,2 +0,0 @@
1
- const e=require(`./runtime-lifecycle.cjs`),t=require(`./utilities.cjs`);let n=require(`@vielzeug/stateit`);var r=new WeakMap,i=(t,n)=>{let i=e.currentRuntime().el;r.has(i)||r.set(i,new Map),r.get(i).set(t,n)};function a(t,...n){let i=e.currentRuntime().el;for(;i;){if(i instanceof HTMLElement){let e=r.get(i)?.get(t);if(e!==void 0)return e}let e=i.getRootNode();i=i.parentElement??(e instanceof ShadowRoot?e.host:null)}return n.length>0?n[0]:void 0}function o(e){return Symbol(e)}var s=(t,n,r)=>{t&&e.onMount(()=>{e.effect(()=>{for(let e of r){let r=t[e]?.value;r!==void 0&&(n[e].value=r)}})})},c=new Set,l=(e,t,n)=>{let r=`${n}:${e.localName}:${t||`default`}`;c.has(r)||(c.add(r),console.warn(`[craftit:E10] ${n} could not find a matching <slot${t?` name="${t}"`:``}> in <${e.localName}>. Render the slot before using ${n}.`))},u=(t,n)=>{let r=e.currentRuntime().el,i=t===`default`?``:t,a=i?`slot[name="${i}"]`:`slot:not([name])`,o=r.shadowRoot?.querySelector(a);if(!o){l(r,i,`onSlotChange()`);return}let s=()=>n(o.assignedElements({flatten:!0}));s(),o.addEventListener(`slotchange`,s),e.onCleanup(()=>o.removeEventListener(`slotchange`,s))},d=()=>{let t=e.currentRuntime().el,r=new Map,i=i=>{if(r.has(i))return r.get(i);let a=(0,n.signal)(!1);return r.set(i,a),e.onMount(()=>{let e=i?`slot[name="${i}"]`:`slot:not([name])`,n=t.shadowRoot?.querySelector(e);if(!n){l(t,i,`slots.has()`);return}let r=()=>{a.value=n.assignedNodes().length>0};return r(),n.addEventListener(`slotchange`,r),()=>n.removeEventListener(`slotchange`,r)}),a};return{has(e){return i(e===`default`?``:String(e))}}};function f(t,n){for(let[r,i]of Object.entries(n))if(r===`classMap`)m(t,i);else if(r.startsWith(`on`)&&r.length>2&&typeof i==`function`){let n=r.slice(2);e.handle(t,n[0].toLowerCase()+n.slice(1),i)}else p(t,r,i)}function p(n,r,i){typeof i==`function`?e.effect(()=>t.setAttr(n,r,i())):t.setAttr(n,r,i)}function m(t,n){let r=new Set;e.effect(()=>{let e=new Set(Object.entries(n()).filter(([,e])=>e).map(([e])=>e));for(let n of r)e.has(n)||t.classList.remove(n);for(let n of e)r.has(n)||t.classList.add(n);r=e})}exports.createContext=o,exports.createSlots=d,exports.inject=a,exports.onSlotChange=u,exports.provide=i,exports.reflect=f,exports.syncContextProps=s;
2
- //# sourceMappingURL=host.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"host.cjs","names":[],"sources":["../../src/core/host.ts"],"sourcesContent":["/**\n * Host utilities — component context injection, slot observation, and attribute/class reflection.\n *\n * - Context API (provide, inject, createContext, syncContextProps)\n * - Slot observation and detection (Slots type, createSlots, onSlotChange)\n * - Host element binding (reflect) for attributes, events, and classes\n */\n\nimport { type ReadonlySignal, type Signal, signal } from '@vielzeug/stateit';\n\n// Use the wrapped effect from runtime-lifecycle so reactive bindings are\n// automatically cleaned up on unmount — raw stateit effect has no lifecycle awareness.\nimport { currentRuntime, effect, handle, onCleanup, onMount } from './runtime-lifecycle';\nimport { setAttr } from './utilities';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// CONTEXT API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst contextRegistry = new WeakMap<HTMLElement, Map<InjectionKey<unknown> | string | symbol, unknown>>();\n\nexport type InjectionKey<T> = symbol & {\n readonly __craftit_injection_key?: T;\n};\n\nexport const provide = <T>(key: InjectionKey<T> | string | symbol, value: T): void => {\n const el = currentRuntime().el;\n\n if (!contextRegistry.has(el)) contextRegistry.set(el, new Map());\n\n contextRegistry.get(el)!.set(key, value);\n};\n\nexport function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;\nexport function inject<T>(key: InjectionKey<T> | string | symbol, ...rest: [T?]): T | undefined {\n let node: Node | null = currentRuntime().el;\n\n while (node) {\n if (node instanceof HTMLElement) {\n const v = contextRegistry.get(node)?.get(key);\n\n if (v !== undefined) return v as T;\n }\n\n const root = node.getRootNode() as Node;\n\n node = (node as HTMLElement).parentElement ?? (root instanceof ShadowRoot ? root.host : null);\n }\n\n return rest.length > 0 ? rest[0] : undefined;\n}\n\nexport function createContext<T>(description?: string): InjectionKey<T> {\n return Symbol(description) as InjectionKey<T>;\n}\n\n/**\n * Reactively inherits prop values from a context object provided by an ancestor component.\n * For each key, when the context value is not `undefined`, it is written into the matching prop signal.\n * The effect is automatically cleaned up when the component unmounts.\n *\n * Deferred to `onMount` so context values win over HTML attribute values set on the child.\n *\n * @example\n * syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);\n */\nexport const syncContextProps = <\n K extends string,\n Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>,\n Props extends Record<K, Signal<unknown>>,\n>(\n ctx: Ctx | undefined,\n props: Props,\n keys: K[],\n): void => {\n if (!ctx) return;\n\n onMount(() => {\n effect(() => {\n for (const k of keys) {\n const v = ctx[k]?.value;\n\n if (v !== undefined) props[k].value = v;\n }\n });\n });\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SLOTS API\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst missingSlotWarnings = new Set<string>();\n\nconst warnMissingSlot = (el: HTMLElement, slotName: string, source: 'onSlotChange()' | 'slots.has()'): void => {\n const key = `${source}:${el.localName}:${slotName || 'default'}`;\n\n if (missingSlotWarnings.has(key)) return;\n\n missingSlotWarnings.add(key);\n console.warn(\n `[craftit:E10] ${source} could not find a matching <slot${slotName ? ` name=\"${slotName}\"` : ''}> in <${el.localName}>. Render the slot before using ${source}.`,\n );\n};\n\nexport type Slots<T extends Record<string, unknown> = Record<string, unknown>> = {\n /**\n * Returns a `ReadonlySignal<boolean>` that is `true` when the slot has assigned content.\n * Reactive — use the signal directly in templates, computed(), or effects.\n * @example const hasIcon = slots.has('icon'); // ReadonlySignal<boolean>\n */\n has(name: keyof T): ReadonlySignal<boolean>;\n};\n\n/**\n * Observes a slot and calls `callback` with assigned elements whenever they change.\n * Must be called inside an {@link onMount} callback.\n *\n * @example\n * onMount(() => {\n * onSlotChange('icon', (nodes) => setHasIcon(nodes.length > 0));\n * });\n */\nexport const onSlotChange = (slotName: string, callback: (elements: Element[]) => void): void => {\n const el = currentRuntime().el;\n const name = slotName === 'default' ? '' : slotName;\n const selector = name ? `slot[name=\"${name}\"]` : 'slot:not([name])';\n const slot = el.shadowRoot?.querySelector<HTMLSlotElement>(selector);\n\n if (!slot) {\n warnMissingSlot(el, name, 'onSlotChange()');\n\n return;\n }\n\n const handler = () => callback(slot.assignedElements({ flatten: true }));\n\n handler();\n slot.addEventListener('slotchange', handler);\n onCleanup(() => slot.removeEventListener('slotchange', handler));\n};\n\nexport const createSlots = <T extends Record<string, unknown> = Record<string, unknown>>(): Slots<T> => {\n const el = currentRuntime().el;\n const sigs = new Map<string, Signal<boolean>>();\n\n const get = (slotName: string): Signal<boolean> => {\n if (sigs.has(slotName)) return sigs.get(slotName)!;\n\n const s = signal(false);\n\n sigs.set(slotName, s);\n\n onMount(() => {\n const selector = slotName ? `slot[name=\"${slotName}\"]` : 'slot:not([name])';\n const slot = el.shadowRoot?.querySelector<HTMLSlotElement>(selector);\n\n if (!slot) {\n warnMissingSlot(el, slotName, 'slots.has()');\n\n return;\n }\n\n const update = () => {\n s.value = slot.assignedNodes().length > 0;\n };\n\n update();\n slot.addEventListener('slotchange', update);\n\n return () => slot.removeEventListener('slotchange', update);\n });\n\n return s;\n };\n\n return {\n has(name: keyof T): ReadonlySignal<boolean> {\n return get(name === 'default' ? '' : String(name));\n },\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// REFLECT API (HOST ATTRIBUTE/EVENT/CLASS BINDING)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Describes a reactive or static host binding (attribute, event, class).\n */\nexport type HostBindingValue =\n | (() => string | number | boolean | null | undefined)\n | string\n | number\n | boolean\n | null\n | undefined;\n\n/**\n * Configuration for `reflect()`.\n */\nexport type ReflectConfig = {\n [key: string]: HostBindingValue | ((e: Event) => void);\n classMap?: () => Record<string, boolean>;\n};\n\n/**\n * Reflect reactive attributes, events, and classes to a host element.\n * Must be called within a component setup context.\n *\n * - `on*` keys map to event listeners: `onClick` → `'click'`, `onValueChanged` → `'valueChanged'`\n * - `classMap` maps to a reactive class object\n * - all other keys map to attributes (static or reactive getter)\n *\n * @example\n * setup({ reflect }) {\n * reflect({\n * role: 'checkbox',\n * tabindex: () => props.disabled.value ? undefined : 0,\n * checked: () => props.checked.value,\n * classMap: () => ({ checked: props.checked.value }),\n * onClick: handleToggle,\n * });\n * }\n */\nexport function reflect(host: HTMLElement, config: ReflectConfig): void {\n for (const [key, value] of Object.entries(config)) {\n if (key === 'classMap') {\n applyClassMap(host, value as () => Record<string, boolean>);\n } else if (key.startsWith('on') && key.length > 2 && typeof value === 'function') {\n // onClick → 'click', onValueChanged → 'valueChanged', onKeydown → 'keydown'\n const raw = key.slice(2);\n\n handle(host, raw[0].toLowerCase() + raw.slice(1), value as (e: Event) => void);\n } else {\n applyAttribute(host, key, value as HostBindingValue);\n }\n }\n}\n\nfunction applyAttribute(host: HTMLElement, name: string, value: HostBindingValue): void {\n if (typeof value === 'function') {\n effect(() => setAttr(host, name, (value as () => HostBindingValue)()));\n } else {\n setAttr(host, name, value);\n }\n}\n\nfunction applyClassMap(host: HTMLElement, getter: () => Record<string, boolean>): void {\n let prev = new Set<string>();\n\n effect(() => {\n const next = new Set(\n Object.entries(getter())\n .filter(([, active]) => active)\n .map(([cls]) => cls),\n );\n\n for (const cls of prev) if (!next.has(cls)) host.classList.remove(cls);\n for (const cls of next) if (!prev.has(cls)) host.classList.add(cls);\n\n prev = next;\n });\n}\n"],"mappings":"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"}
@@ -1,77 +0,0 @@
1
- /**
2
- * Host utilities — component context injection, slot observation, and attribute/class reflection.
3
- *
4
- * - Context API (provide, inject, createContext, syncContextProps)
5
- * - Slot observation and detection (Slots type, createSlots, onSlotChange)
6
- * - Host element binding (reflect) for attributes, events, and classes
7
- */
8
- import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
9
- export type InjectionKey<T> = symbol & {
10
- readonly __craftit_injection_key?: T;
11
- };
12
- export declare const provide: <T>(key: InjectionKey<T> | string | symbol, value: T) => void;
13
- export declare function inject<T>(key: InjectionKey<T> | string | symbol): T | undefined;
14
- export declare function inject<T>(key: InjectionKey<T> | string | symbol, fallback: T): T;
15
- export declare function createContext<T>(description?: string): InjectionKey<T>;
16
- /**
17
- * Reactively inherits prop values from a context object provided by an ancestor component.
18
- * For each key, when the context value is not `undefined`, it is written into the matching prop signal.
19
- * The effect is automatically cleaned up when the component unmounts.
20
- *
21
- * Deferred to `onMount` so context values win over HTML attribute values set on the child.
22
- *
23
- * @example
24
- * syncContextProps(inject(BUTTON_GROUP_CTX), props, ['color', 'size', 'variant']);
25
- */
26
- export declare const syncContextProps: <K extends string, Ctx extends Partial<Record<K, ReadonlySignal<unknown>>>, Props extends Record<K, Signal<unknown>>>(ctx: Ctx | undefined, props: Props, keys: K[]) => void;
27
- export type Slots<T extends Record<string, unknown> = Record<string, unknown>> = {
28
- /**
29
- * Returns a `ReadonlySignal<boolean>` that is `true` when the slot has assigned content.
30
- * Reactive — use the signal directly in templates, computed(), or effects.
31
- * @example const hasIcon = slots.has('icon'); // ReadonlySignal<boolean>
32
- */
33
- has(name: keyof T): ReadonlySignal<boolean>;
34
- };
35
- /**
36
- * Observes a slot and calls `callback` with assigned elements whenever they change.
37
- * Must be called inside an {@link onMount} callback.
38
- *
39
- * @example
40
- * onMount(() => {
41
- * onSlotChange('icon', (nodes) => setHasIcon(nodes.length > 0));
42
- * });
43
- */
44
- export declare const onSlotChange: (slotName: string, callback: (elements: Element[]) => void) => void;
45
- export declare const createSlots: <T extends Record<string, unknown> = Record<string, unknown>>() => Slots<T>;
46
- /**
47
- * Describes a reactive or static host binding (attribute, event, class).
48
- */
49
- export type HostBindingValue = (() => string | number | boolean | null | undefined) | string | number | boolean | null | undefined;
50
- /**
51
- * Configuration for `reflect()`.
52
- */
53
- export type ReflectConfig = {
54
- [key: string]: HostBindingValue | ((e: Event) => void);
55
- classMap?: () => Record<string, boolean>;
56
- };
57
- /**
58
- * Reflect reactive attributes, events, and classes to a host element.
59
- * Must be called within a component setup context.
60
- *
61
- * - `on*` keys map to event listeners: `onClick` → `'click'`, `onValueChanged` → `'valueChanged'`
62
- * - `classMap` maps to a reactive class object
63
- * - all other keys map to attributes (static or reactive getter)
64
- *
65
- * @example
66
- * setup({ reflect }) {
67
- * reflect({
68
- * role: 'checkbox',
69
- * tabindex: () => props.disabled.value ? undefined : 0,
70
- * checked: () => props.checked.value,
71
- * classMap: () => ({ checked: props.checked.value }),
72
- * onClick: handleToggle,
73
- * });
74
- * }
75
- */
76
- export declare function reflect(host: HTMLElement, config: ReflectConfig): void;
77
- //# sourceMappingURL=host.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/core/host.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAU,MAAM,mBAAmB,CAAC;AAa7E,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,MAAM,GAAG;IACrC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC;CACtC,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,KAAG,IAM7E,CAAC;AAEF,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;AACjF,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;AAmBlF,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAEtE;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAC3B,CAAC,SAAS,MAAM,EAChB,GAAG,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EACvD,KAAK,SAAS,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,EAExC,KAAK,GAAG,GAAG,SAAS,EACpB,OAAO,KAAK,EACZ,MAAM,CAAC,EAAE,KACR,IAYF,CAAC;AAmBF,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC/E;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,KAAG,IAiBxF,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAK,KAAK,CAAC,CAAC,CAuClG,CAAC;AAMF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GACxB,CAAC,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GACpD,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAatE"}