@vielzeug/craftit 2.0.1 → 3.0.1

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 (432) hide show
  1. package/README.md +60 -108
  2. package/dist/controls/a11y-control.cjs +2 -0
  3. package/dist/controls/a11y-control.cjs.map +1 -0
  4. package/dist/controls/a11y-control.d.ts +16 -0
  5. package/dist/controls/a11y-control.d.ts.map +1 -0
  6. package/dist/controls/a11y-control.js +2 -0
  7. package/dist/controls/a11y-control.js.map +1 -0
  8. package/dist/controls/checkable-control.cjs +2 -0
  9. package/dist/controls/checkable-control.cjs.map +1 -0
  10. package/dist/controls/checkable-control.d.ts +15 -0
  11. package/dist/controls/checkable-control.d.ts.map +1 -0
  12. package/dist/controls/checkable-control.js +2 -0
  13. package/dist/controls/checkable-control.js.map +1 -0
  14. package/dist/controls/choice-field-control.cjs +2 -0
  15. package/dist/controls/choice-field-control.cjs.map +1 -0
  16. package/dist/controls/choice-field-control.d.ts +3 -0
  17. package/dist/controls/choice-field-control.d.ts.map +1 -0
  18. package/dist/controls/choice-field-control.js +2 -0
  19. package/dist/controls/choice-field-control.js.map +1 -0
  20. package/dist/controls/field-control.cjs +2 -0
  21. package/dist/controls/field-control.cjs.map +1 -0
  22. package/dist/controls/field-control.d.ts +111 -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 +12 -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 +21 -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 +23 -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/overlay-control.cjs +2 -0
  59. package/dist/controls/overlay-control.cjs.map +1 -0
  60. package/dist/{labs/overlay.d.ts → controls/overlay-control.d.ts} +19 -14
  61. package/dist/controls/overlay-control.d.ts.map +1 -0
  62. package/dist/controls/overlay-control.js +2 -0
  63. package/dist/controls/overlay-control.js.map +1 -0
  64. package/dist/controls/popup-list-control.cjs +2 -0
  65. package/dist/controls/popup-list-control.cjs.map +1 -0
  66. package/dist/controls/popup-list-control.d.ts +160 -0
  67. package/dist/controls/popup-list-control.d.ts.map +1 -0
  68. package/dist/controls/popup-list-control.js +2 -0
  69. package/dist/controls/popup-list-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/swipe-control.cjs +2 -0
  89. package/dist/controls/swipe-control.cjs.map +1 -0
  90. package/dist/controls/swipe-control.d.ts +32 -0
  91. package/dist/controls/swipe-control.d.ts.map +1 -0
  92. package/dist/controls/swipe-control.js +2 -0
  93. package/dist/controls/swipe-control.js.map +1 -0
  94. package/dist/controls/text-field-control.cjs +2 -0
  95. package/dist/controls/text-field-control.cjs.map +1 -0
  96. package/dist/controls/text-field-control.d.ts +3 -0
  97. package/dist/controls/text-field-control.d.ts.map +1 -0
  98. package/dist/controls/text-field-control.js +2 -0
  99. package/dist/controls/text-field-control.js.map +1 -0
  100. package/dist/controls.cjs +1 -0
  101. package/dist/controls.js +1 -0
  102. package/dist/craftit.cjs +1 -1
  103. package/dist/craftit.cjs.map +1 -1
  104. package/dist/craftit.js +1 -1
  105. package/dist/craftit.js.map +1 -1
  106. package/dist/directives/classMap.cjs +2 -0
  107. package/dist/directives/classMap.cjs.map +1 -0
  108. package/dist/directives/classMap.d.ts +19 -0
  109. package/dist/directives/classMap.d.ts.map +1 -0
  110. package/dist/directives/classMap.js +2 -0
  111. package/dist/directives/classMap.js.map +1 -0
  112. package/dist/directives/each.cjs +1 -1
  113. package/dist/directives/each.cjs.map +1 -1
  114. package/dist/directives/each.d.ts +12 -49
  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/guard.cjs +2 -0
  119. package/dist/directives/guard.cjs.map +1 -0
  120. package/dist/directives/guard.d.ts +10 -0
  121. package/dist/directives/guard.d.ts.map +1 -0
  122. package/dist/directives/guard.js +2 -0
  123. package/dist/directives/guard.js.map +1 -0
  124. package/dist/directives/live.cjs +2 -0
  125. package/dist/directives/live.cjs.map +1 -0
  126. package/dist/directives/live.d.ts +23 -0
  127. package/dist/directives/live.d.ts.map +1 -0
  128. package/dist/directives/live.js +2 -0
  129. package/dist/directives/live.js.map +1 -0
  130. package/dist/directives/raw.cjs +1 -1
  131. package/dist/directives/raw.cjs.map +1 -1
  132. package/dist/directives/raw.d.ts +4 -6
  133. package/dist/directives/raw.d.ts.map +1 -1
  134. package/dist/directives/raw.js +1 -1
  135. package/dist/directives/raw.js.map +1 -1
  136. package/dist/directives/resource.cjs +2 -0
  137. package/dist/directives/resource.cjs.map +1 -0
  138. package/dist/directives/resource.d.ts +32 -0
  139. package/dist/directives/resource.d.ts.map +1 -0
  140. package/dist/directives/resource.js +2 -0
  141. package/dist/directives/resource.js.map +1 -0
  142. package/dist/directives/styleMap.cjs +2 -0
  143. package/dist/directives/styleMap.cjs.map +1 -0
  144. package/dist/directives/styleMap.d.ts +11 -0
  145. package/dist/directives/styleMap.d.ts.map +1 -0
  146. package/dist/directives/styleMap.js +2 -0
  147. package/dist/directives/styleMap.js.map +1 -0
  148. package/dist/directives/when.cjs +1 -1
  149. package/dist/directives/when.cjs.map +1 -1
  150. package/dist/directives/when.d.ts +7 -14
  151. package/dist/directives/when.d.ts.map +1 -1
  152. package/dist/directives/when.js +1 -1
  153. package/dist/directives/when.js.map +1 -1
  154. package/dist/errors.cjs +2 -0
  155. package/dist/errors.cjs.map +1 -0
  156. package/dist/errors.d.ts +12 -0
  157. package/dist/errors.d.ts.map +1 -0
  158. package/dist/errors.js +2 -0
  159. package/dist/errors.js.map +1 -0
  160. package/dist/form.cjs +2 -0
  161. package/dist/form.cjs.map +1 -0
  162. package/dist/form.d.ts +15 -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 +78 -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 +16 -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 +111 -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 +5 -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/mutation-observe.cjs +2 -0
  197. package/dist/observers/mutation-observe.cjs.map +1 -0
  198. package/dist/observers/mutation-observe.d.ts +10 -0
  199. package/dist/observers/mutation-observe.d.ts.map +1 -0
  200. package/dist/observers/mutation-observe.js +2 -0
  201. package/dist/observers/mutation-observe.js.map +1 -0
  202. package/dist/observers/resize-observe.cjs +2 -0
  203. package/dist/observers/resize-observe.cjs.map +1 -0
  204. package/dist/observers/resize-observe.d.ts +11 -0
  205. package/dist/observers/resize-observe.d.ts.map +1 -0
  206. package/dist/observers/resize-observe.js +2 -0
  207. package/dist/observers/resize-observe.js.map +1 -0
  208. package/dist/observers.cjs +1 -0
  209. package/dist/observers.js +1 -0
  210. package/dist/props.cjs +2 -0
  211. package/dist/props.cjs.map +1 -0
  212. package/dist/props.d.ts +39 -0
  213. package/dist/props.d.ts.map +1 -0
  214. package/dist/props.js +2 -0
  215. package/dist/props.js.map +1 -0
  216. package/dist/registration.cjs +2 -0
  217. package/dist/registration.cjs.map +1 -0
  218. package/dist/registration.d.ts +38 -0
  219. package/dist/registration.d.ts.map +1 -0
  220. package/dist/registration.js +2 -0
  221. package/dist/registration.js.map +1 -0
  222. package/dist/runtime.cjs +2 -0
  223. package/dist/runtime.cjs.map +1 -0
  224. package/dist/runtime.d.ts +33 -0
  225. package/dist/runtime.d.ts.map +1 -0
  226. package/dist/runtime.js +2 -0
  227. package/dist/runtime.js.map +1 -0
  228. package/dist/template-bindings.cjs +2 -0
  229. package/dist/template-bindings.cjs.map +1 -0
  230. package/dist/template-bindings.d.ts +25 -0
  231. package/dist/template-bindings.d.ts.map +1 -0
  232. package/dist/template-bindings.js +2 -0
  233. package/dist/template-bindings.js.map +1 -0
  234. package/dist/template-compiler.cjs +2 -0
  235. package/dist/template-compiler.cjs.map +1 -0
  236. package/dist/template-compiler.d.ts +4 -0
  237. package/dist/template-compiler.d.ts.map +1 -0
  238. package/dist/template-compiler.js +2 -0
  239. package/dist/template-compiler.js.map +1 -0
  240. package/dist/testing/index.d.ts +2 -0
  241. package/dist/testing/index.d.ts.map +1 -0
  242. package/dist/testing/testing.cjs +2 -0
  243. package/dist/testing/testing.cjs.map +1 -0
  244. package/dist/{test/test.d.ts → testing/testing.d.ts} +18 -11
  245. package/dist/testing/testing.d.ts.map +1 -0
  246. package/dist/testing/testing.js +2 -0
  247. package/dist/testing/testing.js.map +1 -0
  248. package/dist/testing.cjs +1 -0
  249. package/dist/testing.js +1 -0
  250. package/package.json +21 -22
  251. package/dist/core/component.cjs +0 -2
  252. package/dist/core/component.cjs.map +0 -1
  253. package/dist/core/component.d.ts +0 -172
  254. package/dist/core/component.d.ts.map +0 -1
  255. package/dist/core/component.js +0 -2
  256. package/dist/core/component.js.map +0 -1
  257. package/dist/core/host.cjs +0 -2
  258. package/dist/core/host.cjs.map +0 -1
  259. package/dist/core/host.d.ts +0 -77
  260. package/dist/core/host.d.ts.map +0 -1
  261. package/dist/core/host.js +0 -2
  262. package/dist/core/host.js.map +0 -1
  263. package/dist/core/internal.cjs +0 -2
  264. package/dist/core/internal.cjs.map +0 -1
  265. package/dist/core/internal.d.ts +0 -107
  266. package/dist/core/internal.d.ts.map +0 -1
  267. package/dist/core/internal.js +0 -2
  268. package/dist/core/internal.js.map +0 -1
  269. package/dist/core/runtime-bindings.cjs +0 -2
  270. package/dist/core/runtime-bindings.cjs.map +0 -1
  271. package/dist/core/runtime-bindings.d.ts +0 -6
  272. package/dist/core/runtime-bindings.d.ts.map +0 -1
  273. package/dist/core/runtime-bindings.js +0 -2
  274. package/dist/core/runtime-bindings.js.map +0 -1
  275. package/dist/core/runtime-lifecycle.cjs +0 -2
  276. package/dist/core/runtime-lifecycle.cjs.map +0 -1
  277. package/dist/core/runtime-lifecycle.d.ts +0 -116
  278. package/dist/core/runtime-lifecycle.d.ts.map +0 -1
  279. package/dist/core/runtime-lifecycle.js +0 -2
  280. package/dist/core/runtime-lifecycle.js.map +0 -1
  281. package/dist/core/runtime.cjs +0 -1
  282. package/dist/core/runtime.d.ts +0 -3
  283. package/dist/core/runtime.d.ts.map +0 -1
  284. package/dist/core/runtime.js +0 -1
  285. package/dist/core/template-bindings.cjs +0 -2
  286. package/dist/core/template-bindings.cjs.map +0 -1
  287. package/dist/core/template-bindings.d.ts +0 -59
  288. package/dist/core/template-bindings.d.ts.map +0 -1
  289. package/dist/core/template-bindings.js +0 -2
  290. package/dist/core/template-bindings.js.map +0 -1
  291. package/dist/core/template-compiler.cjs +0 -2
  292. package/dist/core/template-compiler.cjs.map +0 -1
  293. package/dist/core/template-compiler.d.ts +0 -25
  294. package/dist/core/template-compiler.d.ts.map +0 -1
  295. package/dist/core/template-compiler.js +0 -2
  296. package/dist/core/template-compiler.js.map +0 -1
  297. package/dist/core/template-dom.cjs +0 -2
  298. package/dist/core/template-dom.cjs.map +0 -1
  299. package/dist/core/template-dom.d.ts +0 -13
  300. package/dist/core/template-dom.d.ts.map +0 -1
  301. package/dist/core/template-dom.js +0 -2
  302. package/dist/core/template-dom.js.map +0 -1
  303. package/dist/core/template-html.cjs +0 -2
  304. package/dist/core/template-html.cjs.map +0 -1
  305. package/dist/core/template-html.d.ts +0 -26
  306. package/dist/core/template-html.d.ts.map +0 -1
  307. package/dist/core/template-html.js +0 -2
  308. package/dist/core/template-html.js.map +0 -1
  309. package/dist/core/template.cjs +0 -2
  310. package/dist/core/template.cjs.map +0 -1
  311. package/dist/core/template.d.ts +0 -11
  312. package/dist/core/template.d.ts.map +0 -1
  313. package/dist/core/template.js +0 -2
  314. package/dist/core/template.js.map +0 -1
  315. package/dist/core/utilities.cjs +0 -2
  316. package/dist/core/utilities.cjs.map +0 -1
  317. package/dist/core/utilities.d.ts +0 -68
  318. package/dist/core/utilities.d.ts.map +0 -1
  319. package/dist/core/utilities.js +0 -2
  320. package/dist/core/utilities.js.map +0 -1
  321. package/dist/directives/attr.cjs +0 -2
  322. package/dist/directives/attr.cjs.map +0 -1
  323. package/dist/directives/attr.d.ts +0 -14
  324. package/dist/directives/attr.d.ts.map +0 -1
  325. package/dist/directives/attr.js +0 -2
  326. package/dist/directives/attr.js.map +0 -1
  327. package/dist/directives/bind.cjs +0 -2
  328. package/dist/directives/bind.cjs.map +0 -1
  329. package/dist/directives/bind.d.ts +0 -30
  330. package/dist/directives/bind.d.ts.map +0 -1
  331. package/dist/directives/bind.js +0 -2
  332. package/dist/directives/bind.js.map +0 -1
  333. package/dist/directives/choose.cjs +0 -2
  334. package/dist/directives/choose.cjs.map +0 -1
  335. package/dist/directives/choose.d.ts +0 -34
  336. package/dist/directives/choose.d.ts.map +0 -1
  337. package/dist/directives/choose.js +0 -2
  338. package/dist/directives/choose.js.map +0 -1
  339. package/dist/directives/classes.cjs +0 -2
  340. package/dist/directives/classes.cjs.map +0 -1
  341. package/dist/directives/classes.d.ts +0 -20
  342. package/dist/directives/classes.d.ts.map +0 -1
  343. package/dist/directives/classes.js +0 -2
  344. package/dist/directives/classes.js.map +0 -1
  345. package/dist/directives/index.cjs +0 -1
  346. package/dist/directives/index.d.ts +0 -14
  347. package/dist/directives/index.d.ts.map +0 -1
  348. package/dist/directives/index.js +0 -1
  349. package/dist/directives/match.cjs +0 -2
  350. package/dist/directives/match.cjs.map +0 -1
  351. package/dist/directives/match.d.ts +0 -31
  352. package/dist/directives/match.d.ts.map +0 -1
  353. package/dist/directives/match.js +0 -2
  354. package/dist/directives/match.js.map +0 -1
  355. package/dist/directives/memo.cjs +0 -2
  356. package/dist/directives/memo.cjs.map +0 -1
  357. package/dist/directives/memo.d.ts +0 -23
  358. package/dist/directives/memo.d.ts.map +0 -1
  359. package/dist/directives/memo.js +0 -2
  360. package/dist/directives/memo.js.map +0 -1
  361. package/dist/directives/on.cjs +0 -2
  362. package/dist/directives/on.cjs.map +0 -1
  363. package/dist/directives/on.d.ts +0 -25
  364. package/dist/directives/on.d.ts.map +0 -1
  365. package/dist/directives/on.js +0 -2
  366. package/dist/directives/on.js.map +0 -1
  367. package/dist/directives/spread.cjs +0 -2
  368. package/dist/directives/spread.cjs.map +0 -1
  369. package/dist/directives/spread.d.ts +0 -14
  370. package/dist/directives/spread.d.ts.map +0 -1
  371. package/dist/directives/spread.js +0 -2
  372. package/dist/directives/spread.js.map +0 -1
  373. package/dist/directives/style.cjs +0 -2
  374. package/dist/directives/style.cjs.map +0 -1
  375. package/dist/directives/style.d.ts +0 -22
  376. package/dist/directives/style.d.ts.map +0 -1
  377. package/dist/directives/style.js +0 -2
  378. package/dist/directives/style.js.map +0 -1
  379. package/dist/directives/until.cjs +0 -2
  380. package/dist/directives/until.cjs.map +0 -1
  381. package/dist/directives/until.d.ts +0 -26
  382. package/dist/directives/until.d.ts.map +0 -1
  383. package/dist/directives/until.js +0 -2
  384. package/dist/directives/until.js.map +0 -1
  385. package/dist/labs/a11y.cjs +0 -2
  386. package/dist/labs/a11y.cjs.map +0 -1
  387. package/dist/labs/a11y.d.ts +0 -61
  388. package/dist/labs/a11y.d.ts.map +0 -1
  389. package/dist/labs/a11y.js +0 -2
  390. package/dist/labs/a11y.js.map +0 -1
  391. package/dist/labs/index.d.ts +0 -8
  392. package/dist/labs/index.d.ts.map +0 -1
  393. package/dist/labs/list.cjs +0 -2
  394. package/dist/labs/list.cjs.map +0 -1
  395. package/dist/labs/list.d.ts +0 -26
  396. package/dist/labs/list.d.ts.map +0 -1
  397. package/dist/labs/list.js +0 -2
  398. package/dist/labs/list.js.map +0 -1
  399. package/dist/labs/observers.cjs +0 -2
  400. package/dist/labs/observers.cjs.map +0 -1
  401. package/dist/labs/observers.d.ts +0 -42
  402. package/dist/labs/observers.d.ts.map +0 -1
  403. package/dist/labs/observers.js +0 -2
  404. package/dist/labs/observers.js.map +0 -1
  405. package/dist/labs/overlay.cjs +0 -2
  406. package/dist/labs/overlay.cjs.map +0 -1
  407. package/dist/labs/overlay.d.ts.map +0 -1
  408. package/dist/labs/overlay.js +0 -2
  409. package/dist/labs/overlay.js.map +0 -1
  410. package/dist/labs/selectable.cjs +0 -2
  411. package/dist/labs/selectable.cjs.map +0 -1
  412. package/dist/labs/selectable.d.ts +0 -70
  413. package/dist/labs/selectable.d.ts.map +0 -1
  414. package/dist/labs/selectable.js +0 -2
  415. package/dist/labs/selectable.js.map +0 -1
  416. package/dist/labs/selection.cjs +0 -2
  417. package/dist/labs/selection.cjs.map +0 -1
  418. package/dist/labs/selection.d.ts +0 -68
  419. package/dist/labs/selection.d.ts.map +0 -1
  420. package/dist/labs/selection.js +0 -2
  421. package/dist/labs/selection.js.map +0 -1
  422. package/dist/labs.cjs +0 -1
  423. package/dist/labs.js +0 -1
  424. package/dist/test/index.d.ts +0 -2
  425. package/dist/test/index.d.ts.map +0 -1
  426. package/dist/test/test.cjs +0 -2
  427. package/dist/test/test.cjs.map +0 -1
  428. package/dist/test/test.d.ts.map +0 -1
  429. package/dist/test/test.js +0 -2
  430. package/dist/test/test.js.map +0 -1
  431. package/dist/test.cjs +0 -1
  432. package/dist/test.js +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.js","names":[],"sources":["../src/registration.ts"],"sourcesContent":["import { onCleanup as _onCleanup, scope as _scope, type Scope, untrack } from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { createHost, createSlots, type ComponentHost, type ComponentSlots } from './host';\nimport {\n createEmitFn,\n type CSSResult,\n type EmitFn,\n extractResult,\n type HTMLResult,\n loadStylesheet,\n toKebab,\n} from './internal';\nimport {\n createProps,\n isReflecting,\n normalizePropDefinition,\n prop,\n propRegistry,\n type InferPropsFromDefs,\n type InferPropsSignals,\n type PropDef,\n type PropInputDefs,\n type PropOptions,\n type PropsDef,\n} from './props';\nimport { type OnMountedCallback, type RuntimeScope, withCurrentElement, withRuntimeScope } from './runtime';\nimport { applyBindingsInContainer, applyHtmlBinding, parseHTML } from './template-bindings';\n\nexport type ComponentRegistrationOptions = {\n /** Indicates if this should be a form-associated element */\n formAssociated?: boolean;\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\nexport type ComponentTemplate = () => HTMLResult;\n\ntype ComponentState = {\n mountCallbacks: OnMountedCallback[];\n mountedCallbacksRan: boolean;\n mountToken: number;\n scope: Scope;\n setupDone: boolean;\n styles?: (string | CSSStyleSheet | CSSResult)[];\n templateMounted: boolean;\n templateResult: HTMLResult | null;\n};\n\nclass BaseElement extends HTMLElement {\n // Lifecycle: setup() runs on first connect (initializes scope + calls user setup).\n // _init() runs on every connect (applies initial attributes to reset prop state).\n // disconnectedCallback() disposes scope to run effect cleanups, then recreates it.\n // This means setup() re-runs on reconnect. Future optimization: track \"mounted\" state\n // separately to avoid re-running setup() on reconnect while still running cleanups.\n // On disconnect: cleanups run; on reconnect, styles and bindings are re-applied.\n static _options?: ComponentRegistrationOptions;\n static _setup: () => ComponentTemplate;\n static formAssociated = false;\n static observedAttributes: string[] = [];\n\n shadow: ShadowRoot;\n private _component: ComponentState;\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._component = {\n mountCallbacks: [],\n mountedCallbacksRan: false,\n mountToken: 0,\n scope: _scope(),\n setupDone: false,\n styles: options?.styles,\n templateMounted: false,\n templateResult: null,\n };\n }\n\n connectedCallback(): void {\n untrack(() => {\n if (!this._component.setupDone) this._runSetup();\n\n this._init();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (isReflecting(this, name)) return;\n\n const propMeta = propRegistry.get(this)?.get(name);\n\n if (!propMeta) return;\n\n const parsed = propMeta.parse(newValue);\n\n if (\n !Object.is(\n untrack(() => propMeta.signal.value),\n parsed,\n )\n ) {\n propMeta.signal.value = parsed as never;\n }\n }\n\n disconnectedCallback(): void {\n this._component.mountToken++;\n // Dispose and recreate scope to run all effect cleanups\n this._component.scope.dispose();\n this._component.scope = _scope();\n // Reset mount state for fresh mount callbacks on reconnect\n this._component.mountCallbacks = [];\n this._component.mountedCallbacksRan = false;\n this._component.templateMounted = false;\n this._component.templateResult = null;\n // Reset setupDone to re-run setup() on reconnect, ensuring effects are re-registered\n this._component.setupDone = false;\n }\n\n private _handleError(err: unknown): void {\n console.error(CRAFTIT_ERRORS.unhandledComponentError(this.localName), err);\n\n throw err instanceof Error ? err : new Error(String(err));\n }\n\n private _runSetup(): void {\n const setupScope: RuntimeScope = {\n element: this,\n mountCallbacks: [],\n };\n\n try {\n this._component.scope.run(() => {\n const template = withRuntimeScope(setupScope, () =>\n withCurrentElement(this, () => (this.constructor as typeof BaseElement)._setup()),\n );\n\n this._component.templateResult = withRuntimeScope(setupScope, () => withCurrentElement(this, () => template()));\n });\n\n this._component.mountCallbacks.push(...setupScope.mountCallbacks);\n this._component.setupDone = true;\n } catch (err) {\n this._handleError(err);\n }\n }\n\n private _init(): void {\n const { styles } = this._component;\n\n if (styles?.length) this.shadow.adoptedStyleSheets = styles.map(loadStylesheet);\n\n if (!this._component.templateMounted && this._component.templateResult != null) {\n const { bindings, html: htmlString } = extractResult(this._component.templateResult);\n\n this.shadow.replaceChildren(parseHTML(htmlString));\n this._component.templateMounted = true;\n\n if (bindings.length) {\n this._component.scope.run(() => {\n applyBindingsInContainer(this.shadow, bindings, _onCleanup, {\n onHtml: (binding) => applyHtmlBinding(this.shadow, binding, _onCleanup),\n });\n });\n }\n }\n\n if (!this._component.mountedCallbacksRan && this._component.mountCallbacks.length > 0) {\n this._component.mountedCallbacksRan = true;\n\n const token = ++this._component.mountToken;\n\n queueMicrotask(() => {\n if (!this.isConnected || token !== this._component.mountToken) return;\n\n try {\n for (const callback of this._component.mountCallbacks) {\n this._component.scope.run(() => {\n withRuntimeScope(\n {\n element: this,\n mountCallbacks: [],\n },\n () =>\n withCurrentElement(this, () => {\n const cleanup = callback();\n\n if (typeof cleanup === 'function') _onCleanup(cleanup);\n }),\n );\n });\n }\n } catch (err) {\n this._handleError(err);\n }\n });\n }\n }\n}\n\nconst defineComponent = (\n tag: string,\n setup: () => ComponentTemplate,\n options: ComponentRegistrationOptions = {},\n): string => {\n if (!tag) throw new Error(CRAFTIT_ERRORS.defineRequiresTag);\n\n if (customElements.get(tag)) {\n throw new Error(CRAFTIT_ERRORS.defineDuplicate(tag));\n }\n\n class Element extends BaseElement {\n static override _options = options;\n static override _setup = setup;\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// PUBLIC COMPONENT AUTHORING API (absorbed from component.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport { prop };\nexport type { InferPropsFromDefs, InferPropsSignals, PropDef, PropInputDefs, PropOptions, PropsDef };\n\n/**\n * Setup context passed as the second argument to the component setup function.\n */\nexport type SetupContextBag<Emits extends Record<string, unknown> = Record<string, unknown>> = {\n emit: EmitFn<Emits>;\n host: ComponentHost;\n slots: ComponentSlots;\n};\n\nexport type ComponentDefinition<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Enable form association for the custom element */\n formAssociated?: boolean;\n /** Component properties and their metadata */\n props?: PropsDef<Props>;\n /** Main setup function. Props are the first positional parameter, context bag is second. Returns a template function. */\n setup: (props: InferPropsSignals<Props>, ctx: SetupContextBag<Emits>) => ComponentTemplate;\n /** Shadow DOM configuration (mode is always 'open') */\n shadow?: Omit<ShadowRootInit, 'mode'>;\n /** Component-specific styles */\n styles?: (string | CSSStyleSheet | CSSResult)[];\n};\n\nconst createSetupProps = <Props extends Record<string, unknown>>(\n defs: PropsDef<Props> | undefined,\n): InferPropsSignals<Props> => {\n if (!defs) return {} as InferPropsSignals<Props>;\n\n return createProps(defs) as InferPropsSignals<Props>;\n};\n\nexport function define<\n Props extends Record<string, unknown> = Record<never, never>,\n Emits extends Record<string, unknown> = Record<string, never>,\n>(tag: string, definition: ComponentDefinition<Props, Emits>): string {\n const { formAssociated, props: propDefs, setup, shadow: shadowOptions, styles } = definition;\n\n // Normalize props at define-time for early error feedback\n const normalizedPropDefs: PropsDef<Props> | undefined = (() => {\n if (!propDefs) return undefined;\n\n const normalized: PropInputDefs = {};\n\n for (const [key, def] of Object.entries(propDefs)) {\n normalized[key] = normalizePropDefinition(def);\n }\n\n return normalized as PropsDef<Props>;\n })();\n\n const observedAttrs = normalizedPropDefs ? Object.keys(normalizedPropDefs).map(toKebab) : [];\n\n return defineComponent(\n tag,\n () => {\n const props = createSetupProps(normalizedPropDefs);\n const host = createHost();\n const emit = createEmitFn<Emits>();\n const slots = createSlots();\n\n return setup(props, { emit, host, slots });\n },\n { formAssociated, observedAttrs, shadow: shadowOptions, styles },\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./errors.cjs`),t=require(`./internal.cjs`);let n=require(`@vielzeug/stateit`);var r=null,i=null,a=(e,t)=>{let n=r;r=e;try{return t()}finally{r=n}},o=()=>{if(r)return r;throw Error(e.CRAFTIT_ERRORS.lifecycleOutsideSetup)},s=(e,t)=>{let n=i;i=e;try{return t()}finally{i=n}},c=e=>i?((0,n.onCleanup)(e),!0):!1,l=n.onCleanup,u=t=>{if(!i)throw Error(e.CRAFTIT_ERRORS.lifecycleOutsideSetup);i.mountCallbacks.push(t)},d=e=>{let t=(0,n.effect)(()=>e());return c(t),t};function f(n,r,a,o){if(!i)throw Error(e.CRAFTIT_ERRORS.lifecycleOutsideSetup);n&&c(t.listen(n,r,a,o))}function p(e,n,r,i){return t.listen(e,n,r,i)}var m=(e,t)=>d(()=>{let n=e.value;if(n)return t(n)});exports.currentElementOrThrow=o,exports.effect=d,exports.listen=p,exports.on=f,exports.onCleanup=l,exports.onElement=m,exports.onMounted=u,exports.tryRegisterCleanup=c,exports.withCurrentElement=a,exports.withRuntimeScope=s;
2
+ //# sourceMappingURL=runtime.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.cjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n effect as _effect,\n onCleanup as _onCleanup,\n type CleanupFn,\n type EffectCallback,\n type ReadonlySignal,\n type Subscription,\n} from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { fire, listen as listenInternal } from './internal';\n\nexport { fire };\n\nlet currentElement: HTMLElement | null = null;\nlet currentScope: RuntimeScope | null = null;\n\nexport type OnMountedCallback = () => CleanupFn | void;\n\nexport type RuntimeScope = {\n element: HTMLElement;\n mountCallbacks: OnMountedCallback[];\n};\n\nexport const withCurrentElement = <T>(el: HTMLElement, fn: () => T): T => {\n const previous = currentElement;\n\n currentElement = el;\n\n try {\n return fn();\n } finally {\n currentElement = previous;\n }\n};\n\nexport const currentElementOrThrow = (): HTMLElement => {\n if (currentElement) return currentElement;\n\n throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n};\n\n/** @internal */\nexport const withRuntimeScope = <T>(runtimeScope: RuntimeScope, fn: () => T): T => {\n const prev = currentScope;\n\n currentScope = runtimeScope;\n\n try {\n return fn();\n } finally {\n currentScope = prev;\n }\n};\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentScope) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to be called on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts.\n * Multiple callbacks are supported and run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n currentScope.mountCallbacks.push(fn);\n};\n\nexport const effect = (fn: EffectCallback): Subscription => {\n const dispose = _effect(() => {\n return fn();\n });\n\n tryRegisterCleanup(dispose);\n\n return dispose;\n};\n\nexport function on<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function on(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n tryRegisterCleanup(cleanup);\n}\n\n/**\n * Attaches an event listener and returns a disposal function.\n * Unlike `on()`, this does not require a runtime scope and cleanup must be\n * managed manually by calling the returned function.\n */\nexport function listen<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): () => void;\nexport function listen(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): () => void {\n return listenInternal(target, event, listener, options);\n}\n\nexport const onElement = <T extends HTMLElement>(\n ref: ReadonlySignal<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): Subscription => {\n return effect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"+FAcA,IAAI,EAAqC,KACrC,EAAoC,KAS3B,GAAyB,EAAiB,IAAmB,CACxE,IAAM,EAAW,EAEjB,EAAiB,EAEjB,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAiB,CACnB,CACF,EAEa,MAA2C,CACtD,GAAI,EAAgB,OAAO,EAE3B,MAAU,MAAM,EAAA,eAAe,qBAAqB,CACtD,EAGa,GAAuB,EAA4B,IAAmB,CACjF,IAAM,EAAO,EAEb,EAAe,EAEf,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAe,CACjB,CACF,EAEa,EAAsB,GAC5B,IAEL,EAAA,EAAA,WAAW,CAAE,EAEN,IAJmB,GAWf,EAAY,EAAA,UAMZ,EAAa,GAAgC,CACxD,GAAI,CAAC,EAAc,MAAU,MAAM,EAAA,eAAe,qBAAqB,EAEvE,EAAa,eAAe,KAAK,CAAE,CACrC,EAEa,EAAU,GAAqC,CAC1D,IAAM,GAAA,EAAA,EAAA,YACG,EAAG,CACX,EAID,OAFA,EAAmB,CAAO,EAEnB,CACT,EAQA,SAAgB,EACd,EACA,EACA,EACA,EACM,CACN,GAAI,CAAC,EAAc,MAAU,MAAM,EAAA,eAAe,qBAAqB,EAElE,GAIL,EAFgB,EAAA,OAAe,EAAQ,EAAO,EAAU,CAErC,CAAO,CAC5B,CAaA,SAAgB,EACd,EACA,EACA,EACA,EACY,CACZ,OAAO,EAAA,OAAe,EAAQ,EAAO,EAAU,CAAO,CACxD,CAEA,IAAa,GACX,EACA,IAEO,MAAa,CAClB,IAAM,EAAK,EAAI,MAEf,GAAI,EAAI,OAAO,EAAS,CAAE,CAC5B,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type CleanupFn, type EffectCallback, type ReadonlySignal, type Subscription } from '@vielzeug/stateit';
2
+ import { fire } from './internal';
3
+ export { fire };
4
+ export type OnMountedCallback = () => CleanupFn | void;
5
+ export type RuntimeScope = {
6
+ element: HTMLElement;
7
+ mountCallbacks: OnMountedCallback[];
8
+ };
9
+ export declare const withCurrentElement: <T>(el: HTMLElement, fn: () => T) => T;
10
+ export declare const currentElementOrThrow: () => HTMLElement;
11
+ /** @internal */
12
+ export declare const withRuntimeScope: <T>(runtimeScope: RuntimeScope, fn: () => T) => T;
13
+ export declare const tryRegisterCleanup: (fn: CleanupFn) => boolean;
14
+ /**
15
+ * Register a cleanup function to be called on component disconnect.
16
+ * Must be called synchronously during component setup or inside scope.run().
17
+ */
18
+ export declare const onCleanup: (fn: CleanupFn) => void;
19
+ /**
20
+ * Register work to run after the component template mounts.
21
+ * Multiple callbacks are supported and run in registration order.
22
+ */
23
+ export declare const onMounted: (fn: OnMountedCallback) => void;
24
+ export declare const effect: (fn: EffectCallback) => Subscription;
25
+ export declare function on<K extends keyof HTMLElementEventMap>(target: EventTarget | null | undefined, event: K, listener: (e: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): void;
26
+ /**
27
+ * Attaches an event listener and returns a disposal function.
28
+ * Unlike `on()`, this does not require a runtime scope and cleanup must be
29
+ * managed manually by calling the returned function.
30
+ */
31
+ export declare function listen<K extends keyof HTMLElementEventMap>(target: EventTarget | null | undefined, event: K, listener: (e: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): () => void;
32
+ export declare const onElement: <T extends HTMLElement>(ref: ReadonlySignal<T | null>, callback: (el: T) => CleanupFn | undefined | void) => Subscription;
33
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,IAAI,EAA4B,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,IAAI,EAAE,CAAC;AAKhB,MAAM,MAAM,iBAAiB,GAAG,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,WAAW,CAAC;IACrB,cAAc,EAAE,iBAAiB,EAAE,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAAE,IAAI,WAAW,EAAE,IAAI,MAAM,CAAC,KAAG,CAUpE,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAO,WAIxC,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,cAAc,YAAY,EAAE,IAAI,MAAM,CAAC,KAAG,CAU7E,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,IAAI,SAAS,KAAG,OAMlD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,yBAAa,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,IAAI,iBAAiB,KAAG,IAIjD,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,IAAI,cAAc,KAAG,YAQ3C,CAAC;AAEF,wBAAgB,EAAE,CAAC,CAAC,SAAS,MAAM,mBAAmB,EACpD,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,CAAC,EAAE,uBAAuB,GAChC,IAAI,CAAC;AAgBR;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,mBAAmB,EACxD,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAC7C,OAAO,CAAC,EAAE,uBAAuB,GAChC,MAAM,IAAI,CAAC;AAUd,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,EAC7C,KAAK,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC,EAC7B,UAAU,CAAC,EAAE,EAAE,CAAC,KAAK,SAAS,GAAG,SAAS,GAAG,IAAI,KAChD,YAMF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{CRAFTIT_ERRORS as e}from"./errors.js";import{listen as t}from"./internal.js";import{effect as n,onCleanup as r}from"@vielzeug/stateit";var i=null,a=null,o=(e,t)=>{let n=i;i=e;try{return t()}finally{i=n}},s=()=>{if(i)return i;throw Error(e.lifecycleOutsideSetup)},c=(e,t)=>{let n=a;a=e;try{return t()}finally{a=n}},l=e=>a?(r(e),!0):!1,u=r,d=t=>{if(!a)throw Error(e.lifecycleOutsideSetup);a.mountCallbacks.push(t)},f=e=>{let t=n(()=>e());return l(t),t};function p(n,r,i,o){if(!a)throw Error(e.lifecycleOutsideSetup);n&&l(t(n,r,i,o))}function m(e,n,r,i){return t(e,n,r,i)}var h=(e,t)=>f(()=>{let n=e.value;if(n)return t(n)});export{s as currentElementOrThrow,f as effect,m as listen,p as on,u as onCleanup,h as onElement,d as onMounted,l as tryRegisterCleanup,o as withCurrentElement,c as withRuntimeScope};
2
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import {\n effect as _effect,\n onCleanup as _onCleanup,\n type CleanupFn,\n type EffectCallback,\n type ReadonlySignal,\n type Subscription,\n} from '@vielzeug/stateit';\n\nimport { CRAFTIT_ERRORS } from './errors';\nimport { fire, listen as listenInternal } from './internal';\n\nexport { fire };\n\nlet currentElement: HTMLElement | null = null;\nlet currentScope: RuntimeScope | null = null;\n\nexport type OnMountedCallback = () => CleanupFn | void;\n\nexport type RuntimeScope = {\n element: HTMLElement;\n mountCallbacks: OnMountedCallback[];\n};\n\nexport const withCurrentElement = <T>(el: HTMLElement, fn: () => T): T => {\n const previous = currentElement;\n\n currentElement = el;\n\n try {\n return fn();\n } finally {\n currentElement = previous;\n }\n};\n\nexport const currentElementOrThrow = (): HTMLElement => {\n if (currentElement) return currentElement;\n\n throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n};\n\n/** @internal */\nexport const withRuntimeScope = <T>(runtimeScope: RuntimeScope, fn: () => T): T => {\n const prev = currentScope;\n\n currentScope = runtimeScope;\n\n try {\n return fn();\n } finally {\n currentScope = prev;\n }\n};\n\nexport const tryRegisterCleanup = (fn: CleanupFn): boolean => {\n if (!currentScope) return false;\n\n _onCleanup(fn);\n\n return true;\n};\n\n/**\n * Register a cleanup function to be called on component disconnect.\n * Must be called synchronously during component setup or inside scope.run().\n */\nexport const onCleanup = _onCleanup;\n\n/**\n * Register work to run after the component template mounts.\n * Multiple callbacks are supported and run in registration order.\n */\nexport const onMounted = (fn: OnMountedCallback): void => {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n currentScope.mountCallbacks.push(fn);\n};\n\nexport const effect = (fn: EffectCallback): Subscription => {\n const dispose = _effect(() => {\n return fn();\n });\n\n tryRegisterCleanup(dispose);\n\n return dispose;\n};\n\nexport function on<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): void;\nexport function on(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): void {\n if (!currentScope) throw new Error(CRAFTIT_ERRORS.lifecycleOutsideSetup);\n\n if (!target) return;\n\n const cleanup = listenInternal(target, event, listener, options);\n\n tryRegisterCleanup(cleanup);\n}\n\n/**\n * Attaches an event listener and returns a disposal function.\n * Unlike `on()`, this does not require a runtime scope and cleanup must be\n * managed manually by calling the returned function.\n */\nexport function listen<K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): () => void;\nexport function listen(\n target: EventTarget | null | undefined,\n event: string,\n listener: EventListener,\n options?: AddEventListenerOptions,\n): () => void {\n return listenInternal(target, event, listener, options);\n}\n\nexport const onElement = <T extends HTMLElement>(\n ref: ReadonlySignal<T | null>,\n callback: (el: T) => CleanupFn | undefined | void,\n): Subscription => {\n return effect(() => {\n const el = ref.value;\n\n if (el) return callback(el);\n });\n};\n"],"mappings":"8IAcA,IAAI,EAAqC,KACrC,EAAoC,KAS3B,GAAyB,EAAiB,IAAmB,CACxE,IAAM,EAAW,EAEjB,EAAiB,EAEjB,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAiB,CACnB,CACF,EAEa,MAA2C,CACtD,GAAI,EAAgB,OAAO,EAE3B,MAAU,MAAM,EAAe,qBAAqB,CACtD,EAGa,GAAuB,EAA4B,IAAmB,CACjF,IAAM,EAAO,EAEb,EAAe,EAEf,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAe,CACjB,CACF,EAEa,EAAsB,GAC5B,GAEL,EAAW,CAAE,EAEN,IAJmB,GAWf,EAAY,EAMZ,EAAa,GAAgC,CACxD,GAAI,CAAC,EAAc,MAAU,MAAM,EAAe,qBAAqB,EAEvE,EAAa,eAAe,KAAK,CAAE,CACrC,EAEa,EAAU,GAAqC,CAC1D,IAAM,EAAU,MACP,EAAG,CACX,EAID,OAFA,EAAmB,CAAO,EAEnB,CACT,EAQA,SAAgB,EACd,EACA,EACA,EACA,EACM,CACN,GAAI,CAAC,EAAc,MAAU,MAAM,EAAe,qBAAqB,EAElE,GAIL,EAFgB,EAAe,EAAQ,EAAO,EAAU,CAErC,CAAO,CAC5B,CAaA,SAAgB,EACd,EACA,EACA,EACA,EACY,CACZ,OAAO,EAAe,EAAQ,EAAO,EAAU,CAAO,CACxD,CAEA,IAAa,GACX,EACA,IAEO,MAAa,CAClB,IAAM,EAAK,EAAI,MAEf,GAAI,EAAI,OAAO,EAAS,CAAE,CAC5B,CAAC"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./internal.cjs`),t=require(`./props.cjs`),n=require(`./directives/live.cjs`);let r=require(`@vielzeug/stateit`);var i=e=>{let t=document.createElement(`template`);return t.innerHTML=e,t.content.cloneNode(!0)},a=(e,t)=>{if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue;n&&t.comments.set(n,e);return}if(e.nodeType!==Node.ELEMENT_NODE)return;let n=e.getAttribute(`u`);n&&t.elements.set(n,e)},o=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_ELEMENT);for(t(e);n.nextNode();)t(n.currentNode)},s=e=>{let t={comments:new Map,elements:new Map};for(let n of e)o(n,e=>a(e,t));return t},c=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT);for(;n.nextNode();){let e=n.currentNode;if(e.nodeValue===t)return e}return null},l=e=>Array.isArray(e)||typeof e==`object`&&!!e,u=e=>e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement,d=(e,t,n,r)=>{let i=t==null?``:String(t);n&&r.last!==void 0&&!Object.is(e.value,r.last)&&!Object.is(e.value,i)||(e.value=i,n&&(r.last=i))},f=(e,t,n,r)=>{let i=!!t;n&&r.last!==void 0&&e.checked!==!!r.last&&e.checked!==i||(e.checked=i,n&&(r.last=i))},p=(t,n,i,a)=>{let o=l(a)?a:n.parse(i.mode===`bool`?a?``:null:a==null||a===!1?null:String(a));if(Object.is((0,r.untrack)(()=>n.signal.value),o)||(n.signal.value=o),!n.reflect){if(l(a))return;i.mode===`bool`?t.toggleAttribute(i.name,!!a):e.setAttr(t,i.name,a)}},m=(e,t,n)=>{n((0,r.effect)(()=>t(e.value)))},h=(n,r,i)=>{let a=t.propRegistry.get(n)?.get(r.name),o={last:void 0},s=t=>{if(!a&&l(t)){n[r.name]=t;return}if(!a&&r.name===`value`&&u(n)){d(n,t,r.live,o);return}if(!a&&r.name===`checked`&&n instanceof HTMLInputElement){f(n,t,r.live,o);return}if(!a){r.mode===`bool`?n.toggleAttribute(r.name,!!t):e.setAttr(n,r.name,t);return}p(n,a,r,t)};r.signal?m(r.signal,s,i):s(r.value)},g=(t,n,r)=>{r(e.listen(t,n.name,n.handler,n.options))},_=(e,t,n)=>{let{ref:r}=t;if(typeof r==`function`){r(e),n(()=>r(null));return}if(Array.isArray(r)){r.push(e),n(()=>{let t=r.indexOf(e);t!==-1&&r.splice(t,1)});return}r.value=e,n(()=>{r.value=null})},v=(e,t,n,r)=>{let i=new Map;for(let a of e){let e=a.uid;if(a.type===`text`){let r=n.comments.get(e);if(r){let i=document.createTextNode(``);r.replaceWith(i),n.comments.delete(e),m(a.signal,e=>{i.textContent=String(e)},t)}}else if(a.type===`directive`){let r=n.comments.get(e);r&&(a.directive.mount(r,t),n.comments.delete(e))}else if(a.type===`html`)r?.onHtml?.(a);else{let t=i.get(e);t?t.push(a):i.set(e,[a])}}for(let[e,r]of i){let i=n.elements.get(e);if(i){i.removeAttribute(`u`),n.elements.delete(e);for(let e of r)e.type===`attr`?h(i,e,t):e.type===`event`?g(i,e,t):e.type===`ref`&&_(i,e,t)}}},y=(e,t,n,r)=>{v(t,n,s([e]),r)},b=(e,t,i,a)=>n.isLiveSignal(a)?{live:!0,mode:e,name:t,signal:a,type:`attr`,uid:i}:typeof a==`function`?{mode:e,name:t,signal:(0,r.computed)(a),type:`attr`,uid:i}:(0,r.isSignal)(a)?{mode:e,name:t,signal:a,type:`attr`,uid:i}:{mode:e,name:t,type:`attr`,uid:i,value:a},x=(t,n,a)=>{let o=c(t,n.uid);if(!o)return;let s=document.createComment(`html-binding`);o.replaceWith(s);let l=[],u=e=>l.push(e),d=()=>{e.runAll(l),l=[]},f=null,p=[];a((0,r.effect)(()=>{(0,r.batch)(()=>{let a;try{a=n.signal.value}catch(e){if(e instanceof Error&&e.message.includes(`[stateit] Cannot read disposed computed signal`))return;throw e}if(a.html===f)return;f=a.html,d();let{bindings:o,html:c}=a,l=s.parentElement||t;(0,r.untrack)(()=>{(0,r.batch)(()=>{e.removeNodes(p);let t=i(c);p=Array.from(t.childNodes),s.after(t)}),y(l,o,u,{onHtml:e=>x(l,e,u)})})})})),a(d)};exports.applyBindingsInContainer=y,exports.applyBindingsWithTargets=v,exports.applyHtmlBinding=x,exports.createAttrBinding=b,exports.indexBindingTargets=s,exports.parseHTML=i;
2
+ //# sourceMappingURL=template-bindings.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-bindings.cjs","names":[],"sources":["../src/template-bindings.ts"],"sourcesContent":["import {\n batch,\n computed,\n effect as rawEffect,\n isSignal,\n type CleanupFn,\n type ReadonlySignal,\n untrack,\n} from '@vielzeug/stateit';\n\nimport { isLiveSignal } from './directives/live';\nimport {\n CF_ID_ATTR,\n type AttrBinding,\n type Binding,\n type EventBinding,\n type HtmlBinding,\n type RefBinding,\n listen,\n removeNodes,\n runAll,\n setAttr,\n} from './internal';\nimport { propRegistry } from './props';\n\nexport type RegisterCleanup = (fn: CleanupFn) => void;\n\nexport type BindingTargets = {\n comments: Map<string, Comment>;\n elements: Map<string, HTMLElement>;\n};\n\nexport const parseHTML = (html: string): DocumentFragment => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n return tpl.content.cloneNode(true) as DocumentFragment;\n};\n\nconst collectBindingTarget = (node: Node, targets: BindingTargets): void => {\n if (node.nodeType === Node.COMMENT_NODE) {\n const marker = (node as Comment).nodeValue;\n\n if (marker) targets.comments.set(marker, node as Comment);\n\n return;\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n\n const id = (node as Element).getAttribute(CF_ID_ATTR);\n\n if (id) targets.elements.set(id, node as HTMLElement);\n};\n\nconst walkBindingTargets = (root: Node, visit: (node: Node) => void): void => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_ELEMENT);\n\n visit(root);\n\n while (walker.nextNode()) visit(walker.currentNode);\n};\n\nexport const indexBindingTargets = (nodes: Iterable<Node>): BindingTargets => {\n const targets: BindingTargets = { comments: new Map(), elements: new Map() };\n\n for (const node of nodes) walkBindingTargets(node, (current) => collectBindingTarget(current, targets));\n\n return targets;\n};\n\nexport const findCommentMarker = (root: Node, marker: string): Comment | null => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n\n if (comment.nodeValue === marker) return comment;\n }\n\n return null;\n};\n\nconst isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n\nconst isNativeFormInput = (el: HTMLElement): el is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement =>\n el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement;\n\ntype LiveWriteState = { last: unknown };\n\nconst applyFormValue = (\n el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = value == null ? '' : String(value);\n\n if (isLive && state.last !== undefined && !Object.is(el.value, state.last) && !Object.is(el.value, next)) return;\n\n el.value = next;\n\n if (isLive) state.last = next;\n};\n\nconst applyCheckedValue = (\n el: HTMLInputElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = Boolean(value);\n\n if (isLive && state.last !== undefined && el.checked !== Boolean(state.last) && el.checked !== next) return;\n\n el.checked = next;\n\n if (isLive) state.last = next;\n};\n\ntype PropMetaLike = { parse: (v: string | null) => unknown; reflect: boolean; signal: { value: unknown } };\n\nconst syncRegisteredProp = (el: HTMLElement, meta: PropMetaLike, binding: AttrBinding, value: unknown): void => {\n const parsed = isStructuredValue(value)\n ? value\n : meta.parse(\n binding.mode === 'bool' ? (value ? '' : null) : value == null || value === false ? null : String(value),\n );\n\n if (\n !Object.is(\n untrack(() => meta.signal.value),\n parsed,\n )\n ) {\n meta.signal.value = parsed as never;\n }\n\n // When reflect:false the prop signal has no reflect-effect; write the attribute\n // directly so the DOM stays in sync with template bindings.\n if (!meta.reflect) {\n if (isStructuredValue(value)) return;\n\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n }\n};\n\nconst signalEffect = (\n signal: ReadonlySignal<unknown>,\n update: (v: unknown) => void,\n registerCleanup: RegisterCleanup,\n): void => {\n registerCleanup(rawEffect(() => update(signal.value)));\n};\n\nexport const applyAttrBinding = (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup): void => {\n const meta = propRegistry.get(el)?.get(binding.name) as PropMetaLike | undefined;\n const liveState: LiveWriteState = { last: undefined };\n\n const update = (value: unknown): void => {\n if (!meta && isStructuredValue(value)) {\n (el as unknown as Record<string, unknown>)[binding.name] = value;\n\n return;\n }\n\n if (!meta && binding.name === 'value' && isNativeFormInput(el)) {\n applyFormValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta && binding.name === 'checked' && el instanceof HTMLInputElement) {\n applyCheckedValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta) {\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n\n return;\n }\n\n syncRegisteredProp(el, meta, binding, value);\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n};\n\nexport const applyEventBinding = (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => {\n registerCleanup(listen(el, binding.name, binding.handler, binding.options));\n};\n\nexport const applyRefBinding = (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => {\n const { ref } = binding;\n\n if (typeof ref === 'function') {\n ref(el as never);\n registerCleanup(() => ref(null as never));\n\n return;\n }\n\n if (Array.isArray(ref)) {\n ref.push(el);\n registerCleanup(() => {\n const i = ref.indexOf(el);\n\n if (i !== -1) ref.splice(i, 1);\n });\n\n return;\n }\n\n ref.value = el as never;\n registerCleanup(() => {\n ref.value = null as never;\n });\n};\n\ntype ElementBinding = AttrBinding | EventBinding | RefBinding;\n\nexport const applyBindingsWithTargets = (\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n targets: BindingTargets,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n const bindingMap = new Map<string, ElementBinding[]>();\n\n for (const b of bindings) {\n const id = b.uid;\n\n if (b.type === 'text') {\n const found = targets.comments.get(id);\n\n if (found) {\n const textNode = document.createTextNode('');\n\n found.replaceWith(textNode);\n targets.comments.delete(id);\n signalEffect(\n b.signal,\n (v) => {\n textNode.textContent = String(v);\n },\n registerCleanup,\n );\n }\n } else if (b.type === 'directive') {\n const found = targets.comments.get(id);\n\n if (found) {\n b.directive.mount(found, registerCleanup);\n targets.comments.delete(id);\n }\n } else if (b.type === 'html') {\n opts?.onHtml?.(b);\n } else {\n const grouped = bindingMap.get(id);\n\n if (grouped) grouped.push(b);\n else bindingMap.set(id, [b]);\n }\n }\n\n for (const [id, elBindings] of bindingMap) {\n const el = targets.elements.get(id);\n\n if (!el) continue;\n\n el.removeAttribute(CF_ID_ATTR);\n targets.elements.delete(id);\n\n // Inline element binding dispatch\n for (const b of elBindings) {\n if (b.type === 'attr') {\n applyAttrBinding(el, b, registerCleanup);\n } else if (b.type === 'event') {\n applyEventBinding(el, b, registerCleanup);\n } else if (b.type === 'ref') {\n applyRefBinding(el, b, registerCleanup);\n }\n }\n }\n};\n\nexport const applyBindingsInContainer = (\n container: ParentNode,\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n applyBindingsWithTargets(bindings, registerCleanup, indexBindingTargets([container]), opts);\n};\n\nexport const createAttrBinding = (mode: 'bool' | 'attr', name: string, uid: string, value: unknown): AttrBinding => {\n if (isLiveSignal(value)) {\n return { live: true, mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n if (typeof value === 'function') {\n return { mode, name, signal: computed(value as () => unknown), type: 'attr', uid };\n }\n\n if (isSignal(value)) {\n return { mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n return { mode, name, type: 'attr', uid, value };\n};\n\n/**\n * Sets up the reactive effect for an html-binding marker using full fragment replacement.\n */\nexport const applyHtmlBinding = (root: Node, b: HtmlBinding, registerCleanup: RegisterCleanup): void => {\n const found = findCommentMarker(root, b.uid);\n\n if (!found) return;\n\n const marker = document.createComment('html-binding');\n\n found.replaceWith(marker);\n\n let currentCleanups: CleanupFn[] = [];\n const registerInnerCleanup: RegisterCleanup = (fn) => currentCleanups.push(fn);\n const runCurrentCleanups = () => {\n runAll(currentCleanups);\n currentCleanups = [];\n };\n let lastHtml: string | null = null;\n let lastInsertedNodes: Node[] = [];\n\n const stop = rawEffect(() => {\n batch(() => {\n let data: HtmlBinding['signal']['value'];\n\n try {\n data = b.signal.value;\n } catch (error) {\n if (error instanceof Error && error.message.includes('[stateit] Cannot read disposed computed signal')) return;\n\n throw error;\n }\n\n if (data.html === lastHtml) {\n return;\n }\n\n lastHtml = data.html;\n runCurrentCleanups();\n\n const { bindings, html } = data;\n const container = (marker.parentElement || root) as ParentNode;\n\n untrack(() => {\n batch(() => {\n removeNodes(lastInsertedNodes);\n\n const parsed = parseHTML(html);\n\n lastInsertedNodes = Array.from(parsed.childNodes);\n marker.after(parsed);\n });\n\n applyBindingsInContainer(container, bindings, registerInnerCleanup, {\n onHtml: (binding) => applyHtmlBinding(container as unknown as Node, binding, registerInnerCleanup),\n });\n });\n });\n });\n\n registerCleanup(stop);\n registerCleanup(runCurrentCleanups);\n};\n"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type CleanupFn } from '@vielzeug/stateit';
2
+ import { type AttrBinding, type Binding, type EventBinding, type HtmlBinding, type RefBinding } from './internal';
3
+ export type RegisterCleanup = (fn: CleanupFn) => void;
4
+ export type BindingTargets = {
5
+ comments: Map<string, Comment>;
6
+ elements: Map<string, HTMLElement>;
7
+ };
8
+ export declare const parseHTML: (html: string) => DocumentFragment;
9
+ export declare const indexBindingTargets: (nodes: Iterable<Node>) => BindingTargets;
10
+ export declare const findCommentMarker: (root: Node, marker: string) => Comment | null;
11
+ export declare const applyAttrBinding: (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup) => void;
12
+ export declare const applyEventBinding: (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => void;
13
+ export declare const applyRefBinding: (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => void;
14
+ export declare const applyBindingsWithTargets: (bindings: Binding[], registerCleanup: RegisterCleanup, targets: BindingTargets, opts?: {
15
+ onHtml?: (b: HtmlBinding) => void;
16
+ }) => void;
17
+ export declare const applyBindingsInContainer: (container: ParentNode, bindings: Binding[], registerCleanup: RegisterCleanup, opts?: {
18
+ onHtml?: (b: HtmlBinding) => void;
19
+ }) => void;
20
+ export declare const createAttrBinding: (mode: "bool" | "attr", name: string, uid: string, value: unknown) => AttrBinding;
21
+ /**
22
+ * Sets up the reactive effect for an html-binding marker using full fragment replacement.
23
+ */
24
+ export declare const applyHtmlBinding: (root: Node, b: HtmlBinding, registerCleanup: RegisterCleanup) => void;
25
+ //# sourceMappingURL=template-bindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-bindings.d.ts","sourceRoot":"","sources":["../src/template-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,EAKhB,MAAM,YAAY,CAAC;AAGpB,MAAM,MAAM,eAAe,GAAG,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACpC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,gBAMxC,CAAC;AA0BF,eAAO,MAAM,mBAAmB,GAAI,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAG,cAM3D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,IAAI,EAAE,QAAQ,MAAM,KAAG,OAAO,GAAG,IAUxE,CAAC;AA4EF,eAAO,MAAM,gBAAgB,GAAI,IAAI,WAAW,EAAE,SAAS,WAAW,EAAE,iBAAiB,eAAe,KAAG,IAsC1G,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,IAAI,WAAW,EAAE,SAAS,YAAY,EAAE,iBAAiB,eAAe,SAEzG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,IAAI,WAAW,EAAE,SAAS,UAAU,EAAE,iBAAiB,eAAe,SAyBrG,CAAC;AAIF,eAAO,MAAM,wBAAwB,GACnC,UAAU,OAAO,EAAE,EACnB,iBAAiB,eAAe,EAChC,SAAS,cAAc,EACvB,OAAO;IAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;CAAE,SA2D7C,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,WAAW,UAAU,EACrB,UAAU,OAAO,EAAE,EACnB,iBAAiB,eAAe,EAChC,OAAO;IAAE,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;CAAE,SAG7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,MAAM,EAAE,OAAO,OAAO,KAAG,WAcpG,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,IAAI,EAAE,GAAG,WAAW,EAAE,iBAAiB,eAAe,KAAG,IA2D/F,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{listen as e,removeNodes as t,runAll as n,setAttr as r}from"./internal.js";import{propRegistry as i}from"./props.js";import{isLiveSignal as a}from"./directives/live.js";import{batch as o,computed as s,effect as c,isSignal as l,untrack as u}from"@vielzeug/stateit";var d=e=>{let t=document.createElement(`template`);return t.innerHTML=e,t.content.cloneNode(!0)},f=(e,t)=>{if(e.nodeType===Node.COMMENT_NODE){let n=e.nodeValue;n&&t.comments.set(n,e);return}if(e.nodeType!==Node.ELEMENT_NODE)return;let n=e.getAttribute(`u`);n&&t.elements.set(n,e)},p=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_ELEMENT);for(t(e);n.nextNode();)t(n.currentNode)},m=e=>{let t={comments:new Map,elements:new Map};for(let n of e)p(n,e=>f(e,t));return t},h=(e,t)=>{let n=document.createTreeWalker(e,NodeFilter.SHOW_COMMENT);for(;n.nextNode();){let e=n.currentNode;if(e.nodeValue===t)return e}return null},g=e=>Array.isArray(e)||typeof e==`object`&&!!e,_=e=>e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement,v=(e,t,n,r)=>{let i=t==null?``:String(t);n&&r.last!==void 0&&!Object.is(e.value,r.last)&&!Object.is(e.value,i)||(e.value=i,n&&(r.last=i))},y=(e,t,n,r)=>{let i=!!t;n&&r.last!==void 0&&e.checked!==!!r.last&&e.checked!==i||(e.checked=i,n&&(r.last=i))},b=(e,t,n,i)=>{let a=g(i)?i:t.parse(n.mode===`bool`?i?``:null:i==null||i===!1?null:String(i));if(Object.is(u(()=>t.signal.value),a)||(t.signal.value=a),!t.reflect){if(g(i))return;n.mode===`bool`?e.toggleAttribute(n.name,!!i):r(e,n.name,i)}},x=(e,t,n)=>{n(c(()=>t(e.value)))},S=(e,t,n)=>{let a=i.get(e)?.get(t.name),o={last:void 0},s=n=>{if(!a&&g(n)){e[t.name]=n;return}if(!a&&t.name===`value`&&_(e)){v(e,n,t.live,o);return}if(!a&&t.name===`checked`&&e instanceof HTMLInputElement){y(e,n,t.live,o);return}if(!a){t.mode===`bool`?e.toggleAttribute(t.name,!!n):r(e,t.name,n);return}b(e,a,t,n)};t.signal?x(t.signal,s,n):s(t.value)},C=(t,n,r)=>{r(e(t,n.name,n.handler,n.options))},w=(e,t,n)=>{let{ref:r}=t;if(typeof r==`function`){r(e),n(()=>r(null));return}if(Array.isArray(r)){r.push(e),n(()=>{let t=r.indexOf(e);t!==-1&&r.splice(t,1)});return}r.value=e,n(()=>{r.value=null})},T=(e,t,n,r)=>{let i=new Map;for(let a of e){let e=a.uid;if(a.type===`text`){let r=n.comments.get(e);if(r){let i=document.createTextNode(``);r.replaceWith(i),n.comments.delete(e),x(a.signal,e=>{i.textContent=String(e)},t)}}else if(a.type===`directive`){let r=n.comments.get(e);r&&(a.directive.mount(r,t),n.comments.delete(e))}else if(a.type===`html`)r?.onHtml?.(a);else{let t=i.get(e);t?t.push(a):i.set(e,[a])}}for(let[e,r]of i){let i=n.elements.get(e);if(i){i.removeAttribute(`u`),n.elements.delete(e);for(let e of r)e.type===`attr`?S(i,e,t):e.type===`event`?C(i,e,t):e.type===`ref`&&w(i,e,t)}}},E=(e,t,n,r)=>{T(t,n,m([e]),r)},D=(e,t,n,r)=>a(r)?{live:!0,mode:e,name:t,signal:r,type:`attr`,uid:n}:typeof r==`function`?{mode:e,name:t,signal:s(r),type:`attr`,uid:n}:l(r)?{mode:e,name:t,signal:r,type:`attr`,uid:n}:{mode:e,name:t,type:`attr`,uid:n,value:r},O=(e,r,i)=>{let a=h(e,r.uid);if(!a)return;let s=document.createComment(`html-binding`);a.replaceWith(s);let l=[],f=e=>l.push(e),p=()=>{n(l),l=[]},m=null,g=[];i(c(()=>{o(()=>{let n;try{n=r.signal.value}catch(e){if(e instanceof Error&&e.message.includes(`[stateit] Cannot read disposed computed signal`))return;throw e}if(n.html===m)return;m=n.html,p();let{bindings:i,html:a}=n,c=s.parentElement||e;u(()=>{o(()=>{t(g);let e=d(a);g=Array.from(e.childNodes),s.after(e)}),E(c,i,f,{onHtml:e=>O(c,e,f)})})})})),i(p)};export{E as applyBindingsInContainer,T as applyBindingsWithTargets,O as applyHtmlBinding,D as createAttrBinding,m as indexBindingTargets,d as parseHTML};
2
+ //# sourceMappingURL=template-bindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-bindings.js","names":[],"sources":["../src/template-bindings.ts"],"sourcesContent":["import {\n batch,\n computed,\n effect as rawEffect,\n isSignal,\n type CleanupFn,\n type ReadonlySignal,\n untrack,\n} from '@vielzeug/stateit';\n\nimport { isLiveSignal } from './directives/live';\nimport {\n CF_ID_ATTR,\n type AttrBinding,\n type Binding,\n type EventBinding,\n type HtmlBinding,\n type RefBinding,\n listen,\n removeNodes,\n runAll,\n setAttr,\n} from './internal';\nimport { propRegistry } from './props';\n\nexport type RegisterCleanup = (fn: CleanupFn) => void;\n\nexport type BindingTargets = {\n comments: Map<string, Comment>;\n elements: Map<string, HTMLElement>;\n};\n\nexport const parseHTML = (html: string): DocumentFragment => {\n const tpl = document.createElement('template');\n\n tpl.innerHTML = html;\n\n return tpl.content.cloneNode(true) as DocumentFragment;\n};\n\nconst collectBindingTarget = (node: Node, targets: BindingTargets): void => {\n if (node.nodeType === Node.COMMENT_NODE) {\n const marker = (node as Comment).nodeValue;\n\n if (marker) targets.comments.set(marker, node as Comment);\n\n return;\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) return;\n\n const id = (node as Element).getAttribute(CF_ID_ATTR);\n\n if (id) targets.elements.set(id, node as HTMLElement);\n};\n\nconst walkBindingTargets = (root: Node, visit: (node: Node) => void): void => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_ELEMENT);\n\n visit(root);\n\n while (walker.nextNode()) visit(walker.currentNode);\n};\n\nexport const indexBindingTargets = (nodes: Iterable<Node>): BindingTargets => {\n const targets: BindingTargets = { comments: new Map(), elements: new Map() };\n\n for (const node of nodes) walkBindingTargets(node, (current) => collectBindingTarget(current, targets));\n\n return targets;\n};\n\nexport const findCommentMarker = (root: Node, marker: string): Comment | null => {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n\n if (comment.nodeValue === marker) return comment;\n }\n\n return null;\n};\n\nconst isStructuredValue = (value: unknown): value is object =>\n Array.isArray(value) || (typeof value === 'object' && value !== null);\n\nconst isNativeFormInput = (el: HTMLElement): el is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement =>\n el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement;\n\ntype LiveWriteState = { last: unknown };\n\nconst applyFormValue = (\n el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = value == null ? '' : String(value);\n\n if (isLive && state.last !== undefined && !Object.is(el.value, state.last) && !Object.is(el.value, next)) return;\n\n el.value = next;\n\n if (isLive) state.last = next;\n};\n\nconst applyCheckedValue = (\n el: HTMLInputElement,\n value: unknown,\n isLive: boolean | undefined,\n state: LiveWriteState,\n): void => {\n const next = Boolean(value);\n\n if (isLive && state.last !== undefined && el.checked !== Boolean(state.last) && el.checked !== next) return;\n\n el.checked = next;\n\n if (isLive) state.last = next;\n};\n\ntype PropMetaLike = { parse: (v: string | null) => unknown; reflect: boolean; signal: { value: unknown } };\n\nconst syncRegisteredProp = (el: HTMLElement, meta: PropMetaLike, binding: AttrBinding, value: unknown): void => {\n const parsed = isStructuredValue(value)\n ? value\n : meta.parse(\n binding.mode === 'bool' ? (value ? '' : null) : value == null || value === false ? null : String(value),\n );\n\n if (\n !Object.is(\n untrack(() => meta.signal.value),\n parsed,\n )\n ) {\n meta.signal.value = parsed as never;\n }\n\n // When reflect:false the prop signal has no reflect-effect; write the attribute\n // directly so the DOM stays in sync with template bindings.\n if (!meta.reflect) {\n if (isStructuredValue(value)) return;\n\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n }\n};\n\nconst signalEffect = (\n signal: ReadonlySignal<unknown>,\n update: (v: unknown) => void,\n registerCleanup: RegisterCleanup,\n): void => {\n registerCleanup(rawEffect(() => update(signal.value)));\n};\n\nexport const applyAttrBinding = (el: HTMLElement, binding: AttrBinding, registerCleanup: RegisterCleanup): void => {\n const meta = propRegistry.get(el)?.get(binding.name) as PropMetaLike | undefined;\n const liveState: LiveWriteState = { last: undefined };\n\n const update = (value: unknown): void => {\n if (!meta && isStructuredValue(value)) {\n (el as unknown as Record<string, unknown>)[binding.name] = value;\n\n return;\n }\n\n if (!meta && binding.name === 'value' && isNativeFormInput(el)) {\n applyFormValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta && binding.name === 'checked' && el instanceof HTMLInputElement) {\n applyCheckedValue(el, value, binding.live, liveState);\n\n return;\n }\n\n if (!meta) {\n if (binding.mode === 'bool') el.toggleAttribute(binding.name, Boolean(value));\n else setAttr(el, binding.name, value);\n\n return;\n }\n\n syncRegisteredProp(el, meta, binding, value);\n };\n\n if (binding.signal) {\n signalEffect(binding.signal, update, registerCleanup);\n } else {\n update(binding.value!);\n }\n};\n\nexport const applyEventBinding = (el: HTMLElement, binding: EventBinding, registerCleanup: RegisterCleanup) => {\n registerCleanup(listen(el, binding.name, binding.handler, binding.options));\n};\n\nexport const applyRefBinding = (el: HTMLElement, binding: RefBinding, registerCleanup: RegisterCleanup) => {\n const { ref } = binding;\n\n if (typeof ref === 'function') {\n ref(el as never);\n registerCleanup(() => ref(null as never));\n\n return;\n }\n\n if (Array.isArray(ref)) {\n ref.push(el);\n registerCleanup(() => {\n const i = ref.indexOf(el);\n\n if (i !== -1) ref.splice(i, 1);\n });\n\n return;\n }\n\n ref.value = el as never;\n registerCleanup(() => {\n ref.value = null as never;\n });\n};\n\ntype ElementBinding = AttrBinding | EventBinding | RefBinding;\n\nexport const applyBindingsWithTargets = (\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n targets: BindingTargets,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n const bindingMap = new Map<string, ElementBinding[]>();\n\n for (const b of bindings) {\n const id = b.uid;\n\n if (b.type === 'text') {\n const found = targets.comments.get(id);\n\n if (found) {\n const textNode = document.createTextNode('');\n\n found.replaceWith(textNode);\n targets.comments.delete(id);\n signalEffect(\n b.signal,\n (v) => {\n textNode.textContent = String(v);\n },\n registerCleanup,\n );\n }\n } else if (b.type === 'directive') {\n const found = targets.comments.get(id);\n\n if (found) {\n b.directive.mount(found, registerCleanup);\n targets.comments.delete(id);\n }\n } else if (b.type === 'html') {\n opts?.onHtml?.(b);\n } else {\n const grouped = bindingMap.get(id);\n\n if (grouped) grouped.push(b);\n else bindingMap.set(id, [b]);\n }\n }\n\n for (const [id, elBindings] of bindingMap) {\n const el = targets.elements.get(id);\n\n if (!el) continue;\n\n el.removeAttribute(CF_ID_ATTR);\n targets.elements.delete(id);\n\n // Inline element binding dispatch\n for (const b of elBindings) {\n if (b.type === 'attr') {\n applyAttrBinding(el, b, registerCleanup);\n } else if (b.type === 'event') {\n applyEventBinding(el, b, registerCleanup);\n } else if (b.type === 'ref') {\n applyRefBinding(el, b, registerCleanup);\n }\n }\n }\n};\n\nexport const applyBindingsInContainer = (\n container: ParentNode,\n bindings: Binding[],\n registerCleanup: RegisterCleanup,\n opts?: { onHtml?: (b: HtmlBinding) => void },\n) => {\n applyBindingsWithTargets(bindings, registerCleanup, indexBindingTargets([container]), opts);\n};\n\nexport const createAttrBinding = (mode: 'bool' | 'attr', name: string, uid: string, value: unknown): AttrBinding => {\n if (isLiveSignal(value)) {\n return { live: true, mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n if (typeof value === 'function') {\n return { mode, name, signal: computed(value as () => unknown), type: 'attr', uid };\n }\n\n if (isSignal(value)) {\n return { mode, name, signal: value as ReadonlySignal<unknown>, type: 'attr', uid };\n }\n\n return { mode, name, type: 'attr', uid, value };\n};\n\n/**\n * Sets up the reactive effect for an html-binding marker using full fragment replacement.\n */\nexport const applyHtmlBinding = (root: Node, b: HtmlBinding, registerCleanup: RegisterCleanup): void => {\n const found = findCommentMarker(root, b.uid);\n\n if (!found) return;\n\n const marker = document.createComment('html-binding');\n\n found.replaceWith(marker);\n\n let currentCleanups: CleanupFn[] = [];\n const registerInnerCleanup: RegisterCleanup = (fn) => currentCleanups.push(fn);\n const runCurrentCleanups = () => {\n runAll(currentCleanups);\n currentCleanups = [];\n };\n let lastHtml: string | null = null;\n let lastInsertedNodes: Node[] = [];\n\n const stop = rawEffect(() => {\n batch(() => {\n let data: HtmlBinding['signal']['value'];\n\n try {\n data = b.signal.value;\n } catch (error) {\n if (error instanceof Error && error.message.includes('[stateit] Cannot read disposed computed signal')) return;\n\n throw error;\n }\n\n if (data.html === lastHtml) {\n return;\n }\n\n lastHtml = data.html;\n runCurrentCleanups();\n\n const { bindings, html } = data;\n const container = (marker.parentElement || root) as ParentNode;\n\n untrack(() => {\n batch(() => {\n removeNodes(lastInsertedNodes);\n\n const parsed = parseHTML(html);\n\n lastInsertedNodes = Array.from(parsed.childNodes);\n marker.after(parsed);\n });\n\n applyBindingsInContainer(container, bindings, registerInnerCleanup, {\n onHtml: (binding) => applyHtmlBinding(container as unknown as Node, binding, registerInnerCleanup),\n });\n });\n });\n });\n\n registerCleanup(stop);\n registerCleanup(runCurrentCleanups);\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./internal.cjs`),t=require(`./template-bindings.cjs`);let n=require(`@vielzeug/stateit`);var r=[{kind:`event`,regex:/\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\s*=\s*["']?$/},{kind:`ref`,regex:/\s+ref\s*=\s*["']?$/},{kind:`boolAttr`,regex:/\s+\?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/},{kind:`attr`,regex:/\s+:?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/}],i=new WeakMap,a=new WeakMap,o=new WeakMap,s={prevent:e=>t=>{t.preventDefault(),e(t)},self:e=>t=>{t.target===t.currentTarget&&e(t)},stop:e=>t=>{t.stopPropagation(),e(t)}},c=(e,t)=>{let n=t.reduce((e,t)=>s[t]?.(e)??e,e),r={};return t.includes(`capture`)&&(r.capture=!0),t.includes(`once`)&&(r.once=!0),t.includes(`passive`)&&(r.passive=!0),{handler:n,...Object.keys(r).length?{options:r}:{}}},l=t=>typeof t==`string`?e.escapeHtml(t):t==null?``:e.isHtmlResult(t)?t.__html:e.escapeHtml(String(t)),u=t=>{let r={bindings:[],html:``};return{bindings:[],signal:(0,n.computed)(()=>{let n=t(),i=Array.isArray(n)?n:[n],a=e.createMarkerIdFactory(),o=``,s=[];for(let t of i)if(e.isHtmlResult(t)){let n=e.rekeyHtmlResult(t,a);o+=n.html,s.push(...n.bindings)}else o+=l(t);let c=s.length!==r.bindings.length||s.some((e,t)=>e!==r.bindings[t]);return(o!==r.html||c)&&(r={bindings:s,html:o}),r})}},d=t=>{if(typeof t==`function`){let e=t,n=a.get(e);if(n)return{signal:n};let{signal:r}=u(e);return a.set(e,r),{signal:r}}if((0,n.isSignal)(t)&&e.isHtmlResult(t.value)){let r=t,i=o.get(r);if(i)return{signal:i};let a=(0,n.computed)(()=>{let t=r.value;if(!e.isHtmlResult(t))return{bindings:[],html:l(t)};let n=e.rekeyHtmlResult(t,e.createMarkerIdFactory());return{bindings:n.bindings,html:n.html}});return o.set(r,a),{signal:a}}return null},f=e=>{let t=[];for(let n=0;n<e.length-1;n++){let i=e[n],a=!1;for(let e of r){let n=e.regex.exec(i);if(!n)continue;let r=i.slice(0,-n[0].length);if(a=!0,e.kind===`event`){let e=n[1].split(`.`),a=e[0],o=e.slice(1);t.push({kind:`event`,modifiers:o,name:a,prefix:r,raw:i})}else e.kind===`ref`?t.push({kind:`ref`,prefix:r,raw:i}):e.kind===`boolAttr`?t.push({kind:`boolAttr`,mode:`bool`,name:n[1],prefix:r,raw:i}):e.kind===`attr`&&t.push({kind:`attr`,mode:`attr`,name:n[1],prefix:r,raw:i});break}a||t.push({kind:`node`,prefix:i,raw:i})}return{slots:t,tail:e[e.length-1]??``}},p=e=>{let t=i.get(e);return t||(t=f(e),i.set(e,t)),t},m=(r,i)=>{let a=p(r),o=``,s=[],u=null,f=e.createMarkerIdFactory(),m=e=>e.lastIndexOf(`<`)>e.lastIndexOf(`>`),h=e=>((!u||m(e))&&(u=f()),u),g=()=>{u=null};for(let r=0;r<a.slots.length;r++){let u=a.slots[r],p=i[r];if(u.kind===`event`){if(typeof p==`function`){let e=h(u.prefix),{handler:t,options:n}=c(p,u.modifiers??[]);o+=`${u.prefix} u="${e}"`,s.push({handler:t,name:u.name,options:n,type:`event`,uid:e})}else if((0,n.isSignal)(p)){let e=h(u.prefix),{handler:t,options:n}=c(e=>{let t=p.value;typeof t==`function`&&t(e)},u.modifiers??[]);o+=`${u.prefix} u="${e}"`,s.push({handler:t,name:u.name,options:n,type:`event`,uid:e})}else o+=u.raw;continue}if(u.kind===`ref`){if(p){let e=h(u.prefix);o+=`${u.prefix} u="${e}"`,s.push({ref:p,type:`ref`,uid:e})}else o+=u.raw;continue}if(u.kind===`boolAttr`||u.kind===`attr`){let e=h(u.prefix);o+=`${u.prefix} u="${e}"`,s.push(t.createAttrBinding(u.mode,u.name,e,p));continue}if(u.kind===`node`){if(g(),e.isDirectiveResult(p)){let e=f();o+=`${u.raw}<!--${e}-->`,s.push({directive:p,type:`directive`,uid:e});continue}let t=d(p);if(t){let e=f();o+=`${u.raw}<!--${e}-->`,s.push({signal:t.signal,type:`html`,uid:e});continue}if(Array.isArray(p)){let t=``;for(let n of p)if(e.isHtmlResult(n)){let r=e.rekeyHtmlResult(n,f);t+=r.html,s.push(...r.bindings)}else t+=l(n);o+=u.raw+t;continue}if((0,n.isSignal)(p)){let e=f();o+=`${u.raw}<!--${e}-->`,s.push({signal:p,type:`text`,uid:e})}else if(e.isHtmlResult(p)){let t=e.rekeyHtmlResult(p,f);o+=u.raw+t.html,s.push(...t.bindings)}else o+=u.raw+l(p);continue}}return o+=a.tail,e.htmlResult(o,s)},h=(e,...t)=>m(e,t);exports.html=h;
2
+ //# sourceMappingURL=template-compiler.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-compiler.cjs","names":[],"sources":["../src/template-compiler.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport {\n CF_ID_ATTR,\n createMarkerIdFactory,\n escapeHtml,\n htmlResult,\n isDirectiveResult,\n isHtmlResult,\n rekeyHtmlResult,\n type Binding,\n type HTMLResult,\n type Ref,\n type RefCallback,\n} from './internal';\nimport { createAttrBinding } from './template-bindings';\n\n// Templates use the HTML as-is; no aggressive whitespace normalization\n\n// Slot patterns applied in priority order; first match wins\nconst SLOT_PATTERNS = [\n { kind: 'event' as const, regex: /\\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\\s*=\\s*[\"']?$/ },\n { kind: 'ref' as const, regex: /\\s+ref\\s*=\\s*[\"']?$/ },\n { kind: 'boolAttr' as const, regex: /\\s+\\?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/ },\n { kind: 'attr' as const, regex: /\\s+:?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/ },\n] as const;\n\ntype CompiledTemplateSlot = {\n kind: (typeof SLOT_PATTERNS)[number]['kind'] | 'node';\n mode?: 'attr' | 'bool';\n modifiers?: string[];\n // For 'event' and attribute slots\n name?: string;\n prefix: string;\n raw: string;\n};\n\ntype CompiledTemplatePlan = {\n slots: CompiledTemplateSlot[];\n tail: string;\n};\n\ntype HtmlWrapperSignal = ReadonlySignal<{\n bindings: Binding[];\n html: string;\n}>;\n\nconst templatePlanCache = new WeakMap<TemplateStringsArray, CompiledTemplatePlan>();\nconst htmlGetterSignalCache = new WeakMap<() => unknown, HtmlWrapperSignal>();\nconst htmlSignalWrapperCache = new WeakMap<ReadonlySignal<unknown>, HtmlWrapperSignal>();\n\nconst MODIFIER_WRAPPERS: Record<string, (fn: (e: Event) => void) => (e: Event) => void> = {\n prevent: (fn) => (e) => {\n e.preventDefault();\n fn(e);\n },\n self: (fn) => (e) => {\n if (e.target === e.currentTarget) fn(e);\n },\n stop: (fn) => (e) => {\n e.stopPropagation();\n fn(e);\n },\n};\n\nconst applyModifiers = (\n handler: (e: Event) => void,\n modifiers: string[],\n): { handler: (e: Event) => void; options?: AddEventListenerOptions } => {\n const wrapped = modifiers.reduce((fn, m) => MODIFIER_WRAPPERS[m]?.(fn) ?? fn, handler);\n\n const options: AddEventListenerOptions = {};\n\n if (modifiers.includes('capture')) options.capture = true;\n\n if (modifiers.includes('once')) options.once = true;\n\n if (modifiers.includes('passive')) options.passive = true;\n\n return { handler: wrapped, ...(Object.keys(options).length ? { options } : {}) };\n};\n\nconst resolveDirectiveValue = (value: unknown): string => {\n if (typeof value === 'string') return escapeHtml(value);\n\n if (value == null) return '';\n\n if (isHtmlResult(value)) return value.__html;\n\n return escapeHtml(String(value));\n};\n\nconst renderHtmlItems = (getter: () => unknown): { bindings: Binding[]; signal: ReadonlySignal<any> } => {\n let cached = { bindings: [] as Binding[], html: '' };\n const fnSignal = computed(() => {\n const res = getter();\n const items = Array.isArray(res) ? res : [res];\n const getNestedId = createMarkerIdFactory();\n let html = '';\n const nextBindings: Binding[] = [];\n\n for (const item of items) {\n if (isHtmlResult(item)) {\n const entry = rekeyHtmlResult(item, getNestedId);\n\n html += entry.html;\n nextBindings.push(...entry.bindings);\n } else {\n html += resolveDirectiveValue(item);\n }\n }\n\n const bindingsChanged =\n nextBindings.length !== cached.bindings.length || nextBindings.some((b, i) => b !== cached.bindings[i]);\n\n if (html !== cached.html || bindingsChanged) {\n cached = { bindings: nextBindings, html };\n }\n\n return cached;\n });\n\n return { bindings: [], signal: fnSignal };\n};\n\nconst createHtmlWrapperSignal = (\n value: unknown,\n): {\n signal: HtmlWrapperSignal;\n} | null => {\n if (typeof value === 'function') {\n const getter = value as () => unknown;\n const cached = htmlGetterSignalCache.get(getter);\n\n if (cached) {\n return { signal: cached };\n }\n\n const { signal: sig } = renderHtmlItems(getter);\n\n htmlGetterSignalCache.set(getter, sig);\n\n return { signal: sig };\n }\n\n if (isSignal(value) && isHtmlResult((value as ReadonlySignal<unknown>).value)) {\n const htmlSignal = value as ReadonlySignal<unknown>;\n const cached = htmlSignalWrapperCache.get(htmlSignal);\n\n if (cached) {\n return { signal: cached };\n }\n\n const wrapped = computed(() => {\n const next = htmlSignal.value;\n\n if (!isHtmlResult(next)) {\n return { bindings: [], html: resolveDirectiveValue(next) };\n }\n\n const entry = rekeyHtmlResult(next, createMarkerIdFactory());\n\n return { bindings: entry.bindings, html: entry.html };\n });\n\n htmlSignalWrapperCache.set(htmlSignal, wrapped);\n\n return { signal: wrapped };\n }\n\n return null;\n};\n\nconst buildTemplatePlan = (strings: TemplateStringsArray): CompiledTemplatePlan => {\n const slots: CompiledTemplateSlot[] = [];\n\n for (let i = 0; i < strings.length - 1; i++) {\n const str = strings[i];\n let matched = false;\n\n for (const pattern of SLOT_PATTERNS) {\n const m = pattern.regex.exec(str);\n\n if (!m) continue;\n\n const prefix = str.slice(0, -m[0].length);\n\n matched = true;\n\n if (pattern.kind === 'event') {\n const parts = m[1].split('.');\n const eventName = parts[0];\n const modifiers = parts.slice(1);\n\n slots.push({ kind: 'event', modifiers, name: eventName, prefix, raw: str });\n } else if (pattern.kind === 'ref') {\n slots.push({ kind: 'ref', prefix, raw: str });\n } else if (pattern.kind === 'boolAttr') {\n slots.push({ kind: 'boolAttr', mode: 'bool', name: m[1], prefix, raw: str });\n } else if (pattern.kind === 'attr') {\n slots.push({ kind: 'attr', mode: 'attr', name: m[1], prefix, raw: str });\n }\n\n break;\n }\n\n if (!matched) {\n slots.push({ kind: 'node', prefix: str, raw: str });\n }\n }\n\n return { slots, tail: strings[strings.length - 1] ?? '' };\n};\n\nconst getCompiledTemplatePlan = (strings: TemplateStringsArray): CompiledTemplatePlan => {\n let plan = templatePlanCache.get(strings);\n\n if (!plan) {\n plan = buildTemplatePlan(strings);\n templatePlanCache.set(strings, plan);\n }\n\n return plan;\n};\n\nexport const compileTemplate = (strings: TemplateStringsArray, values: unknown[]): HTMLResult => {\n const plan = getCompiledTemplatePlan(strings);\n let result = '';\n const bindings: Binding[] = [];\n let activeElementId: string | null = null;\n\n const getNextId = createMarkerIdFactory();\n const isInsideStartTag = (prefix: string) => prefix.lastIndexOf('<') > prefix.lastIndexOf('>');\n const getElementBindingId = (prefix: string): string => {\n if (!activeElementId || isInsideStartTag(prefix)) {\n activeElementId = getNextId();\n }\n\n return activeElementId;\n };\n const resetElementBindingId = (): void => {\n activeElementId = null;\n };\n\n for (let i = 0; i < plan.slots.length; i++) {\n const slot = plan.slots[i];\n const value = values[i];\n\n if (slot.kind === 'event') {\n if (typeof value === 'function') {\n const id = getElementBindingId(slot.prefix);\n const { handler, options } = applyModifiers(value as (e: Event) => void, slot.modifiers ?? []);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push({ handler, name: slot.name!, options, type: 'event', uid: id });\n } else if (isSignal(value)) {\n // If a signal is passed to an event binding, we assume its current value\n // is the intended handler.\n const id = getElementBindingId(slot.prefix);\n const signalHandler = (e: Event) => {\n const currentHandler = (value as ReadonlySignal<unknown>).value;\n\n if (typeof currentHandler === 'function') {\n (currentHandler as (e: Event) => void)(e);\n }\n };\n const { handler, options } = applyModifiers(signalHandler, slot.modifiers ?? []);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push({ handler, name: slot.name!, options, type: 'event', uid: id });\n } else result += slot.raw;\n\n continue;\n }\n\n if (slot.kind === 'ref') {\n if (value) {\n const id = getElementBindingId(slot.prefix);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push({\n ref: value as Ref<Element> | RefCallback<Element>,\n type: 'ref',\n uid: id,\n });\n } else result += slot.raw;\n\n continue;\n }\n\n if (slot.kind === 'boolAttr' || slot.kind === 'attr') {\n const id = getElementBindingId(slot.prefix);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push(createAttrBinding(slot.mode!, slot.name!, id, value));\n continue;\n }\n\n if (slot.kind === 'node') {\n resetElementBindingId();\n\n if (isDirectiveResult(value)) {\n const id = getNextId();\n\n result += `${slot.raw}<!--${id}-->`;\n bindings.push({ directive: value, type: 'directive', uid: id });\n continue;\n }\n\n const htmlWrapper = createHtmlWrapperSignal(value);\n\n if (htmlWrapper) {\n const id = getNextId();\n\n result += `${slot.raw}<!--${id}-->`;\n bindings.push({ signal: htmlWrapper.signal, type: 'html', uid: id });\n continue;\n }\n\n if (Array.isArray(value)) {\n let combinedHtml = '';\n\n for (const item of value) {\n if (isHtmlResult(item)) {\n const entry = rekeyHtmlResult(item, getNextId);\n\n combinedHtml += entry.html;\n bindings.push(...entry.bindings);\n } else {\n combinedHtml += resolveDirectiveValue(item);\n }\n }\n result += slot.raw + combinedHtml;\n continue;\n }\n\n if (isSignal(value)) {\n const id = getNextId();\n\n result += `${slot.raw}<!--${id}-->`;\n bindings.push({ signal: value as Signal<unknown>, type: 'text', uid: id });\n } else if (isHtmlResult(value)) {\n const entry = rekeyHtmlResult(value, getNextId);\n\n result += slot.raw + entry.html;\n bindings.push(...entry.bindings);\n } else {\n result += slot.raw + resolveDirectiveValue(value);\n }\n\n continue;\n }\n }\n\n result += plan.tail;\n\n return htmlResult(result, bindings);\n};\n\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): HTMLResult =>\n compileTemplate(strings, values);\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type HTMLResult } from './internal';
2
+ export declare const compileTemplate: (strings: TemplateStringsArray, values: unknown[]) => HTMLResult;
3
+ export declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => HTMLResult;
4
+ //# sourceMappingURL=template-compiler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-compiler.d.ts","sourceRoot":"","sources":["../src/template-compiler.ts"],"names":[],"mappings":"AAEA,OAAO,EASL,KAAK,UAAU,EAGhB,MAAM,YAAY,CAAC;AAmNpB,eAAO,MAAM,eAAe,GAAI,SAAS,oBAAoB,EAAE,QAAQ,OAAO,EAAE,KAAG,UAoIlF,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,SAAS,oBAAoB,EAAE,GAAG,QAAQ,OAAO,EAAE,KAAG,UACzC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{createMarkerIdFactory as e,escapeHtml as t,htmlResult as n,isDirectiveResult as r,isHtmlResult as i,rekeyHtmlResult as a}from"./internal.js";import{createAttrBinding as o}from"./template-bindings.js";import{computed as s,isSignal as c}from"@vielzeug/stateit";var l=[{kind:`event`,regex:/\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\s*=\s*["']?$/},{kind:`ref`,regex:/\s+ref\s*=\s*["']?$/},{kind:`boolAttr`,regex:/\s+\?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/},{kind:`attr`,regex:/\s+:?([a-zA-Z_][-a-zA-Z0-9_]*)\s*=\s*["']?$/}],u=new WeakMap,d=new WeakMap,f=new WeakMap,p={prevent:e=>t=>{t.preventDefault(),e(t)},self:e=>t=>{t.target===t.currentTarget&&e(t)},stop:e=>t=>{t.stopPropagation(),e(t)}},m=(e,t)=>{let n=t.reduce((e,t)=>p[t]?.(e)??e,e),r={};return t.includes(`capture`)&&(r.capture=!0),t.includes(`once`)&&(r.once=!0),t.includes(`passive`)&&(r.passive=!0),{handler:n,...Object.keys(r).length?{options:r}:{}}},h=e=>typeof e==`string`?t(e):e==null?``:i(e)?e.__html:t(String(e)),g=t=>{let n={bindings:[],html:``};return{bindings:[],signal:s(()=>{let r=t(),o=Array.isArray(r)?r:[r],s=e(),c=``,l=[];for(let e of o)if(i(e)){let t=a(e,s);c+=t.html,l.push(...t.bindings)}else c+=h(e);let u=l.length!==n.bindings.length||l.some((e,t)=>e!==n.bindings[t]);return(c!==n.html||u)&&(n={bindings:l,html:c}),n})}},_=t=>{if(typeof t==`function`){let e=t,n=d.get(e);if(n)return{signal:n};let{signal:r}=g(e);return d.set(e,r),{signal:r}}if(c(t)&&i(t.value)){let n=t,r=f.get(n);if(r)return{signal:r};let o=s(()=>{let t=n.value;if(!i(t))return{bindings:[],html:h(t)};let r=a(t,e());return{bindings:r.bindings,html:r.html}});return f.set(n,o),{signal:o}}return null},v=e=>{let t=[];for(let n=0;n<e.length-1;n++){let r=e[n],i=!1;for(let e of l){let n=e.regex.exec(r);if(!n)continue;let a=r.slice(0,-n[0].length);if(i=!0,e.kind===`event`){let e=n[1].split(`.`),i=e[0],o=e.slice(1);t.push({kind:`event`,modifiers:o,name:i,prefix:a,raw:r})}else e.kind===`ref`?t.push({kind:`ref`,prefix:a,raw:r}):e.kind===`boolAttr`?t.push({kind:`boolAttr`,mode:`bool`,name:n[1],prefix:a,raw:r}):e.kind===`attr`&&t.push({kind:`attr`,mode:`attr`,name:n[1],prefix:a,raw:r});break}i||t.push({kind:`node`,prefix:r,raw:r})}return{slots:t,tail:e[e.length-1]??``}},y=e=>{let t=u.get(e);return t||(t=v(e),u.set(e,t)),t},b=(t,s)=>{let l=y(t),u=``,d=[],f=null,p=e(),g=e=>e.lastIndexOf(`<`)>e.lastIndexOf(`>`),v=e=>((!f||g(e))&&(f=p()),f),b=()=>{f=null};for(let e=0;e<l.slots.length;e++){let t=l.slots[e],n=s[e];if(t.kind===`event`){if(typeof n==`function`){let e=v(t.prefix),{handler:r,options:i}=m(n,t.modifiers??[]);u+=`${t.prefix} u="${e}"`,d.push({handler:r,name:t.name,options:i,type:`event`,uid:e})}else if(c(n)){let e=v(t.prefix),{handler:r,options:i}=m(e=>{let t=n.value;typeof t==`function`&&t(e)},t.modifiers??[]);u+=`${t.prefix} u="${e}"`,d.push({handler:r,name:t.name,options:i,type:`event`,uid:e})}else u+=t.raw;continue}if(t.kind===`ref`){if(n){let e=v(t.prefix);u+=`${t.prefix} u="${e}"`,d.push({ref:n,type:`ref`,uid:e})}else u+=t.raw;continue}if(t.kind===`boolAttr`||t.kind===`attr`){let e=v(t.prefix);u+=`${t.prefix} u="${e}"`,d.push(o(t.mode,t.name,e,n));continue}if(t.kind===`node`){if(b(),r(n)){let e=p();u+=`${t.raw}<!--${e}-->`,d.push({directive:n,type:`directive`,uid:e});continue}let e=_(n);if(e){let n=p();u+=`${t.raw}<!--${n}-->`,d.push({signal:e.signal,type:`html`,uid:n});continue}if(Array.isArray(n)){let e=``;for(let t of n)if(i(t)){let n=a(t,p);e+=n.html,d.push(...n.bindings)}else e+=h(t);u+=t.raw+e;continue}if(c(n)){let e=p();u+=`${t.raw}<!--${e}-->`,d.push({signal:n,type:`text`,uid:e})}else if(i(n)){let e=a(n,p);u+=t.raw+e.html,d.push(...e.bindings)}else u+=t.raw+h(n);continue}}return u+=l.tail,n(u,d)},x=(e,...t)=>b(e,t);export{x as html};
2
+ //# sourceMappingURL=template-compiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-compiler.js","names":[],"sources":["../src/template-compiler.ts"],"sourcesContent":["import { computed, isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport {\n CF_ID_ATTR,\n createMarkerIdFactory,\n escapeHtml,\n htmlResult,\n isDirectiveResult,\n isHtmlResult,\n rekeyHtmlResult,\n type Binding,\n type HTMLResult,\n type Ref,\n type RefCallback,\n} from './internal';\nimport { createAttrBinding } from './template-bindings';\n\n// Templates use the HTML as-is; no aggressive whitespace normalization\n\n// Slot patterns applied in priority order; first match wins\nconst SLOT_PATTERNS = [\n { kind: 'event' as const, regex: /\\s+@([a-zA-Z_][-a-zA-Z0-9_.-]*)\\s*=\\s*[\"']?$/ },\n { kind: 'ref' as const, regex: /\\s+ref\\s*=\\s*[\"']?$/ },\n { kind: 'boolAttr' as const, regex: /\\s+\\?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/ },\n { kind: 'attr' as const, regex: /\\s+:?([a-zA-Z_][-a-zA-Z0-9_]*)\\s*=\\s*[\"']?$/ },\n] as const;\n\ntype CompiledTemplateSlot = {\n kind: (typeof SLOT_PATTERNS)[number]['kind'] | 'node';\n mode?: 'attr' | 'bool';\n modifiers?: string[];\n // For 'event' and attribute slots\n name?: string;\n prefix: string;\n raw: string;\n};\n\ntype CompiledTemplatePlan = {\n slots: CompiledTemplateSlot[];\n tail: string;\n};\n\ntype HtmlWrapperSignal = ReadonlySignal<{\n bindings: Binding[];\n html: string;\n}>;\n\nconst templatePlanCache = new WeakMap<TemplateStringsArray, CompiledTemplatePlan>();\nconst htmlGetterSignalCache = new WeakMap<() => unknown, HtmlWrapperSignal>();\nconst htmlSignalWrapperCache = new WeakMap<ReadonlySignal<unknown>, HtmlWrapperSignal>();\n\nconst MODIFIER_WRAPPERS: Record<string, (fn: (e: Event) => void) => (e: Event) => void> = {\n prevent: (fn) => (e) => {\n e.preventDefault();\n fn(e);\n },\n self: (fn) => (e) => {\n if (e.target === e.currentTarget) fn(e);\n },\n stop: (fn) => (e) => {\n e.stopPropagation();\n fn(e);\n },\n};\n\nconst applyModifiers = (\n handler: (e: Event) => void,\n modifiers: string[],\n): { handler: (e: Event) => void; options?: AddEventListenerOptions } => {\n const wrapped = modifiers.reduce((fn, m) => MODIFIER_WRAPPERS[m]?.(fn) ?? fn, handler);\n\n const options: AddEventListenerOptions = {};\n\n if (modifiers.includes('capture')) options.capture = true;\n\n if (modifiers.includes('once')) options.once = true;\n\n if (modifiers.includes('passive')) options.passive = true;\n\n return { handler: wrapped, ...(Object.keys(options).length ? { options } : {}) };\n};\n\nconst resolveDirectiveValue = (value: unknown): string => {\n if (typeof value === 'string') return escapeHtml(value);\n\n if (value == null) return '';\n\n if (isHtmlResult(value)) return value.__html;\n\n return escapeHtml(String(value));\n};\n\nconst renderHtmlItems = (getter: () => unknown): { bindings: Binding[]; signal: ReadonlySignal<any> } => {\n let cached = { bindings: [] as Binding[], html: '' };\n const fnSignal = computed(() => {\n const res = getter();\n const items = Array.isArray(res) ? res : [res];\n const getNestedId = createMarkerIdFactory();\n let html = '';\n const nextBindings: Binding[] = [];\n\n for (const item of items) {\n if (isHtmlResult(item)) {\n const entry = rekeyHtmlResult(item, getNestedId);\n\n html += entry.html;\n nextBindings.push(...entry.bindings);\n } else {\n html += resolveDirectiveValue(item);\n }\n }\n\n const bindingsChanged =\n nextBindings.length !== cached.bindings.length || nextBindings.some((b, i) => b !== cached.bindings[i]);\n\n if (html !== cached.html || bindingsChanged) {\n cached = { bindings: nextBindings, html };\n }\n\n return cached;\n });\n\n return { bindings: [], signal: fnSignal };\n};\n\nconst createHtmlWrapperSignal = (\n value: unknown,\n): {\n signal: HtmlWrapperSignal;\n} | null => {\n if (typeof value === 'function') {\n const getter = value as () => unknown;\n const cached = htmlGetterSignalCache.get(getter);\n\n if (cached) {\n return { signal: cached };\n }\n\n const { signal: sig } = renderHtmlItems(getter);\n\n htmlGetterSignalCache.set(getter, sig);\n\n return { signal: sig };\n }\n\n if (isSignal(value) && isHtmlResult((value as ReadonlySignal<unknown>).value)) {\n const htmlSignal = value as ReadonlySignal<unknown>;\n const cached = htmlSignalWrapperCache.get(htmlSignal);\n\n if (cached) {\n return { signal: cached };\n }\n\n const wrapped = computed(() => {\n const next = htmlSignal.value;\n\n if (!isHtmlResult(next)) {\n return { bindings: [], html: resolveDirectiveValue(next) };\n }\n\n const entry = rekeyHtmlResult(next, createMarkerIdFactory());\n\n return { bindings: entry.bindings, html: entry.html };\n });\n\n htmlSignalWrapperCache.set(htmlSignal, wrapped);\n\n return { signal: wrapped };\n }\n\n return null;\n};\n\nconst buildTemplatePlan = (strings: TemplateStringsArray): CompiledTemplatePlan => {\n const slots: CompiledTemplateSlot[] = [];\n\n for (let i = 0; i < strings.length - 1; i++) {\n const str = strings[i];\n let matched = false;\n\n for (const pattern of SLOT_PATTERNS) {\n const m = pattern.regex.exec(str);\n\n if (!m) continue;\n\n const prefix = str.slice(0, -m[0].length);\n\n matched = true;\n\n if (pattern.kind === 'event') {\n const parts = m[1].split('.');\n const eventName = parts[0];\n const modifiers = parts.slice(1);\n\n slots.push({ kind: 'event', modifiers, name: eventName, prefix, raw: str });\n } else if (pattern.kind === 'ref') {\n slots.push({ kind: 'ref', prefix, raw: str });\n } else if (pattern.kind === 'boolAttr') {\n slots.push({ kind: 'boolAttr', mode: 'bool', name: m[1], prefix, raw: str });\n } else if (pattern.kind === 'attr') {\n slots.push({ kind: 'attr', mode: 'attr', name: m[1], prefix, raw: str });\n }\n\n break;\n }\n\n if (!matched) {\n slots.push({ kind: 'node', prefix: str, raw: str });\n }\n }\n\n return { slots, tail: strings[strings.length - 1] ?? '' };\n};\n\nconst getCompiledTemplatePlan = (strings: TemplateStringsArray): CompiledTemplatePlan => {\n let plan = templatePlanCache.get(strings);\n\n if (!plan) {\n plan = buildTemplatePlan(strings);\n templatePlanCache.set(strings, plan);\n }\n\n return plan;\n};\n\nexport const compileTemplate = (strings: TemplateStringsArray, values: unknown[]): HTMLResult => {\n const plan = getCompiledTemplatePlan(strings);\n let result = '';\n const bindings: Binding[] = [];\n let activeElementId: string | null = null;\n\n const getNextId = createMarkerIdFactory();\n const isInsideStartTag = (prefix: string) => prefix.lastIndexOf('<') > prefix.lastIndexOf('>');\n const getElementBindingId = (prefix: string): string => {\n if (!activeElementId || isInsideStartTag(prefix)) {\n activeElementId = getNextId();\n }\n\n return activeElementId;\n };\n const resetElementBindingId = (): void => {\n activeElementId = null;\n };\n\n for (let i = 0; i < plan.slots.length; i++) {\n const slot = plan.slots[i];\n const value = values[i];\n\n if (slot.kind === 'event') {\n if (typeof value === 'function') {\n const id = getElementBindingId(slot.prefix);\n const { handler, options } = applyModifiers(value as (e: Event) => void, slot.modifiers ?? []);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push({ handler, name: slot.name!, options, type: 'event', uid: id });\n } else if (isSignal(value)) {\n // If a signal is passed to an event binding, we assume its current value\n // is the intended handler.\n const id = getElementBindingId(slot.prefix);\n const signalHandler = (e: Event) => {\n const currentHandler = (value as ReadonlySignal<unknown>).value;\n\n if (typeof currentHandler === 'function') {\n (currentHandler as (e: Event) => void)(e);\n }\n };\n const { handler, options } = applyModifiers(signalHandler, slot.modifiers ?? []);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push({ handler, name: slot.name!, options, type: 'event', uid: id });\n } else result += slot.raw;\n\n continue;\n }\n\n if (slot.kind === 'ref') {\n if (value) {\n const id = getElementBindingId(slot.prefix);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push({\n ref: value as Ref<Element> | RefCallback<Element>,\n type: 'ref',\n uid: id,\n });\n } else result += slot.raw;\n\n continue;\n }\n\n if (slot.kind === 'boolAttr' || slot.kind === 'attr') {\n const id = getElementBindingId(slot.prefix);\n\n result += `${slot.prefix} ${CF_ID_ATTR}=\"${id}\"`;\n bindings.push(createAttrBinding(slot.mode!, slot.name!, id, value));\n continue;\n }\n\n if (slot.kind === 'node') {\n resetElementBindingId();\n\n if (isDirectiveResult(value)) {\n const id = getNextId();\n\n result += `${slot.raw}<!--${id}-->`;\n bindings.push({ directive: value, type: 'directive', uid: id });\n continue;\n }\n\n const htmlWrapper = createHtmlWrapperSignal(value);\n\n if (htmlWrapper) {\n const id = getNextId();\n\n result += `${slot.raw}<!--${id}-->`;\n bindings.push({ signal: htmlWrapper.signal, type: 'html', uid: id });\n continue;\n }\n\n if (Array.isArray(value)) {\n let combinedHtml = '';\n\n for (const item of value) {\n if (isHtmlResult(item)) {\n const entry = rekeyHtmlResult(item, getNextId);\n\n combinedHtml += entry.html;\n bindings.push(...entry.bindings);\n } else {\n combinedHtml += resolveDirectiveValue(item);\n }\n }\n result += slot.raw + combinedHtml;\n continue;\n }\n\n if (isSignal(value)) {\n const id = getNextId();\n\n result += `${slot.raw}<!--${id}-->`;\n bindings.push({ signal: value as Signal<unknown>, type: 'text', uid: id });\n } else if (isHtmlResult(value)) {\n const entry = rekeyHtmlResult(value, getNextId);\n\n result += slot.raw + entry.html;\n bindings.push(...entry.bindings);\n } else {\n result += slot.raw + resolveDirectiveValue(value);\n }\n\n continue;\n }\n }\n\n result += plan.tail;\n\n return htmlResult(result, bindings);\n};\n\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): HTMLResult =>\n compileTemplate(strings, values);\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './testing';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ require(`../runtime.cjs`);const e=require(`../internal.cjs`),t=require(`../registration.cjs`);var n=[],r=0,i=()=>{e._resetIdCounter(),r=0};async function a(){let e=async e=>{for(let t=0;t<e;t++)await Promise.resolve(),await new Promise(e=>queueMicrotask(e))};await e(12),await new Promise(e=>typeof requestAnimationFrame<`u`?requestAnimationFrame(()=>e()):e()),await e(2)}function o(e){e(x)}function s(e,t,n){n===!1?e.removeAttribute(t):e.setAttribute(t,n===!0?``:String(n))}var c=e=>e instanceof Error?e:Error(String(e)),l=async e=>{if(typeof window>`u`)return e();let t=null,n=e=>{t=c(e.error??e.message),e.preventDefault()},r=e=>{t=c(e.reason),e.preventDefault()};window.addEventListener(`error`,n),window.addEventListener(`unhandledrejection`,r);try{let n=await e();if(t)throw t;return n}finally{window.removeEventListener(`error`,n),window.removeEventListener(`unhandledrejection`,r)}};async function u(e,i={}){let{attrs:o={},componentOptions:c,container:u=document.body,html:p,props:m={}}=i,h=e=>(t,n)=>{let r=e(t,n);return typeof r==`function`?r:()=>r},g,_;typeof e==`string`?g=e:(g=`trial-${++r}`,_={...c??{},setup:h(e)}),_&&t.define(g,_);let v=document.createElement(g);p&&(v.innerHTML=p),Object.keys(m).length&&Object.assign(v,m);for(let[e,t]of Object.entries(o))s(v,e,t);return await l(async()=>{u.appendChild(v),n.push(v),await a()}),{async act(e){await e(),await a()},async attr(e,t){s(v,e,t),await a()},async attrs(e){for(let[t,n]of Object.entries(e))s(v,t,n);await a()},destroy(){v.remove();let e=n.indexOf(v);e!==-1&&n.splice(e,1)},element:v,flush:a,query(e){return v.shadowRoot?.querySelector(e)??null},queryAll(e){return Array.from(v.shadowRoot?.querySelectorAll(e)??[])},queryAllByTestId(e){return Array.from(v.shadowRoot?.querySelectorAll(`[data-testid="${e}"]`)??[])},queryAllByText(e,t=`*`){return f(v.shadowRoot,e,t)},queryByTestId(e){return v.shadowRoot?.querySelector(`[data-testid="${e}"]`)??null},queryByText(e,t=`*`){return d(v.shadowRoot,e,t)},get shadow(){return v.shadowRoot}}}function d(e,t,n){for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null}function f(e,t,n){return Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t)}function p(e){return{query:t=>e.querySelector(t),queryAll:t=>Array.from(e.querySelectorAll(t)),queryAllByTestId:t=>Array.from(e.querySelectorAll(`[data-testid="${t}"]`)),queryAllByText:(t,n=`*`)=>f(e,t,n),queryByTestId:t=>e.querySelector(`[data-testid="${t}"]`),queryByText:(t,n=`*`)=>d(e,t,n)}}var m=(e,t={})=>typeof PointerEvent<`u`?new PointerEvent(e,t):new MouseEvent(e,t),h={blur:(t,n)=>e.fire.event(t,new FocusEvent(`blur`,{bubbles:!0,...n})),change:(t,n)=>e.fire.event(t,new Event(`change`,{bubbles:!0,...n})),click:(t,n)=>e.fire.event(t,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...n})),custom(t,n,r,i){e.fire.event(t,new CustomEvent(n,{bubbles:!0,cancelable:!0,detail:r,...i}))},focus:(t,n)=>e.fire.event(t,new FocusEvent(`focus`,{bubbles:!0,...n})),input:(t,n)=>e.fire.event(t,new Event(`input`,{bubbles:!0,...n})),keyDown:(t,n)=>e.fire.event(t,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...n})),keyUp:(t,n)=>e.fire.event(t,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...n})),pointerDown:(t,n)=>e.fire.event(t,m(`pointerdown`,{bubbles:!0,cancelable:!0,...n})),pointerEnter:(t,n)=>e.fire.event(t,m(`pointerenter`,{bubbles:!1,...n})),pointerLeave:(t,n)=>e.fire.event(t,m(`pointerleave`,{bubbles:!1,...n})),pointerUp:(t,n)=>e.fire.event(t,m(`pointerup`,{bubbles:!0,cancelable:!0,...n})),submit:(t,n)=>e.fire.event(t,new Event(`submit`,{bubbles:!0,cancelable:!0,...n}))},g=()=>a(),_={async clear(e){e.focus(),e.value=``,h.input(e),h.change(e),await g()},async click(e,t){h.pointerEnter(e,t),h.click(e,t),await g()},async dblClick(e){for(let t=0;t<2;t++)h.pointerDown(e),h.pointerUp(e),h.click(e);e.dispatchEvent(new MouseEvent(`dblclick`,{bubbles:!0,cancelable:!0})),await g()},async fill(e,t){e.focus(),e.value=``;for(let n of t)e.value+=n,h.input(e),h.keyDown(e,{key:n}),h.keyUp(e,{key:n}),await g();h.change(e)},async hover(e){h.pointerEnter(e),await g()},async press(e,t,n){h.keyDown(e,{key:t,...n}),h.keyUp(e,{key:t,...n}),await g()},async select(e,t){let n=Array.isArray(t)?t:[t];for(let t of e.options)t.selected=n.includes(t.value);h.change(e),await g()},async type(e,t){e.focus();for(let n of t)e.value+=n,h.input(e),h.keyDown(e,{key:n}),h.keyUp(e,{key:n}),await g();h.change(e)},async unhover(e){h.pointerLeave(e),await g()}};async function v(e,{interval:t=50,message:n,timeout:r=1e3}={}){let i=Date.now()+r,a,o=async()=>{try{let t=await e();return t===void 0||!!t}catch(e){return a=e,!1}};for(;Date.now()<i;){if(await o())return;await new Promise(e=>setTimeout(e,t))}if(await o())return;let s=n??`waitFor timed out after ${r}ms`;throw a instanceof Error?(a.message=`${s}\n${a.message}`,a):Error(a==null?s:`${s}\nCause: ${a}`)}function y(e,t,n=1e3){return new Promise((r,i)=>{let a=setTimeout(()=>i(Error(`waitForEvent: "${t}" timed out after ${n}ms`)),n);e.addEventListener(t,e=>{clearTimeout(a),r(e)},{once:!0})})}function b(e,t=``){customElements.get(e)||customElements.define(e,class extends HTMLElement{connectedCallback(){this.innerHTML=t}})}function x(){for(let e of n)e.remove();n.length=0}exports._resetCounters=i,exports.cleanup=x,exports.fire=h,exports.flush=a,exports.install=o,exports.mock=b,exports.mount=u,exports.user=_,exports.waitFor=v,exports.waitForEvent=y,exports.within=p;
2
+ //# sourceMappingURL=testing.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.cjs","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 type { Signal } from '@vielzeug/stateit';\n\nimport type { ComponentTemplate } from '../registration';\n\nimport { _resetIdCounter, type HTMLResult } from '../internal';\nimport { define, type ComponentDefinition, type SetupContextBag } from '../registration';\nimport { fire as runtimeFire } from '../runtime';\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 TestSetup<\n Props extends Record<string, unknown> = Record<string, never>,\n Events extends Record<string, unknown> = Record<string, unknown>,\n> = (...args: Parameters<ComponentDefinition<Props, Events>['setup']>) => ComponentTemplate | HTMLResult;\n\ntype MountProps = { readonly [x: string]: Signal<unknown> };\n\n// Bivariant callback type keeps inline test callbacks ergonomic across varying setup context specializations.\nexport type MountSetup = {\n bivarianceHack: (props: MountProps, ctx: SetupContextBag<any>) => ComponentTemplate | HTMLResult;\n}['bivarianceHack'];\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 _componentTagCounter = 0;\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 tagOrSetup: string,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetup: MountSetup,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetup: string | MountSetup,\n options: MountOptions = {},\n): Promise<Fixture<T>> {\n const { attrs = {}, componentOptions, container = document.body, html, props = {} } = options;\n\n const normalizeSetup = <P extends Record<string, unknown>, E extends Record<string, unknown>>(\n setup: TestSetup<P, E>,\n ): ComponentDefinition<P, E>['setup'] => {\n return (setupProps, setupCtx) => {\n const result = setup(setupProps, setupCtx);\n\n if (typeof result === 'function') {\n return result;\n }\n\n return () => result;\n };\n };\n\n let tagName: string;\n let inlineDefinition: ComponentDefinition<any, any> | undefined;\n\n if (typeof tagOrSetup === 'string') {\n tagName = tagOrSetup;\n } else {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = {\n ...(componentOptions ?? {}),\n setup: normalizeSetup(tagOrSetup as TestSetup<any, any>),\n };\n }\n\n if (inlineDefinition) {\n define(tagName, inlineDefinition);\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) =>\n runtimeFire.event(el, new FocusEvent('blur', { bubbles: true, ...opts })),\n change: (el: Element, opts?: EventInit) => runtimeFire.event(el, new Event('change', { bubbles: true, ...opts })),\n click: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, 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 runtimeFire.event(el, new CustomEvent<D>(name, { bubbles: true, cancelable: true, detail, ...opts }));\n },\n focus: (el: Element, opts?: FocusEventInit) =>\n runtimeFire.event(el, new FocusEvent('focus', { bubbles: true, ...opts })),\n input: (el: Element, opts?: EventInit) => runtimeFire.event(el, new Event('input', { bubbles: true, ...opts })),\n keyDown: (el: Element, opts?: KeyboardEventInit) =>\n runtimeFire.event(el, new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...opts })),\n keyUp: (el: Element, opts?: KeyboardEventInit) =>\n runtimeFire.event(el, new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...opts })),\n pointerDown: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerdown', { bubbles: true, cancelable: true, ...opts })),\n pointerEnter: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerenter', { bubbles: false, ...opts })),\n pointerLeave: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerleave', { bubbles: false, ...opts })),\n pointerUp: (el: Element, opts?: PointerEventInit) =>\n runtimeFire.event(el, createPointerEvent('pointerup', { bubbles: true, cancelable: true, ...opts })),\n submit: (el: Element, opts?: EventInit) =>\n runtimeFire.event(el, 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":"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"}
@@ -3,7 +3,10 @@
3
3
  *
4
4
  * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)
5
5
  */
6
- import { type BuildPropSchema, type DefineComponentOptions } from '../core/component';
6
+ import type { Signal } from '@vielzeug/stateit';
7
+ import type { ComponentTemplate } from '../registration';
8
+ import { type HTMLResult } from '../internal';
9
+ import { type ComponentDefinition, type SetupContextBag } from '../registration';
7
10
  export interface Fixture<T extends HTMLElement = HTMLElement> {
8
11
  /** The component element */
9
12
  element: T;
@@ -50,10 +53,15 @@ export interface MountOptions {
50
53
  html?: string;
51
54
  /** Parent container (default: document.body) */
52
55
  container?: HTMLElement;
53
- /** Extra defineComponent options when passing an inline setup function */
54
- componentOptions?: Omit<DefineComponentOptions<any, any>, 'setup' | 'tag'>;
56
+ /** Extra component options when passing an inline setup function */
57
+ componentOptions?: Omit<ComponentDefinition<any, any>, 'setup'>;
55
58
  }
56
- type TestComponentOptions<Props extends Record<string, unknown> = Record<string, never>, Events extends Record<string, unknown> = Record<string, unknown>> = Omit<DefineComponentOptions<BuildPropSchema<Props>, Events>, 'tag'>;
59
+ type MountProps = {
60
+ readonly [x: string]: Signal<unknown>;
61
+ };
62
+ export type MountSetup = {
63
+ bivarianceHack: (props: MountProps, ctx: SetupContextBag<any>) => ComponentTemplate | HTMLResult;
64
+ }['bivarianceHack'];
57
65
  export interface WaitOptions {
58
66
  /** Maximum wait time in ms (default: 1000) */
59
67
  timeout?: number;
@@ -69,8 +77,8 @@ export interface WaitOptions {
69
77
  export declare const _resetCounters: () => void;
70
78
  /**
71
79
  * Flush pending reactive updates.
72
- * Drains the microtask queue completely, then yields one animation frame
73
- * for any rAF-scheduled work.
80
+ * Drains several microtask turns, then yields one animation frame and
81
+ * one final microtask pass for rAF-scheduled work.
74
82
  */
75
83
  export declare function flush(): Promise<void>;
76
84
  /**
@@ -79,7 +87,7 @@ export declare function flush(): Promise<void>;
79
87
  * @example
80
88
  * // vitest.setup.ts
81
89
  * import { afterEach } from 'vitest';
82
- * import { install } from '@vielzeug/craftit/test';
90
+ * import { install } from '@vielzeug/craftit/testing';
83
91
  * install(afterEach);
84
92
  */
85
93
  export declare function install(afterEachHook: (fn: () => void) => void): void;
@@ -98,9 +106,8 @@ export declare function install(afterEachHook: (fn: () => void) => void): void;
98
106
  * @example — registered tag name
99
107
  * const { query } = await mount('my-counter');
100
108
  */
101
- export declare function mount<T extends HTMLElement = HTMLElement>(tagOrSetupOrOptions: string, options?: MountOptions): Promise<Fixture<T>>;
102
- export declare function mount<T extends HTMLElement = HTMLElement>(tagOrSetupOrOptions: TestComponentOptions['setup'], options?: MountOptions): Promise<Fixture<T>>;
103
- export declare function mount<T extends HTMLElement = HTMLElement>(tagOrSetupOrOptions: TestComponentOptions<any, any>, options?: MountOptions): Promise<Fixture<T>>;
109
+ export declare function mount<T extends HTMLElement = HTMLElement>(tagOrSetup: string, options?: MountOptions): Promise<Fixture<T>>;
110
+ export declare function mount<T extends HTMLElement = HTMLElement>(tagOrSetup: MountSetup, options?: MountOptions): Promise<Fixture<T>>;
104
111
  /**
105
112
  * Create query helpers scoped to any element — useful for slotted/light DOM content.
106
113
  *
@@ -195,4 +202,4 @@ export declare function mock(tagName: string, template?: string): void;
195
202
  */
196
203
  export declare function cleanup(): void;
197
204
  export {};
198
- //# sourceMappingURL=test.d.ts.map
205
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/testing/testing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAU,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAKzF,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IAC1D,4BAA4B;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,gDAAgD;IAChD,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IAC/D,4CAA4C;IAC5C,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAC7D,iEAAiE;IACjE,WAAW,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IACpF,4DAA4D;IAC5D,cAAc,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAClF,4DAA4D;IAC5D,aAAa,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IACrE,0DAA0D;IAC1D,gBAAgB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IACnE,+DAA+D;IAC/D,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,yCAAyC;IACzC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,yDAAyD;IACzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,2FAA2F;IAC3F,GAAG,CAAC,EAAE,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,wCAAwC;IACxC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IAC/D,QAAQ,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAC7D,WAAW,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IACpF,cAAc,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;IAClF,aAAa,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC;IACrE,gBAAgB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;CACpE;AAED,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;CACjE;AAOD,KAAK,UAAU,GAAG;IAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC;AAG5D,MAAM,MAAM,UAAU,GAAG;IACvB,cAAc,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,CAAC,GAAG,CAAC,KAAK,iBAAiB,GAAG,UAAU,CAAC;CAClG,CAAC,gBAAgB,CAAC,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAOD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,IAGjC,CAAC;AAIF;;;;GAIG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAe3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,GAAG,IAAI,CAErE;AAuCD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,KAAK,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC7D,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,wBAAsB,KAAK,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC7D,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AA+HvB;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAYnD;AAYD;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI;wBACJ,OAAO,SAAS,cAAc;0BAE5B,OAAO,SAAS,SAAS;yBAC1B,OAAO,SAAS,gBAAgB;sBAErC,CAAC,gBAAgB,OAAO,QAAQ,MAAM,WAAW,CAAC,SAAS,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAG,IAAI;yBAG/F,OAAO,SAAS,cAAc;yBAE9B,OAAO,SAAS,SAAS;2BACvB,OAAO,SAAS,iBAAiB;yBAEnC,OAAO,SAAS,iBAAiB;+BAE3B,OAAO,SAAS,gBAAgB;gCAE/B,OAAO,SAAS,gBAAgB;gCAEhC,OAAO,SAAS,gBAAgB;6BAEnC,OAAO,SAAS,gBAAgB;0BAEnC,OAAO,SAAS,SAAS;CAE9B,CAAC;AAMX;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI;yBACC,gBAAgB,GAAG,mBAAmB,KAAG,OAAO,CAAC,IAAI,CAAC;yBAOtD,OAAO,SAAS,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAAC;4BAM7C,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;IAU1C,gFAAgF;wBACjE,gBAAgB,GAAG,mBAAmB,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;yBAanE,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;IAKvC,gDAAgD;yBAChC,OAAO,OAAO,MAAM,SAAS,iBAAiB,KAAG,OAAO,CAAC,IAAI,CAAC;0BAM7D,iBAAiB,SAAS,MAAM,GAAG,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAAC;IAQ5E,wEAAwE;wBACzD,gBAAgB,GAAG,mBAAmB,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;2BAYjE,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC;CAIjC,CAAC;AAIX;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAC3B,EAAE,EAAE,MAAM,OAAO,EACjB,EAAE,QAAa,EAAE,OAAO,EAAE,OAAc,EAAE,GAAE,WAAgB,GAC3D,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAahH;AAID;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,IAAI,CAWzD;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,IAAI,IAAI,CAG9B"}
@@ -0,0 +1,2 @@
1
+ import"../runtime.js";import{_resetIdCounter as e,fire as t}from"../internal.js";import{define as n}from"../registration.js";var r=[],i=0,a=()=>{e(),i=0};async function o(){let e=async e=>{for(let t=0;t<e;t++)await Promise.resolve(),await new Promise(e=>queueMicrotask(e))};await e(12),await new Promise(e=>typeof requestAnimationFrame<`u`?requestAnimationFrame(()=>e()):e()),await e(2)}function s(e){e(S)}function c(e,t,n){n===!1?e.removeAttribute(t):e.setAttribute(t,n===!0?``:String(n))}var l=e=>e instanceof Error?e:Error(String(e)),u=async e=>{if(typeof window>`u`)return e();let t=null,n=e=>{t=l(e.error??e.message),e.preventDefault()},r=e=>{t=l(e.reason),e.preventDefault()};window.addEventListener(`error`,n),window.addEventListener(`unhandledrejection`,r);try{let n=await e();if(t)throw t;return n}finally{window.removeEventListener(`error`,n),window.removeEventListener(`unhandledrejection`,r)}};async function d(e,t={}){let{attrs:a={},componentOptions:s,container:l=document.body,html:d,props:m={}}=t,h=e=>(t,n)=>{let r=e(t,n);return typeof r==`function`?r:()=>r},g,_;typeof e==`string`?g=e:(g=`trial-${++i}`,_={...s??{},setup:h(e)}),_&&n(g,_);let v=document.createElement(g);d&&(v.innerHTML=d),Object.keys(m).length&&Object.assign(v,m);for(let[e,t]of Object.entries(a))c(v,e,t);return await u(async()=>{l.appendChild(v),r.push(v),await o()}),{async act(e){await e(),await o()},async attr(e,t){c(v,e,t),await o()},async attrs(e){for(let[t,n]of Object.entries(e))c(v,t,n);await o()},destroy(){v.remove();let e=r.indexOf(v);e!==-1&&r.splice(e,1)},element:v,flush:o,query(e){return v.shadowRoot?.querySelector(e)??null},queryAll(e){return Array.from(v.shadowRoot?.querySelectorAll(e)??[])},queryAllByTestId(e){return Array.from(v.shadowRoot?.querySelectorAll(`[data-testid="${e}"]`)??[])},queryAllByText(e,t=`*`){return p(v.shadowRoot,e,t)},queryByTestId(e){return v.shadowRoot?.querySelector(`[data-testid="${e}"]`)??null},queryByText(e,t=`*`){return f(v.shadowRoot,e,t)},get shadow(){return v.shadowRoot}}}function f(e,t,n){for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null}function p(e,t,n){return Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t)}function m(e){return{query:t=>e.querySelector(t),queryAll:t=>Array.from(e.querySelectorAll(t)),queryAllByTestId:t=>Array.from(e.querySelectorAll(`[data-testid="${t}"]`)),queryAllByText:(t,n=`*`)=>p(e,t,n),queryByTestId:t=>e.querySelector(`[data-testid="${t}"]`),queryByText:(t,n=`*`)=>f(e,t,n)}}var h=(e,t={})=>typeof PointerEvent<`u`?new PointerEvent(e,t):new MouseEvent(e,t),g={blur:(e,n)=>t.event(e,new FocusEvent(`blur`,{bubbles:!0,...n})),change:(e,n)=>t.event(e,new Event(`change`,{bubbles:!0,...n})),click:(e,n)=>t.event(e,new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...n})),custom(e,n,r,i){t.event(e,new CustomEvent(n,{bubbles:!0,cancelable:!0,detail:r,...i}))},focus:(e,n)=>t.event(e,new FocusEvent(`focus`,{bubbles:!0,...n})),input:(e,n)=>t.event(e,new Event(`input`,{bubbles:!0,...n})),keyDown:(e,n)=>t.event(e,new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...n})),keyUp:(e,n)=>t.event(e,new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...n})),pointerDown:(e,n)=>t.event(e,h(`pointerdown`,{bubbles:!0,cancelable:!0,...n})),pointerEnter:(e,n)=>t.event(e,h(`pointerenter`,{bubbles:!1,...n})),pointerLeave:(e,n)=>t.event(e,h(`pointerleave`,{bubbles:!1,...n})),pointerUp:(e,n)=>t.event(e,h(`pointerup`,{bubbles:!0,cancelable:!0,...n})),submit:(e,n)=>t.event(e,new Event(`submit`,{bubbles:!0,cancelable:!0,...n}))},_=()=>o(),v={async clear(e){e.focus(),e.value=``,g.input(e),g.change(e),await _()},async click(e,t){g.pointerEnter(e,t),g.click(e,t),await _()},async dblClick(e){for(let t=0;t<2;t++)g.pointerDown(e),g.pointerUp(e),g.click(e);e.dispatchEvent(new MouseEvent(`dblclick`,{bubbles:!0,cancelable:!0})),await _()},async fill(e,t){e.focus(),e.value=``;for(let n of t)e.value+=n,g.input(e),g.keyDown(e,{key:n}),g.keyUp(e,{key:n}),await _();g.change(e)},async hover(e){g.pointerEnter(e),await _()},async press(e,t,n){g.keyDown(e,{key:t,...n}),g.keyUp(e,{key:t,...n}),await _()},async select(e,t){let n=Array.isArray(t)?t:[t];for(let t of e.options)t.selected=n.includes(t.value);g.change(e),await _()},async type(e,t){e.focus();for(let n of t)e.value+=n,g.input(e),g.keyDown(e,{key:n}),g.keyUp(e,{key:n}),await _();g.change(e)},async unhover(e){g.pointerLeave(e),await _()}};async function y(e,{interval:t=50,message:n,timeout:r=1e3}={}){let i=Date.now()+r,a,o=async()=>{try{let t=await e();return t===void 0||!!t}catch(e){return a=e,!1}};for(;Date.now()<i;){if(await o())return;await new Promise(e=>setTimeout(e,t))}if(await o())return;let s=n??`waitFor timed out after ${r}ms`;throw a instanceof Error?(a.message=`${s}\n${a.message}`,a):Error(a==null?s:`${s}\nCause: ${a}`)}function b(e,t,n=1e3){return new Promise((r,i)=>{let a=setTimeout(()=>i(Error(`waitForEvent: "${t}" timed out after ${n}ms`)),n);e.addEventListener(t,e=>{clearTimeout(a),r(e)},{once:!0})})}function x(e,t=``){customElements.get(e)||customElements.define(e,class extends HTMLElement{connectedCallback(){this.innerHTML=t}})}function S(){for(let e of r)e.remove();r.length=0}export{a as _resetCounters,S as cleanup,g as fire,o as flush,s as install,x as mock,d as mount,v as user,y as waitFor,b as waitForEvent,m as within};
2
+ //# sourceMappingURL=testing.js.map