@bquery/bquery 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. package/README.md +716 -586
  2. package/dist/a11y/announce.d.ts +43 -0
  3. package/dist/a11y/announce.d.ts.map +1 -0
  4. package/dist/a11y/audit.d.ts +42 -0
  5. package/dist/a11y/audit.d.ts.map +1 -0
  6. package/dist/a11y/index.d.ts +53 -0
  7. package/dist/a11y/index.d.ts.map +1 -0
  8. package/dist/a11y/media-preferences.d.ts +77 -0
  9. package/dist/a11y/media-preferences.d.ts.map +1 -0
  10. package/dist/a11y/roving-tab-index.d.ts +38 -0
  11. package/dist/a11y/roving-tab-index.d.ts.map +1 -0
  12. package/dist/a11y/skip-link.d.ts +37 -0
  13. package/dist/a11y/skip-link.d.ts.map +1 -0
  14. package/dist/a11y/trap-focus.d.ts +49 -0
  15. package/dist/a11y/trap-focus.d.ts.map +1 -0
  16. package/dist/a11y/types.d.ts +152 -0
  17. package/dist/a11y/types.d.ts.map +1 -0
  18. package/dist/a11y-C5QOVvRn.js +421 -0
  19. package/dist/a11y-C5QOVvRn.js.map +1 -0
  20. package/dist/a11y.es.mjs +14 -0
  21. package/dist/component/component.d.ts.map +1 -1
  22. package/dist/component/html.d.ts.map +1 -1
  23. package/dist/component/index.d.ts +2 -1
  24. package/dist/component/index.d.ts.map +1 -1
  25. package/dist/component/library.d.ts.map +1 -1
  26. package/dist/component/scope.d.ts +138 -0
  27. package/dist/component/scope.d.ts.map +1 -0
  28. package/dist/component/types.d.ts +53 -1
  29. package/dist/component/types.d.ts.map +1 -1
  30. package/dist/component-CuuTijA6.js +684 -0
  31. package/dist/component-CuuTijA6.js.map +1 -0
  32. package/dist/component.es.mjs +9 -6
  33. package/dist/{config-DRmZZno3.js → config-BW35FKuA.js} +4 -4
  34. package/dist/{config-DRmZZno3.js.map → config-BW35FKuA.js.map} +1 -1
  35. package/dist/constraints-3lV9yyBw.js +100 -0
  36. package/dist/constraints-3lV9yyBw.js.map +1 -0
  37. package/dist/core/collection.d.ts +48 -0
  38. package/dist/core/collection.d.ts.map +1 -1
  39. package/dist/core/element.d.ts +92 -0
  40. package/dist/core/element.d.ts.map +1 -1
  41. package/dist/core/env.d.ts +18 -0
  42. package/dist/core/env.d.ts.map +1 -0
  43. package/dist/core/index.d.ts +1 -0
  44. package/dist/core/index.d.ts.map +1 -1
  45. package/dist/core/shared.d.ts +8 -0
  46. package/dist/core/shared.d.ts.map +1 -1
  47. package/dist/core/utils/index.d.ts +52 -41
  48. package/dist/core/utils/index.d.ts.map +1 -1
  49. package/dist/core-Cjl7GUu8.js +717 -0
  50. package/dist/core-Cjl7GUu8.js.map +1 -0
  51. package/dist/core-DnlyjbF2.js +112 -0
  52. package/dist/core-DnlyjbF2.js.map +1 -0
  53. package/dist/core.es.mjs +45 -44
  54. package/dist/custom-directives-7wAShnnd.js +9 -0
  55. package/dist/custom-directives-7wAShnnd.js.map +1 -0
  56. package/dist/devtools/devtools.d.ts +212 -0
  57. package/dist/devtools/devtools.d.ts.map +1 -0
  58. package/dist/devtools/index.d.ts +20 -0
  59. package/dist/devtools/index.d.ts.map +1 -0
  60. package/dist/devtools/types.d.ts +69 -0
  61. package/dist/devtools/types.d.ts.map +1 -0
  62. package/dist/devtools-D2fQLhDN.js +122 -0
  63. package/dist/devtools-D2fQLhDN.js.map +1 -0
  64. package/dist/devtools.es.mjs +19 -0
  65. package/dist/dnd/draggable.d.ts +51 -0
  66. package/dist/dnd/draggable.d.ts.map +1 -0
  67. package/dist/dnd/droppable.d.ts +38 -0
  68. package/dist/dnd/droppable.d.ts.map +1 -0
  69. package/dist/dnd/index.d.ts +47 -0
  70. package/dist/dnd/index.d.ts.map +1 -0
  71. package/dist/dnd/sortable.d.ts +43 -0
  72. package/dist/dnd/sortable.d.ts.map +1 -0
  73. package/dist/dnd/types.d.ts +250 -0
  74. package/dist/dnd/types.d.ts.map +1 -0
  75. package/dist/dnd-B8EgyzaI.js +244 -0
  76. package/dist/dnd-B8EgyzaI.js.map +1 -0
  77. package/dist/dnd.es.mjs +6 -0
  78. package/dist/env-NeVmr4Gf.js +19 -0
  79. package/dist/env-NeVmr4Gf.js.map +1 -0
  80. package/dist/forms/create-form.d.ts +49 -0
  81. package/dist/forms/create-form.d.ts.map +1 -0
  82. package/dist/forms/index.d.ts +39 -0
  83. package/dist/forms/index.d.ts.map +1 -0
  84. package/dist/forms/types.d.ts +139 -0
  85. package/dist/forms/types.d.ts.map +1 -0
  86. package/dist/forms/validators.d.ts +179 -0
  87. package/dist/forms/validators.d.ts.map +1 -0
  88. package/dist/forms-C3yovgH9.js +141 -0
  89. package/dist/forms-C3yovgH9.js.map +1 -0
  90. package/dist/forms.es.mjs +14 -0
  91. package/dist/full.d.ts +35 -7
  92. package/dist/full.d.ts.map +1 -1
  93. package/dist/full.es.mjs +182 -91
  94. package/dist/full.iife.js +47 -31
  95. package/dist/full.iife.js.map +1 -1
  96. package/dist/full.umd.js +47 -31
  97. package/dist/full.umd.js.map +1 -1
  98. package/dist/i18n/formatting.d.ts +40 -0
  99. package/dist/i18n/formatting.d.ts.map +1 -0
  100. package/dist/i18n/i18n.d.ts +48 -0
  101. package/dist/i18n/i18n.d.ts.map +1 -0
  102. package/dist/i18n/index.d.ts +57 -0
  103. package/dist/i18n/index.d.ts.map +1 -0
  104. package/dist/i18n/translate.d.ts +83 -0
  105. package/dist/i18n/translate.d.ts.map +1 -0
  106. package/dist/i18n/types.d.ts +156 -0
  107. package/dist/i18n/types.d.ts.map +1 -0
  108. package/dist/i18n-BnnhTFOS.js +89 -0
  109. package/dist/i18n-BnnhTFOS.js.map +1 -0
  110. package/dist/i18n.es.mjs +6 -0
  111. package/dist/index.d.ts +11 -0
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.es.mjs +227 -136
  114. package/dist/media/battery.d.ts +35 -0
  115. package/dist/media/battery.d.ts.map +1 -0
  116. package/dist/media/breakpoints.d.ts +51 -0
  117. package/dist/media/breakpoints.d.ts.map +1 -0
  118. package/dist/media/clipboard.d.ts +30 -0
  119. package/dist/media/clipboard.d.ts.map +1 -0
  120. package/dist/media/device-sensors.d.ts +54 -0
  121. package/dist/media/device-sensors.d.ts.map +1 -0
  122. package/dist/media/geolocation.d.ts +38 -0
  123. package/dist/media/geolocation.d.ts.map +1 -0
  124. package/dist/media/index.d.ts +42 -0
  125. package/dist/media/index.d.ts.map +1 -0
  126. package/dist/media/media-query.d.ts +36 -0
  127. package/dist/media/media-query.d.ts.map +1 -0
  128. package/dist/media/network.d.ts +35 -0
  129. package/dist/media/network.d.ts.map +1 -0
  130. package/dist/media/types.d.ts +173 -0
  131. package/dist/media/types.d.ts.map +1 -0
  132. package/dist/media/viewport.d.ts +32 -0
  133. package/dist/media/viewport.d.ts.map +1 -0
  134. package/dist/media-Di2Ta22s.js +340 -0
  135. package/dist/media-Di2Ta22s.js.map +1 -0
  136. package/dist/media.es.mjs +12 -0
  137. package/dist/motion/index.d.ts +7 -3
  138. package/dist/motion/index.d.ts.map +1 -1
  139. package/dist/motion/morph.d.ts +27 -0
  140. package/dist/motion/morph.d.ts.map +1 -0
  141. package/dist/motion/parallax.d.ts +30 -0
  142. package/dist/motion/parallax.d.ts.map +1 -0
  143. package/dist/motion/reduced-motion.d.ts +36 -3
  144. package/dist/motion/reduced-motion.d.ts.map +1 -1
  145. package/dist/motion/types.d.ts +58 -0
  146. package/dist/motion/types.d.ts.map +1 -1
  147. package/dist/motion/typewriter.d.ts +31 -0
  148. package/dist/motion/typewriter.d.ts.map +1 -0
  149. package/dist/motion-qPj_TYGv.js +530 -0
  150. package/dist/motion-qPj_TYGv.js.map +1 -0
  151. package/dist/motion.es.mjs +27 -23
  152. package/dist/{view-C70lA3vf.js → mount-SM07RUa6.js} +166 -160
  153. package/dist/mount-SM07RUa6.js.map +1 -0
  154. package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
  155. package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
  156. package/dist/{platform-Dr9b6fsq.js → platform-CPbCprb6.js} +21 -22
  157. package/dist/{platform-Dr9b6fsq.js.map → platform-CPbCprb6.js.map} +1 -1
  158. package/dist/platform.es.mjs +2 -2
  159. package/dist/plugin/index.d.ts +22 -0
  160. package/dist/plugin/index.d.ts.map +1 -0
  161. package/dist/plugin/registry.d.ts +108 -0
  162. package/dist/plugin/registry.d.ts.map +1 -0
  163. package/dist/plugin/types.d.ts +110 -0
  164. package/dist/plugin/types.d.ts.map +1 -0
  165. package/dist/plugin-cPoOHFLY.js +64 -0
  166. package/dist/plugin-cPoOHFLY.js.map +1 -0
  167. package/dist/plugin.es.mjs +9 -0
  168. package/dist/reactive/computed.d.ts +7 -0
  169. package/dist/reactive/computed.d.ts.map +1 -1
  170. package/dist/reactive-Cfv0RK6x.js +233 -0
  171. package/dist/reactive-Cfv0RK6x.js.map +1 -0
  172. package/dist/reactive.es.mjs +19 -20
  173. package/dist/registry-CWf368tT.js +26 -0
  174. package/dist/registry-CWf368tT.js.map +1 -0
  175. package/dist/router/bq-link.d.ts +112 -0
  176. package/dist/router/bq-link.d.ts.map +1 -0
  177. package/dist/router/constraints.d.ts +9 -0
  178. package/dist/router/constraints.d.ts.map +1 -0
  179. package/dist/router/index.d.ts +14 -6
  180. package/dist/router/index.d.ts.map +1 -1
  181. package/dist/router/match.d.ts +0 -1
  182. package/dist/router/match.d.ts.map +1 -1
  183. package/dist/router/path-pattern.d.ts +14 -0
  184. package/dist/router/path-pattern.d.ts.map +1 -0
  185. package/dist/router/query.d.ts.map +1 -1
  186. package/dist/router/router.d.ts +3 -1
  187. package/dist/router/router.d.ts.map +1 -1
  188. package/dist/router/types.d.ts +48 -4
  189. package/dist/router/types.d.ts.map +1 -1
  190. package/dist/router/use-route.d.ts +50 -0
  191. package/dist/router/use-route.d.ts.map +1 -0
  192. package/dist/router/utils.d.ts +3 -0
  193. package/dist/router/utils.d.ts.map +1 -1
  194. package/dist/router-BrthaP_z.js +473 -0
  195. package/dist/router-BrthaP_z.js.map +1 -0
  196. package/dist/router.es.mjs +13 -10
  197. package/dist/{sanitize-Bs2dkMby.js → sanitize-B1V4JswB.js} +2 -1
  198. package/dist/{sanitize-Bs2dkMby.js.map → sanitize-B1V4JswB.js.map} +1 -1
  199. package/dist/security/index.d.ts +2 -2
  200. package/dist/security/index.d.ts.map +1 -1
  201. package/dist/security.es.mjs +1 -1
  202. package/dist/ssr/hydrate.d.ts +65 -0
  203. package/dist/ssr/hydrate.d.ts.map +1 -0
  204. package/dist/ssr/index.d.ts +59 -0
  205. package/dist/ssr/index.d.ts.map +1 -0
  206. package/dist/ssr/render.d.ts +62 -0
  207. package/dist/ssr/render.d.ts.map +1 -0
  208. package/dist/ssr/serialize.d.ts +118 -0
  209. package/dist/ssr/serialize.d.ts.map +1 -0
  210. package/dist/ssr/types.d.ts +70 -0
  211. package/dist/ssr/types.d.ts.map +1 -0
  212. package/dist/ssr-B2qd_WBB.js +248 -0
  213. package/dist/ssr-B2qd_WBB.js.map +1 -0
  214. package/dist/ssr.es.mjs +9 -0
  215. package/dist/store/create-store.d.ts.map +1 -1
  216. package/dist/store/index.d.ts +1 -1
  217. package/dist/store/index.d.ts.map +1 -1
  218. package/dist/store/persisted.d.ts +38 -4
  219. package/dist/store/persisted.d.ts.map +1 -1
  220. package/dist/store/types.d.ts +138 -1
  221. package/dist/store/types.d.ts.map +1 -1
  222. package/dist/store/utils.d.ts +2 -2
  223. package/dist/store/utils.d.ts.map +1 -1
  224. package/dist/store-DWpyH6p5.js +338 -0
  225. package/dist/store-DWpyH6p5.js.map +1 -0
  226. package/dist/store.es.mjs +11 -10
  227. package/dist/storybook/index.d.ts.map +1 -1
  228. package/dist/storybook.es.mjs +1 -1
  229. package/dist/storybook.es.mjs.map +1 -1
  230. package/dist/testing/index.d.ts +23 -0
  231. package/dist/testing/index.d.ts.map +1 -0
  232. package/dist/testing/testing.d.ts +156 -0
  233. package/dist/testing/testing.d.ts.map +1 -0
  234. package/dist/testing/types.d.ts +134 -0
  235. package/dist/testing/types.d.ts.map +1 -0
  236. package/dist/testing-CsqjNUyy.js +224 -0
  237. package/dist/testing-CsqjNUyy.js.map +1 -0
  238. package/dist/testing.es.mjs +9 -0
  239. package/dist/type-guards-Do9DWgNp.js +44 -0
  240. package/dist/type-guards-Do9DWgNp.js.map +1 -0
  241. package/dist/untrack-DJVQQ2WM.js +33 -0
  242. package/dist/untrack-DJVQQ2WM.js.map +1 -0
  243. package/dist/view/custom-directives.d.ts +20 -0
  244. package/dist/view/custom-directives.d.ts.map +1 -0
  245. package/dist/view/evaluate.d.ts.map +1 -1
  246. package/dist/view/process.d.ts.map +1 -1
  247. package/dist/view.es.mjs +9 -9
  248. package/package.json +177 -141
  249. package/src/a11y/announce.ts +131 -0
  250. package/src/a11y/audit.ts +314 -0
  251. package/src/a11y/index.ts +68 -0
  252. package/src/a11y/media-preferences.ts +255 -0
  253. package/src/a11y/roving-tab-index.ts +164 -0
  254. package/src/a11y/skip-link.ts +255 -0
  255. package/src/a11y/trap-focus.ts +184 -0
  256. package/src/a11y/types.ts +183 -0
  257. package/src/component/component.ts +104 -29
  258. package/src/component/html.ts +5 -5
  259. package/src/component/index.ts +2 -0
  260. package/src/component/library.ts +26 -2
  261. package/src/component/scope.ts +212 -0
  262. package/src/component/types.ts +94 -40
  263. package/src/core/collection.ts +707 -628
  264. package/src/core/element.ts +981 -774
  265. package/src/core/env.ts +60 -0
  266. package/src/core/index.ts +49 -48
  267. package/src/core/shared.ts +62 -13
  268. package/src/core/utils/index.ts +148 -83
  269. package/src/devtools/devtools.ts +410 -0
  270. package/src/devtools/index.ts +48 -0
  271. package/src/devtools/types.ts +104 -0
  272. package/src/dnd/draggable.ts +296 -0
  273. package/src/dnd/droppable.ts +228 -0
  274. package/src/dnd/index.ts +62 -0
  275. package/src/dnd/sortable.ts +307 -0
  276. package/src/dnd/types.ts +293 -0
  277. package/src/forms/create-form.ts +278 -0
  278. package/src/forms/index.ts +65 -0
  279. package/src/forms/types.ts +154 -0
  280. package/src/forms/validators.ts +265 -0
  281. package/src/full.ts +253 -2
  282. package/src/i18n/formatting.ts +67 -0
  283. package/src/i18n/i18n.ts +200 -0
  284. package/src/i18n/index.ts +67 -0
  285. package/src/i18n/translate.ts +182 -0
  286. package/src/i18n/types.ts +171 -0
  287. package/src/index.ts +108 -36
  288. package/src/media/battery.ts +116 -0
  289. package/src/media/breakpoints.ts +131 -0
  290. package/src/media/clipboard.ts +80 -0
  291. package/src/media/device-sensors.ts +158 -0
  292. package/src/media/geolocation.ts +119 -0
  293. package/src/media/index.ts +76 -0
  294. package/src/media/media-query.ts +92 -0
  295. package/src/media/network.ts +115 -0
  296. package/src/media/types.ts +177 -0
  297. package/src/media/viewport.ts +84 -0
  298. package/src/motion/index.ts +57 -48
  299. package/src/motion/morph.ts +151 -0
  300. package/src/motion/parallax.ts +120 -0
  301. package/src/motion/reduced-motion.ts +66 -17
  302. package/src/motion/types.ts +271 -208
  303. package/src/motion/typewriter.ts +164 -0
  304. package/src/plugin/index.ts +37 -0
  305. package/src/plugin/registry.ts +269 -0
  306. package/src/plugin/types.ts +137 -0
  307. package/src/reactive/computed.ts +130 -92
  308. package/src/router/bq-link.ts +279 -0
  309. package/src/router/constraints.ts +201 -0
  310. package/src/router/index.ts +49 -41
  311. package/src/router/match.ts +312 -106
  312. package/src/router/path-pattern.ts +52 -0
  313. package/src/router/query.ts +38 -35
  314. package/src/router/router.ts +402 -211
  315. package/src/router/types.ts +139 -93
  316. package/src/router/use-route.ts +68 -0
  317. package/src/router/utils.ts +157 -116
  318. package/src/security/index.ts +2 -7
  319. package/src/security/sanitize.ts +70 -70
  320. package/src/security/trusted-html.ts +71 -71
  321. package/src/ssr/hydrate.ts +82 -0
  322. package/src/ssr/index.ts +70 -0
  323. package/src/ssr/render.ts +508 -0
  324. package/src/ssr/serialize.ts +296 -0
  325. package/src/ssr/types.ts +81 -0
  326. package/src/store/create-store.ts +467 -329
  327. package/src/store/define-store.ts +49 -49
  328. package/src/store/index.ts +27 -22
  329. package/src/store/mapping.ts +74 -74
  330. package/src/store/persisted.ts +206 -19
  331. package/src/store/types.ts +157 -2
  332. package/src/store/utils.ts +135 -141
  333. package/src/store/watch.ts +53 -53
  334. package/src/storybook/index.ts +2 -1
  335. package/src/testing/index.ts +42 -0
  336. package/src/testing/testing.ts +593 -0
  337. package/src/testing/types.ts +170 -0
  338. package/src/view/custom-directives.ts +30 -0
  339. package/src/view/evaluate.ts +292 -290
  340. package/src/view/process.ts +108 -92
  341. package/dist/component-BEQgt5hl.js +0 -600
  342. package/dist/component-BEQgt5hl.js.map +0 -1
  343. package/dist/core-BGQJVw0-.js +0 -35
  344. package/dist/core-BGQJVw0-.js.map +0 -1
  345. package/dist/core-CCEabVHl.js +0 -648
  346. package/dist/core-CCEabVHl.js.map +0 -1
  347. package/dist/effect-AFRW_Plg.js +0 -84
  348. package/dist/effect-AFRW_Plg.js.map +0 -1
  349. package/dist/motion-D9TcHxOF.js +0 -415
  350. package/dist/motion-D9TcHxOF.js.map +0 -1
  351. package/dist/reactive-DSkct0dO.js +0 -254
  352. package/dist/reactive-DSkct0dO.js.map +0 -1
  353. package/dist/router-CbDhl8rS.js +0 -188
  354. package/dist/router-CbDhl8rS.js.map +0 -1
  355. package/dist/store-BwDvI45q.js +0 -263
  356. package/dist/store-BwDvI45q.js.map +0 -1
  357. package/dist/untrack-B0rVscTc.js +0 -7
  358. package/dist/untrack-B0rVscTc.js.map +0 -1
  359. package/dist/view-C70lA3vf.js.map +0 -1
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Component-scoped reactive primitives.
3
+ *
4
+ * Provides `useSignal`, `useComputed`, and `useEffect` that automatically
5
+ * dispose when their owning component disconnects from the DOM.
6
+ *
7
+ * @module bquery/component
8
+ */
9
+
10
+ import type { Computed } from '../reactive/computed';
11
+ import { computed } from '../reactive/computed';
12
+ import { detectDevEnvironment } from '../core/env';
13
+ import type { Signal } from '../reactive/core';
14
+ import { signal } from '../reactive/core';
15
+ import { effect } from '../reactive/effect';
16
+ import type { CleanupFn } from '../reactive/index';
17
+
18
+ /**
19
+ * Holds disposable resources created inside a component scope.
20
+ * All registered disposers run when the component disconnects.
21
+ * @internal
22
+ */
23
+ export interface ComponentScope {
24
+ /** Register a cleanup function to run on dispose */
25
+ addDisposer(fn: CleanupFn): void;
26
+ /** Dispose all registered resources */
27
+ dispose(): void;
28
+ }
29
+
30
+ /** Currently active component scope. @internal */
31
+ let currentScope: ComponentScope | undefined;
32
+
33
+ /**
34
+ * Sets the active component scope.
35
+ * @internal
36
+ */
37
+ export function setCurrentScope(scope: ComponentScope | undefined): ComponentScope | undefined {
38
+ const previousScope = currentScope;
39
+ currentScope = scope;
40
+ return previousScope;
41
+ }
42
+
43
+ /**
44
+ * Returns the active component scope, or undefined if none.
45
+ * @internal
46
+ */
47
+ export function getCurrentScope(): ComponentScope | undefined {
48
+ return currentScope;
49
+ }
50
+
51
+ /**
52
+ * Creates a new component scope that tracks disposable resources.
53
+ * @internal
54
+ */
55
+ export function createComponentScope(): ComponentScope {
56
+ const disposers: CleanupFn[] = [];
57
+
58
+ return {
59
+ addDisposer(fn: CleanupFn): void {
60
+ disposers.push(fn);
61
+ },
62
+ dispose(): void {
63
+ for (const fn of disposers) {
64
+ try {
65
+ fn();
66
+ } catch (error) {
67
+ if (
68
+ detectDevEnvironment() &&
69
+ typeof console !== 'undefined' &&
70
+ typeof console.error === 'function'
71
+ ) {
72
+ console.error('bQuery component: Error disposing scoped resource', error);
73
+ }
74
+ }
75
+ }
76
+ disposers.length = 0;
77
+ },
78
+ };
79
+ }
80
+
81
+ /**
82
+ * Creates a reactive signal scoped to the current component.
83
+ *
84
+ * The signal is automatically disposed when the component disconnects
85
+ * from the DOM, removing all subscribers and preventing memory leaks.
86
+ *
87
+ * Must be called during a component lifecycle hook such as `connected`,
88
+ * `beforeMount`, `onAdopted`, or `onAttributeChanged`.
89
+ *
90
+ * Do not create scoped primitives from `render()`. Repeated renders can
91
+ * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.
92
+ *
93
+ * @template T - The type of the signal value
94
+ * @param initialValue - The initial value of the signal
95
+ * @returns A new Signal instance that auto-disposes with the component
96
+ * @throws {Error} If called outside a component scope
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * import { component, html, useSignal } from '@bquery/bquery/component';
101
+ *
102
+ * component('my-counter', {
103
+ * connected() {
104
+ * const count = useSignal(0);
105
+ * // count.dispose() is called automatically on disconnect
106
+ * },
107
+ * render({ state }) {
108
+ * return html`<span>${state.count}</span>`;
109
+ * },
110
+ * });
111
+ * ```
112
+ */
113
+ export function useSignal<T>(initialValue: T): Signal<T> {
114
+ const scope = currentScope;
115
+ if (!scope) {
116
+ throw new Error(
117
+ 'bQuery component: useSignal() must be called inside a component lifecycle hook. Avoid calling it directly from render()'
118
+ );
119
+ }
120
+ const s = signal(initialValue);
121
+ scope.addDisposer(() => s.dispose());
122
+ return s;
123
+ }
124
+
125
+ /**
126
+ * Creates a computed value scoped to the current component.
127
+ *
128
+ * The computed value's internal effect is automatically cleaned up
129
+ * when the component disconnects from the DOM.
130
+ *
131
+ * Must be called during a component lifecycle hook such as `connected`,
132
+ * `beforeMount`, `onAdopted`, or `onAttributeChanged`.
133
+ *
134
+ * Do not create scoped primitives from `render()`. Repeated renders can
135
+ * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.
136
+ *
137
+ * @template T - The type of the computed value
138
+ * @param fn - Derivation function that reads reactive sources
139
+ * @returns A new Computed instance that auto-cleans-up with the component
140
+ * @throws {Error} If called outside a component scope
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * import { component, html, useSignal, useComputed } from '@bquery/bquery/component';
145
+ *
146
+ * component('my-doubler', {
147
+ * connected() {
148
+ * const count = useSignal(1);
149
+ * const doubled = useComputed(() => count.value * 2);
150
+ * },
151
+ * render({ state }) {
152
+ * return html`<span>${state.doubled}</span>`;
153
+ * },
154
+ * });
155
+ * ```
156
+ */
157
+ export function useComputed<T>(fn: () => T): Computed<T> {
158
+ const scope = currentScope;
159
+ if (!scope) {
160
+ throw new Error(
161
+ 'bQuery component: useComputed() must be called inside a component lifecycle hook. Avoid calling it directly from render()'
162
+ );
163
+ }
164
+ const c = computed(fn);
165
+ scope.addDisposer(() => c.dispose());
166
+ return c;
167
+ }
168
+
169
+ /**
170
+ * Creates a side effect scoped to the current component.
171
+ *
172
+ * The effect runs immediately and re-runs when its reactive dependencies
173
+ * change. It is automatically disposed when the component disconnects
174
+ * from the DOM.
175
+ *
176
+ * Must be called during a component lifecycle hook such as `connected`,
177
+ * `beforeMount`, `onAdopted`, or `onAttributeChanged`.
178
+ *
179
+ * Do not create scoped primitives from `render()`. Repeated renders can
180
+ * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.
181
+ *
182
+ * @param fn - The effect function; may return a cleanup function
183
+ * @returns A cleanup function to manually stop the effect early
184
+ * @throws {Error} If called outside a component scope
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * import { component, useSignal, useEffect } from '@bquery/bquery/component';
189
+ *
190
+ * component('my-logger', {
191
+ * connected() {
192
+ * const count = useSignal(0);
193
+ * useEffect(() => {
194
+ * console.log('Count changed:', count.value);
195
+ * return () => console.log('Cleanup');
196
+ * });
197
+ * },
198
+ * render() { return '<p>Logger</p>'; },
199
+ * });
200
+ * ```
201
+ */
202
+ export function useEffect(fn: () => void | CleanupFn): CleanupFn {
203
+ const scope = currentScope;
204
+ if (!scope) {
205
+ throw new Error(
206
+ 'bQuery component: useEffect() must be called inside a component lifecycle hook. Avoid calling it directly from render()'
207
+ );
208
+ }
209
+ const cleanup = effect(fn);
210
+ scope.addDisposer(cleanup);
211
+ return cleanup;
212
+ }
@@ -51,54 +51,48 @@ export type PropDefinition<T = unknown> = {
51
51
  * When no explicit state generic is provided, component state falls back to
52
52
  * an untyped string-keyed record for backwards compatibility.
53
53
  */
54
- export type ComponentStateShape<
55
- TState extends Record<string, unknown> | undefined = undefined,
56
- > = TState extends Record<string, unknown> ? TState : Record<string, unknown>;
54
+ export type ComponentStateShape<TState extends Record<string, unknown> | undefined = undefined> =
55
+ TState extends Record<string, unknown> ? TState : Record<string, unknown>;
57
56
 
58
57
  /**
59
58
  * Component state keys are string-based because runtime state access is backed
60
59
  * by plain object properties.
61
60
  */
62
- export type ComponentStateKey<
63
- TState extends Record<string, unknown> | undefined = undefined,
64
- > =
61
+ export type ComponentStateKey<TState extends Record<string, unknown> | undefined = undefined> =
65
62
  keyof ComponentStateShape<TState> & string;
66
63
 
67
64
  /**
68
65
  * Public component element instance shape exposed by lifecycle hooks and
69
66
  * `defineComponent()` return values.
70
67
  */
71
- export type ComponentElement<
72
- TState extends Record<string, unknown> | undefined = undefined,
73
- > = HTMLElement & {
74
- /**
75
- * Updates a state property and triggers a re-render.
76
- *
77
- * @param key - The state property key
78
- * @param value - The new value
79
- */
80
- setState<TKey extends ComponentStateKey<TState>>(
81
- key: TKey,
82
- value: ComponentStateShape<TState>[TKey]
83
- ): void;
84
- /**
85
- * Gets a state property value.
86
- *
87
- * @param key - The state property key
88
- * @returns The current value
89
- */
90
- getState<TKey extends ComponentStateKey<TState>>(
91
- key: TKey
92
- ): ComponentStateShape<TState>[TKey];
93
- /**
94
- * Gets a state property value with an explicit cast for backwards
95
- * compatibility with the pre-typed-state API.
96
- *
97
- * @param key - The state property key
98
- * @returns The current value cast to `TResult`
99
- */
100
- getState<TResult = unknown>(key: string): TResult;
101
- };
68
+ export type ComponentElement<TState extends Record<string, unknown> | undefined = undefined> =
69
+ HTMLElement & {
70
+ /**
71
+ * Updates a state property and triggers a re-render.
72
+ *
73
+ * @param key - The state property key
74
+ * @param value - The new value
75
+ */
76
+ setState<TKey extends ComponentStateKey<TState>>(
77
+ key: TKey,
78
+ value: ComponentStateShape<TState>[TKey]
79
+ ): void;
80
+ /**
81
+ * Gets a state property value.
82
+ *
83
+ * @param key - The state property key
84
+ * @returns The current value
85
+ */
86
+ getState<TKey extends ComponentStateKey<TState>>(key: TKey): ComponentStateShape<TState>[TKey];
87
+ /**
88
+ * Gets a state property value with an explicit cast for backwards
89
+ * compatibility with the pre-typed-state API.
90
+ *
91
+ * @param key - The state property key
92
+ * @returns The current value cast to `TResult`
93
+ */
94
+ getState<TResult = unknown>(key: string): TResult;
95
+ };
102
96
 
103
97
  /**
104
98
  * Constructor returned by `defineComponent()`.
@@ -185,8 +179,8 @@ type ComponentHookWithProps<
185
179
  TState extends Record<string, unknown> | undefined = undefined,
186
180
  TResult = void,
187
181
  > = {
188
- (this: ComponentElement<TState>, newProps: TProps, oldProps: TProps): TResult;
189
- (newProps: TProps, oldProps: TProps): TResult;
182
+ (this: ComponentElement<TState>, newProps: TProps, oldProps: TProps): TResult;
183
+ (newProps: TProps, oldProps: TProps): TResult;
190
184
  };
191
185
  type ComponentUpdatedHook<
192
186
  TState extends Record<string, unknown> | undefined = undefined,
@@ -200,6 +194,17 @@ type ComponentErrorHook<TState extends Record<string, unknown> | undefined = und
200
194
  (error: Error): void;
201
195
  };
202
196
 
197
+ type ComponentAttributeChangedHook<TState extends Record<string, unknown> | undefined = undefined> =
198
+ {
199
+ (
200
+ this: ComponentElement<TState>,
201
+ name: string,
202
+ oldValue: string | null,
203
+ newValue: string | null
204
+ ): void;
205
+ (name: string, oldValue: string | null, newValue: string | null): void;
206
+ };
207
+
203
208
  type ComponentStateDefinition<TState extends Record<string, unknown> | undefined = undefined> =
204
209
  TState extends Record<string, unknown>
205
210
  ? {
@@ -222,6 +227,15 @@ type ComponentSignalsDefinition<TSignals extends ComponentSignals = Record<strin
222
227
  signals: TSignals;
223
228
  };
224
229
 
230
+ /**
231
+ * Controls Shadow DOM mode for the component.
232
+ *
233
+ * - `true` or `'open'` — attach an open shadow root (default)
234
+ * - `'closed'` — attach a closed shadow root
235
+ * - `false` — no shadow root; render directly into the host element
236
+ */
237
+ export type ShadowMode = boolean | 'open' | 'closed';
238
+
225
239
  export type ComponentDefinition<
226
240
  TProps extends Record<string, unknown> = Record<string, unknown>,
227
241
  TState extends Record<string, unknown> | undefined = undefined,
@@ -230,8 +244,25 @@ export type ComponentDefinition<
230
244
  ComponentSignalsDefinition<TSignals> & {
231
245
  /** Prop definitions with types and defaults */
232
246
  props?: Record<keyof TProps, PropDefinition>;
233
- /** CSS styles scoped to the component's shadow DOM */
247
+ /**
248
+ * CSS styles injected for the component.
249
+ *
250
+ * When `shadow` uses a shadow root (`true`, `'open'`, or `'closed'`), these
251
+ * styles are scoped to that shadow tree. When `shadow` is `false`, the
252
+ * generated `<style>` element is rendered into the host's light DOM and may
253
+ * therefore affect surrounding markup according to normal CSS cascade rules.
254
+ */
234
255
  styles?: string;
256
+ /**
257
+ * Controls Shadow DOM mode.
258
+ *
259
+ * - `true` or `'open'` — open shadow root (default)
260
+ * - `'closed'` — closed shadow root
261
+ * - `false` — no shadow root; render into the host element
262
+ *
263
+ * @default true
264
+ */
265
+ shadow?: ShadowMode;
235
266
  /**
236
267
  * Extra sanitizer options merged with the framework base allowlist during render.
237
268
  * Only opt in attributes/tags whose values you control or validate. Sensitive
@@ -239,12 +270,35 @@ export type ComponentDefinition<
239
270
  * or UI-redressing risks if used with untrusted input.
240
271
  */
241
272
  sanitize?: ComponentSanitizeOptions;
273
+ /**
274
+ * Additional attributes to observe beyond those declared in `props`.
275
+ *
276
+ * Useful when you want `onAttributeChanged` to fire for attributes
277
+ * that are not part of the typed props system.
278
+ */
279
+ observeAttributes?: string[];
242
280
  /** Lifecycle hook called before the component mounts (before first render) */
243
281
  beforeMount?: ComponentHook<TState>;
244
282
  /** Lifecycle hook called when component is added to DOM */
245
283
  connected?: ComponentHook<TState>;
246
284
  /** Lifecycle hook called when component is removed from DOM */
247
285
  disconnected?: ComponentHook<TState>;
286
+ /**
287
+ * Lifecycle hook called when the component is moved to a new document
288
+ * (e.g. via `document.adoptNode`).
289
+ */
290
+ onAdopted?: ComponentHook<TState>;
291
+ /**
292
+ * Lifecycle hook called when any observed attribute changes.
293
+ *
294
+ * Observed attributes are automatically derived from `props` keys
295
+ * plus any additional names in `observeAttributes`.
296
+ *
297
+ * @param name - The attribute name that changed
298
+ * @param oldValue - The previous attribute value (null if added)
299
+ * @param newValue - The new attribute value (null if removed)
300
+ */
301
+ onAttributeChanged?: ComponentAttributeChangedHook<TState>;
248
302
  /** Lifecycle hook called before an update render; return false to prevent */
249
303
  beforeUpdate?: ComponentHookWithProps<TProps, TState, boolean | void>;
250
304
  /** Lifecycle hook called after update renders; receives attribute change info when applicable */