@bquery/bquery 1.7.0 → 1.8.2

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 (262) hide show
  1. package/README.md +760 -716
  2. package/dist/{a11y-C5QOVvRn.js → a11y-DVBCy09c.js} +3 -3
  3. package/dist/a11y-DVBCy09c.js.map +1 -0
  4. package/dist/a11y.es.mjs +1 -1
  5. package/dist/component/library.d.ts.map +1 -1
  6. package/dist/{component-CuuTijA6.js → component-L3-JfOFz.js} +5 -5
  7. package/dist/component-L3-JfOFz.js.map +1 -0
  8. package/dist/component.es.mjs +1 -1
  9. package/dist/{config-BW35FKuA.js → config-DhT9auRm.js} +1 -1
  10. package/dist/{config-BW35FKuA.js.map → config-DhT9auRm.js.map} +1 -1
  11. package/dist/{constraints-3lV9yyBw.js → constraints-D5RHQLmP.js} +1 -1
  12. package/dist/constraints-D5RHQLmP.js.map +1 -0
  13. package/dist/core/collection.d.ts +86 -0
  14. package/dist/core/collection.d.ts.map +1 -1
  15. package/dist/core/element.d.ts +28 -0
  16. package/dist/core/element.d.ts.map +1 -1
  17. package/dist/core/shared.d.ts +6 -0
  18. package/dist/core/shared.d.ts.map +1 -1
  19. package/dist/core-DdtZHzsS.js +168 -0
  20. package/dist/core-DdtZHzsS.js.map +1 -0
  21. package/dist/{core-Cjl7GUu8.js → core-EMYSLzaT.js} +289 -259
  22. package/dist/core-EMYSLzaT.js.map +1 -0
  23. package/dist/core.es.mjs +48 -47
  24. package/dist/{custom-directives-7wAShnnd.js → custom-directives-Dr4C5lVV.js} +1 -1
  25. package/dist/custom-directives-Dr4C5lVV.js.map +1 -0
  26. package/dist/{devtools-D2fQLhDN.js → devtools-BhB2iDPT.js} +2 -2
  27. package/dist/devtools-BhB2iDPT.js.map +1 -0
  28. package/dist/devtools.es.mjs +1 -1
  29. package/dist/{dnd-B8EgyzaI.js → dnd-NwZBYh4l.js} +1 -1
  30. package/dist/dnd-NwZBYh4l.js.map +1 -0
  31. package/dist/dnd.es.mjs +1 -1
  32. package/dist/{env-NeVmr4Gf.js → env-CTdvLaH2.js} +1 -1
  33. package/dist/env-CTdvLaH2.js.map +1 -0
  34. package/dist/forms/create-form.d.ts.map +1 -1
  35. package/dist/forms/index.d.ts +3 -2
  36. package/dist/forms/index.d.ts.map +1 -1
  37. package/dist/forms/types.d.ts +46 -0
  38. package/dist/forms/types.d.ts.map +1 -1
  39. package/dist/forms/use-field.d.ts +34 -0
  40. package/dist/forms/use-field.d.ts.map +1 -0
  41. package/dist/forms/validators.d.ts +25 -0
  42. package/dist/forms/validators.d.ts.map +1 -1
  43. package/dist/forms-UcRHsYxC.js +227 -0
  44. package/dist/forms-UcRHsYxC.js.map +1 -0
  45. package/dist/forms.es.mjs +14 -12
  46. package/dist/full.d.ts +17 -26
  47. package/dist/full.d.ts.map +1 -1
  48. package/dist/full.es.mjs +206 -181
  49. package/dist/full.iife.js +33 -33
  50. package/dist/full.iife.js.map +1 -1
  51. package/dist/full.umd.js +33 -33
  52. package/dist/full.umd.js.map +1 -1
  53. package/dist/function-Cybd57JV.js +33 -0
  54. package/dist/function-Cybd57JV.js.map +1 -0
  55. package/dist/{i18n-BnnhTFOS.js → i18n-kuF6Ekj6.js} +3 -3
  56. package/dist/i18n-kuF6Ekj6.js.map +1 -0
  57. package/dist/i18n.es.mjs +1 -1
  58. package/dist/index.es.mjs +251 -228
  59. package/dist/media/breakpoints.d.ts.map +1 -1
  60. package/dist/media/types.d.ts +2 -2
  61. package/dist/media/types.d.ts.map +1 -1
  62. package/dist/{media-Di2Ta22s.js → media-i-fB5WxI.js} +3 -3
  63. package/dist/media-i-fB5WxI.js.map +1 -0
  64. package/dist/media.es.mjs +1 -1
  65. package/dist/{motion-qPj_TYGv.js → motion-BJsAuULb.js} +2 -2
  66. package/dist/motion-BJsAuULb.js.map +1 -0
  67. package/dist/motion.es.mjs +1 -1
  68. package/dist/{mount-SM07RUa6.js → mount-B4Y8bk8Z.js} +5 -5
  69. package/dist/mount-B4Y8bk8Z.js.map +1 -0
  70. package/dist/{platform-CPbCprb6.js → platform-Dw2gE3zI.js} +3 -3
  71. package/dist/{platform-CPbCprb6.js.map → platform-Dw2gE3zI.js.map} +1 -1
  72. package/dist/platform.es.mjs +2 -2
  73. package/dist/plugin/registry.d.ts.map +1 -1
  74. package/dist/{plugin-cPoOHFLY.js → plugin-C2WuC8SF.js} +20 -18
  75. package/dist/plugin-C2WuC8SF.js.map +1 -0
  76. package/dist/plugin.es.mjs +1 -1
  77. package/dist/reactive/async-data.d.ts +28 -3
  78. package/dist/reactive/async-data.d.ts.map +1 -1
  79. package/dist/reactive/computed.d.ts +3 -0
  80. package/dist/reactive/computed.d.ts.map +1 -1
  81. package/dist/reactive/effect.d.ts +3 -0
  82. package/dist/reactive/effect.d.ts.map +1 -1
  83. package/dist/reactive/http.d.ts +194 -0
  84. package/dist/reactive/http.d.ts.map +1 -0
  85. package/dist/reactive/index.d.ts +2 -2
  86. package/dist/reactive/index.d.ts.map +1 -1
  87. package/dist/reactive/pagination.d.ts +126 -0
  88. package/dist/reactive/pagination.d.ts.map +1 -0
  89. package/dist/reactive/polling.d.ts +55 -0
  90. package/dist/reactive/polling.d.ts.map +1 -0
  91. package/dist/reactive/readonly.d.ts +20 -1
  92. package/dist/reactive/readonly.d.ts.map +1 -1
  93. package/dist/reactive/rest.d.ts +293 -0
  94. package/dist/reactive/rest.d.ts.map +1 -0
  95. package/dist/reactive/scope.d.ts +140 -0
  96. package/dist/reactive/scope.d.ts.map +1 -0
  97. package/dist/reactive/signal.d.ts +16 -2
  98. package/dist/reactive/signal.d.ts.map +1 -1
  99. package/dist/reactive/to-value.d.ts +57 -0
  100. package/dist/reactive/to-value.d.ts.map +1 -0
  101. package/dist/reactive/websocket.d.ts +285 -0
  102. package/dist/reactive/websocket.d.ts.map +1 -0
  103. package/dist/reactive-DwkhUJfP.js +1148 -0
  104. package/dist/reactive-DwkhUJfP.js.map +1 -0
  105. package/dist/reactive.es.mjs +38 -19
  106. package/dist/{registry-CWf368tT.js → registry-B08iilIh.js} +1 -1
  107. package/dist/{registry-CWf368tT.js.map → registry-B08iilIh.js.map} +1 -1
  108. package/dist/router/constraints.d.ts.map +1 -1
  109. package/dist/router/index.d.ts +1 -1
  110. package/dist/router/index.d.ts.map +1 -1
  111. package/dist/router/router.d.ts.map +1 -1
  112. package/dist/router/state.d.ts +25 -2
  113. package/dist/router/state.d.ts.map +1 -1
  114. package/dist/router-CQikC9Ed.js +492 -0
  115. package/dist/router-CQikC9Ed.js.map +1 -0
  116. package/dist/router.es.mjs +9 -8
  117. package/dist/ssr/hydrate.d.ts.map +1 -1
  118. package/dist/{ssr-B2qd_WBB.js → ssr-_dAcGdzu.js} +4 -4
  119. package/dist/ssr-_dAcGdzu.js.map +1 -0
  120. package/dist/ssr.es.mjs +1 -1
  121. package/dist/store/persisted.d.ts.map +1 -1
  122. package/dist/{store-DWpyH6p5.js → store-Cb3gPRve.js} +7 -7
  123. package/dist/store-Cb3gPRve.js.map +1 -0
  124. package/dist/store.es.mjs +2 -2
  125. package/dist/storybook.es.mjs.map +1 -1
  126. package/dist/{testing-CsqjNUyy.js → testing-C5Sjfsna.js} +8 -8
  127. package/dist/testing-C5Sjfsna.js.map +1 -0
  128. package/dist/testing.es.mjs +1 -1
  129. package/dist/{type-guards-Do9DWgNp.js → type-guards-BMX2c0LP.js} +1 -1
  130. package/dist/{type-guards-Do9DWgNp.js.map → type-guards-BMX2c0LP.js.map} +1 -1
  131. package/dist/untrack-D0fnO5k2.js +36 -0
  132. package/dist/untrack-D0fnO5k2.js.map +1 -0
  133. package/dist/view/custom-directives.d.ts.map +1 -1
  134. package/dist/view.es.mjs +4 -4
  135. package/package.json +178 -177
  136. package/src/a11y/announce.ts +131 -131
  137. package/src/a11y/audit.ts +314 -314
  138. package/src/a11y/index.ts +68 -68
  139. package/src/a11y/media-preferences.ts +255 -255
  140. package/src/a11y/roving-tab-index.ts +164 -164
  141. package/src/a11y/skip-link.ts +255 -255
  142. package/src/a11y/trap-focus.ts +184 -184
  143. package/src/a11y/types.ts +183 -183
  144. package/src/component/component.ts +599 -599
  145. package/src/component/html.ts +153 -153
  146. package/src/component/index.ts +52 -52
  147. package/src/component/library.ts +540 -542
  148. package/src/component/scope.ts +212 -212
  149. package/src/component/types.ts +310 -310
  150. package/src/core/collection.ts +876 -707
  151. package/src/core/element.ts +1015 -981
  152. package/src/core/env.ts +60 -60
  153. package/src/core/index.ts +49 -49
  154. package/src/core/shared.ts +77 -62
  155. package/src/core/utils/index.ts +148 -148
  156. package/src/devtools/devtools.ts +410 -410
  157. package/src/devtools/index.ts +48 -48
  158. package/src/devtools/types.ts +104 -104
  159. package/src/dnd/draggable.ts +296 -296
  160. package/src/dnd/droppable.ts +228 -228
  161. package/src/dnd/index.ts +62 -62
  162. package/src/dnd/sortable.ts +307 -307
  163. package/src/dnd/types.ts +293 -293
  164. package/src/forms/create-form.ts +320 -278
  165. package/src/forms/index.ts +70 -65
  166. package/src/forms/types.ts +203 -154
  167. package/src/forms/use-field.ts +231 -0
  168. package/src/forms/validators.ts +294 -265
  169. package/src/full.ts +554 -480
  170. package/src/i18n/formatting.ts +67 -67
  171. package/src/i18n/i18n.ts +200 -200
  172. package/src/i18n/index.ts +67 -67
  173. package/src/i18n/translate.ts +182 -182
  174. package/src/i18n/types.ts +171 -171
  175. package/src/index.ts +108 -108
  176. package/src/media/battery.ts +116 -116
  177. package/src/media/breakpoints.ts +129 -131
  178. package/src/media/clipboard.ts +80 -80
  179. package/src/media/device-sensors.ts +158 -158
  180. package/src/media/geolocation.ts +119 -119
  181. package/src/media/index.ts +76 -76
  182. package/src/media/media-query.ts +92 -92
  183. package/src/media/network.ts +115 -115
  184. package/src/media/types.ts +177 -177
  185. package/src/media/viewport.ts +84 -84
  186. package/src/motion/index.ts +57 -57
  187. package/src/motion/morph.ts +151 -151
  188. package/src/motion/parallax.ts +120 -120
  189. package/src/motion/reduced-motion.ts +66 -66
  190. package/src/motion/types.ts +271 -271
  191. package/src/motion/typewriter.ts +164 -164
  192. package/src/plugin/index.ts +37 -37
  193. package/src/plugin/registry.ts +284 -269
  194. package/src/plugin/types.ts +137 -137
  195. package/src/reactive/async-data.ts +250 -29
  196. package/src/reactive/computed.ts +144 -130
  197. package/src/reactive/effect.ts +29 -6
  198. package/src/reactive/http.ts +790 -0
  199. package/src/reactive/index.ts +60 -0
  200. package/src/reactive/pagination.ts +317 -0
  201. package/src/reactive/polling.ts +179 -0
  202. package/src/reactive/readonly.ts +52 -8
  203. package/src/reactive/rest.ts +859 -0
  204. package/src/reactive/scope.ts +276 -0
  205. package/src/reactive/signal.ts +61 -1
  206. package/src/reactive/to-value.ts +71 -0
  207. package/src/reactive/websocket.ts +849 -0
  208. package/src/router/bq-link.ts +279 -279
  209. package/src/router/constraints.ts +204 -201
  210. package/src/router/index.ts +49 -49
  211. package/src/router/match.ts +312 -312
  212. package/src/router/path-pattern.ts +52 -52
  213. package/src/router/query.ts +38 -38
  214. package/src/router/router.ts +421 -402
  215. package/src/router/state.ts +51 -3
  216. package/src/router/types.ts +139 -139
  217. package/src/router/use-route.ts +68 -68
  218. package/src/router/utils.ts +157 -157
  219. package/src/security/index.ts +12 -12
  220. package/src/ssr/hydrate.ts +84 -82
  221. package/src/ssr/index.ts +70 -70
  222. package/src/ssr/render.ts +508 -508
  223. package/src/ssr/serialize.ts +296 -296
  224. package/src/ssr/types.ts +81 -81
  225. package/src/store/create-store.ts +467 -467
  226. package/src/store/index.ts +27 -27
  227. package/src/store/persisted.ts +245 -249
  228. package/src/store/types.ts +247 -247
  229. package/src/store/utils.ts +135 -135
  230. package/src/storybook/index.ts +480 -480
  231. package/src/testing/index.ts +42 -42
  232. package/src/testing/testing.ts +593 -593
  233. package/src/testing/types.ts +170 -170
  234. package/src/view/custom-directives.ts +28 -30
  235. package/src/view/evaluate.ts +292 -292
  236. package/src/view/process.ts +108 -108
  237. package/dist/a11y-C5QOVvRn.js.map +0 -1
  238. package/dist/component-CuuTijA6.js.map +0 -1
  239. package/dist/constraints-3lV9yyBw.js.map +0 -1
  240. package/dist/core-Cjl7GUu8.js.map +0 -1
  241. package/dist/core-DnlyjbF2.js +0 -112
  242. package/dist/core-DnlyjbF2.js.map +0 -1
  243. package/dist/custom-directives-7wAShnnd.js.map +0 -1
  244. package/dist/devtools-D2fQLhDN.js.map +0 -1
  245. package/dist/dnd-B8EgyzaI.js.map +0 -1
  246. package/dist/env-NeVmr4Gf.js.map +0 -1
  247. package/dist/forms-C3yovgH9.js +0 -141
  248. package/dist/forms-C3yovgH9.js.map +0 -1
  249. package/dist/i18n-BnnhTFOS.js.map +0 -1
  250. package/dist/media-Di2Ta22s.js.map +0 -1
  251. package/dist/motion-qPj_TYGv.js.map +0 -1
  252. package/dist/mount-SM07RUa6.js.map +0 -1
  253. package/dist/plugin-cPoOHFLY.js.map +0 -1
  254. package/dist/reactive-Cfv0RK6x.js +0 -233
  255. package/dist/reactive-Cfv0RK6x.js.map +0 -1
  256. package/dist/router-BrthaP_z.js +0 -473
  257. package/dist/router-BrthaP_z.js.map +0 -1
  258. package/dist/ssr-B2qd_WBB.js.map +0 -1
  259. package/dist/store-DWpyH6p5.js.map +0 -1
  260. package/dist/testing-CsqjNUyy.js.map +0 -1
  261. package/dist/untrack-DJVQQ2WM.js +0 -33
  262. package/dist/untrack-DJVQQ2WM.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"full.umd.js","names":[],"sources":["../src/security/constants.ts","../src/security/sanitize-core.ts","../src/security/trusted-html.ts","../src/security/csp.ts","../src/security/trusted-types.ts","../src/security/sanitize.ts","../src/core/shared.ts","../src/core/dom.ts","../src/core/utils/object.ts","../src/core/element.ts","../src/core/collection.ts","../src/core/selector.ts","../src/core/utils/array.ts","../src/core/utils/function.ts","../src/core/utils/misc.ts","../src/core/utils/number.ts","../src/core/utils/string.ts","../src/core/utils/type-guards.ts","../src/core/utils/index.ts","../src/reactive/internals.ts","../src/reactive/batch.ts","../src/platform/config.ts","../src/reactive/computed.ts","../src/reactive/effect.ts","../src/reactive/core.ts","../src/reactive/untrack.ts","../src/reactive/async-data.ts","../src/reactive/linked.ts","../src/reactive/persisted.ts","../src/reactive/readonly.ts","../src/reactive/type-guards.ts","../src/reactive/watch.ts","../src/component/props.ts","../src/core/env.ts","../src/component/scope.ts","../src/component/component.ts","../src/component/html.ts","../src/component/library.ts","../src/motion/reduced-motion.ts","../src/motion/animate.ts","../src/motion/easing.ts","../src/motion/flip.ts","../src/motion/keyframes.ts","../src/motion/morph.ts","../src/motion/parallax.ts","../src/motion/scroll.ts","../src/motion/spring.ts","../src/motion/stagger.ts","../src/motion/timeline.ts","../src/motion/transition.ts","../src/motion/typewriter.ts","../src/platform/buckets.ts","../src/platform/cache.ts","../src/platform/cookies.ts","../src/platform/notifications.ts","../src/platform/announcer.ts","../src/platform/meta.ts","../src/platform/storage.ts","../src/router/state.ts","../src/router/navigation.ts","../src/router/bq-link.ts","../src/router/links.ts","../src/router/query.ts","../src/router/constraints.ts","../src/router/path-pattern.ts","../src/router/match.ts","../src/router/utils.ts","../src/router/router.ts","../src/router/use-route.ts","../src/store/devtools.ts","../src/store/plugins.ts","../src/store/registry.ts","../src/store/utils.ts","../src/store/create-store.ts","../src/store/mapping.ts","../src/store/persisted.ts","../src/view/evaluate.ts","../src/view/directives/bind.ts","../src/view/directives/class.ts","../src/view/directives/for.ts","../src/view/directives/html.ts","../src/view/directives/if.ts","../src/view/directives/model.ts","../src/view/directives/on.ts","../src/view/directives/ref.ts","../src/view/directives/show.ts","../src/view/directives/style.ts","../src/view/directives/text.ts","../src/view/custom-directives.ts","../src/view/process.ts","../src/view/mount.ts","../src/forms/create-form.ts","../src/forms/validators.ts","../src/i18n/formatting.ts","../src/i18n/translate.ts","../src/i18n/i18n.ts","../src/a11y/announce.ts","../src/a11y/audit.ts","../src/a11y/media-preferences.ts","../src/a11y/roving-tab-index.ts","../src/a11y/skip-link.ts","../src/a11y/trap-focus.ts","../src/dnd/draggable.ts","../src/dnd/droppable.ts","../src/dnd/sortable.ts","../src/media/media-query.ts","../src/media/breakpoints.ts","../src/media/viewport.ts","../src/media/network.ts","../src/media/battery.ts","../src/media/geolocation.ts","../src/media/device-sensors.ts","../src/media/clipboard.ts","../src/plugin/registry.ts","../src/devtools/devtools.ts","../src/testing/testing.ts","../src/ssr/hydrate.ts","../src/ssr/serialize.ts","../src/ssr/render.ts"],"sourcesContent":["/**\n * Security constants and safe lists.\n *\n * @module bquery/security\n */\n\n/**\n * Trusted Types policy name.\n */\nexport const POLICY_NAME = 'bquery-sanitizer';\n\n/**\n * Default allowed HTML tags considered safe.\n */\nexport const DEFAULT_ALLOWED_TAGS = new Set([\n 'a',\n 'abbr',\n 'address',\n 'article',\n 'aside',\n 'b',\n 'bdi',\n 'bdo',\n 'blockquote',\n 'br',\n 'button',\n 'caption',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'data',\n 'dd',\n 'del',\n 'details',\n 'dfn',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hgroup',\n 'hr',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'mark',\n 'nav',\n 'ol',\n 'optgroup',\n 'option',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'small',\n 'source',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'u',\n 'ul',\n 'var',\n 'wbr',\n]);\n\n/**\n * Explicitly dangerous tags that should never be allowed.\n * These are checked even if somehow added to allowTags.\n */\nexport const DANGEROUS_TAGS = new Set([\n 'script',\n 'iframe',\n 'frame',\n 'frameset',\n 'object',\n 'embed',\n 'applet',\n 'link',\n 'meta',\n 'style',\n 'base',\n 'template',\n // 'slot' is intentionally excluded here so component shadow markup can opt in\n // via sanitizeHtml(..., { allowTags: ['slot'] }). It remains disallowed by default\n // for general HTML writes, because DEFAULT_ALLOWED_TAGS does not include it.\n 'math',\n 'svg',\n 'foreignobject',\n 'noscript',\n]);\n\n/**\n * Reserved IDs that could cause DOM clobbering attacks.\n * These are prevented to avoid overwriting global browser objects.\n */\nexport const RESERVED_IDS = new Set([\n // Global objects\n 'document',\n 'window',\n 'location',\n 'top',\n 'self',\n 'parent',\n 'frames',\n 'history',\n 'navigator',\n 'screen',\n // Dangerous functions\n 'alert',\n 'confirm',\n 'prompt',\n 'eval',\n 'function',\n // Document properties\n 'cookie',\n 'domain',\n 'referrer',\n 'body',\n 'head',\n 'forms',\n 'images',\n 'links',\n 'scripts',\n // DOM traversal properties\n 'children',\n 'parentnode',\n 'firstchild',\n 'lastchild',\n // Content manipulation\n 'innerhtml',\n 'outerhtml',\n 'textcontent',\n]);\n\n/**\n * Default allowed attributes considered safe.\n * Note: 'style' is excluded by default because inline CSS can be abused for:\n * - UI redressing attacks\n * - Data exfiltration via url() in CSS\n * - CSS injection vectors\n * If you need to allow inline styles, add 'style' to allowAttributes in your\n * sanitizeHtml options, but ensure you implement proper CSS value validation.\n */\nexport const DEFAULT_ALLOWED_ATTRIBUTES = new Set([\n 'alt',\n 'class',\n 'dir',\n 'height',\n 'hidden',\n 'href',\n 'id',\n 'lang',\n 'loading',\n 'name',\n 'rel',\n 'role',\n 'src',\n 'srcset',\n 'tabindex',\n 'target',\n 'title',\n 'type',\n 'width',\n 'aria-*',\n]);\n\n/**\n * Dangerous attribute prefixes to always remove.\n */\nexport const DANGEROUS_ATTR_PREFIXES = ['on', 'formaction', 'xlink:', 'xmlns:'];\n\n/**\n * Dangerous URL protocols to block.\n */\nexport const DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'file:'];\n","/**\n * Core HTML sanitization logic.\n *\n * @module bquery/security\n * @internal\n */\n\nimport {\n DANGEROUS_ATTR_PREFIXES,\n DANGEROUS_PROTOCOLS,\n DANGEROUS_TAGS,\n DEFAULT_ALLOWED_ATTRIBUTES,\n DEFAULT_ALLOWED_TAGS,\n RESERVED_IDS,\n} from './constants';\nimport type { SanitizeOptions } from './types';\n\n/**\n * Check if an attribute name is allowed.\n * @internal\n */\nconst isAllowedAttribute = (\n name: string,\n allowedSet: Set<string>,\n allowDataAttrs: boolean\n): boolean => {\n const lowerName = name.toLowerCase();\n\n // Check dangerous prefixes\n for (const prefix of DANGEROUS_ATTR_PREFIXES) {\n if (lowerName.startsWith(prefix)) return false;\n }\n\n // Check data attributes\n if (allowDataAttrs && lowerName.startsWith('data-')) return true;\n\n // Check aria attributes (allowed by default)\n if (lowerName.startsWith('aria-')) return true;\n\n // Check explicit allow list\n return allowedSet.has(lowerName);\n};\n\n/**\n * Check if an ID/name value could cause DOM clobbering.\n * @internal\n */\nconst isSafeIdOrName = (value: string): boolean => {\n const lowerValue = value.toLowerCase().trim();\n return !RESERVED_IDS.has(lowerValue);\n};\n\n/**\n * Normalize URL by removing control characters, whitespace, and Unicode tricks.\n * Enhanced to prevent various bypass techniques.\n * @internal\n */\nconst normalizeUrl = (value: string): string =>\n value\n // Remove null bytes and control characters\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\n // Remove zero-width characters that could hide malicious content\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\n // Remove escaped Unicode sequences\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\n // Remove whitespace\n .replace(/\\s+/g, '')\n // Normalize case\n .toLowerCase();\n\n/**\n * Check if a URL value is safe.\n * @internal\n */\nconst isSafeUrl = (value: string): boolean => {\n const normalized = normalizeUrl(value);\n for (const protocol of DANGEROUS_PROTOCOLS) {\n if (normalized.startsWith(protocol)) return false;\n }\n return true;\n};\n\n/**\n * Check if a srcset attribute value is safe.\n * srcset contains comma-separated entries of \"url [descriptor]\".\n * Each individual URL must be validated.\n * @internal\n */\nconst isSafeSrcset = (value: string): boolean => {\n const entries = value.split(',');\n for (const entry of entries) {\n const url = entry.trim().split(/\\s+/)[0];\n if (url && !isSafeUrl(url)) return false;\n }\n return true;\n};\n\n/**\n * Check if a URL is external (different origin).\n * @internal\n */\nconst isExternalUrl = (url: string): boolean => {\n try {\n // Normalize URL by trimming whitespace\n const trimmedUrl = url.trim();\n\n // Protocol-relative URLs (//example.com) are always external.\n // CRITICAL: This check must run before the relative-URL check below;\n // otherwise, a protocol-relative URL like \"//evil.com\" would be treated\n // as a non-http(s) relative URL and incorrectly classified as same-origin.\n // Handling them up front guarantees correct security classification.\n if (trimmedUrl.startsWith('//')) {\n return true;\n }\n\n // Normalize URL for case-insensitive protocol checks\n const lowerUrl = trimmedUrl.toLowerCase();\n\n // Check for non-http(s) protocols which are considered external/special\n // (mailto:, tel:, ftp:, etc.)\n const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmedUrl);\n if (hasProtocol && !lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\n // These are special protocols, not traditional \"external\" links\n // but we treat them as external for security consistency\n return true;\n }\n\n // Relative URLs are not external\n if (!lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\n return false;\n }\n\n // In non-browser environments (e.g., Node.js), treat all absolute URLs as external\n if (typeof window === 'undefined' || !window.location) {\n return true;\n }\n\n const urlObj = new URL(trimmedUrl, window.location.href);\n return urlObj.origin !== window.location.origin;\n } catch {\n // If URL parsing fails, treat as potentially external for safety\n return true;\n }\n};\n\n/**\n * Parse an HTML string into a Document using DOMParser.\n * This helper is intentionally separated to make the control-flow around HTML parsing\n * explicit for static analysis tools. It should ONLY be called when the input is\n * known to contain HTML syntax (angle brackets).\n *\n * DOMParser creates an inert document where scripts don't execute, making it safe\n * for parsing untrusted HTML that will subsequently be sanitized.\n *\n * @param htmlContent - A string that is known to contain HTML markup (has < or >)\n * @returns The parsed Document\n * @internal\n */\nconst parseHtmlDocument = (htmlContent: string): Document => {\n const parser = new DOMParser();\n // Parse as a full HTML document in an inert context; scripts won't execute\n return parser.parseFromString(htmlContent, 'text/html');\n};\n\n/**\n * Safely parse HTML string into a DocumentFragment using DOMParser.\n * DOMParser is preferred over innerHTML for security as it creates an inert document\n * where scripts don't execute and provides better static analysis recognition.\n *\n * This function includes input normalization to satisfy static analysis tools:\n * - Coerces input to string and trims whitespace\n * - For plain text (no HTML tags), creates a Text node directly without parsing\n * - Only invokes DOMParser for actual HTML-like content via parseHtmlDocument\n *\n * The separation between plain text handling and HTML parsing is intentional:\n * DOM text that contains no HTML syntax is never fed into an HTML parser,\n * preventing \"DOM text reinterpreted as HTML\" issues.\n *\n * @internal\n */\nconst parseHtmlSafely = (html: string): DocumentFragment => {\n // Step 1: Normalize input - coerce to string and trim\n // This defensive check handles edge cases even though TypeScript says it's a string\n const normalizedHtml = (typeof html === 'string' ? html : String(html ?? '')).trim();\n\n // Step 2: Create the fragment that will hold our result\n const fragment = document.createDocumentFragment();\n\n // Step 3: Early return for empty input\n if (normalizedHtml.length === 0) {\n return fragment;\n }\n\n // Step 4: If input contains no angle brackets, it's plain text - no HTML parsing needed.\n // Plain text is handled as a Text node, never passed to an HTML parser.\n // This explicitly prevents \"DOM text reinterpreted as HTML\" for purely textual inputs.\n const containsHtmlSyntax = normalizedHtml.includes('<') || normalizedHtml.includes('>');\n if (!containsHtmlSyntax) {\n fragment.appendChild(document.createTextNode(normalizedHtml));\n return fragment;\n }\n\n // Step 5: Input contains HTML syntax - parse it via the dedicated HTML parsing helper.\n // This separation makes the data-flow explicit: only strings with HTML syntax\n // are passed to DOMParser, satisfying static analysis requirements.\n const doc = parseHtmlDocument(normalizedHtml);\n\n // Move all children from the document body into the fragment.\n // This avoids interpolating untrusted HTML into an outer wrapper string.\n const body = doc.body;\n\n if (!body) {\n return fragment;\n }\n\n while (body.firstChild) {\n fragment.appendChild(body.firstChild);\n }\n\n return fragment;\n};\n\n/**\n * Core sanitization logic (without Trusted Types wrapper).\n * @internal\n */\nexport const sanitizeHtmlCore = (html: string, options: SanitizeOptions = {}): string => {\n const {\n allowTags = [],\n allowAttributes = [],\n allowDataAttributes = true,\n stripAllTags = false,\n } = options;\n\n // Build combined allow sets (excluding dangerous tags even if specified)\n const allowedTags = new Set(\n [...DEFAULT_ALLOWED_TAGS, ...allowTags.map((t) => t.toLowerCase())].filter(\n (tag) => !DANGEROUS_TAGS.has(tag)\n )\n );\n const allowedAttrs = new Set([\n ...DEFAULT_ALLOWED_ATTRIBUTES,\n ...allowAttributes.map((a) => a.toLowerCase()),\n ]);\n\n // Use DOMParser for safe HTML parsing (inert context, no script execution)\n const fragment = parseHtmlSafely(html);\n\n if (stripAllTags) {\n return fragment.textContent ?? '';\n }\n\n // Walk the DOM tree\n const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_ELEMENT);\n\n const toRemove: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n const tagName = el.tagName.toLowerCase();\n\n // Remove explicitly dangerous tags even if in allow list\n if (DANGEROUS_TAGS.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // Remove disallowed tags entirely\n if (!allowedTags.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // Process attributes\n const attrsToRemove: string[] = [];\n for (const attr of Array.from(el.attributes)) {\n const attrName = attr.name.toLowerCase();\n\n // Check if attribute is allowed\n if (!isAllowedAttribute(attrName, allowedAttrs, allowDataAttributes)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Check for DOM clobbering on id and name attributes\n if ((attrName === 'id' || attrName === 'name') && !isSafeIdOrName(attr.value)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Validate URL attributes\n if (\n (attrName === 'href' || attrName === 'src' || attrName === 'action') &&\n !isSafeUrl(attr.value)\n ) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Validate srcset URLs individually\n if (attrName === 'srcset' && !isSafeSrcset(attr.value)) {\n attrsToRemove.push(attr.name);\n }\n }\n\n // Remove disallowed attributes\n for (const attrName of attrsToRemove) {\n el.removeAttribute(attrName);\n }\n\n // Add rel=\"noopener noreferrer\" to external links for security\n if (tagName === 'a') {\n const href = el.getAttribute('href');\n const target = el.getAttribute('target');\n const hasTargetBlank = target?.toLowerCase() === '_blank';\n const isExternal = href && isExternalUrl(href);\n\n // Add security attributes to links opening in new window or external links\n if (hasTargetBlank || isExternal) {\n const existingRel = el.getAttribute('rel');\n const relValues = new Set(existingRel ? existingRel.split(/\\s+/).filter(Boolean) : []);\n\n // Add noopener and noreferrer\n relValues.add('noopener');\n relValues.add('noreferrer');\n\n el.setAttribute('rel', Array.from(relValues).join(' '));\n }\n }\n }\n\n // Remove disallowed elements\n for (const el of toRemove) {\n el.remove();\n }\n\n // Serialize the sanitized fragment to HTML string.\n // We use a temporary container to get the innerHTML of the fragment.\n const serializeFragment = (frag: DocumentFragment): string => {\n const container = document.createElement('div');\n container.appendChild(frag.cloneNode(true));\n return container.innerHTML;\n };\n\n // Double-parse to prevent mutation XSS (mXSS).\n // Browsers may normalize HTML during serialization in ways that could create\n // new dangerous content when re-parsed. By re-parsing the sanitized output\n // and verifying stability, we ensure the final HTML is safe.\n const firstPass = serializeFragment(fragment);\n\n // Re-parse through DOMParser for mXSS detection.\n // Using DOMParser instead of innerHTML for security.\n const verifyFragment = parseHtmlSafely(firstPass);\n const secondPass = serializeFragment(verifyFragment);\n\n // Verify stability: if content mutates between parses, it indicates mXSS attempt\n if (firstPass !== secondPass) {\n // Content mutated during re-parse - potential mXSS detected.\n // Return safely escaped text content as fallback.\n return fragment.textContent ?? '';\n }\n\n return secondPass;\n};\n","declare const sanitizedHtmlBrand: unique symbol;\nconst trustedHtmlBrand: unique symbol = Symbol('bquery.trusted-html.brand');\nconst TRUSTED_HTML_VALUE = Symbol('bquery.trusted-html');\n\n/**\n * Branded HTML string produced by bQuery's sanitization or escaping template helpers.\n *\n * Values returned from {@link sanitizeHtml} carry sanitized markup. Values returned from\n * {@link safeHtml} preserve the template's static markup while escaping normal interpolations\n * and splicing {@link trusted} fragments verbatim. This brand is not intended for arbitrary\n * strings or manual concatenation outside those helpers.\n */\nexport type SanitizedHtml = string & { readonly [sanitizedHtmlBrand]: true };\n\n/**\n * Marker object that safeHtml can splice into templates without escaping again.\n */\nexport type TrustedHtml = { readonly [trustedHtmlBrand]: true; toString(): string };\n\ntype TrustedHtmlValue = TrustedHtml & { readonly [TRUSTED_HTML_VALUE]: string };\n\n/**\n * Apply the internal {@link SanitizedHtml} brand to helper output.\n *\n * @internal\n */\nexport const toSanitizedHtml = (html: string): SanitizedHtml => html as SanitizedHtml;\n\n/**\n * Mark a sanitized HTML string for verbatim splicing into safeHtml templates.\n *\n * @param html - HTML previously produced by sanitizeHtml, safeHtml, or another trusted bQuery helper\n * @returns Trusted HTML marker object for safeHtml interpolations\n *\n * @example\n * ```ts\n * const badge = trusted(sanitizeHtml('<strong onclick=\"alert(1)\">New</strong>'));\n * const markup = safeHtml`<span>${badge}</span>`;\n * ```\n */\nexport const trusted = (html: SanitizedHtml): TrustedHtml => {\n const value = String(html);\n return Object.freeze({\n [trustedHtmlBrand]: true as const,\n [TRUSTED_HTML_VALUE]: value,\n toString: () => value,\n });\n};\n\n/**\n * Check whether a value is a trusted HTML marker created by trusted().\n *\n * @internal\n */\nexport const isTrustedHtml = (value: unknown): value is TrustedHtml => {\n return (\n typeof value === 'object' &&\n value !== null &&\n trustedHtmlBrand in value &&\n TRUSTED_HTML_VALUE in value\n );\n};\n\n/**\n * Unwrap the raw HTML string stored inside a trusted HTML marker.\n *\n * @internal\n */\nexport const unwrapTrustedHtml = (value: TrustedHtml): string => {\n return (value as TrustedHtmlValue)[TRUSTED_HTML_VALUE];\n};\n","/**\n * Content Security Policy helpers.\n *\n * @module bquery/security\n */\n\n/** Maximum allowed nonce length to prevent memory issues */\nconst MAX_NONCE_LENGTH = 1024;\n\n/** Chunk size for building strings to avoid argument limit in String.fromCharCode */\nconst CHUNK_SIZE = 8192;\n\n/**\n * Generate a nonce for inline scripts/styles.\n * Use with Content-Security-Policy nonce directives.\n *\n * @param length - Nonce length in bytes (default: 16, max: 1024)\n * @returns Cryptographically random nonce string\n * @throws {Error} If crypto.getRandomValues or btoa are not available\n * @throws {RangeError} If length is invalid (negative, non-integer, or exceeds maximum)\n */\nexport const generateNonce = (length: number = 16): string => {\n // Validate length parameter\n if (!Number.isInteger(length) || length < 1) {\n throw new RangeError('generateNonce length must be a positive integer');\n }\n if (length > MAX_NONCE_LENGTH) {\n throw new RangeError(`generateNonce length must not exceed ${MAX_NONCE_LENGTH}`);\n }\n\n // Check for required globals in browser/crypto environments\n if (\n typeof globalThis.crypto === 'undefined' ||\n typeof globalThis.crypto.getRandomValues !== 'function'\n ) {\n throw new Error(\n 'generateNonce requires crypto.getRandomValues (not available in this environment)'\n );\n }\n if (typeof globalThis.btoa !== 'function') {\n throw new Error('generateNonce requires btoa (not available in this environment)');\n }\n\n const array = new Uint8Array(length);\n globalThis.crypto.getRandomValues(array);\n\n // Build string in chunks to avoid argument limit in String.fromCharCode\n let binaryString = '';\n for (let i = 0; i < array.length; i += CHUNK_SIZE) {\n const chunk = array.subarray(i, Math.min(i + CHUNK_SIZE, array.length));\n binaryString += String.fromCharCode(...chunk);\n }\n\n return globalThis.btoa(binaryString).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n};\n\n/**\n * Check if a CSP header is present with specific directive.\n * Useful for feature detection and fallback strategies.\n *\n * @param directive - The CSP directive to check (e.g., 'script-src')\n * @returns True if the directive appears to be enforced\n */\nexport const hasCSPDirective = (directive: string): boolean => {\n // Guard for non-DOM environments (SSR, tests, etc.)\n if (typeof document === 'undefined') {\n return false;\n }\n\n // Check meta tag\n const meta = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\n if (meta) {\n const content = meta.getAttribute('content') ?? '';\n return content.includes(directive);\n }\n return false;\n};\n","/**\n * Trusted Types helpers for CSP compatibility.\n *\n * @module bquery/security\n */\n\nimport { POLICY_NAME } from './constants';\nimport { sanitizeHtmlCore } from './sanitize-core';\nimport type { TrustedHTML, TrustedTypePolicy, TrustedTypesWindow } from './types';\n\n/** Cached Trusted Types policy */\nlet cachedPolicy: TrustedTypePolicy | null = null;\n\n/** Whether policy initialization has been attempted (to avoid retry spam) */\nlet policyInitAttempted = false;\n\n/**\n * Check if Trusted Types API is available.\n * @returns True if Trusted Types are supported\n */\nexport const isTrustedTypesSupported = (): boolean => {\n return (\n typeof window !== 'undefined' &&\n typeof (window as TrustedTypesWindow).trustedTypes !== 'undefined'\n );\n};\n\n/**\n * Get or create the bQuery Trusted Types policy.\n * @returns The Trusted Types policy or null if unsupported\n */\nexport const getTrustedTypesPolicy = (): TrustedTypePolicy | null => {\n if (cachedPolicy) return cachedPolicy;\n if (policyInitAttempted) return null;\n\n if (typeof window === 'undefined') return null;\n\n const win = window as TrustedTypesWindow;\n if (!win.trustedTypes) return null;\n\n policyInitAttempted = true;\n\n try {\n cachedPolicy = win.trustedTypes.createPolicy(POLICY_NAME, {\n createHTML: (input: string) => sanitizeHtmlCore(input),\n });\n return cachedPolicy;\n } catch (error) {\n // Policy may already exist or be blocked by CSP\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.warn(`bQuery: Could not create Trusted Types policy \"${POLICY_NAME}\": ${errorMessage}`);\n return null;\n }\n};\n\n/**\n * Create a Trusted HTML value for use with Trusted Types-enabled sites.\n * Falls back to regular string when Trusted Types are unavailable.\n *\n * @param html - The HTML string to wrap\n * @returns Trusted HTML value or sanitized string\n */\nexport const createTrustedHtml = (html: string): TrustedHTML | string => {\n const policy = getTrustedTypesPolicy();\n if (policy) {\n return policy.createHTML(html);\n }\n return sanitizeHtmlCore(html);\n};\n","/**\n * Security utilities for HTML sanitization.\n * All DOM writes are sanitized by default to prevent XSS attacks.\n *\n * @module bquery/security\n */\n\nimport { sanitizeHtmlCore } from './sanitize-core';\nimport { toSanitizedHtml } from './trusted-html';\nimport type { SanitizedHtml } from './trusted-html';\nimport type { SanitizeOptions } from './types';\nexport { generateNonce } from './csp';\nexport { isTrustedTypesSupported } from './trusted-types';\nexport { trusted } from './trusted-html';\nexport type { SanitizedHtml, TrustedHtml } from './trusted-html';\n\n/**\n * Sanitize HTML string, removing dangerous elements and attributes.\n * Uses Trusted Types when available for CSP compliance.\n *\n * @param html - The HTML string to sanitize\n * @param options - Sanitization options\n * @returns Sanitized HTML string\n *\n * @example\n * ```ts\n * const safe = sanitizeHtml('<div onclick=\"alert(1)\">Hello</div>');\n * // Returns: '<div>Hello</div>'\n * ```\n */\nexport const sanitizeHtml = (html: string, options: SanitizeOptions = {}): SanitizedHtml => {\n return toSanitizedHtml(sanitizeHtmlCore(html, options));\n};\n\n/**\n * Escape HTML entities to prevent XSS.\n * Use this for displaying user content as text.\n *\n * @param text - The text to escape\n * @returns Escaped HTML string\n *\n * @example\n * ```ts\n * escapeHtml('<script>alert(1)</script>');\n * // Returns: '&lt;script&gt;alert(1)&lt;/script&gt;'\n * ```\n */\nexport const escapeHtml = (text: string): string => {\n const escapeMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n '`': '&#x60;',\n };\n return text.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\n};\n\n/**\n * Strip all HTML tags and return plain text.\n *\n * @param html - The HTML string to strip\n * @returns Plain text content\n */\nexport const stripTags = (html: string): string => {\n return sanitizeHtmlCore(html, { stripAllTags: true });\n};\n\nexport type { SanitizeOptions } from './types';\n","/**\r\n * Shared helpers for element wrappers.\r\n */\r\nexport type ElementList = Element[];\r\n\r\nexport const toElementList = (input: Element | ElementList): ElementList =>\r\n Array.isArray(input) ? input : [input];\r\n\r\nexport const applyAll = (elements: ElementList, action: (el: Element) => void) => {\r\n for (const el of elements) {\r\n action(el);\r\n }\r\n};\r\n\r\n/** @internal */\r\nexport const isHTMLElement = (element: Element | null | undefined): element is HTMLElement => {\r\n if (!element) {\r\n return false;\r\n }\r\n\r\n const view = element.ownerDocument?.defaultView;\r\n const HTMLElementCtor = view?.HTMLElement ?? globalThis.HTMLElement;\r\n return typeof HTMLElementCtor === 'function' && element instanceof HTMLElementCtor;\r\n};\r\n\r\n/**\r\n * Gets an element's outer size, optionally including margins.\r\n *\r\n * @internal\r\n */\r\nexport const getOuterSize = (\r\n element: Element | null | undefined,\r\n dimension: 'width' | 'height',\r\n includeMargin: boolean\r\n): number => {\r\n if (!isHTMLElement(element)) {\r\n return 0;\r\n }\r\n\r\n const size = dimension === 'width' ? element.offsetWidth : element.offsetHeight;\r\n if (!includeMargin) {\r\n return size;\r\n }\r\n\r\n const view = element.ownerDocument?.defaultView;\r\n if (!view || typeof view.getComputedStyle !== 'function') {\r\n return size;\r\n }\r\n\r\n const computedStyle = view.getComputedStyle(element);\r\n const startMargin = Number.parseFloat(\r\n computedStyle.getPropertyValue(dimension === 'width' ? 'margin-left' : 'margin-top')\r\n );\r\n const endMargin = Number.parseFloat(\r\n computedStyle.getPropertyValue(dimension === 'width' ? 'margin-right' : 'margin-bottom')\r\n );\r\n\r\n const safeStartMargin = Number.isNaN(startMargin) ? 0 : startMargin;\r\n const safeEndMargin = Number.isNaN(endMargin) ? 0 : endMargin;\r\n\r\n return size + safeStartMargin + safeEndMargin;\r\n};\r\n","import { sanitizeHtml } from '../security/sanitize';\nimport { applyAll, toElementList } from './shared';\n\nexport type InsertableContent = string | Element | Element[];\n\nexport const sanitizeContent = (html: string): string => sanitizeHtml(html);\n\nexport const setHtml = (element: Element, html: string): void => {\n element.innerHTML = sanitizeHtml(html);\n};\n\nexport const createElementFromHtml = (html: string): Element => {\n const template = document.createElement('template');\n template.innerHTML = sanitizeHtml(html);\n return template.content.firstElementChild ?? document.createElement('div');\n};\n\nexport const insertContent = (\n target: Element,\n content: InsertableContent,\n position: InsertPosition\n): void => {\n if (typeof content === 'string') {\n target.insertAdjacentHTML(position, sanitizeHtml(content));\n return;\n }\n\n const elements = toElementList(content);\n\n // For positions that insert at the beginning (afterbegin, afterend), reverse\n // the array to maintain the caller's order. For beforeend/beforebegin, keep order.\n const needsReverse = position === 'afterbegin' || position === 'afterend';\n const orderedElements = needsReverse ? elements.slice().reverse() : elements;\n\n applyAll(orderedElements, (el) => {\n target.insertAdjacentElement(position, el);\n });\n};\n","/**\n * Object-focused utility helpers.\n *\n * @module bquery/core/utils/object\n */\n\n/**\n * Checks if a value is a plain object (not null, array, or class instance).\n *\n * @param value - The value to check\n * @returns True if the value is a plain object\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\n/**\n * Checks if a key could cause prototype pollution.\n * These keys are dangerous when used in object merging operations.\n *\n * @param key - The key to check\n * @returns True if the key is a prototype pollution vector\n *\n * @internal\n */\nexport function isPrototypePollutionKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype';\n}\n\n/**\n * Creates a deep clone using structuredClone if available, otherwise fallback to JSON.\n *\n * @template T - The type of value being cloned\n * @param value - The value to clone\n * @returns A deep copy of the value\n *\n * @remarks\n * When `structuredClone` is available (modern browsers, Node 17+, Bun), this function\n * provides full deep cloning including circular references, Date, Map, Set, ArrayBuffer, etc.\n *\n * **JSON fallback limitations** (older environments without `structuredClone`):\n * - **Throws** on circular references\n * - **Drops** functions, `undefined`, and Symbol properties\n * - **Transforms** Date → ISO string, Map/Set → empty object, BigInt → throws\n * - **Loses** prototype chains and non-enumerable properties\n *\n * For guaranteed safe cloning of arbitrary data, ensure your environment supports\n * `structuredClone` or pre-validate your data structure.\n *\n * @example\n * ```ts\n * const original = { nested: { value: 1 } };\n * const copy = clone(original);\n * copy.nested.value = 2;\n * console.log(original.nested.value); // 1\n * ```\n */\nexport function clone<T>(value: T): T {\n if (typeof structuredClone === 'function') {\n return structuredClone(value);\n }\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\n/**\n * Deep-merges plain objects into a new object.\n * Later sources override earlier ones for primitive values.\n * Objects are recursively merged.\n *\n * @param sources - Objects to merge\n * @returns A new object with all sources merged as an intersection type\n *\n * @remarks\n * This function uses overloads to provide accurate intersection types for up to 5 sources.\n * For more than 5 sources, the return type falls back to `Record<string, unknown>`.\n *\n * Note that deep merging creates a shallow intersection at the type level. Nested objects\n * are merged at runtime, but TypeScript sees them as intersected types which may not\n * perfectly represent the merged structure for deeply nested conflicting types.\n *\n * @example\n * ```ts\n * const result = merge(\n * { a: 1, nested: { x: 1 } },\n * { b: 2, nested: { y: 2 } }\n * );\n * // Result: { a: 1, b: 2, nested: { x: 1, y: 2 } }\n * // Type: { a: number; nested: { x: number } } & { b: number; nested: { y: number } }\n * ```\n *\n * @security This method is protected against prototype pollution attacks.\n * Keys like `__proto__`, `constructor`, and `prototype` are ignored.\n */\nexport function merge<T1 extends Record<string, unknown>>(source1: T1): T1;\nexport function merge<T1 extends Record<string, unknown>, T2 extends Record<string, unknown>>(\n source1: T1,\n source2: T2\n): T1 & T2;\nexport function merge<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n T3 extends Record<string, unknown>,\n>(source1: T1, source2: T2, source3: T3): T1 & T2 & T3;\nexport function merge<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n T3 extends Record<string, unknown>,\n T4 extends Record<string, unknown>,\n>(source1: T1, source2: T2, source3: T3, source4: T4): T1 & T2 & T3 & T4;\nexport function merge<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n T3 extends Record<string, unknown>,\n T4 extends Record<string, unknown>,\n T5 extends Record<string, unknown>,\n>(source1: T1, source2: T2, source3: T3, source4: T4, source5: T5): T1 & T2 & T3 & T4 & T5;\nexport function merge(...sources: Record<string, unknown>[]): Record<string, unknown>;\nexport function merge(...sources: Record<string, unknown>[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const source of sources) {\n for (const [key, value] of Object.entries(source)) {\n if (isPrototypePollutionKey(key)) continue;\n\n if (isPlainObject(value) && isPlainObject(result[key])) {\n result[key] = merge(\n result[key] as Record<string, unknown>,\n value as Record<string, unknown>\n );\n } else {\n result[key] = value;\n }\n }\n }\n return result;\n}\n\n/**\n * Picks specified keys from an object.\n *\n * @template T - The object type\n * @template K - The key type\n * @param obj - The source object\n * @param keys - Keys to pick\n * @returns A new object with only the specified keys\n *\n * @example\n * ```ts\n * const user = { name: 'John', age: 30, email: 'john@example.com' };\n * pick(user, ['name', 'email']); // { name: 'John', email: 'john@example.com' }\n * ```\n */\nexport function pick<T extends Record<string, unknown>, K extends keyof T>(\n obj: T,\n keys: K[]\n): Pick<T, K> {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in obj) {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\n/**\n * Omits specified keys from an object.\n *\n * @template T - The object type\n * @template K - The key type\n * @param obj - The source object\n * @param keys - Keys to omit\n * @returns A new object without the specified keys\n *\n * @example\n * ```ts\n * const user = { name: 'John', age: 30, password: 'secret' };\n * omit(user, ['password']); // { name: 'John', age: 30 }\n * ```\n */\nexport function omit<T extends Record<string, unknown>, K extends keyof T>(\n obj: T,\n keys: K[]\n): Omit<T, K> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, K>;\n}\n\n/**\n * Checks if an object has a given own property.\n *\n * @template T - The object type\n * @param obj - The object to check\n * @param key - The property key\n * @returns True if the property exists on the object\n *\n * @example\n * ```ts\n * hasOwn({ a: 1 }, 'a'); // true\n * ```\n */\nexport function hasOwn<T extends object>(obj: T, key: PropertyKey): key is keyof T {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n","import { createElementFromHtml, insertContent, setHtml } from './dom';\r\nimport { getOuterSize, isHTMLElement } from './shared';\r\nimport { isPrototypePollutionKey } from './utils/object';\r\n\r\n/**\r\n * Wrapper for a single DOM element.\r\n * Provides a chainable, jQuery-like API for DOM manipulation.\r\n *\r\n * This class encapsulates a DOM element and provides methods for:\r\n * - Class manipulation (addClass, removeClass, toggleClass)\r\n * - Attribute and property access (attr, prop, data)\r\n * - Content manipulation (text, html, append, prepend)\r\n * - Style manipulation (css)\r\n * - Event handling (on, off, once, trigger)\r\n * - DOM traversal (find, closest, parent, children, siblings)\r\n *\r\n * All mutating methods return `this` for method chaining.\r\n *\r\n * @example\r\n * ```ts\r\n * $('#button')\r\n * .addClass('active')\r\n * .css({ color: 'blue' })\r\n * .on('click', () => console.log('clicked'));\r\n * ```\r\n */\r\n/** Handler signature for delegated events */\r\ntype DelegatedHandler = (event: Event, target: Element) => void;\r\n\r\ntype SerializableFormControl = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\r\n\r\nconst isSerializableFormControl = (element: Element): element is SerializableFormControl => {\r\n const tagName = element.tagName.toLowerCase();\r\n return tagName === 'input' || tagName === 'textarea' || tagName === 'select';\r\n};\r\n\r\nconst collectFormEntries = (form: HTMLFormElement): Array<[string, string]> => {\r\n const entries: Array<[string, string]> = [];\r\n const elementCtor = form.ownerDocument.defaultView?.Element ?? Element;\r\n\r\n for (const control of Array.from(form.elements)) {\r\n if (!(control instanceof elementCtor) || !isSerializableFormControl(control)) {\r\n continue;\r\n }\r\n\r\n const name = control.name;\r\n if (!name || control.disabled || isPrototypePollutionKey(name)) {\r\n continue;\r\n }\r\n\r\n if (control.tagName.toLowerCase() === 'input') {\r\n const input = control as HTMLInputElement;\r\n const type = input.type.toLowerCase();\r\n\r\n if (type === 'checkbox' || type === 'radio') {\r\n if (input.checked) {\r\n entries.push([name, input.value]);\r\n }\r\n continue;\r\n }\r\n\r\n if (\r\n type === 'file' ||\r\n type === 'submit' ||\r\n type === 'button' ||\r\n type === 'reset' ||\r\n type === 'image'\r\n ) {\r\n continue;\r\n }\r\n\r\n entries.push([name, input.value]);\r\n continue;\r\n }\r\n\r\n if (control.tagName.toLowerCase() === 'select') {\r\n const select = control as HTMLSelectElement;\r\n\r\n if (select.multiple) {\r\n for (const option of Array.from(select.selectedOptions)) {\r\n entries.push([name, option.value]);\r\n }\r\n } else {\r\n entries.push([name, select.value]);\r\n }\r\n continue;\r\n }\r\n\r\n entries.push([name, (control as HTMLTextAreaElement).value]);\r\n }\r\n\r\n return entries;\r\n};\r\n\r\nconst getFormEntries = (form: HTMLFormElement): Array<[string, string]> => {\r\n if (typeof FormData === 'function') {\r\n try {\r\n const entries: Array<[string, string]> = [];\r\n\r\n for (const [key, value] of new FormData(form).entries()) {\r\n if (isPrototypePollutionKey(key) || typeof value !== 'string') {\r\n continue;\r\n }\r\n entries.push([key, value]);\r\n }\r\n\r\n // Some environments expose FormData(form) but fail to populate entries for\r\n // successful controls. Fall back to manual collection only in that zero-entry case.\r\n return entries.length > 0 ? entries : collectFormEntries(form);\r\n } catch {\r\n // Fall back to manual collection when FormData is unavailable for this form\r\n // or the environment does not fully support constructing it.\r\n }\r\n }\r\n\r\n return collectFormEntries(form);\r\n};\r\n\r\nexport class BQueryElement {\r\n /**\r\n * Stores delegated event handlers for cleanup via undelegate().\r\n * Key format: `${event}:${selector}`\r\n * @internal\r\n */\r\n private readonly delegatedHandlers = new Map<string, Map<DelegatedHandler, EventListener>>();\r\n\r\n /**\r\n * Creates a new BQueryElement wrapper.\r\n * @param element - The DOM element to wrap\r\n */\r\n constructor(private readonly element: Element) {}\r\n\r\n /**\r\n * Exposes the raw DOM element when direct access is needed.\r\n * Use sparingly; prefer the wrapper methods for consistency.\r\n */\r\n get raw(): Element {\r\n return this.element;\r\n }\r\n\r\n /**\r\n * Exposes the underlying DOM element.\r\n * Provided for spec compatibility and read-only access.\r\n */\r\n get node(): Element {\r\n return this.element;\r\n }\r\n\r\n /** Add one or more classes. */\r\n addClass(...classNames: string[]): this {\r\n this.element.classList.add(...classNames);\r\n return this;\r\n }\r\n\r\n /** Remove one or more classes. */\r\n removeClass(...classNames: string[]): this {\r\n this.element.classList.remove(...classNames);\r\n return this;\r\n }\r\n\r\n /** Toggle a class by name. */\r\n toggleClass(className: string, force?: boolean): this {\r\n this.element.classList.toggle(className, force);\r\n return this;\r\n }\r\n\r\n /** Get or set an attribute. */\r\n attr(name: string, value?: string): string | this {\r\n if (value === undefined) {\r\n return this.element.getAttribute(name) ?? '';\r\n }\r\n this.element.setAttribute(name, value);\r\n return this;\r\n }\r\n\r\n /** Remove an attribute. */\r\n removeAttr(name: string): this {\r\n this.element.removeAttribute(name);\r\n return this;\r\n }\r\n\r\n /** Toggle an attribute on/off. */\r\n toggleAttr(name: string, force?: boolean): this {\r\n const hasAttr = this.element.hasAttribute(name);\r\n const shouldAdd = force ?? !hasAttr;\r\n if (shouldAdd) {\r\n this.element.setAttribute(name, '');\r\n } else {\r\n this.element.removeAttribute(name);\r\n }\r\n return this;\r\n }\r\n\r\n /** Get or set a property. */\r\n prop<T extends keyof Element>(name: T, value?: Element[T]): Element[T] | this {\r\n if (value === undefined) {\r\n return this.element[name];\r\n }\r\n this.element[name] = value;\r\n return this;\r\n }\r\n\r\n /** Read or write data attributes in camelCase. */\r\n data(name: string, value?: string): string | this {\r\n const key = name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\r\n if (value === undefined) {\r\n return this.element.getAttribute(`data-${key}`) ?? '';\r\n }\r\n this.element.setAttribute(`data-${key}`, value);\r\n return this;\r\n }\r\n\r\n /** Get or set text content. */\r\n text(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.element.textContent ?? '';\r\n }\r\n this.element.textContent = value;\r\n return this;\r\n }\r\n\r\n /** Set HTML content using a sanitized string. */\r\n /**\r\n * Sets sanitized HTML content on the element.\r\n * Uses the security module to sanitize input and prevent XSS attacks.\r\n *\r\n * @param value - The HTML string to set (will be sanitized)\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#content').html('<strong>Hello</strong>');\r\n * ```\r\n */\r\n html(value: string): this {\r\n setHtml(this.element, value);\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets HTML content without sanitization.\r\n * Use only when you trust the HTML source completely.\r\n *\r\n * @param value - The raw HTML string to set\r\n * @returns The instance for method chaining\r\n *\r\n * @warning This method bypasses XSS protection. Use with caution.\r\n */\r\n htmlUnsafe(value: string): this {\r\n this.element.innerHTML = value;\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets or sets CSS styles on the element.\r\n *\r\n * @param property - A CSS property name or an object of property-value pairs\r\n * @param value - The value when setting a single property\r\n * @returns The computed style value when getting a single property, or the instance for method chaining when setting\r\n *\r\n * @example\r\n * ```ts\r\n * // Get a computed style value\r\n * const color = $('#box').css('color');\r\n *\r\n * // Set a single property\r\n * $('#box').css('color', 'red');\r\n *\r\n * // Set multiple properties\r\n * $('#box').css({ color: 'red', 'font-size': '16px' });\r\n * ```\r\n */\r\n css(property: string): string;\r\n css(property: string, value: string): this;\r\n css(property: Record<string, string>): this;\r\n css(property: string | Record<string, string>, value?: string): string | this {\r\n if (typeof property === 'string') {\r\n if (value !== undefined) {\r\n (this.element as HTMLElement).style.setProperty(property, value);\r\n return this;\r\n }\r\n const view = this.element.ownerDocument?.defaultView;\r\n if (!view || typeof view.getComputedStyle !== 'function') {\r\n return '';\r\n }\r\n return view.getComputedStyle(this.element).getPropertyValue(property);\r\n }\r\n\r\n for (const [key, val] of Object.entries(property)) {\r\n (this.element as HTMLElement).style.setProperty(key, val);\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Appends HTML or elements to the end of the element.\r\n *\r\n * @param content - HTML string or element(s) to append\r\n * @returns The instance for method chaining\r\n */\r\n append(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'beforeend');\r\n return this;\r\n }\r\n\r\n /**\r\n * Prepends HTML or elements to the beginning of the element.\r\n *\r\n * @param content - HTML string or element(s) to prepend\r\n * @returns The instance for method chaining\r\n */\r\n prepend(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'afterbegin');\r\n return this;\r\n }\r\n\r\n /**\r\n * Inserts content before this element.\r\n *\r\n * @param content - HTML string or element(s) to insert\r\n * @returns The instance for method chaining\r\n */\r\n before(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'beforebegin');\r\n return this;\r\n }\r\n\r\n /**\r\n * Inserts content after this element.\r\n *\r\n * @param content - HTML string or element(s) to insert\r\n * @returns The instance for method chaining\r\n */\r\n after(content: string | Element | Element[]): this {\r\n this.insertContent(content, 'afterend');\r\n return this;\r\n }\r\n\r\n /**\r\n * Wraps the element with the specified wrapper element or tag.\r\n *\r\n * @param wrapper - Tag name string or Element to wrap with\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#content').wrap('div'); // Wraps with <div>\r\n * $('#content').wrap(document.createElement('section'));\r\n * ```\r\n */\r\n wrap(wrapper: string | Element): this {\r\n const wrapperEl = typeof wrapper === 'string' ? document.createElement(wrapper) : wrapper;\r\n this.element.parentNode?.insertBefore(wrapperEl, this.element);\r\n wrapperEl.appendChild(this.element);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes the parent element, keeping this element in its place.\r\n * Essentially the opposite of wrap().\r\n *\r\n * **Important**: This method only moves the current element out of its parent\r\n * before removing the parent. Any sibling elements will be removed along with\r\n * the parent. For unwrapping multiple siblings, use a collection: `$$(siblings).unwrap()`.\r\n *\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Before: <div><span id=\"text\">Hello</span></div>\r\n * $('#text').unwrap();\r\n * // After: <span id=\"text\">Hello</span>\r\n * ```\r\n */\r\n unwrap(): this {\r\n const parent = this.element.parentElement;\r\n if (parent && parent.parentNode) {\r\n parent.parentNode.insertBefore(this.element, parent);\r\n parent.remove();\r\n }\r\n return this;\r\n }\r\n\r\n /**\r\n * Replaces this element with new content.\r\n *\r\n * @param content - HTML string (sanitized) or Element to replace with\r\n * @returns A new BQueryElement wrapping the replacement element\r\n *\r\n * @example\r\n * ```ts\r\n * const newEl = $('#old').replaceWith('<div id=\"new\">Replaced</div>');\r\n * ```\r\n */\r\n replaceWith(content: string | Element): BQueryElement {\r\n const newEl = typeof content === 'string' ? createElementFromHtml(content) : content;\r\n this.element.replaceWith(newEl);\r\n return new BQueryElement(newEl);\r\n }\r\n\r\n /**\r\n * Removes the element from the DOM while keeping the wrapped node available\r\n * for later reuse.\r\n *\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const item = $('#item').detach();\r\n * document.body.appendChild(item.raw);\r\n * ```\r\n */\r\n detach(): this {\r\n return this.remove();\r\n }\r\n\r\n /**\r\n * Gets the zero-based index of the element among its element siblings.\r\n *\r\n * @returns Index within the parent element, or -1 when detached\r\n *\r\n * @example\r\n * ```ts\r\n * const index = $('#item').index();\r\n * ```\r\n */\r\n index(): number {\r\n const parent = this.element.parentElement;\r\n if (!parent) {\r\n return -1;\r\n }\r\n return Array.from(parent.children).indexOf(this.element);\r\n }\r\n\r\n /**\r\n * Returns all child nodes, including text nodes and comments.\r\n *\r\n * @returns Array of child nodes\r\n *\r\n * @example\r\n * ```ts\r\n * const nodes = $('#content').contents();\r\n * ```\r\n */\r\n contents(): ChildNode[] {\r\n return Array.from(this.element.childNodes);\r\n }\r\n\r\n /**\r\n * Gets the nearest positioned ancestor used for offset calculations.\r\n *\r\n * @returns The offset parent element, or null when unavailable\r\n *\r\n * @example\r\n * ```ts\r\n * const parent = $('#item').offsetParent();\r\n * ```\r\n */\r\n offsetParent(): Element | null {\r\n return isHTMLElement(this.element) ? this.element.offsetParent : null;\r\n }\r\n\r\n /**\r\n * Gets the current position relative to the offset parent.\r\n *\r\n * @returns Position object with top and left coordinates\r\n *\r\n * @example\r\n * ```ts\r\n * const { top, left } = $('#item').position();\r\n * ```\r\n */\r\n position(): { top: number; left: number } {\r\n if (!isHTMLElement(this.element)) {\r\n return { top: 0, left: 0 };\r\n }\r\n\r\n const el = this.element;\r\n return {\r\n top: el.offsetTop,\r\n left: el.offsetLeft,\r\n };\r\n }\r\n\r\n /**\r\n * Gets the outer width of the element, optionally including margins.\r\n *\r\n * @param includeMargin - When true, include horizontal margins\r\n * @returns Outer width in pixels\r\n *\r\n * @example\r\n * ```ts\r\n * const width = $('#panel').outerWidth();\r\n * const widthWithMargin = $('#panel').outerWidth(true);\r\n * ```\r\n */\r\n outerWidth(includeMargin: boolean = false): number {\r\n return getOuterSize(this.element, 'width', includeMargin);\r\n }\r\n\r\n /**\r\n * Gets the outer height of the element, optionally including margins.\r\n *\r\n * @param includeMargin - When true, include vertical margins\r\n * @returns Outer height in pixels\r\n *\r\n * @example\r\n * ```ts\r\n * const height = $('#panel').outerHeight();\r\n * const heightWithMargin = $('#panel').outerHeight(true);\r\n * ```\r\n */\r\n outerHeight(includeMargin: boolean = false): number {\r\n return getOuterSize(this.element, 'height', includeMargin);\r\n }\r\n\r\n /**\r\n * Scrolls the element into view with configurable behavior.\r\n *\r\n * @param options - ScrollIntoView options or boolean for legacy behavior\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * $('#section').scrollTo(); // Smooth scroll\r\n * $('#section').scrollTo({ behavior: 'instant', block: 'start' });\r\n * ```\r\n */\r\n scrollTo(options: ScrollIntoViewOptions | boolean = { behavior: 'smooth' }): this {\r\n this.element.scrollIntoView(options);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes the element from the DOM.\r\n *\r\n * @returns The instance for method chaining (though element is now detached)\r\n */\r\n remove(): this {\r\n this.element.remove();\r\n return this;\r\n }\r\n\r\n /**\r\n * Clears all child nodes from the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n empty(): this {\r\n this.element.innerHTML = '';\r\n return this;\r\n }\r\n\r\n /**\r\n * Clones the element, optionally with all descendants.\r\n *\r\n * @param deep - If true, clone all descendants (default: true)\r\n * @returns A new BQueryElement wrapping the cloned element\r\n */\r\n clone(deep: boolean = true): BQueryElement {\r\n return new BQueryElement(this.element.cloneNode(deep) as Element);\r\n }\r\n\r\n /**\r\n * Finds all descendant elements matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns Array of matching elements\r\n */\r\n find(selector: string): Element[] {\r\n return Array.from(this.element.querySelectorAll(selector));\r\n }\r\n\r\n /**\r\n * Finds the first descendant element matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns The first matching element or null\r\n */\r\n findOne(selector: string): Element | null {\r\n return this.element.querySelector(selector);\r\n }\r\n\r\n /**\r\n * Finds the closest ancestor matching the selector.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns The matching ancestor or null\r\n */\r\n closest(selector: string): Element | null {\r\n return this.element.closest(selector);\r\n }\r\n\r\n /**\r\n * Gets the parent element.\r\n *\r\n * @returns The parent element or null\r\n */\r\n parent(): Element | null {\r\n return this.element.parentElement;\r\n }\r\n\r\n /**\r\n * Gets all child elements.\r\n *\r\n * @returns Array of child elements\r\n */\r\n children(): Element[] {\r\n return Array.from(this.element.children);\r\n }\r\n\r\n /**\r\n * Gets all sibling elements.\r\n *\r\n * @returns Array of sibling elements (excluding this element)\r\n */\r\n siblings(): Element[] {\r\n const parent = this.element.parentElement;\r\n if (!parent) return [];\r\n return Array.from(parent.children).filter((child) => child !== this.element);\r\n }\r\n\r\n /**\r\n * Gets the next sibling element.\r\n *\r\n * @returns The next sibling element or null\r\n */\r\n next(): Element | null {\r\n return this.element.nextElementSibling;\r\n }\r\n\r\n /**\r\n * Gets the previous sibling element.\r\n *\r\n * @returns The previous sibling element or null\r\n */\r\n prev(): Element | null {\r\n return this.element.previousElementSibling;\r\n }\r\n\r\n /**\r\n * Adds an event listener.\r\n *\r\n * @param event - Event type to listen for\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n */\r\n on(event: string, handler: EventListenerOrEventListenerObject): this {\r\n this.element.addEventListener(event, handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a one-time event listener that removes itself after firing.\r\n *\r\n * @param event - Event type to listen for\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n */\r\n once(event: string, handler: EventListener): this {\r\n this.element.addEventListener(event, handler, { once: true });\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an event listener.\r\n *\r\n * @param event - Event type\r\n * @param handler - The handler to remove\r\n * @returns The instance for method chaining\r\n */\r\n off(event: string, handler: EventListenerOrEventListenerObject): this {\r\n this.element.removeEventListener(event, handler);\r\n return this;\r\n }\r\n\r\n /**\r\n * Triggers a custom event on the element.\r\n *\r\n * @param event - Event type to trigger\r\n * @param detail - Optional detail data to include with the event\r\n * @returns The instance for method chaining\r\n */\r\n trigger(event: string, detail?: unknown): this {\r\n this.element.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a delegated event listener that only triggers for matching descendants.\r\n * More efficient than adding listeners to many elements individually.\r\n *\r\n * Use `undelegate()` to remove the listener later.\r\n *\r\n * @param event - Event type to listen for\r\n * @param selector - CSS selector to match against event targets\r\n * @param handler - Event handler function, receives the matched element as context\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // Instead of adding listeners to each button:\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $('#list').delegate('click', '.item', handler);\r\n *\r\n * // Later, remove the delegated listener:\r\n * $('#list').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n delegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n const wrapper: EventListener = (e: Event) => {\r\n const target = (e.target as Element).closest(selector);\r\n if (target && this.element.contains(target)) {\r\n handler(e, target);\r\n }\r\n };\r\n\r\n // Store the wrapper so it can be removed later\r\n if (!this.delegatedHandlers.has(key)) {\r\n this.delegatedHandlers.set(key, new Map());\r\n }\r\n this.delegatedHandlers.get(key)!.set(handler, wrapper);\r\n\r\n this.element.addEventListener(event, wrapper);\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes a delegated event listener previously added with `delegate()`.\r\n *\r\n * @param event - Event type that was registered\r\n * @param selector - CSS selector that was used\r\n * @param handler - The original handler function passed to delegate()\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $('#list').delegate('click', '.item', handler);\r\n *\r\n * // Remove the delegated listener:\r\n * $('#list').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n undelegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n const handlers = this.delegatedHandlers.get(key);\r\n\r\n if (handlers) {\r\n const wrapper = handlers.get(handler);\r\n if (wrapper) {\r\n this.element.removeEventListener(event, wrapper);\r\n handlers.delete(handler);\r\n\r\n // Clean up empty maps\r\n if (handlers.size === 0) {\r\n this.delegatedHandlers.delete(key);\r\n }\r\n }\r\n }\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Checks if the element matches a CSS selector.\r\n *\r\n * @param selector - CSS selector to match against\r\n * @returns True if the element matches the selector\r\n */\r\n matches(selector: string): boolean {\r\n return this.element.matches(selector);\r\n }\r\n\r\n /**\r\n * Alias for `matches()`. Checks if the element matches a CSS selector.\r\n *\r\n * @param selector - CSS selector to match against\r\n * @returns True if the element matches the selector\r\n *\r\n * @example\r\n * ```ts\r\n * if ($('#el').is('.active')) {\r\n * console.log('Element is active');\r\n * }\r\n * ```\r\n */\r\n is(selector: string): boolean {\r\n return this.matches(selector);\r\n }\r\n\r\n /**\r\n * Checks if the element has a specific class.\r\n *\r\n * @param className - Class name to check\r\n * @returns True if the element has the class\r\n */\r\n hasClass(className: string): boolean {\r\n return this.element.classList.contains(className);\r\n }\r\n\r\n /**\r\n * Shows the element by removing the hidden attribute and setting display.\r\n *\r\n * @param display - Optional display value (default: '')\r\n * @returns The instance for method chaining\r\n */\r\n show(display: string = ''): this {\r\n this.element.removeAttribute('hidden');\r\n (this.element as HTMLElement).style.display = display;\r\n return this;\r\n }\r\n\r\n /**\r\n * Hides the element by setting display to 'none'.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n hide(): this {\r\n (this.element as HTMLElement).style.display = 'none';\r\n return this;\r\n }\r\n\r\n /**\r\n * Toggles the visibility of the element.\r\n *\r\n * @param force - Optional force show (true) or hide (false)\r\n * @returns The instance for method chaining\r\n */\r\n toggle(force?: boolean): this {\r\n const isHidden = (this.element as HTMLElement).style.display === 'none';\r\n const shouldShow = force ?? isHidden;\r\n return shouldShow ? this.show() : this.hide();\r\n }\r\n\r\n /**\r\n * Focuses the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n focus(): this {\r\n (this.element as HTMLElement).focus();\r\n return this;\r\n }\r\n\r\n /**\r\n * Blurs (unfocuses) the element.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n blur(): this {\r\n (this.element as HTMLElement).blur();\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets or sets the value of form elements.\r\n *\r\n * @param newValue - Optional value to set\r\n * @returns The current value when getting, or the instance when setting\r\n */\r\n val(newValue?: string): string | this {\r\n const input = this.element as HTMLInputElement;\r\n if (newValue === undefined) {\r\n return input.value ?? '';\r\n }\r\n input.value = newValue;\r\n return this;\r\n }\r\n\r\n /**\r\n * Serializes form data to a plain object.\r\n * Only works on form elements; returns empty object for non-forms.\r\n *\r\n * For security hardening, the returned object uses a null prototype,\r\n * so inherited members like `hasOwnProperty` are not available directly.\r\n * Prefer `Object.keys()` or `Object.prototype.hasOwnProperty.call(...)`\r\n * when checking for fields on the serialized result.\r\n *\r\n * @returns Object with form field names as keys and values\r\n *\r\n * @example\r\n * ```ts\r\n * // For a form with <input name=\"email\" value=\"test@example.com\">\r\n * const data = $('#myForm').serialize();\r\n * // { email: 'test@example.com' }\r\n * Object.prototype.hasOwnProperty.call(data, 'email'); // true\r\n * ```\r\n */\r\n serialize(): Record<string, string | string[]> {\r\n const form = this.element as HTMLFormElement;\r\n if (form.tagName.toLowerCase() !== 'form') {\r\n return {};\r\n }\r\n\r\n const result = Object.create(null) as Record<string, string | string[]>;\r\n\r\n for (const [key, value] of getFormEntries(form)) {\r\n if (Object.prototype.hasOwnProperty.call(result, key)) {\r\n // Handle multiple values (e.g., checkboxes)\r\n const existing = result[key];\r\n if (Array.isArray(existing)) {\r\n existing.push(value);\r\n } else {\r\n result[key] = [existing, value];\r\n }\r\n } else {\r\n result[key] = value;\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Serializes form data to a URL-encoded query string.\r\n *\r\n * @returns URL-encoded string suitable for form submission\r\n *\r\n * @example\r\n * ```ts\r\n * const queryString = $('#myForm').serializeString();\r\n * // 'email=test%40example.com&name=John'\r\n * ```\r\n */\r\n serializeString(): string {\r\n const form = this.element as HTMLFormElement;\r\n if (form.tagName.toLowerCase() !== 'form') {\r\n return '';\r\n }\r\n\r\n const params = new URLSearchParams();\r\n\r\n for (const [key, value] of getFormEntries(form)) {\r\n params.append(key, value);\r\n }\r\n\r\n return params.toString();\r\n }\r\n\r\n /**\r\n * Gets the bounding client rectangle of the element.\r\n *\r\n * @returns The element's bounding rectangle\r\n */\r\n rect(): DOMRect {\r\n return this.element.getBoundingClientRect();\r\n }\r\n\r\n /**\r\n * Gets the offset dimensions (width, height, top, left).\r\n *\r\n * @returns Object with offset dimensions\r\n */\r\n offset(): { width: number; height: number; top: number; left: number } {\r\n const el = this.element as HTMLElement;\r\n return {\r\n width: el.offsetWidth,\r\n height: el.offsetHeight,\r\n top: el.offsetTop,\r\n left: el.offsetLeft,\r\n };\r\n }\r\n\r\n /**\r\n * Internal method to insert content at a specified position.\r\n * @internal\r\n */\r\n private insertContent(content: string | Element | Element[], position: InsertPosition) {\r\n insertContent(this.element, content, position);\r\n }\r\n}\r\n","import {\r\n createElementFromHtml,\r\n insertContent,\r\n sanitizeContent,\r\n type InsertableContent,\r\n} from './dom';\r\nimport { BQueryElement } from './element';\r\nimport { applyAll, getOuterSize, isHTMLElement, toElementList } from './shared';\r\n\r\n/** Handler signature for delegated events */\r\ntype DelegatedHandler = (event: Event, target: Element) => void;\r\n\r\n/**\r\n * Wrapper for multiple DOM elements.\r\n * Provides batch operations on a collection of elements with chainable API.\r\n *\r\n * This class enables jQuery-like operations across multiple elements:\r\n * - All mutating methods apply to every element in the collection\r\n * - Getter methods return data from the first element\r\n * - Supports iteration via forEach, map, filter, and reduce\r\n *\r\n * @example\r\n * ```ts\r\n * $$('.items')\r\n * .addClass('highlight')\r\n * .css({ opacity: '0.8' })\r\n * .on('click', () => console.log('clicked'));\r\n * ```\r\n */\r\nexport class BQueryCollection {\r\n /**\r\n * Stores delegated event handlers for cleanup via undelegate().\r\n * Outer map: element -> (key -> (handler -> wrapper))\r\n * Key format: `${event}:${selector}`\r\n * @internal\r\n */\r\n private readonly delegatedHandlers = new WeakMap<\r\n Element,\r\n Map<string, Map<DelegatedHandler, EventListener>>\r\n >();\r\n\r\n /**\r\n * Creates a new collection wrapper.\r\n * @param elements - Array of DOM elements to wrap\r\n */\r\n constructor(public readonly elements: Element[]) {}\r\n\r\n /**\r\n * Gets the number of elements in the collection.\r\n */\r\n get length(): number {\r\n return this.elements.length;\r\n }\r\n\r\n /**\r\n * Gets the first element in the collection, if any.\r\n * @internal\r\n */\r\n private first(): Element | undefined {\r\n return this.elements[0];\r\n }\r\n\r\n /**\r\n * Gets a single element as a BQueryElement wrapper.\r\n *\r\n * @param index - Zero-based index of the element\r\n * @returns BQueryElement wrapper or undefined if out of range\r\n */\r\n eq(index: number): BQueryElement | undefined {\r\n const el = this.elements[index];\r\n return el ? new BQueryElement(el) : undefined;\r\n }\r\n\r\n /**\r\n * Gets the first element as a BQueryElement wrapper.\r\n *\r\n * @returns BQueryElement wrapper or undefined if empty\r\n */\r\n firstEl(): BQueryElement | undefined {\r\n return this.eq(0);\r\n }\r\n\r\n /**\r\n * Gets the last element as a BQueryElement wrapper.\r\n *\r\n * @returns BQueryElement wrapper or undefined if empty\r\n */\r\n lastEl(): BQueryElement | undefined {\r\n return this.eq(this.elements.length - 1);\r\n }\r\n\r\n /**\r\n * Iterates over each element in the collection.\r\n *\r\n * @param callback - Function to call for each wrapped element\r\n * @returns The instance for method chaining\r\n */\r\n each(callback: (element: BQueryElement, index: number) => void): this {\r\n this.elements.forEach((element, index) => {\r\n callback(new BQueryElement(element), index);\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Maps each element to a new value.\r\n *\r\n * @param callback - Function to transform each element\r\n * @returns Array of transformed values\r\n */\r\n map<T>(callback: (element: Element, index: number) => T): T[] {\r\n return this.elements.map(callback);\r\n }\r\n\r\n /**\r\n * Filters elements based on a predicate.\r\n *\r\n * @param predicate - Function to test each element\r\n * @returns New BQueryCollection with matching elements\r\n */\r\n filter(predicate: (element: Element, index: number) => boolean): BQueryCollection {\r\n return new BQueryCollection(this.elements.filter(predicate));\r\n }\r\n\r\n /**\r\n * Reduces the collection to a single value.\r\n *\r\n * @param callback - Reducer function\r\n * @param initialValue - Initial accumulator value\r\n * @returns Accumulated result\r\n */\r\n reduce<T>(callback: (accumulator: T, element: Element, index: number) => T, initialValue: T): T {\r\n return this.elements.reduce(callback, initialValue);\r\n }\r\n\r\n /**\r\n * Converts the collection to an array of BQueryElement wrappers.\r\n *\r\n * @returns Array of BQueryElement instances\r\n */\r\n toArray(): BQueryElement[] {\r\n return this.elements.map((el) => new BQueryElement(el));\r\n }\r\n\r\n /** Add one or more classes to all elements. */\r\n addClass(...classNames: string[]): this {\r\n applyAll(this.elements, (el) => el.classList.add(...classNames));\r\n return this;\r\n }\r\n\r\n /** Remove one or more classes from all elements. */\r\n removeClass(...classNames: string[]): this {\r\n applyAll(this.elements, (el) => el.classList.remove(...classNames));\r\n return this;\r\n }\r\n\r\n /** Toggle a class on all elements. */\r\n toggleClass(className: string, force?: boolean): this {\r\n applyAll(this.elements, (el) => el.classList.toggle(className, force));\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets an attribute on all elements or gets from first.\r\n *\r\n * @param name - Attribute name\r\n * @param value - Value to set (optional)\r\n * @returns Attribute value when getting, instance when setting\r\n */\r\n attr(name: string, value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.getAttribute(name) ?? '';\r\n }\r\n applyAll(this.elements, (el) => el.setAttribute(name, value));\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an attribute from all elements.\r\n *\r\n * @param name - Attribute name to remove\r\n * @returns The instance for method chaining\r\n */\r\n removeAttr(name: string): this {\r\n applyAll(this.elements, (el) => el.removeAttribute(name));\r\n return this;\r\n }\r\n\r\n /** Toggle an attribute on all elements. */\r\n toggleAttr(name: string, force?: boolean): this {\r\n applyAll(this.elements, (el) => {\r\n const hasAttr = el.hasAttribute(name);\r\n const shouldAdd = force ?? !hasAttr;\r\n if (shouldAdd) {\r\n el.setAttribute(name, '');\r\n } else {\r\n el.removeAttribute(name);\r\n }\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets text content on all elements or gets from first.\r\n *\r\n * @param value - Text to set (optional)\r\n * @returns Text content when getting, instance when setting\r\n */\r\n text(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.textContent ?? '';\r\n }\r\n applyAll(this.elements, (el) => {\r\n el.textContent = value;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets sanitized HTML on all elements or gets from first.\r\n *\r\n * @param value - HTML to set (optional, will be sanitized)\r\n * @returns HTML content when getting, instance when setting\r\n */\r\n html(value?: string): string | this {\r\n if (value === undefined) {\r\n return this.first()?.innerHTML ?? '';\r\n }\r\n const sanitized = sanitizeContent(value);\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = sanitized;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets HTML on all elements without sanitization.\r\n *\r\n * @param value - Raw HTML to set\r\n * @returns The instance for method chaining\r\n * @warning Bypasses XSS protection\r\n */\r\n htmlUnsafe(value: string): this {\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = value;\r\n });\r\n return this;\r\n }\r\n\r\n /** Append content to all elements. */\r\n append(content: InsertableContent): this {\r\n this.insertAll(content, 'beforeend');\r\n return this;\r\n }\r\n\r\n /** Prepend content to all elements. */\r\n prepend(content: InsertableContent): this {\r\n this.insertAll(content, 'afterbegin');\r\n return this;\r\n }\r\n\r\n /** Insert content before all elements. */\r\n before(content: InsertableContent): this {\r\n this.insertAll(content, 'beforebegin');\r\n return this;\r\n }\r\n\r\n /** Insert content after all elements. */\r\n after(content: InsertableContent): this {\r\n this.insertAll(content, 'afterend');\r\n return this;\r\n }\r\n\r\n /**\r\n * Gets or sets CSS styles on all elements.\r\n * When getting, returns the computed style value from the first element.\r\n *\r\n * @param property - Property name or object of properties\r\n * @param value - Value when setting single property\r\n * @returns The computed style value when getting, instance when setting\r\n */\r\n css(property: string): string;\r\n css(property: string, value: string): this;\r\n css(property: Record<string, string>): this;\r\n css(property: string | Record<string, string>, value?: string): string | this {\r\n if (typeof property === 'string') {\r\n if (value !== undefined) {\r\n applyAll(this.elements, (el) => {\r\n (el as HTMLElement).style.setProperty(property, value);\r\n });\r\n return this;\r\n }\r\n const first = this.first();\r\n if (!first) {\r\n return '';\r\n }\r\n const view = first.ownerDocument?.defaultView;\r\n if (!view || typeof view.getComputedStyle !== 'function') {\r\n return '';\r\n }\r\n return view.getComputedStyle(first).getPropertyValue(property);\r\n }\r\n\r\n applyAll(this.elements, (el) => {\r\n for (const [key, val] of Object.entries(property)) {\r\n (el as HTMLElement).style.setProperty(key, val);\r\n }\r\n });\r\n return this;\r\n }\r\n\r\n /** Wrap each element with a wrapper element or tag. */\r\n wrap(wrapper: string | Element): this {\r\n this.elements.forEach((el, index) => {\r\n const wrapperEl =\r\n typeof wrapper === 'string'\r\n ? document.createElement(wrapper)\r\n : index === 0\r\n ? wrapper\r\n : (wrapper.cloneNode(true) as Element);\r\n el.parentNode?.insertBefore(wrapperEl, el);\r\n wrapperEl.appendChild(el);\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Remove the parent element of each element, keeping the elements in place.\r\n *\r\n * **Important**: This method unwraps ALL children of each parent element,\r\n * not just the elements in the collection. If you call `unwrap()` on a\r\n * collection containing only some children of a parent, all siblings will\r\n * also be unwrapped. This behavior is consistent with jQuery's `.unwrap()`.\r\n *\r\n * @returns The collection for chaining\r\n *\r\n * @example\r\n * ```ts\r\n * // HTML: <div><section><span>A</span><span>B</span></section></div>\r\n * const spans = $$('span');\r\n * spans.unwrap(); // Removes <section>, both spans move to <div>\r\n * // Result: <div><span>A</span><span>B</span></div>\r\n * ```\r\n */\r\n unwrap(): this {\r\n // Collect unique parent elements to avoid removing the same parent multiple times.\r\n const parents = new Set<Element>();\r\n for (const el of this.elements) {\r\n if (el.parentElement) {\r\n parents.add(el.parentElement);\r\n }\r\n }\r\n\r\n // Unwrap each parent once: move all children out, then remove the wrapper.\r\n parents.forEach((parent) => {\r\n const grandParent = parent.parentNode;\r\n if (!grandParent) return;\r\n\r\n while (parent.firstChild) {\r\n grandParent.insertBefore(parent.firstChild, parent);\r\n }\r\n\r\n parent.remove();\r\n });\r\n return this;\r\n }\r\n\r\n /** Replace each element with provided content. */\r\n replaceWith(content: string | Element): BQueryCollection {\r\n const replacements: Element[] = [];\r\n this.elements.forEach((el, index) => {\r\n const replacement =\r\n typeof content === 'string'\r\n ? createElementFromHtml(content)\r\n : index === 0\r\n ? content\r\n : (content.cloneNode(true) as Element);\r\n el.replaceWith(replacement);\r\n replacements.push(replacement);\r\n });\r\n return new BQueryCollection(replacements);\r\n }\r\n\r\n /**\r\n * Removes all elements from the DOM while keeping the wrapped nodes available\r\n * for later reuse.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n detach(): this {\r\n return this.remove();\r\n }\r\n\r\n /**\r\n * Gets the zero-based sibling index of the first element in the collection.\r\n *\r\n * @returns Index of the first element, or -1 when unavailable\r\n */\r\n index(): number {\r\n const first = this.first();\r\n if (!first?.parentElement) {\r\n return -1;\r\n }\r\n return Array.from(first.parentElement.children).indexOf(first);\r\n }\r\n\r\n /**\r\n * Returns the child nodes of the first element, including text nodes and comments.\r\n *\r\n * @returns Array of child nodes from the first element\r\n */\r\n contents(): ChildNode[] {\r\n return Array.from(this.first()?.childNodes ?? []);\r\n }\r\n\r\n /**\r\n * Gets the offset parent of the first element in the collection.\r\n *\r\n * @returns Offset parent element, or null when unavailable\r\n */\r\n offsetParent(): Element | null {\r\n const first = this.first();\r\n return isHTMLElement(first) ? first.offsetParent : null;\r\n }\r\n\r\n /**\r\n * Gets the position of the first element relative to its offset parent.\r\n *\r\n * @returns Position object with top and left coordinates\r\n */\r\n position(): { top: number; left: number } {\r\n const first = this.first();\r\n if (!isHTMLElement(first)) {\r\n return { top: 0, left: 0 };\r\n }\r\n\r\n return {\r\n top: first.offsetTop,\r\n left: first.offsetLeft,\r\n };\r\n }\r\n\r\n /**\r\n * Gets the outer width of the first element, optionally including margins.\r\n *\r\n * @param includeMargin - When true, include horizontal margins\r\n * @returns Outer width in pixels\r\n */\r\n outerWidth(includeMargin: boolean = false): number {\r\n return getOuterSize(this.first(), 'width', includeMargin);\r\n }\r\n\r\n /**\r\n * Gets the outer height of the first element, optionally including margins.\r\n *\r\n * @param includeMargin - When true, include vertical margins\r\n * @returns Outer height in pixels\r\n */\r\n outerHeight(includeMargin: boolean = false): number {\r\n return getOuterSize(this.first(), 'height', includeMargin);\r\n }\r\n\r\n /**\r\n * Shows all elements.\r\n *\r\n * @param display - Optional display value (default: '')\r\n * @returns The instance for method chaining\r\n */\r\n show(display: string = ''): this {\r\n applyAll(this.elements, (el) => {\r\n el.removeAttribute('hidden');\r\n (el as HTMLElement).style.display = display;\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Hides all elements.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n hide(): this {\r\n applyAll(this.elements, (el) => {\r\n (el as HTMLElement).style.display = 'none';\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds an event listener to all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - Event handler\r\n * @returns The instance for method chaining\r\n */\r\n on(event: string, handler: EventListenerOrEventListenerObject): this {\r\n applyAll(this.elements, (el) => el.addEventListener(event, handler));\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a one-time event listener to all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - Event handler\r\n * @returns The instance for method chaining\r\n */\r\n once(event: string, handler: EventListener): this {\r\n applyAll(this.elements, (el) => el.addEventListener(event, handler, { once: true }));\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes an event listener from all elements.\r\n *\r\n * @param event - Event type\r\n * @param handler - The handler to remove\r\n * @returns The instance for method chaining\r\n */\r\n off(event: string, handler: EventListenerOrEventListenerObject): this {\r\n applyAll(this.elements, (el) => el.removeEventListener(event, handler));\r\n return this;\r\n }\r\n\r\n /**\r\n * Triggers a custom event on all elements.\r\n *\r\n * @param event - Event type\r\n * @param detail - Optional event detail\r\n * @returns The instance for method chaining\r\n */\r\n trigger(event: string, detail?: unknown): this {\r\n applyAll(this.elements, (el) => {\r\n el.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\r\n });\r\n return this;\r\n }\r\n\r\n /**\r\n * Adds a delegated event listener to all elements.\r\n * Events are delegated to matching descendants.\r\n *\r\n * Use `undelegate()` to remove the listener later.\r\n *\r\n * @param event - Event type to listen for\r\n * @param selector - CSS selector to match against event targets\r\n * @param handler - Event handler function\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $$('.container').delegate('click', '.item', handler);\r\n *\r\n * // Later, remove the delegated listener:\r\n * $$('.container').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n delegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n\r\n applyAll(this.elements, (el) => {\r\n const wrapper: EventListener = (e: Event) => {\r\n const target = (e.target as Element).closest(selector);\r\n if (target && el.contains(target)) {\r\n handler(e, target);\r\n }\r\n };\r\n\r\n // Get or create the handler maps for this element\r\n if (!this.delegatedHandlers.has(el)) {\r\n this.delegatedHandlers.set(el, new Map());\r\n }\r\n const elementHandlers = this.delegatedHandlers.get(el)!;\r\n\r\n if (!elementHandlers.has(key)) {\r\n elementHandlers.set(key, new Map());\r\n }\r\n elementHandlers.get(key)!.set(handler, wrapper);\r\n\r\n el.addEventListener(event, wrapper);\r\n });\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Removes a delegated event listener previously added with `delegate()`.\r\n *\r\n * @param event - Event type that was registered\r\n * @param selector - CSS selector that was used\r\n * @param handler - The original handler function passed to delegate()\r\n * @returns The instance for method chaining\r\n *\r\n * @example\r\n * ```ts\r\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\r\n * $$('.container').delegate('click', '.item', handler);\r\n *\r\n * // Remove the delegated listener:\r\n * $$('.container').undelegate('click', '.item', handler);\r\n * ```\r\n */\r\n undelegate(\r\n event: string,\r\n selector: string,\r\n handler: (event: Event, target: Element) => void\r\n ): this {\r\n const key = `${event}:${selector}`;\r\n\r\n applyAll(this.elements, (el) => {\r\n const elementHandlers = this.delegatedHandlers.get(el);\r\n if (!elementHandlers) return;\r\n\r\n const handlers = elementHandlers.get(key);\r\n if (!handlers) return;\r\n\r\n const wrapper = handlers.get(handler);\r\n if (wrapper) {\r\n el.removeEventListener(event, wrapper);\r\n handlers.delete(handler);\r\n\r\n // Clean up empty maps\r\n if (handlers.size === 0) {\r\n elementHandlers.delete(key);\r\n }\r\n if (elementHandlers.size === 0) {\r\n this.delegatedHandlers.delete(el);\r\n }\r\n }\r\n });\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * Finds all descendant elements matching the selector across all elements\r\n * in the collection. Returns a new BQueryCollection with the results.\r\n *\r\n * @param selector - CSS selector to match\r\n * @returns A new BQueryCollection with all matching descendants\r\n *\r\n * @example\r\n * ```ts\r\n * $$('.container').find('.item').addClass('highlight');\r\n * ```\r\n */\r\n find(selector: string): BQueryCollection {\r\n const seen = new Set<Element>();\r\n const results: Element[] = [];\r\n for (const el of this.elements) {\r\n const found = el.querySelectorAll(selector);\r\n for (let i = 0; i < found.length; i++) {\r\n if (!seen.has(found[i])) {\r\n seen.add(found[i]);\r\n results.push(found[i]);\r\n }\r\n }\r\n }\r\n return new BQueryCollection(results);\r\n }\r\n\r\n /**\r\n * Removes all elements from the DOM.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n remove(): this {\r\n applyAll(this.elements, (el) => el.remove());\r\n return this;\r\n }\r\n\r\n /**\r\n * Clears all child nodes from all elements.\r\n *\r\n * @returns The instance for method chaining\r\n */\r\n empty(): this {\r\n applyAll(this.elements, (el) => {\r\n el.innerHTML = '';\r\n });\r\n return this;\r\n }\r\n\r\n /** @internal */\r\n private insertAll(content: InsertableContent, position: InsertPosition): void {\r\n if (typeof content === 'string') {\r\n // Sanitize once and reuse for all elements\r\n const sanitized = sanitizeContent(content);\r\n applyAll(this.elements, (el) => {\r\n el.insertAdjacentHTML(position, sanitized);\r\n });\r\n return;\r\n }\r\n\r\n const elements = toElementList(content);\r\n this.elements.forEach((el, index) => {\r\n const nodes =\r\n index === 0 ? elements : elements.map((node) => node.cloneNode(true) as Element);\r\n insertContent(el, nodes, position);\r\n });\r\n }\r\n}\r\n","import { BQueryCollection } from './collection';\nimport { BQueryElement } from './element';\n\n/**\n * Select a single element. Returns a wrapper for chainable operations.\n */\nexport const $ = (selector: string | Element): BQueryElement => {\n if (typeof selector !== 'string') {\n return new BQueryElement(selector);\n }\n const element = document.querySelector(selector);\n if (!element) {\n throw new Error(`bQuery: element not found for selector \"${selector}\"`);\n }\n return new BQueryElement(element);\n};\n\n/**\n * Select multiple elements. Returns a collection wrapper.\n */\nexport const $$ = (selector: string | Element[] | NodeListOf<Element>): BQueryCollection => {\n if (Array.isArray(selector)) {\n return new BQueryCollection(selector);\n }\n if (selector instanceof NodeList) {\n return new BQueryCollection(Array.from(selector));\n }\n return new BQueryCollection(Array.from(document.querySelectorAll(selector)));\n};\n","/**\n * Array-focused utility helpers.\n *\n * @module bquery/core/utils/array\n */\n\n/**\n * Ensures the input is always returned as an array.\n *\n * @template T - The item type\n * @param value - A single value, array, or nullish value\n * @returns An array (empty if nullish)\n *\n * @example\n * ```ts\n * ensureArray('a'); // ['a']\n * ensureArray(['a', 'b']); // ['a', 'b']\n * ensureArray(null); // []\n * ```\n */\nexport function ensureArray<T>(value: T | T[] | null | undefined): T[] {\n if (value == null) return [];\n return Array.isArray(value) ? value : [value];\n}\n\n/**\n * Removes duplicate entries from an array.\n *\n * @template T - The item type\n * @param items - The array to deduplicate\n * @returns A new array with unique items\n *\n * @example\n * ```ts\n * unique([1, 2, 2, 3]); // [1, 2, 3]\n * ```\n */\nexport function unique<T>(items: T[]): T[] {\n return Array.from(new Set(items));\n}\n\n/**\n * Splits an array into chunks of a given size.\n *\n * @template T - The item type\n * @param items - The array to chunk\n * @param size - The maximum size of each chunk\n * @returns An array of chunks\n *\n * @example\n * ```ts\n * chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]\n * ```\n */\nexport function chunk<T>(items: T[], size: number): T[][] {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < items.length; i += size) {\n result.push(items.slice(i, i + size));\n }\n return result;\n}\n\n/**\n * Removes falsy values from an array.\n *\n * @template T - The item type\n * @param items - The array to compact\n * @returns A new array without falsy values\n *\n * @example\n * ```ts\n * compact([0, 1, '', 'ok', null]); // [1, 'ok']\n * ```\n */\nexport function compact<T>(items: Array<T | null | undefined | false | 0 | ''>): T[] {\n return items.filter(Boolean) as T[];\n}\n\n/**\n * Flattens a single level of nested arrays.\n *\n * @template T - The item type\n * @param items - The array to flatten\n * @returns A new flattened array\n *\n * @example\n * ```ts\n * flatten([1, [2, 3], 4]); // [1, 2, 3, 4]\n * ```\n */\nexport function flatten<T>(items: Array<T | T[]>): T[] {\n const result: T[] = [];\n for (const item of items) {\n if (Array.isArray(item)) {\n result.push(...item);\n } else {\n result.push(item);\n }\n }\n return result;\n}\n","/**\n * Function-focused utility helpers.\n *\n * @module bquery/core/utils/function\n */\n\n/** A debounced function with a cancel method to clear the pending timeout. */\nexport interface DebouncedFn<TArgs extends unknown[]> {\n (...args: TArgs): void;\n /** Cancels the pending debounced invocation. */\n cancel(): void;\n}\n\n/** A throttled function with a cancel method to reset the throttle timer. */\nexport interface ThrottledFn<TArgs extends unknown[]> {\n (...args: TArgs): void;\n /** Resets the throttle timer, allowing the next call to execute immediately. */\n cancel(): void;\n}\n\n/**\n * Creates a debounced function that delays execution until after\n * the specified delay has elapsed since the last call.\n *\n * @template TArgs - The argument types of the function\n * @param fn - The function to debounce\n * @param delayMs - Delay in milliseconds\n * @returns A debounced version of the function with a `cancel()` method\n *\n * @example\n * ```ts\n * const search = debounce((query: string) => {\n * console.log('Searching:', query);\n * }, 300);\n *\n * search('h');\n * search('he');\n * search('hello'); // Only this call executes after 300ms\n *\n * search('cancel me');\n * search.cancel(); // Cancels the pending invocation\n * ```\n */\nexport function debounce<TArgs extends unknown[]>(\n fn: (...args: TArgs) => void,\n delayMs: number\n): DebouncedFn<TArgs> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const debounced: DebouncedFn<TArgs> = Object.assign(\n (...args: TArgs) => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n timeoutId = setTimeout(() => {\n timeoutId = undefined;\n fn(...args);\n }, delayMs);\n },\n {\n cancel: () => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n timeoutId = undefined;\n }\n },\n }\n );\n return debounced;\n}\n\n/**\n * Creates a throttled function that runs at most once per interval.\n *\n * @template TArgs - The argument types of the function\n * @param fn - The function to throttle\n * @param intervalMs - Minimum interval between calls in milliseconds\n * @returns A throttled version of the function with a `cancel()` method\n *\n * @example\n * ```ts\n * const handleScroll = throttle(() => {\n * console.log('Scroll position:', window.scrollY);\n * }, 100);\n *\n * window.addEventListener('scroll', handleScroll);\n *\n * handleScroll.cancel(); // Resets throttle, next call executes immediately\n * ```\n */\nexport function throttle<TArgs extends unknown[]>(\n fn: (...args: TArgs) => void,\n intervalMs: number\n): ThrottledFn<TArgs> {\n let lastRun = 0;\n const throttled: ThrottledFn<TArgs> = Object.assign(\n (...args: TArgs) => {\n const now = Date.now();\n if (now - lastRun >= intervalMs) {\n lastRun = now;\n fn(...args);\n }\n },\n {\n cancel: () => {\n lastRun = 0;\n },\n }\n );\n return throttled;\n}\n\n/**\n * Ensures a function only runs once. Subsequent calls return the first result.\n *\n * @template TArgs - The argument types of the function\n * @template TResult - The return type of the function\n * @param fn - The function to wrap\n * @returns A function that only runs once\n *\n * @example\n * ```ts\n * const init = once(() => ({ ready: true }));\n * init();\n * init(); // only runs once\n * ```\n */\nexport function once<TArgs extends unknown[], TResult>(\n fn: (...args: TArgs) => TResult\n): (...args: TArgs) => TResult {\n let hasRun = false;\n let result!: TResult;\n return (...args: TArgs) => {\n if (!hasRun) {\n result = fn(...args);\n hasRun = true;\n }\n return result;\n };\n}\n\n/**\n * A no-operation function.\n *\n * @example\n * ```ts\n * noop();\n * ```\n */\nexport function noop(): void {\n // Intentionally empty\n}\n","/**\n * Miscellaneous utility helpers.\n *\n * @module bquery/core/utils/misc\n */\n\n/**\n * Creates a stable unique ID for DOM usage.\n *\n * @param prefix - Optional prefix for the ID (default: 'bQuery')\n * @returns A unique identifier string\n *\n * @example\n * ```ts\n * const id = uid('modal'); // 'modal_x7k2m9p'\n * ```\n */\nexport function uid(prefix = 'bQuery'): string {\n return `${prefix}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\n/**\n * Delays execution for a specified number of milliseconds.\n *\n * @param ms - Milliseconds to delay\n * @returns A promise that resolves after the delay\n *\n * @example\n * ```ts\n * await sleep(1000); // Wait 1 second\n * console.log('Done!');\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Safely parses a JSON string, returning a default value on error.\n *\n * @template T - The expected type of the parsed value\n * @param json - The JSON string to parse\n * @param fallback - The default value if parsing fails\n * @returns The parsed value or the fallback\n *\n * @example\n * ```ts\n * parseJson('{\"name\":\"bQuery\"}', {}); // { name: 'bQuery' }\n * parseJson('invalid', {}); // {}\n * ```\n */\nexport function parseJson<T>(json: string, fallback: T): T {\n try {\n return JSON.parse(json) as T;\n } catch {\n return fallback;\n }\n}\n\n/**\n * Checks for emptiness across common value types.\n *\n * @param value - The value to check\n * @returns True if the value is empty (null, undefined, empty string, empty array, or empty object)\n *\n * @example\n * ```ts\n * isEmpty(''); // true\n * isEmpty([]); // true\n * isEmpty({}); // true\n * isEmpty(null); // true\n * isEmpty('hello'); // false\n * isEmpty([1, 2]); // false\n * ```\n */\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'string') return value.trim().length === 0;\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === 'object') return Object.keys(value as object).length === 0;\n return false;\n}\n","/**\n * Number-focused utility helpers.\n *\n * @module bquery/core/utils/number\n */\n\n/**\n * Generates a random integer between min and max (inclusive).\n *\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns A random integer in the range [min, max]\n *\n * @example\n * ```ts\n * const roll = randomInt(1, 6); // Random dice roll\n * ```\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n/**\n * Clamps a number between a minimum and maximum value.\n *\n * @param value - The value to clamp\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns The clamped value\n *\n * @example\n * ```ts\n * clamp(150, 0, 100); // 100\n * clamp(-10, 0, 100); // 0\n * clamp(50, 0, 100); // 50\n * ```\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Checks if a number is within a range.\n *\n * @param value - The value to check\n * @param min - Minimum value\n * @param max - Maximum value\n * @param inclusive - Whether the range is inclusive (default: true)\n * @returns True if the value is within the range\n *\n * @example\n * ```ts\n * inRange(5, 1, 10); // true\n * inRange(10, 1, 10, false); // false\n * ```\n */\nexport function inRange(value: number, min: number, max: number, inclusive = true): boolean {\n if (inclusive) return value >= min && value <= max;\n return value > min && value < max;\n}\n\n/**\n * Converts a value to a number with a fallback on NaN.\n *\n * @param value - The value to convert\n * @param fallback - The fallback value if conversion fails (default: 0)\n * @returns The parsed number or the fallback\n *\n * @example\n * ```ts\n * toNumber('42'); // 42\n * toNumber('nope', 10); // 10\n * ```\n */\nexport function toNumber(value: unknown, fallback = 0): number {\n const parsed = typeof value === 'number' ? value : Number(value);\n return Number.isNaN(parsed) ? fallback : parsed;\n}\n","/**\n * String-focused utility helpers.\n *\n * @module bquery/core/utils/string\n */\n\n/**\n * Capitalizes the first letter of a string.\n *\n * @param str - The string to capitalize\n * @returns The capitalized string\n *\n * @example\n * ```ts\n * capitalize('hello'); // 'Hello'\n * ```\n */\nexport function capitalize(str: string): string {\n if (!str) return str;\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Converts a string to kebab-case.\n *\n * @param str - The string to convert\n * @returns The kebab-cased string\n *\n * @example\n * ```ts\n * toKebabCase('myVariableName'); // 'my-variable-name'\n * ```\n */\nexport function toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n}\n\n/**\n * Converts a string to camelCase.\n *\n * @param str - The string to convert\n * @returns The camelCased string\n *\n * @example\n * ```ts\n * toCamelCase('my-variable-name'); // 'myVariableName'\n * ```\n */\nexport function toCamelCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))\n .replace(/^[A-Z]/, (char) => char.toLowerCase());\n}\n\n/**\n * Truncates a string to a maximum length.\n *\n * @param str - The string to truncate\n * @param maxLength - The maximum length\n * @param suffix - The suffix to append when truncating (default: '…')\n * @returns The truncated string\n *\n * @example\n * ```ts\n * truncate('Hello world', 8); // 'Hello w…'\n * ```\n */\nexport function truncate(str: string, maxLength: number, suffix = '…'): string {\n if (maxLength <= 0) return '';\n if (str.length <= maxLength) return str;\n const sliceLength = Math.max(0, maxLength - suffix.length);\n return `${str.slice(0, sliceLength)}${suffix}`;\n}\n\n/**\n * Converts a string to a URL-friendly slug.\n *\n * @param str - The string to slugify\n * @returns The slugified string\n *\n * @example\n * ```ts\n * slugify('Hello, World!'); // 'hello-world'\n * ```\n */\nexport function slugify(str: string): string {\n return str\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^\\w\\s-]/g, '')\n .trim()\n .replace(/[\\s_-]+/g, '-')\n .toLowerCase();\n}\n\n/**\n * Escapes a string for safe usage inside a RegExp.\n *\n * @param str - The string to escape\n * @returns The escaped string\n *\n * @example\n * ```ts\n * escapeRegExp('[a-z]+'); // '\\\\[a-z\\\\]+'\n * ```\n */\nexport function escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","/**\n * Type guard helpers.\n *\n * @module bquery/core/utils/type-guards\n */\n\n/**\n * Checks if a value is a DOM Element.\n *\n * @param value - The value to check\n * @returns True if the value is an Element\n */\nexport function isElement(value: unknown): value is Element {\n return typeof Element !== 'undefined' && value instanceof Element;\n}\n\n/**\n * Checks if a value is a BQueryCollection-like object.\n *\n * @param value - The value to check\n * @returns True if the value has an elements array property\n */\nexport function isCollection(value: unknown): value is { elements: Element[] } {\n return Boolean(value && typeof value === 'object' && 'elements' in (value as object));\n}\n\n/**\n * Checks if a value is a function.\n *\n * @param value - The value to check\n * @returns True if the value is a function\n */\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\n return typeof value === 'function';\n}\n\n/**\n * Checks if a value is a string.\n *\n * @param value - The value to check\n * @returns True if the value is a string\n */\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Checks if a value is a number (excluding NaN).\n *\n * @param value - The value to check\n * @returns True if the value is a valid number\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === 'number' && !Number.isNaN(value);\n}\n\n/**\n * Checks if a value is a boolean.\n *\n * @param value - The value to check\n * @returns True if the value is a boolean\n */\nexport function isBoolean(value: unknown): value is boolean {\n return typeof value === 'boolean';\n}\n\n/**\n * Checks if a value is an array.\n *\n * @template T - The type of array elements\n * @param value - The value to check\n * @returns True if the value is an array\n */\nexport function isArray<T = unknown>(value: unknown): value is T[] {\n return Array.isArray(value);\n}\n\n/**\n * Checks if a value is a Date instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Date\n */\nexport function isDate(value: unknown): value is Date {\n return value instanceof Date;\n}\n\n/**\n * Checks if a value is a Promise-like object.\n *\n * @param value - The value to check\n * @returns True if the value is a Promise-like object\n */\nexport function isPromise<T = unknown>(value: unknown): value is Promise<T> {\n return Boolean(\n value &&\n (value instanceof Promise ||\n (typeof value === 'object' &&\n 'then' in (value as object) &&\n typeof (value as { then?: unknown }).then === 'function'))\n );\n}\n\n/**\n * Checks if a value is a non-null object.\n *\n * @param value - The value to check\n * @returns True if the value is an object\n */\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","/**\r\n * Utility helpers used across the framework.\r\n * These are intentionally small and framework-agnostic to keep the core tiny.\r\n *\r\n * @module bquery/core/utils\r\n */\r\n\r\nexport * from './array';\r\nexport * from './function';\r\nexport * from './misc';\r\nexport * from './number';\r\nexport * from './object';\r\nexport * from './string';\r\nexport * from './type-guards';\r\n\r\nimport { chunk, compact, ensureArray, flatten, unique } from './array';\r\nimport { debounce, noop, once, throttle } from './function';\r\nimport { isEmpty, parseJson, sleep, uid } from './misc';\r\nimport { clamp, inRange, randomInt, toNumber } from './number';\r\nimport { clone, hasOwn, isPlainObject, merge, omit, pick } from './object';\r\nimport { capitalize, escapeRegExp, slugify, toCamelCase, toKebabCase, truncate } from './string';\r\nimport {\r\n isArray,\r\n isBoolean,\r\n isCollection,\r\n isDate,\r\n isElement,\r\n isFunction,\r\n isNumber,\r\n isObject,\r\n isPromise,\r\n isString,\r\n} from './type-guards';\r\n\r\n/**\r\n * Describes the public shape of the aggregated {@link utils} namespace.\r\n *\r\n * Every member maps 1-to-1 to a named export from one of the sub-modules\r\n * (`array`, `function`, `misc`, `number`, `object`, `string`, `type-guards`).\r\n *\r\n * `isPrototypePollutionKey` is intentionally excluded as it is an\r\n * internal security helper. It remains available as a named export for\r\n * internal framework use.\r\n */\r\nexport interface BQueryUtils {\r\n // ── object ──────────────────────────────────────────────────────────\r\n readonly clone: typeof clone;\r\n readonly merge: typeof merge;\r\n readonly pick: typeof pick;\r\n readonly omit: typeof omit;\r\n readonly hasOwn: typeof hasOwn;\r\n readonly isPlainObject: typeof isPlainObject;\r\n\r\n // ── function ────────────────────────────────────────────────────────\r\n readonly debounce: typeof debounce;\r\n readonly throttle: typeof throttle;\r\n readonly once: typeof once;\r\n readonly noop: typeof noop;\r\n\r\n // ── misc ────────────────────────────────────────────────────────────\r\n readonly uid: typeof uid;\r\n readonly isEmpty: typeof isEmpty;\r\n readonly parseJson: typeof parseJson;\r\n readonly sleep: typeof sleep;\r\n\r\n // ── type-guards ─────────────────────────────────────────────────────\r\n readonly isElement: typeof isElement;\r\n readonly isCollection: typeof isCollection;\r\n readonly isFunction: typeof isFunction;\r\n readonly isString: typeof isString;\r\n readonly isNumber: typeof isNumber;\r\n readonly isBoolean: typeof isBoolean;\r\n readonly isArray: typeof isArray;\r\n readonly isDate: typeof isDate;\r\n readonly isPromise: typeof isPromise;\r\n readonly isObject: typeof isObject;\r\n\r\n // ── number ──────────────────────────────────────────────────────────\r\n readonly randomInt: typeof randomInt;\r\n readonly clamp: typeof clamp;\r\n readonly inRange: typeof inRange;\r\n readonly toNumber: typeof toNumber;\r\n\r\n // ── string ──────────────────────────────────────────────────────────\r\n readonly capitalize: typeof capitalize;\r\n readonly toKebabCase: typeof toKebabCase;\r\n readonly toCamelCase: typeof toCamelCase;\r\n readonly truncate: typeof truncate;\r\n readonly slugify: typeof slugify;\r\n readonly escapeRegExp: typeof escapeRegExp;\r\n\r\n // ── array ───────────────────────────────────────────────────────────\r\n readonly ensureArray: typeof ensureArray;\r\n readonly unique: typeof unique;\r\n readonly chunk: typeof chunk;\r\n readonly compact: typeof compact;\r\n readonly flatten: typeof flatten;\r\n}\r\n\r\n/**\r\n * Utility object containing common helper functions.\r\n * All utilities are designed to be tree-shakeable and have zero dependencies.\r\n *\r\n * Note: `isPrototypePollutionKey` is intentionally excluded from this namespace\r\n * as it is an internal security helper. It remains available as a named export\r\n * for internal framework use.\r\n */\r\nexport const utils: BQueryUtils = {\r\n clone,\r\n merge,\r\n pick,\r\n omit,\r\n hasOwn,\r\n debounce,\r\n throttle,\r\n once,\r\n noop,\r\n uid,\r\n isElement,\r\n isCollection,\r\n isEmpty,\r\n isPlainObject,\r\n isFunction,\r\n isString,\r\n isNumber,\r\n isBoolean,\r\n isArray,\r\n isDate,\r\n isPromise,\r\n isObject,\r\n parseJson,\r\n sleep,\r\n randomInt,\r\n clamp,\r\n inRange,\r\n toNumber,\r\n capitalize,\r\n toKebabCase,\r\n toCamelCase,\r\n truncate,\r\n slugify,\r\n escapeRegExp,\r\n ensureArray,\r\n unique,\r\n chunk,\r\n compact,\r\n flatten,\r\n};\r\n","/**\n * Internal reactive plumbing shared across primitives.\n * @internal\n */\n\nexport type Observer = () => void;\nexport type CleanupFn = () => void;\n\n/**\n * Interface for reactive sources (Signals, Computed) that can unsubscribe observers.\n * @internal\n */\nexport interface ReactiveSource {\n unsubscribe(observer: Observer): void;\n}\n\nconst observerStack: Observer[] = [];\nlet batchDepth = 0;\nconst pendingObservers = new Set<Observer>();\n\n// Track dependencies for each observer to enable cleanup\nconst observerDependencies = new WeakMap<Observer, Set<ReactiveSource>>();\n\nexport const track = <T>(observer: Observer, fn: () => T): T => {\n observerStack.push(observer);\n try {\n return fn();\n } finally {\n observerStack.pop();\n }\n};\n\nexport const getCurrentObserver = (): Observer | undefined =>\n observerStack[observerStack.length - 1];\n\n/**\n * Executes a function without exposing the current observer to dependencies.\n * Unlike disabling tracking globally, this still allows nested reactive internals\n * (e.g., computed recomputation) to track their own dependencies.\n * @internal\n */\nexport const withoutCurrentObserver = <T>(fn: () => T): T => {\n // Push undefined to temporarily \"hide\" the current observer\n // This way, Signal.value reads won't link to the previous observer,\n // but nested track() calls (e.g., computed recompute) still work normally.\n observerStack.push(undefined as unknown as Observer);\n try {\n return fn();\n } finally {\n observerStack.pop();\n }\n};\n\nexport const scheduleObserver = (observer: Observer): void => {\n if (batchDepth > 0) {\n pendingObservers.add(observer);\n return;\n }\n observer();\n};\n\nconst flushObservers = (): void => {\n for (const observer of Array.from(pendingObservers)) {\n pendingObservers.delete(observer);\n try {\n observer();\n } catch (error) {\n console.error('bQuery reactive: Error in observer during batch flush', error);\n }\n }\n};\n\nexport const beginBatch = (): void => {\n batchDepth += 1;\n};\n\nexport const endBatch = (): void => {\n if (batchDepth <= 0) return;\n batchDepth -= 1;\n if (batchDepth === 0) {\n flushObservers();\n }\n};\n\n/**\n * Registers a dependency between an observer and a reactive source.\n * @internal\n */\nexport const registerDependency = (observer: Observer, source: ReactiveSource): void => {\n let deps = observerDependencies.get(observer);\n if (!deps) {\n deps = new Set();\n observerDependencies.set(observer, deps);\n }\n deps.add(source);\n};\n\n/**\n * Removes a specific source from an observer's dependency set.\n * Used when a source (e.g. Signal) is disposed to prevent stale references.\n * @internal\n */\nexport const removeDependency = (observer: Observer, source: ReactiveSource): void => {\n const deps = observerDependencies.get(observer);\n if (deps) {\n deps.delete(source);\n }\n};\n\n/**\n * Clears all dependencies for an observer, unsubscribing from all sources.\n * @internal\n */\nexport const clearDependencies = (observer: Observer): void => {\n const deps = observerDependencies.get(observer);\n if (deps) {\n for (const source of deps) {\n source.unsubscribe(observer);\n }\n deps.clear();\n }\n};\n","/**\n * Batched reactive updates.\n */\n\nimport { beginBatch, endBatch } from './internals';\n\n/**\n * Batches multiple signal updates into a single notification cycle.\n *\n * Updates made inside the batch function are deferred until the batch\n * completes, preventing intermediate re-renders and improving performance.\n *\n * @param fn - Function containing multiple signal updates\n */\nexport const batch = (fn: () => void): void => {\n beginBatch();\n try {\n fn();\n } finally {\n endBatch();\n }\n};\n","/**\n * Global bQuery configuration helpers.\n *\n * @module bquery/platform\n */\n\nimport { isPlainObject, merge } from '../core/utils/object';\n\n/** Supported response parsing strategies for fetch composables. */\nexport type BqueryFetchParseAs = 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData' | 'response';\n\n/** Global fetch defaults used by useFetch(). */\nexport interface BqueryFetchConfig {\n /** Optional base URL prepended to relative request URLs. */\n baseUrl?: string;\n /** Default request headers. */\n headers?: HeadersInit;\n /** Default response parser. */\n parseAs?: BqueryFetchParseAs;\n}\n\n/** Global cookie defaults used by useCookie(). */\nexport interface BqueryCookieConfig {\n /** Default cookie path. */\n path?: string;\n /** Default SameSite mode. */\n sameSite?: 'Strict' | 'Lax' | 'None';\n /** Whether cookies should be marked secure by default. */\n secure?: boolean;\n}\n\n/** Global announcer defaults used by useAnnouncer(). */\nexport interface BqueryAnnouncerConfig {\n /** Default politeness level. */\n politeness?: 'polite' | 'assertive';\n /** Whether announcements should be treated atomically. */\n atomic?: boolean;\n /** Delay before writing the message into the live region. */\n delay?: number;\n /** Delay after which the live region is cleared automatically. */\n clearDelay?: number;\n}\n\n/** Global page meta defaults used by definePageMeta(). */\nexport interface BqueryPageMetaConfig {\n /** Optional title template function. */\n titleTemplate?: (title: string) => string;\n}\n\n/** Global motion defaults used by transition(). */\nexport interface BqueryTransitionConfig {\n /** Skip transitions when reduced motion is preferred. */\n skipOnReducedMotion?: boolean;\n /** Classes applied to the root element during transitions. */\n classes?: string[];\n /** Transition type identifiers added when supported by the browser. */\n types?: string[];\n}\n\n/** Global default component library configuration. */\nexport interface BqueryComponentLibraryConfig {\n /** Prefix used by registerDefaultComponents(). */\n prefix?: string;\n}\n\n/** Complete global bQuery configuration object. */\nexport interface BqueryConfig {\n /** Fetch composable defaults. */\n fetch?: BqueryFetchConfig;\n /** Cookie composable defaults. */\n cookies?: BqueryCookieConfig;\n /** Announcer composable defaults. */\n announcer?: BqueryAnnouncerConfig;\n /** Page metadata defaults. */\n pageMeta?: BqueryPageMetaConfig;\n /** View transition defaults. */\n transitions?: BqueryTransitionConfig;\n /** Default component library options. */\n components?: BqueryComponentLibraryConfig;\n}\n\nconst defaultConfig: BqueryConfig = {\n fetch: {\n headers: {},\n parseAs: 'json',\n },\n cookies: {\n path: '/',\n sameSite: 'Lax',\n secure: false,\n },\n announcer: {\n politeness: 'polite',\n atomic: true,\n delay: 16,\n clearDelay: 1000,\n },\n pageMeta: {},\n transitions: {\n skipOnReducedMotion: false,\n classes: [],\n types: [],\n },\n components: {\n prefix: 'bq',\n },\n};\n\nconst cloneConfigValue = <T>(value: T): T => {\n if (typeof Headers !== 'undefined' && value instanceof Headers) {\n return new Headers(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => cloneConfigValue(entry)) as T;\n }\n\n if (isPlainObject(value)) {\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n result[key] = cloneConfigValue(entry);\n }\n return result as T;\n }\n\n return value;\n};\n\nlet currentConfig: BqueryConfig = cloneConfigValue(defaultConfig);\n\n/**\n * Define or extend the global bQuery configuration.\n *\n * @param config - Partial configuration values to merge into the current config\n * @returns The resolved configuration after merging\n *\n * @example\n * ```ts\n * defineBqueryConfig({\n * fetch: { baseUrl: 'https://api.example.com' },\n * components: { prefix: 'ui' },\n * });\n * ```\n */\nexport const defineBqueryConfig = (config: BqueryConfig): BqueryConfig => {\n currentConfig = cloneConfigValue(\n merge(\n defaultConfig as Record<string, unknown>,\n currentConfig as Record<string, unknown>,\n config as Record<string, unknown>\n ) as BqueryConfig\n );\n return getBqueryConfig();\n};\n\n/**\n * Get the currently resolved bQuery configuration.\n *\n * @returns A cloned snapshot of the active configuration\n */\nexport const getBqueryConfig = (): BqueryConfig => {\n return cloneConfigValue(currentConfig);\n};\n","/**\r\n * Computed reactive values.\r\n */\r\n\r\nimport {\r\n clearDependencies,\r\n getCurrentObserver,\r\n registerDependency,\r\n scheduleObserver,\r\n track,\r\n withoutCurrentObserver,\r\n type ReactiveSource,\r\n} from './internals';\r\n\r\n/**\r\n * A computed value that derives from other reactive sources.\r\n *\r\n * Computed values are lazily evaluated and cached. They only\r\n * recompute when their dependencies change.\r\n *\r\n * @template T - The type of the computed value\r\n */\r\nexport class Computed<T> implements ReactiveSource {\r\n private cachedValue!: T;\r\n private hasCachedValue = false;\r\n private dirty = true;\r\n private disposed = false;\r\n private subscribers = new Set<() => void>();\r\n private readonly markDirty = () => {\r\n if (this.disposed) {\r\n return;\r\n }\r\n this.dirty = true;\r\n // Create snapshot to avoid issues with subscribers modifying the set during iteration\r\n const subscribersSnapshot = Array.from(this.subscribers);\r\n for (const subscriber of subscribersSnapshot) {\r\n scheduleObserver(subscriber);\r\n }\r\n };\r\n\r\n /**\r\n * Creates a new computed value.\r\n * @param compute - Function that computes the value\r\n */\r\n constructor(private readonly compute: () => T) {}\r\n\r\n /**\r\n * Gets the computed value, recomputing if dependencies changed.\r\n * During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.\r\n */\r\n get value(): T {\r\n if (this.disposed) {\r\n if (!this.hasCachedValue) {\r\n this.cachedValue = withoutCurrentObserver(() => this.compute());\r\n this.hasCachedValue = true;\r\n }\r\n return this.cachedValue;\r\n }\r\n\r\n const current = getCurrentObserver();\r\n if (current) {\r\n this.subscribers.add(current);\r\n registerDependency(current, this);\r\n }\r\n if (this.dirty) {\r\n this.dirty = false;\r\n // Clear old dependencies before recomputing\r\n clearDependencies(this.markDirty);\r\n this.cachedValue = track(this.markDirty, this.compute);\r\n this.hasCachedValue = true;\r\n }\r\n return this.cachedValue;\r\n }\r\n\r\n /**\r\n * Reads the current computed value without tracking.\r\n * Useful when you need the value but don't want to create a dependency.\r\n *\r\n * @returns The current cached value (recomputes if dirty)\r\n */\r\n peek(): T {\r\n if (this.disposed) {\r\n if (!this.hasCachedValue) {\r\n this.cachedValue = withoutCurrentObserver(() => this.compute());\r\n this.hasCachedValue = true;\r\n }\r\n return this.cachedValue;\r\n }\r\n\r\n if (this.dirty) {\r\n this.dirty = false;\r\n // Clear old dependencies before recomputing\r\n clearDependencies(this.markDirty);\r\n this.cachedValue = track(this.markDirty, this.compute);\r\n this.hasCachedValue = true;\r\n }\r\n return this.cachedValue;\r\n }\r\n\r\n /**\r\n * Removes an observer from this computed's subscriber set.\r\n * @internal\r\n */\r\n unsubscribe(observer: () => void): void {\r\n this.subscribers.delete(observer);\r\n }\r\n\r\n /**\r\n * Disposes the computed value by unsubscribing its internal observer\r\n * from all upstream dependencies and clearing subscribers.\r\n */\r\n dispose(): void {\r\n this.disposed = true;\r\n if (this.dirty) {\r\n this.hasCachedValue = false;\r\n }\r\n this.dirty = false;\r\n clearDependencies(this.markDirty);\r\n this.subscribers.clear();\r\n }\r\n}\r\n\r\n/**\r\n * Creates a new computed value.\r\n *\r\n * @template T - The type of the computed value\r\n * @param fn - Function that computes the value from reactive sources\r\n * @returns A new Computed instance\r\n */\r\nexport const computed = <T>(fn: () => T): Computed<T> => new Computed(fn);\r\n","/**\n * Reactive effects.\n */\n\nimport { CleanupFn, Observer, track, clearDependencies } from './internals';\n\n/**\n * Creates a side effect that automatically re-runs when dependencies change.\n *\n * The effect runs immediately upon creation and then re-runs whenever\n * any signal or computed value read inside it changes.\n *\n * @param fn - The effect function to run\n * @returns A cleanup function to stop the effect\n */\nexport const effect = (fn: () => void | CleanupFn): CleanupFn => {\n let cleanupFn: CleanupFn | void;\n let isDisposed = false;\n\n const runCleanup = (): void => {\n if (cleanupFn) {\n try {\n cleanupFn();\n } catch (error) {\n console.error('bQuery reactive: Error in effect cleanup', error);\n }\n cleanupFn = undefined;\n }\n };\n\n const observer: Observer = () => {\n if (isDisposed) return;\n\n runCleanup();\n\n // Clear old dependencies before running to avoid stale subscriptions\n clearDependencies(observer);\n\n try {\n cleanupFn = track(observer, fn);\n } catch (error) {\n console.error('bQuery reactive: Error in effect', error);\n }\n };\n\n observer();\n\n return () => {\n isDisposed = true;\n runCleanup();\n // Clean up all dependencies when effect is disposed\n clearDependencies(observer);\n };\n};\n","/**\n * Core reactive signals.\n */\n\nimport {\n getCurrentObserver,\n registerDependency,\n removeDependency,\n scheduleObserver,\n type ReactiveSource,\n} from './internals';\n\n/**\n * A reactive value container that notifies subscribers on change.\n *\n * Signals are the foundational primitive of the reactive system.\n * Reading a signal's value inside an effect or computed automatically\n * establishes a reactive dependency.\n *\n * @template T - The type of the stored value\n */\nexport class Signal<T> implements ReactiveSource {\n private subscribers = new Set<() => void>();\n\n /**\n * Creates a new signal with an initial value.\n * @param _value - The initial value\n */\n constructor(private _value: T) {}\n\n /**\n * Gets the current value and tracks the read if inside an observer.\n * During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.\n */\n get value(): T {\n const current = getCurrentObserver();\n if (current) {\n this.subscribers.add(current);\n registerDependency(current, this);\n }\n return this._value;\n }\n\n /**\n * Sets a new value and notifies all subscribers if the value changed.\n * Uses Object.is for equality comparison.\n */\n set value(next: T) {\n if (Object.is(this._value, next)) return;\n this._value = next;\n // Create snapshot to avoid issues with subscribers modifying the set during iteration\n const subscribersSnapshot = Array.from(this.subscribers);\n for (const subscriber of subscribersSnapshot) {\n scheduleObserver(subscriber);\n }\n }\n\n /**\n * Reads the current value without tracking.\n * Useful when you need the value but don't want to create a dependency.\n *\n * @returns The current value\n */\n peek(): T {\n return this._value;\n }\n\n /**\n * Updates the value using a function.\n * Useful for updates based on the current value.\n *\n * @param updater - Function that receives current value and returns new value\n */\n update(updater: (current: T) => T): void {\n this.value = updater(this._value);\n }\n\n /**\n * Removes all subscribers from this signal.\n * Use this when a signal is no longer needed to prevent memory leaks.\n *\n * @example\n * ```ts\n * const count = signal(0);\n * effect(() => console.log(count.value));\n * count.dispose(); // All subscribers removed\n * ```\n */\n dispose(): void {\n // Remove this signal from each subscriber's dependency set\n // so the observer no longer holds a strong reference to it\n for (const subscriber of this.subscribers) {\n removeDependency(subscriber, this);\n }\n this.subscribers.clear();\n }\n\n /**\n * Removes an observer from this signal's subscriber set.\n * @internal\n */\n unsubscribe(observer: () => void): void {\n this.subscribers.delete(observer);\n }\n}\n\n/**\n * Creates a new reactive signal.\n *\n * @template T - The type of the signal value\n * @param value - The initial value\n * @returns A new Signal instance\n */\nexport const signal = <T>(value: T): Signal<T> => new Signal(value);\n","/**\n * Dependency tracking control helpers.\n */\n\nimport { withoutCurrentObserver } from './internals';\n\n/**\n * Executes a function without tracking any signal dependencies.\n * Useful when reading a signal value without creating a reactive dependency.\n *\n * This implementation temporarily hides the current observer rather than\n * disabling tracking globally. This ensures that nested reactive internals\n * (e.g., computed recomputation triggered during untrack) can still properly\n * track their own dependencies.\n *\n * @template T - The return type of the function\n * @param fn - The function to execute without tracking\n * @returns The result of the function\n *\n * @example\n * ```ts\n * const count = signal(0);\n * effect(() => {\n * // This read creates a dependency\n * console.log(count.value);\n * // This read does not create a dependency\n * const snapshot = untrack(() => count.value);\n * });\n * ```\n */\nexport const untrack = <T>(fn: () => T): T => withoutCurrentObserver(fn);\n","/**\n * Async data and fetch composables built on bQuery signals.\n *\n * @module bquery/reactive\n */\n\nimport { merge } from '../core/utils/object';\nimport { getBqueryConfig, type BqueryFetchParseAs } from '../platform/config';\nimport { computed } from './computed';\nimport { effect } from './effect';\nimport { Signal, signal } from './core';\nimport { untrack } from './untrack';\n\n/** Allowed status values for async composables. */\nexport type AsyncDataStatus = 'idle' | 'pending' | 'success' | 'error';\n\n/** Reactive source types that can trigger refreshes. */\nexport type AsyncWatchSource = (() => unknown) | { value: unknown };\n\n/** Options shared by async composables. */\nexport interface UseAsyncDataOptions<TResult, TData = TResult> {\n /** Run the handler immediately (default: true). */\n immediate?: boolean;\n /** Default data value before the first successful execution. */\n defaultValue?: TData;\n /** Optional reactive sources that trigger refreshes when they change. */\n watch?: AsyncWatchSource[];\n /** Transform the resolved value before storing it. */\n transform?: (value: TResult) => TData;\n /** Called after a successful execution. */\n onSuccess?: (value: TData) => void;\n /** Called after a failed execution. */\n onError?: (error: Error) => void;\n}\n\n/** Return value of useAsyncData() and useFetch(). */\nexport interface AsyncDataState<TData> {\n /** Reactive data signal. */\n data: Signal<TData | undefined>;\n /** Last error encountered by the composable. */\n error: Signal<Error | null>;\n /** Current lifecycle status. */\n status: Signal<AsyncDataStatus>;\n /** Computed boolean that mirrors `status === 'pending'`. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Execute the handler manually. Returns the cached data value when called after dispose(). */\n execute: () => Promise<TData | undefined>;\n /** Alias for execute(). */\n refresh: () => Promise<TData | undefined>;\n /** Clear data, error, and status back to the initial state. */\n clear: () => void;\n /** Dispose reactive watchers and prevent future executions. */\n dispose: () => void;\n}\n\n/** Options for useFetch(). */\nexport interface UseFetchOptions<TResponse = unknown, TData = TResponse>\n extends UseAsyncDataOptions<TResponse, TData>, Omit<RequestInit, 'body' | 'headers'> {\n /** Base URL prepended to relative URLs. */\n baseUrl?: string;\n /** Query parameters appended to the request URL. */\n query?: Record<string, unknown>;\n /** Request headers. */\n headers?: HeadersInit;\n /** Request body, including plain objects for JSON requests. */\n body?: BodyInit | Record<string, unknown> | unknown[] | null;\n /** Override the parser used for the response body. */\n parseAs?: BqueryFetchParseAs;\n /** Custom fetch implementation for testing or adapters. */\n fetcher?: typeof fetch;\n}\n\n/** Input accepted by useFetch(). */\nexport type FetchInput = string | URL | Request | (() => string | URL | Request);\n\nconst normalizeError = (error: unknown): Error => {\n if (error instanceof Error) return error;\n if (typeof error === 'string') {\n return new Error(error);\n }\n\n try {\n return new Error(JSON.stringify(error));\n } catch {\n return new Error(String(error));\n }\n};\n\nconst readWatchSource = (source: AsyncWatchSource): unknown => {\n if (typeof source === 'function') {\n return source();\n }\n return source.value;\n};\n\nconst toHeaders = (...sources: Array<HeadersInit | undefined>): Headers => {\n const headers = new Headers();\n for (const source of sources) {\n if (!source) continue;\n new Headers(source).forEach((value, key) => {\n headers.set(key, value);\n });\n }\n return headers;\n};\n\nconst isBodyLike = (value: unknown): value is BodyInit => {\n if (typeof value === 'string') return true;\n if (value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams) {\n return true;\n }\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) return true;\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) return true;\n return typeof value === 'object' && value !== null && ArrayBuffer.isView(value);\n};\n\nconst serializeBody = (\n body: UseFetchOptions['body'],\n headers: Headers\n): BodyInit | null | undefined => {\n if (body == null) return body;\n if (isBodyLike(body)) return body;\n\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n return JSON.stringify(body);\n};\n\nconst resolveInput = (input: FetchInput): string | URL | Request => {\n return typeof input === 'function' ? input() : input;\n};\n\nconst appendQuery = (url: URL, query: Record<string, unknown>): void => {\n for (const [key, value] of Object.entries(query)) {\n if (value == null) continue;\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item != null) {\n url.searchParams.append(key, String(item));\n }\n }\n continue;\n }\n\n url.searchParams.set(key, String(value));\n }\n};\n\nconst toUrl = (input: string | URL, baseUrl?: string): URL => {\n const runtimeBase =\n typeof window !== 'undefined' && /^https?:/i.test(window.location.href)\n ? window.location.href\n : 'http://localhost';\n const base = baseUrl ? new URL(baseUrl, runtimeBase).toString() : runtimeBase;\n return input instanceof URL ? new URL(input.toString(), base) : new URL(input, base);\n};\n\nconst parseResponse = async <TResponse>(\n response: Response,\n parseAs: BqueryFetchParseAs\n): Promise<TResponse> => {\n if (parseAs === 'response') return response as TResponse;\n if (parseAs === 'text') return (await response.text()) as TResponse;\n if (parseAs === 'blob') return (await response.blob()) as TResponse;\n if (parseAs === 'arrayBuffer') return (await response.arrayBuffer()) as TResponse;\n if (parseAs === 'formData') return (await response.formData()) as TResponse;\n\n const text = await response.text();\n if (!text) {\n return undefined as TResponse;\n }\n\n try {\n return JSON.parse(text) as TResponse;\n } catch (error) {\n const detail = response.url ? ` for ${response.url}` : '';\n throw new Error(\n `Failed to parse JSON response${detail} (status ${response.status}): ${error instanceof Error ? error.message : String(error)}`\n );\n }\n};\n\nconst normalizeMethod = (method?: string): string | undefined => {\n const normalized = method?.trim();\n return normalized ? normalized.toUpperCase() : undefined;\n};\n\nconst resolveMethod = (\n explicitMethod: string | undefined,\n requestInput: string | URL | Request,\n bodyProvided: boolean\n): string | undefined => {\n const requestMethod =\n requestInput instanceof Request ? normalizeMethod(requestInput.method) : undefined;\n return explicitMethod ?? requestMethod ?? (bodyProvided ? 'POST' : undefined);\n};\n\nconst resolveRequestInitMethod = (\n explicitMethod: string | undefined,\n requestInput: string | URL | Request,\n method: string | undefined\n): string | undefined => {\n if (explicitMethod) return explicitMethod;\n return requestInput instanceof Request ? undefined : method;\n};\n\nconst toRequestInit = (request: Request): RequestInit => {\n const requestMethod = normalizeMethod(request.method);\n let body: BodyInit | undefined;\n if (requestMethod !== 'GET' && requestMethod !== 'HEAD' && !request.bodyUsed) {\n try {\n body = request.clone().body ?? undefined;\n } catch {\n body = undefined;\n }\n }\n\n return {\n method: requestMethod,\n headers: request.headers,\n body,\n cache: request.cache,\n credentials: request.credentials,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: request.signal,\n };\n};\n\n/**\n * Create a reactive wrapper around an async resolver.\n *\n * @template TResult - Raw result type returned by the handler\n * @template TData - Stored data type after optional transformation\n * @param handler - Async function to execute\n * @param options - Execution, transform, and refresh options\n * @returns Reactive data state with execute(), refresh(), and clear()\n *\n * @example\n * ```ts\n * const user = useAsyncData(() => fetch('/api/user').then((res) => res.json()));\n * ```\n */\nexport const useAsyncData = <TResult, TData = TResult>(\n handler: () => Promise<TResult>,\n options: UseAsyncDataOptions<TResult, TData> = {}\n): AsyncDataState<TData> => {\n const immediate = options.immediate ?? true;\n const data = signal<TData | undefined>(options.defaultValue);\n const error = signal<Error | null>(null);\n const status = signal<AsyncDataStatus>('idle');\n const pending = computed(() => status.value === 'pending');\n let executionId = 0;\n let disposed = false;\n let stopWatching = (): void => {};\n\n const clear = (): void => {\n executionId += 1;\n data.value = options.defaultValue;\n error.value = null;\n status.value = 'idle';\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n executionId += 1;\n stopWatching();\n };\n\n const execute = async (): Promise<TData | undefined> => {\n if (disposed) {\n return data.peek();\n }\n\n const currentExecution = ++executionId;\n status.value = 'pending';\n error.value = null;\n\n try {\n const resolved = await handler();\n const transformed = options.transform\n ? options.transform(resolved)\n : (resolved as unknown as TData);\n\n if (disposed || currentExecution !== executionId) {\n return data.peek();\n }\n\n data.value = transformed;\n status.value = 'success';\n options.onSuccess?.(transformed);\n return transformed;\n } catch (caught) {\n const normalizedError = normalizeError(caught);\n\n if (disposed || currentExecution !== executionId) {\n return data.peek();\n }\n\n error.value = normalizedError;\n status.value = 'error';\n options.onError?.(normalizedError);\n return data.peek();\n }\n };\n\n if (options.watch?.length) {\n let initialized = false;\n stopWatching = effect(() => {\n for (const source of options.watch ?? []) {\n readWatchSource(source);\n }\n\n if (!initialized) {\n initialized = true;\n if (immediate) {\n void untrack(() => execute());\n }\n return;\n }\n\n void untrack(() => execute());\n });\n } else if (immediate) {\n void execute();\n }\n\n return {\n data,\n error,\n status,\n pending,\n execute,\n refresh: execute,\n clear,\n dispose,\n };\n};\n\n/**\n * Reactive fetch composable using the browser Fetch API.\n *\n * @template TResponse - Raw parsed response type\n * @template TData - Stored response type after optional transformation\n * @param input - Request URL, Request object, or lazy input factory\n * @param options - Request and reactive state options\n * @returns Reactive fetch state with execute(), refresh(), and clear()\n *\n * @example\n * ```ts\n * const users = useFetch<{ id: number; name: string }[]>('/api/users');\n * ```\n */\nexport const useFetch = <TResponse = unknown, TData = TResponse>(\n input: FetchInput,\n options: UseFetchOptions<TResponse, TData> = {}\n): AsyncDataState<TData> => {\n const fetchConfig = getBqueryConfig().fetch;\n const parseAs = options.parseAs ?? fetchConfig?.parseAs ?? 'json';\n const fetcher = options.fetcher ?? fetch;\n\n return useAsyncData<TResponse, TData>(async () => {\n const requestInput = resolveInput(input);\n const requestUrl =\n typeof requestInput === 'string' || requestInput instanceof URL\n ? toUrl(requestInput, options.baseUrl ?? fetchConfig?.baseUrl)\n : requestInput instanceof Request && options.query\n ? new URL(requestInput.url)\n : null;\n\n if (requestUrl && options.query) {\n appendQuery(requestUrl, options.query);\n }\n\n const headers = toHeaders(\n fetchConfig?.headers,\n requestInput instanceof Request ? requestInput.headers : undefined,\n options.headers\n );\n const bodyProvided = options.body != null;\n const explicitMethod = normalizeMethod(options.method);\n const method = resolveMethod(explicitMethod, requestInput, bodyProvided);\n const bodylessMethod = method === 'GET' || method === 'HEAD' ? method : null;\n if (bodyProvided && bodylessMethod) {\n throw new Error(`Cannot send a request body with ${bodylessMethod} requests`);\n }\n const requestInitMethod = resolveRequestInitMethod(explicitMethod, requestInput, method);\n const requestInit: RequestInit = {\n ...options,\n method: requestInitMethod,\n headers,\n body: serializeBody(options.body, headers),\n };\n\n delete (requestInit as Partial<UseFetchOptions>).baseUrl;\n delete (requestInit as Partial<UseFetchOptions>).query;\n delete (requestInit as Partial<UseFetchOptions>).parseAs;\n delete (requestInit as Partial<UseFetchOptions>).fetcher;\n delete (requestInit as Partial<UseFetchOptions>).defaultValue;\n delete (requestInit as Partial<UseFetchOptions>).immediate;\n delete (requestInit as Partial<UseFetchOptions>).watch;\n delete (requestInit as Partial<UseFetchOptions>).transform;\n delete (requestInit as Partial<UseFetchOptions>).onSuccess;\n delete (requestInit as Partial<UseFetchOptions>).onError;\n\n let requestTarget: Request | string | URL = requestUrl ?? requestInput;\n if (\n requestInput instanceof Request &&\n requestUrl &&\n requestUrl.toString() !== requestInput.url\n ) {\n // Rebuild Request inputs when query params changed so the updated URL is preserved.\n // String/URL inputs already use `requestUrl` directly, so only Request objects need rebuilding.\n requestTarget = new Request(requestUrl.toString(), toRequestInit(requestInput));\n }\n const response = await fetcher(requestTarget, requestInit);\n\n if (!response.ok) {\n throw Object.assign(new Error(`Request failed with status ${response.status}`), {\n response,\n status: response.status,\n statusText: response.statusText,\n });\n }\n\n return parseResponse<TResponse>(response, parseAs);\n }, options);\n};\n\n/**\n * Create a preconfigured useFetch() helper.\n *\n * @param defaults - Default request options merged into every useFetch() call\n * @returns A useFetch-compatible function with merged defaults\n *\n * @example\n * ```ts\n * const useApiFetch = createUseFetch({ baseUrl: 'https://api.example.com' });\n * const profile = useApiFetch('/profile');\n * ```\n */\n/** Overload for factories without a configured transform, preserving per-call `TResponse -> TData` inference. */\nexport function createUseFetch<TDefaultResponse = unknown>(\n defaults?: UseFetchOptions<TDefaultResponse, TDefaultResponse>\n): <TResponse = TDefaultResponse, TData = TResponse>(\n input: FetchInput,\n options?: UseFetchOptions<TResponse, TData>\n) => AsyncDataState<TData>;\n\n/** Overload for factories with a configured transform, preserving the transformed factory data type by default. */\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData>\n): <TResponse = TDefaultResponse, TData = TDefaultData>(\n input: FetchInput,\n options?: UseFetchOptions<TResponse, TData>\n) => AsyncDataState<TData>;\n\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData> = {}\n) {\n return <TResponse = TDefaultResponse, TData = TDefaultData>(\n input: FetchInput,\n options: UseFetchOptions<TResponse, TData> = {}\n ): AsyncDataState<TData> => {\n const resolvedDefaults = defaults as unknown as UseFetchOptions<TResponse, TData>;\n const mergedQuery = merge({}, resolvedDefaults.query ?? {}, options.query ?? {}) as Record<\n string,\n unknown\n >;\n\n return useFetch<TResponse, TData>(input, {\n ...resolvedDefaults,\n ...options,\n headers: toHeaders(resolvedDefaults.headers, options.headers),\n query: Object.keys(mergedQuery).length > 0 ? mergedQuery : undefined,\n });\n };\n}\n","/**\n * Linked (writable) computed helpers.\n */\n\nimport { computed, Computed } from './computed';\n\n/**\n * A writable computed-like signal.\n */\nexport interface LinkedSignal<T> {\n /** Gets or sets the current value with dependency tracking. */\n value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Creates a writable computed signal by linking a getter and setter.\n *\n * @template T - The derived value type\n * @param getValue - Getter that derives the current value\n * @param setValue - Setter that writes back to underlying signals\n * @returns A writable computed-like signal\n *\n * @example\n * ```ts\n * const first = signal('Ada');\n * const last = signal('Lovelace');\n * const fullName = linkedSignal(\n * () => `${first.value} ${last.value}`,\n * (next) => {\n * const [a, b] = next.split(' ');\n * first.value = a ?? '';\n * last.value = b ?? '';\n * }\n * );\n * ```\n */\nexport const linkedSignal = <T>(\n getValue: () => T,\n setValue: (value: T) => void\n): LinkedSignal<T> => {\n const derived: Computed<T> = computed(getValue);\n\n return {\n get value(): T {\n return derived.value;\n },\n set value(next: T) {\n setValue(next);\n },\n peek(): T {\n return derived.peek();\n },\n };\n};\n","/**\n * LocalStorage-backed signals.\n */\n\nimport { signal, Signal } from './core';\nimport { effect } from './effect';\n\n/**\n * Creates a signal that persists to localStorage.\n *\n * @template T - The type of the signal value\n * @param key - The localStorage key\n * @param initialValue - The initial value if not found in storage\n * @returns A Signal that syncs with localStorage (falls back to in-memory if unavailable)\n */\nexport const persistedSignal = <T>(key: string, initialValue: T): Signal<T> => {\n // Check if localStorage is available and accessible\n let hasLocalStorage = false;\n let storage: Storage | null = null;\n\n try {\n // In Safari private mode, accessing localStorage can throw SecurityError\n storage = globalThis.localStorage;\n if (storage) {\n // Test actual access to ensure it's not just present but usable\n // Use a randomized test key to avoid overwriting real user data\n const testKey = `__bquery_test_${Math.random().toString(36).slice(2, 9)}__`;\n const testValue = '__test__';\n try {\n storage.setItem(testKey, testValue);\n storage.getItem(testKey);\n hasLocalStorage = true;\n } finally {\n // Ensure we don't leave any test data behind\n try {\n storage.removeItem(testKey);\n } catch {\n // Ignore cleanup errors (e.g., storage becoming unavailable)\n }\n }\n }\n } catch {\n // localStorage unavailable or access denied (Safari private mode, sandboxed iframes, etc.)\n hasLocalStorage = false;\n }\n\n let stored: T = initialValue;\n\n if (hasLocalStorage && storage) {\n try {\n const raw = storage.getItem(key);\n if (raw !== null) {\n stored = JSON.parse(raw) as T;\n }\n } catch {\n // Use initial value on parse error or access denial\n }\n }\n\n const sig = signal(stored);\n\n // Only set up persistence effect if localStorage is available\n if (hasLocalStorage && storage) {\n effect(() => {\n try {\n storage!.setItem(key, JSON.stringify(sig.value));\n } catch {\n // Ignore storage errors (quota exceeded, sandboxed iframes, etc.)\n }\n });\n }\n\n return sig;\n};\n","/**\n * Read-only signal wrappers.\n */\n\nimport type { Signal } from './core';\n\n/**\n * A readonly wrapper around a signal that prevents writes.\n * Provides read-only access to a signal's value while maintaining reactivity.\n *\n * @template T - The type of the wrapped value\n */\nexport interface ReadonlySignal<T> {\n /** Gets the current value with dependency tracking. */\n readonly value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Creates a read-only view of a signal.\n * Useful for exposing reactive state without allowing modifications.\n *\n * @template T - The type of the signal value\n * @param sig - The signal to wrap\n * @returns A readonly signal wrapper\n */\nexport const readonly = <T>(sig: Signal<T>): ReadonlySignal<T> => ({\n get value(): T {\n return sig.value;\n },\n peek(): T {\n return sig.peek();\n },\n});\n","/**\n * Type guards for reactive primitives.\n */\n\nimport { Computed } from './computed';\nimport { Signal } from './core';\n\n/**\n * Type guard to check if a value is a Signal instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Signal\n */\nexport const isSignal = (value: unknown): value is Signal<unknown> => value instanceof Signal;\n\n/**\n * Type guard to check if a value is a Computed instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Computed\n */\nexport const isComputed = (value: unknown): value is Computed<unknown> => value instanceof Computed;\n","/**\n * Value watching helpers.\n */\n\nimport type { Computed } from './computed';\nimport type { Signal } from './core';\nimport type { CleanupFn } from './internals';\n\nimport { effect } from './effect';\n\n/**\n * Options for the watch function.\n */\nexport interface WatchOptions<T> {\n /** If true, the callback is invoked immediately with the current value. */\n immediate?: boolean;\n /** Custom equality function. Defaults to Object.is. */\n equals?: (a: T, b: T | undefined) => boolean;\n}\n\n/**\n * Watches a signal or computed value and calls a callback with old and new values.\n * Unlike effect, watch provides access to the previous value.\n * The callback is only invoked when the value actually changes (compared via Object.is or custom equals).\n *\n * @template T - The type of the watched value\n * @param source - The signal or computed to watch\n * @param callback - Function called with (newValue, oldValue) on changes\n * @param options - Watch options\n * @returns A cleanup function to stop watching\n *\n * @example\n * ```ts\n * const count = signal(0);\n * watch(count, (newVal, oldVal) => {\n * console.log(`Changed from ${oldVal} to ${newVal}`);\n * });\n *\n * // With custom equality for objects\n * const user = signal({ id: 1, name: 'Alice' });\n * watch(user, (newVal, oldVal) => { ... }, {\n * equals: (a, b) => a?.id === b?.id\n * });\n * ```\n */\nexport const watch = <T>(\n source: Signal<T> | Computed<T>,\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions<T> = {}\n): CleanupFn => {\n const { immediate = false, equals = Object.is } = options;\n let oldValue: T | undefined;\n let isFirst = true;\n\n return effect(() => {\n const newValue = source.value;\n\n if (isFirst) {\n isFirst = false;\n oldValue = newValue;\n if (immediate) {\n callback(newValue, undefined);\n }\n return;\n }\n\n // Only call callback if value actually changed\n if (!equals(newValue, oldValue)) {\n callback(newValue, oldValue);\n oldValue = newValue;\n }\n });\n};\n","/**\n * Prop coercion utilities.\n *\n * @module bquery/component\n */\n\nimport type { PropDefinition } from './types';\n\n/**\n * Coerces a string attribute value into a typed prop value.\n * Supports String, Number, Boolean, Object, Array, and custom converters.\n *\n * @internal\n * @template T - The target type\n * @param rawValue - The raw string value from the attribute\n * @param config - The prop definition with type information\n * @returns The coerced value of type T\n */\nexport const coercePropValue = <T>(rawValue: string, config: PropDefinition<T>): T => {\n const { type } = config;\n\n if (type === String) return rawValue as T;\n\n if (type === Number) {\n return Number(rawValue) as T;\n }\n\n if (type === Boolean) {\n const normalized = rawValue.trim().toLowerCase();\n if (normalized === '' || normalized === 'true' || normalized === '1') {\n return true as T;\n }\n if (normalized === 'false' || normalized === '0') {\n return false as T;\n }\n return Boolean(rawValue) as T;\n }\n\n if (type === Object || type === Array) {\n try {\n return JSON.parse(rawValue) as T;\n } catch {\n return rawValue as T;\n }\n }\n\n if (typeof type === 'function') {\n const callable = type as (value: unknown) => T;\n const constructable = type as new (value: unknown) => T;\n\n // Explicit construct mode takes precedence\n if (config.construct === true) {\n return Reflect.construct(constructable, [rawValue]) as T;\n }\n if (config.construct === false) {\n return callable(rawValue);\n }\n\n // Auto-detect: Check if type is constructable\n // A function is considered constructable if:\n // 1. It has a prototype with properties beyond just constructor, OR\n // 2. Its prototype.constructor is not itself (inherited), OR\n // 3. It's a class (toString starts with \"class\")\n const hasPrototype = type.prototype !== undefined && type.prototype !== null;\n const prototypeProps = hasPrototype ? Object.getOwnPropertyNames(type.prototype) : [];\n const hasPrototypeMethods = prototypeProps.length > 1;\n const hasInheritedConstructor = hasPrototype && type.prototype.constructor !== type;\n const isClassSyntax = /^class\\s/.test(Function.prototype.toString.call(type));\n\n const isConstructable = hasPrototypeMethods || hasInheritedConstructor || isClassSyntax;\n\n // For constructable types (e.g. Date, custom classes), prefer `new` to avoid\n // silent wrong-type returns (Date() returns string, new Date() returns Date)\n if (isConstructable) {\n try {\n return Reflect.construct(constructable, [rawValue]) as T;\n } catch {\n // Fall back to calling as function if construction fails\n return callable(rawValue);\n }\n }\n\n // For non-constructable types (arrow functions, plain functions), call directly\n // but fall back to constructor if result is undefined (common for function constructors)\n try {\n const result = callable(rawValue);\n\n // If calling without `new` returned undefined and the function has a prototype,\n // it's likely a function constructor that should be called with `new`\n if (result === undefined && hasPrototype) {\n try {\n return Reflect.construct(constructable, [rawValue]) as T;\n } catch {\n // Construction also failed, return the undefined\n return result as T;\n }\n }\n\n return result as T;\n } catch (error) {\n // Fall back to constructor if error indicates 'new' is required\n const isNewRequired =\n error instanceof TypeError &&\n /cannot be invoked without 'new'|is not a function/i.test(error.message);\n\n if (isNewRequired) {\n return Reflect.construct(constructable, [rawValue]) as T;\n }\n\n // Rethrow original error for non-constructable converters\n throw error;\n }\n }\n\n return rawValue as T;\n};\n","/**\r\n * Shared environment detection helpers.\r\n *\r\n * @internal\r\n */\r\n\r\ntype BQueryEnvGlobal = typeof globalThis & {\r\n __BQUERY_DEV__?: boolean;\r\n process?: {\r\n env?: {\r\n NODE_ENV?: string;\r\n };\r\n release?: {\r\n name?: string;\r\n };\r\n versions?: {\r\n node?: string;\r\n };\r\n };\r\n};\r\n\r\n/**\r\n * Returns whether development-only diagnostics should be enabled.\r\n *\r\n * Priority:\r\n * 1. Explicit global override via `globalThis.__BQUERY_DEV__`\r\n * 2. `process.env.NODE_ENV`\r\n * 3. Actual Node-like runtimes without `NODE_ENV` default to development\r\n * 4. Production-safe fallback (`false`)\r\n *\r\n * @internal\r\n */\r\nexport const detectDevEnvironment = (): boolean => {\r\n try {\r\n const globalObject = globalThis as BQueryEnvGlobal;\r\n\r\n if (typeof globalObject.__BQUERY_DEV__ === 'boolean') {\r\n return globalObject.__BQUERY_DEV__;\r\n }\r\n\r\n const nodeEnv = globalObject.process?.env?.NODE_ENV;\r\n if (typeof nodeEnv === 'string') {\r\n return nodeEnv !== 'production';\r\n }\r\n\r\n const nodeVersion = globalObject.process?.versions?.node;\r\n if (typeof nodeVersion === 'string' && nodeVersion.length > 0) {\r\n return true;\r\n }\r\n\r\n const releaseName = globalObject.process?.release?.name;\r\n if (releaseName === 'node' || releaseName === 'io.js') {\r\n return true;\r\n }\r\n\r\n return false;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n","/**\r\n * Component-scoped reactive primitives.\r\n *\r\n * Provides `useSignal`, `useComputed`, and `useEffect` that automatically\r\n * dispose when their owning component disconnects from the DOM.\r\n *\r\n * @module bquery/component\r\n */\r\n\r\nimport type { Computed } from '../reactive/computed';\r\nimport { computed } from '../reactive/computed';\r\nimport { detectDevEnvironment } from '../core/env';\r\nimport type { Signal } from '../reactive/core';\r\nimport { signal } from '../reactive/core';\r\nimport { effect } from '../reactive/effect';\r\nimport type { CleanupFn } from '../reactive/index';\r\n\r\n/**\r\n * Holds disposable resources created inside a component scope.\r\n * All registered disposers run when the component disconnects.\r\n * @internal\r\n */\r\nexport interface ComponentScope {\r\n /** Register a cleanup function to run on dispose */\r\n addDisposer(fn: CleanupFn): void;\r\n /** Dispose all registered resources */\r\n dispose(): void;\r\n}\r\n\r\n/** Currently active component scope. @internal */\r\nlet currentScope: ComponentScope | undefined;\r\n\r\n/**\r\n * Sets the active component scope.\r\n * @internal\r\n */\r\nexport function setCurrentScope(scope: ComponentScope | undefined): ComponentScope | undefined {\r\n const previousScope = currentScope;\r\n currentScope = scope;\r\n return previousScope;\r\n}\r\n\r\n/**\r\n * Returns the active component scope, or undefined if none.\r\n * @internal\r\n */\r\nexport function getCurrentScope(): ComponentScope | undefined {\r\n return currentScope;\r\n}\r\n\r\n/**\r\n * Creates a new component scope that tracks disposable resources.\r\n * @internal\r\n */\r\nexport function createComponentScope(): ComponentScope {\r\n const disposers: CleanupFn[] = [];\r\n\r\n return {\r\n addDisposer(fn: CleanupFn): void {\r\n disposers.push(fn);\r\n },\r\n dispose(): void {\r\n for (const fn of disposers) {\r\n try {\r\n fn();\r\n } catch (error) {\r\n if (\r\n detectDevEnvironment() &&\r\n typeof console !== 'undefined' &&\r\n typeof console.error === 'function'\r\n ) {\r\n console.error('bQuery component: Error disposing scoped resource', error);\r\n }\r\n }\r\n }\r\n disposers.length = 0;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Creates a reactive signal scoped to the current component.\r\n *\r\n * The signal is automatically disposed when the component disconnects\r\n * from the DOM, removing all subscribers and preventing memory leaks.\r\n *\r\n * Must be called during a component lifecycle hook such as `connected`,\r\n * `beforeMount`, `onAdopted`, or `onAttributeChanged`.\r\n *\r\n * Do not create scoped primitives from `render()`. Repeated renders can\r\n * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.\r\n *\r\n * @template T - The type of the signal value\r\n * @param initialValue - The initial value of the signal\r\n * @returns A new Signal instance that auto-disposes with the component\r\n * @throws {Error} If called outside a component scope\r\n *\r\n * @example\r\n * ```ts\r\n * import { component, html, useSignal } from '@bquery/bquery/component';\r\n *\r\n * component('my-counter', {\r\n * connected() {\r\n * const count = useSignal(0);\r\n * // count.dispose() is called automatically on disconnect\r\n * },\r\n * render({ state }) {\r\n * return html`<span>${state.count}</span>`;\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport function useSignal<T>(initialValue: T): Signal<T> {\r\n const scope = currentScope;\r\n if (!scope) {\r\n throw new Error(\r\n 'bQuery component: useSignal() must be called inside a component lifecycle hook. Avoid calling it directly from render()'\r\n );\r\n }\r\n const s = signal(initialValue);\r\n scope.addDisposer(() => s.dispose());\r\n return s;\r\n}\r\n\r\n/**\r\n * Creates a computed value scoped to the current component.\r\n *\r\n * The computed value's internal effect is automatically cleaned up\r\n * when the component disconnects from the DOM.\r\n *\r\n * Must be called during a component lifecycle hook such as `connected`,\r\n * `beforeMount`, `onAdopted`, or `onAttributeChanged`.\r\n *\r\n * Do not create scoped primitives from `render()`. Repeated renders can\r\n * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.\r\n *\r\n * @template T - The type of the computed value\r\n * @param fn - Derivation function that reads reactive sources\r\n * @returns A new Computed instance that auto-cleans-up with the component\r\n * @throws {Error} If called outside a component scope\r\n *\r\n * @example\r\n * ```ts\r\n * import { component, html, useSignal, useComputed } from '@bquery/bquery/component';\r\n *\r\n * component('my-doubler', {\r\n * connected() {\r\n * const count = useSignal(1);\r\n * const doubled = useComputed(() => count.value * 2);\r\n * },\r\n * render({ state }) {\r\n * return html`<span>${state.doubled}</span>`;\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport function useComputed<T>(fn: () => T): Computed<T> {\r\n const scope = currentScope;\r\n if (!scope) {\r\n throw new Error(\r\n 'bQuery component: useComputed() must be called inside a component lifecycle hook. Avoid calling it directly from render()'\r\n );\r\n }\r\n const c = computed(fn);\r\n scope.addDisposer(() => c.dispose());\r\n return c;\r\n}\r\n\r\n/**\r\n * Creates a side effect scoped to the current component.\r\n *\r\n * The effect runs immediately and re-runs when its reactive dependencies\r\n * change. It is automatically disposed when the component disconnects\r\n * from the DOM.\r\n *\r\n * Must be called during a component lifecycle hook such as `connected`,\r\n * `beforeMount`, `onAdopted`, or `onAttributeChanged`.\r\n *\r\n * Do not create scoped primitives from `render()`. Repeated renders can\r\n * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.\r\n *\r\n * @param fn - The effect function; may return a cleanup function\r\n * @returns A cleanup function to manually stop the effect early\r\n * @throws {Error} If called outside a component scope\r\n *\r\n * @example\r\n * ```ts\r\n * import { component, useSignal, useEffect } from '@bquery/bquery/component';\r\n *\r\n * component('my-logger', {\r\n * connected() {\r\n * const count = useSignal(0);\r\n * useEffect(() => {\r\n * console.log('Count changed:', count.value);\r\n * return () => console.log('Cleanup');\r\n * });\r\n * },\r\n * render() { return '<p>Logger</p>'; },\r\n * });\r\n * ```\r\n */\r\nexport function useEffect(fn: () => void | CleanupFn): CleanupFn {\r\n const scope = currentScope;\r\n if (!scope) {\r\n throw new Error(\r\n 'bQuery component: useEffect() must be called inside a component lifecycle hook. Avoid calling it directly from render()'\r\n );\r\n }\r\n const cleanup = effect(fn);\r\n scope.addDisposer(cleanup);\r\n return cleanup;\r\n}\r\n","/**\r\n * Web Component factory and registry.\r\n *\r\n * @module bquery/component\r\n */\r\n\r\nimport type { CleanupFn } from '../reactive/signal';\r\nimport { effect, untrack } from '../reactive/signal';\r\nimport { sanitizeHtml } from '../security/sanitize';\r\nimport { coercePropValue } from './props';\r\nimport { createComponentScope, setCurrentScope, type ComponentScope } from './scope';\r\nimport type {\r\n AttributeChange,\r\n ComponentClass,\r\n ComponentDefinition,\r\n ComponentSignalLike,\r\n ComponentSignals,\r\n ComponentStateShape,\r\n PropDefinition,\r\n ShadowMode,\r\n} from './types';\r\n\r\n/**\r\n * Base extra tags preserved for component shadow DOM renders in addition to the\r\n * global sanitizer defaults. `slot` must remain allowed here because shadow DOM\r\n * content projection depends on authored `<slot>` elements in component render\r\n * output.\r\n */\r\nconst COMPONENT_ALLOWED_TAGS = ['slot'];\r\n\r\n/**\r\n * Base extra attributes preserved for component shadow DOM renders in addition\r\n * to the global sanitizer defaults.\r\n */\r\nconst COMPONENT_ALLOWED_ATTRIBUTES = [\r\n 'part',\r\n // Standard form attributes required by interactive shadow DOM content\r\n 'disabled',\r\n 'checked',\r\n 'placeholder',\r\n 'value',\r\n 'rows',\r\n 'cols',\r\n 'readonly',\r\n 'required',\r\n 'maxlength',\r\n 'minlength',\r\n 'max',\r\n 'min',\r\n 'step',\r\n 'pattern',\r\n 'autocomplete',\r\n 'autofocus',\r\n 'for',\r\n 'multiple',\r\n 'selected',\r\n 'wrap',\r\n];\r\n\r\n/**\r\n * Creates a custom element class for a component definition.\r\n *\r\n * This is useful when you want to extend or register the class manually\r\n * (e.g. with different tag names in tests or custom registries).\r\n *\r\n * @template TProps - Type of the component's props\r\n * @param tagName - The custom element tag name (used for diagnostics)\r\n * @param definition - The component configuration\r\n */\r\nconst createComponentClass = <\r\n TProps extends Record<string, unknown>,\r\n TState extends Record<string, unknown> | undefined = undefined,\r\n TSignals extends ComponentSignals = Record<string, never>,\r\n>(\r\n tagName: string,\r\n definition: ComponentDefinition<TProps, TState, TSignals>\r\n): ComponentClass<TState> => {\r\n const componentAllowedTags = [\r\n ...COMPONENT_ALLOWED_TAGS,\r\n ...(definition.sanitize?.allowTags ?? []),\r\n ];\r\n const componentAllowedAttributes = [\r\n ...COMPONENT_ALLOWED_ATTRIBUTES,\r\n ...(definition.sanitize?.allowAttributes ?? []),\r\n ];\r\n const signalSources = Object.values(definition.signals ?? {}) as ComponentSignalLike<unknown>[];\r\n\r\n /** Resolve the Shadow DOM mode from the `shadow` option. */\r\n const resolveShadowMode = (option: ShadowMode | undefined): 'open' | 'closed' | false => {\r\n if (option === false) return false;\r\n if (option === 'closed') return 'closed';\r\n // true, 'open', or undefined all resolve to 'open'\r\n return 'open';\r\n };\r\n const shadowMode = resolveShadowMode(definition.shadow);\r\n\r\n /**\r\n * Merges prop-derived observed attributes with any extra attributes from\r\n * `observeAttributes`, deduplicating to avoid redundant callbacks.\r\n */\r\n const observedAttrs = Array.from(\r\n new Set([...Object.keys(definition.props ?? {}), ...(definition.observeAttributes ?? [])])\r\n );\r\n\r\n class BQueryComponent extends HTMLElement {\r\n /** Internal state object for the component */\r\n private readonly state: ComponentStateShape<TState> = {\r\n ...(definition.state ?? {}),\r\n } as ComponentStateShape<TState>;\r\n /** Typed props object populated from attributes */\r\n private props = {} as TProps;\r\n /** Tracks missing required props for validation during connectedCallback */\r\n private missingRequiredProps = new Set<string>();\r\n /** Tracks whether the component has completed its initial mount */\r\n private hasMounted = false;\r\n /** Cleanup for external signal subscriptions */\r\n private signalEffectCleanup?: CleanupFn;\r\n /** Component-scoped reactive resource tracker */\r\n private scope?: ComponentScope;\r\n /** Render target for open/closed shadow roots or the host element when shadow DOM is disabled */\r\n private readonly renderRootNode: HTMLElement | ShadowRoot;\r\n\r\n constructor() {\r\n super();\r\n if (shadowMode !== false) {\r\n this.renderRootNode = this.attachShadow({ mode: shadowMode });\r\n } else {\r\n this.renderRootNode = this;\r\n }\r\n this.syncProps();\r\n }\r\n\r\n /**\r\n * Returns the list of attributes to observe for changes.\r\n */\r\n static get observedAttributes(): string[] {\r\n return observedAttrs;\r\n }\r\n\r\n /**\r\n * Called when the element is added to the DOM.\r\n */\r\n connectedCallback(): void {\r\n try {\r\n // Defer only the initial mount until all required props are present.\r\n // Already-mounted components must still reconnect their signal\r\n // subscriptions so reactive updates can resume after reattachment.\r\n if (!this.hasMounted && this.missingRequiredProps.size > 0) {\r\n // Component will mount once all required props are satisfied\r\n // via attributeChangedCallback\r\n return;\r\n }\r\n if (this.hasMounted) {\r\n // Recreate scope for reconnected component\r\n this.scope = createComponentScope();\r\n const previousScope = setCurrentScope(this.scope);\r\n try {\r\n definition.connected?.call(this);\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n } finally {\r\n setCurrentScope(previousScope);\r\n }\r\n this.setupSignalSubscriptions(true);\r\n return;\r\n }\r\n this.mount();\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Performs the initial mount of the component.\r\n * Called when the element is connected and all required props are present.\r\n * @internal\r\n */\r\n private mount(): void {\r\n if (this.hasMounted) return;\r\n const previousScope = setCurrentScope(this.ensureScope());\r\n let hookError = false;\r\n try {\r\n definition.beforeMount?.call(this);\r\n definition.connected?.call(this);\r\n } catch (error) {\r\n hookError = true;\r\n this.handleError(error as Error);\r\n } finally {\r\n setCurrentScope(previousScope);\r\n }\r\n if (hookError) {\r\n this.scope?.dispose();\r\n this.scope = undefined;\r\n return;\r\n }\r\n this.render();\r\n this.setupSignalSubscriptions();\r\n this.hasMounted = true;\r\n }\r\n\r\n /**\r\n * Called when the element is removed from the DOM.\r\n */\r\n disconnectedCallback(): void {\r\n try {\r\n this.signalEffectCleanup?.();\r\n this.signalEffectCleanup = undefined;\r\n // Dispose all scoped reactive resources (useSignal, useComputed, useEffect)\r\n this.scope?.dispose();\r\n this.scope = undefined;\r\n definition.disconnected?.call(this);\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Called when an observed attribute changes.\r\n */\r\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\r\n try {\r\n const previousProps = this.cloneProps();\r\n this.syncProps();\r\n\r\n // Fire the user-facing onAttributeChanged hook for every observed attribute change\r\n if (definition.onAttributeChanged) {\r\n const previousScope = setCurrentScope(this.ensureScope());\r\n try {\r\n definition.onAttributeChanged.call(this, name, oldValue, newValue);\r\n } finally {\r\n setCurrentScope(previousScope);\r\n }\r\n }\r\n\r\n if (this.hasMounted) {\r\n // Component already mounted - trigger update render\r\n this.render(true, previousProps, { name, oldValue, newValue });\r\n } else if (this.isConnected && this.missingRequiredProps.size === 0) {\r\n // All required props are now satisfied and element is connected\r\n // Trigger the deferred initial mount\r\n this.mount();\r\n }\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Called when the element is moved to a new document (e.g. via `document.adoptNode`).\r\n */\r\n adoptedCallback(): void {\r\n if (!definition.onAdopted) {\r\n return;\r\n }\r\n\r\n const previousScope = setCurrentScope(this.ensureScope());\r\n try {\r\n definition.onAdopted.call(this);\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n } finally {\r\n setCurrentScope(previousScope);\r\n }\r\n }\r\n\r\n /**\r\n * Handles errors during component lifecycle.\r\n * @internal\r\n */\r\n private handleError(error: Error): void {\r\n if (definition.onError) {\r\n definition.onError.call(this, error);\r\n } else {\r\n console.error(`bQuery component error in <${tagName}>:`, error);\r\n }\r\n }\r\n\r\n /**\r\n * Ensures the component has an active scope for scoped reactive primitives.\r\n * @internal\r\n */\r\n private ensureScope(): ComponentScope {\r\n return (this.scope ??= createComponentScope());\r\n }\r\n\r\n /**\r\n * Updates a state property and triggers a re-render.\r\n *\r\n * @param key - The state property key\r\n * @param value - The new value\r\n */\r\n setState<TKey extends keyof ComponentStateShape<TState>>(\r\n key: TKey,\r\n value: ComponentStateShape<TState>[TKey]\r\n ): void {\r\n this.state[key] = value;\r\n this.render(true, this.cloneProps(), undefined, false);\r\n }\r\n\r\n /**\r\n * Gets a state property value.\r\n *\r\n * @param key - The state property key\r\n * @returns The current value\r\n */\r\n getState<TKey extends keyof ComponentStateShape<TState>>(\r\n key: TKey\r\n ): ComponentStateShape<TState>[TKey];\r\n getState<TResult = unknown>(key: string): TResult;\r\n getState(key: string): unknown {\r\n return (this.state as Record<string, unknown>)[key];\r\n }\r\n\r\n /**\r\n * Subscribes to declared reactive sources and re-renders on change.\r\n *\r\n * @param renderOnInitialRun - When true, immediately re-renders after\r\n * re-subscribing so detached components resync with any signal changes\r\n * that happened while they were disconnected.\r\n * @internal\r\n */\r\n private setupSignalSubscriptions(renderOnInitialRun = false): void {\r\n if (this.signalEffectCleanup || signalSources.length === 0) return;\r\n\r\n let isInitialRun = true;\r\n this.signalEffectCleanup = effect(() => {\r\n try {\r\n for (const source of signalSources) {\r\n // Intentionally read each source to register this effect as a subscriber.\r\n void source.value;\r\n }\r\n\r\n if (isInitialRun) {\r\n isInitialRun = false;\r\n if (renderOnInitialRun && this.hasMounted && this.isConnected) {\r\n // Signal-driven reconnect renders do not change props, so the\r\n // previous-props snapshot is the current prop set at reconnect time.\r\n const previousProps = this.cloneProps();\r\n untrack(() => {\r\n this.render(true, previousProps, undefined, false);\r\n });\r\n }\r\n return;\r\n }\r\n\r\n if (!this.hasMounted || !this.isConnected) return;\r\n\r\n // Signal updates leave props unchanged, so cloning the current props\r\n // provides the previous-props snapshot expected by beforeUpdate().\r\n const previousProps = this.cloneProps();\r\n untrack(() => {\r\n this.render(true, previousProps, undefined, false);\r\n });\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Synchronizes props from attributes.\r\n * @internal\r\n */\r\n private syncProps(): void {\r\n const props = definition.props ?? {};\r\n for (const [key, config] of Object.entries(props) as [string, PropDefinition][]) {\r\n const attrValue = this.getAttribute(key);\r\n let value: unknown;\r\n\r\n if (attrValue == null) {\r\n if (config.required && config.default === undefined) {\r\n // Mark as missing instead of throwing - validate during connectedCallback\r\n this.missingRequiredProps.add(key);\r\n value = undefined;\r\n } else {\r\n value = config.default ?? undefined;\r\n }\r\n } else {\r\n // Attribute is present, remove from missing set if it was there\r\n if (this.missingRequiredProps.has(key)) {\r\n this.missingRequiredProps.delete(key);\r\n }\r\n value = coercePropValue(attrValue, config);\r\n }\r\n\r\n if (config.validator && value !== undefined) {\r\n const isValid = config.validator(value);\r\n if (!isValid) {\r\n throw new Error(\r\n `bQuery component: validation failed for prop \"${key}\" with value ${JSON.stringify(value)}`\r\n );\r\n }\r\n }\r\n\r\n (this.props as Record<string, unknown>)[key] = value;\r\n }\r\n }\r\n\r\n /**\r\n * Creates a shallow snapshot of the current props for lifecycle diffing.\r\n * A shallow copy is sufficient because component props are re-derived from\r\n * reflected attributes on each update, so nested object mutation is not\r\n * tracked as part of this lifecycle diff.\r\n * @internal\r\n */\r\n private cloneProps(): TProps {\r\n return { ...(this.props as Record<string, unknown>) } as TProps;\r\n }\r\n\r\n /**\r\n * Renders the component to its shadow root or host element.\r\n * @internal\r\n */\r\n private render(): void;\r\n private render(triggerUpdated: true, oldProps: TProps, change?: AttributeChange): void;\r\n private render(\r\n triggerUpdated: true,\r\n oldProps: TProps,\r\n change: AttributeChange | undefined,\r\n runBeforeUpdate: boolean\r\n ): void;\r\n private render(\r\n triggerUpdated = false,\r\n oldProps?: TProps,\r\n change?: AttributeChange,\r\n runBeforeUpdate = true\r\n ): void {\r\n try {\r\n if (triggerUpdated && runBeforeUpdate && definition.beforeUpdate) {\r\n if (!oldProps) {\r\n throw new Error('bQuery component: previous props are required for update renders');\r\n }\r\n const shouldUpdate = definition.beforeUpdate.call(this, this.props, oldProps);\r\n if (shouldUpdate === false) return;\r\n }\r\n\r\n const emit = (event: string, detail?: unknown): void => {\r\n this.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, composed: true }));\r\n };\r\n\r\n const renderRoot = this.renderRootNode;\r\n\r\n const markup = definition.render({\r\n props: this.props,\r\n state: this.state,\r\n signals: (definition.signals ?? {}) as TSignals,\r\n emit,\r\n });\r\n\r\n // Component render output is authored by the component definition itself,\r\n // so we can explicitly preserve shadow-DOM-specific markup such as <slot>,\r\n // the stylistic `part` attribute, and standard form/input attributes without\r\n // relaxing the global DOM sanitization rules.\r\n const sanitizedMarkup = sanitizeHtml(markup, {\r\n allowTags: componentAllowedTags,\r\n allowAttributes: componentAllowedAttributes,\r\n });\r\n let existingStyleElement: HTMLStyleElement | null = null;\r\n if (definition.styles) {\r\n existingStyleElement = renderRoot.querySelector<HTMLStyleElement>(\r\n 'style[data-bquery-component-style]'\r\n );\r\n }\r\n\r\n renderRoot.innerHTML = sanitizedMarkup;\r\n\r\n if (definition.styles) {\r\n const styleElement = existingStyleElement ?? document.createElement('style');\r\n if (!existingStyleElement) {\r\n styleElement.setAttribute('data-bquery-component-style', '');\r\n }\r\n styleElement.textContent = definition.styles;\r\n renderRoot.prepend(styleElement);\r\n }\r\n\r\n if (triggerUpdated) {\r\n definition.updated?.call(this, change);\r\n }\r\n } catch (error) {\r\n this.handleError(error as Error);\r\n }\r\n }\r\n }\r\n\r\n return BQueryComponent as ComponentClass<TState>;\r\n};\r\n\r\n/**\r\n * Creates a custom element class for a component definition.\r\n *\r\n * This is useful when you want to extend or register the class manually\r\n * (e.g. with different tag names in tests or custom registries).\r\n *\r\n * @template TProps - Type of the component's props\r\n * @template TState - Type of the component's internal state. When provided,\r\n * `definition.state` is required, `render({ state })` is strongly typed, and\r\n * returned instances expose typed `getState()` / `setState()` helpers.\r\n * @param tagName - The custom element tag name (used for diagnostics)\r\n * @param definition - The component configuration\r\n */\r\nexport function defineComponent<\r\n TProps extends Record<string, unknown>,\r\n TSignals extends ComponentSignals = Record<string, never>,\r\n>(\r\n tagName: string,\r\n definition: ComponentDefinition<TProps, undefined, TSignals>\r\n): ComponentClass<undefined>;\r\nexport function defineComponent<\r\n TProps extends Record<string, unknown>,\r\n TState extends Record<string, unknown>,\r\n TSignals extends ComponentSignals = Record<string, never>,\r\n>(\r\n tagName: string,\r\n definition: ComponentDefinition<TProps, TState, TSignals>\r\n): ComponentClass<TState>;\r\nexport function defineComponent<\r\n TProps extends Record<string, unknown>,\r\n TState extends Record<string, unknown> | undefined = undefined,\r\n TSignals extends ComponentSignals = Record<string, never>,\r\n>(\r\n tagName: string,\r\n definition: ComponentDefinition<TProps, TState, TSignals>\r\n): ComponentClass<TState> {\r\n return createComponentClass(tagName, definition);\r\n}\r\n\r\n/**\r\n * Defines and registers a custom Web Component.\r\n *\r\n * This function creates a new custom element with the given tag name\r\n * and configuration. The component uses Shadow DOM for encapsulation\r\n * and automatically re-renders when observed attributes change.\r\n *\r\n * @template TProps - Type of the component's props\r\n * @template TState - Type of the component's internal state. When provided,\r\n * `definition.state` is required and lifecycle hooks receive typed state\r\n * helpers via `this.getState()` / `this.setState()`.\r\n * @param tagName - The custom element tag name (must contain a hyphen)\r\n * @param definition - The component configuration\r\n *\r\n * @example\r\n * ```ts\r\n * component<{ start: number }, { count: number }>('counter-button', {\r\n * props: {\r\n * start: { type: Number, default: 0 },\r\n * },\r\n * state: { count: 0 },\r\n * styles: `\r\n * button { padding: 0.5rem 1rem; }\r\n * `,\r\n * connected() {\r\n * // Use event delegation on shadow root so handler survives re-renders\r\n * const handleClick = (event: Event) => {\r\n * const target = event.target as HTMLElement | null;\r\n * if (target?.matches('button')) {\r\n * this.setState('count', this.getState('count') + 1);\r\n * }\r\n * };\r\n * this.shadowRoot?.addEventListener('click', handleClick);\r\n * // Store handler for cleanup\r\n * (this as any)._handleClick = handleClick;\r\n * },\r\n * disconnected() {\r\n * // Clean up event listener to prevent memory leaks\r\n * const handleClick = (this as any)._handleClick;\r\n * if (handleClick) {\r\n * this.shadowRoot?.removeEventListener('click', handleClick);\r\n * }\r\n * },\r\n * render({ props, state }) {\r\n * return html`\r\n * <button>\r\n * Count: ${state.count}\r\n * </button>\r\n * `;\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport function component<\r\n TProps extends Record<string, unknown>,\r\n TSignals extends ComponentSignals = Record<string, never>,\r\n>(tagName: string, definition: ComponentDefinition<TProps, undefined, TSignals>): void;\r\nexport function component<\r\n TProps extends Record<string, unknown>,\r\n TState extends Record<string, unknown>,\r\n TSignals extends ComponentSignals = Record<string, never>,\r\n>(tagName: string, definition: ComponentDefinition<TProps, TState, TSignals>): void;\r\nexport function component<\r\n TProps extends Record<string, unknown>,\r\n TState extends Record<string, unknown> | undefined = undefined,\r\n TSignals extends ComponentSignals = Record<string, never>,\r\n>(tagName: string, definition: ComponentDefinition<TProps, TState, TSignals>): void {\r\n const elementClass = createComponentClass(tagName, definition);\r\n\r\n if (!customElements.get(tagName)) {\r\n customElements.define(tagName, elementClass);\r\n }\r\n}\r\n","import {\r\n isTrustedHtml,\r\n type SanitizedHtml,\r\n toSanitizedHtml,\r\n unwrapTrustedHtml,\r\n} from '../security/trusted-html';\r\nconst BOOLEAN_ATTRIBUTE_MARKER: unique symbol = Symbol('bquery.booleanAttribute');\r\nconst BOOLEAN_ATTRIBUTE_NAME = /^[^\\0-\\x20\"'/>=]+$/;\r\n\r\n/**\r\n * Public shape of a boolean HTML attribute created by {@link bool}.\r\n *\r\n * This type is returned from {@link bool} and can be interpolated into\r\n * {@link html} / {@link safeHtml} templates to conditionally include or omit\r\n * an attribute by name. The internal marker property used for runtime checks\r\n * remains private and is not part of the public API.\r\n *\r\n * @example\r\n * ```ts\r\n * const disabled = bool('disabled', isDisabled);\r\n * const button = html`<button ${disabled}>Click</button>`;\r\n * ```\r\n */\r\nexport interface BooleanAttribute {\r\n readonly enabled: boolean;\r\n readonly name: string;\r\n}\r\n\r\ninterface BooleanAttributeValue extends BooleanAttribute {\r\n readonly [BOOLEAN_ATTRIBUTE_MARKER]: true;\r\n}\r\n\r\nconst isBooleanAttributeValue = (value: unknown): value is BooleanAttributeValue => {\r\n if (typeof value !== 'object' || value === null) {\r\n return false;\r\n }\r\n\r\n const candidate = value as Partial<BooleanAttributeValue>;\r\n return (\r\n candidate[BOOLEAN_ATTRIBUTE_MARKER] === true &&\r\n typeof candidate.enabled === 'boolean' &&\r\n typeof candidate.name === 'string'\r\n );\r\n};\r\n\r\nconst stringifyTemplateValue = (value: unknown): string => {\r\n if (isBooleanAttributeValue(value)) {\r\n return value.enabled ? value.name : '';\r\n }\r\n\r\n return String(value ?? '');\r\n};\r\n\r\nconst escapeMap: Record<string, string> = {\r\n '&': '&amp;',\r\n '<': '&lt;',\r\n '>': '&gt;',\r\n '\"': '&quot;',\r\n \"'\": '&#x27;',\r\n '`': '&#x60;',\r\n};\r\n\r\nconst escapeTemplateValue = (value: unknown): string => {\r\n if (isBooleanAttributeValue(value)) {\r\n return value.enabled ? value.name : '';\r\n }\r\n\r\n return stringifyTemplateValue(value).replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\r\n};\r\n\r\n/**\r\n * Creates a boolean-attribute marker for the {@link html} and {@link safeHtml} template tags.\r\n *\r\n * When the condition is truthy, the attribute name is rendered without a value.\r\n * When the condition is falsy, an empty string is rendered and any surrounding\r\n * template-literal whitespace is preserved.\r\n *\r\n * @param name - HTML attribute name to emit\r\n * @param enabled - Whether the boolean attribute should be present\r\n * @returns Internal marker consumed by template tags\r\n *\r\n * @example\r\n * ```ts\r\n * html`<button ${bool('disabled', isDisabled)}>Save</button>`;\r\n * // Result when isDisabled = true: '<button disabled>Save</button>'\r\n * ```\r\n */\r\nexport const bool = (name: string, enabled: unknown): BooleanAttribute => {\r\n if (!BOOLEAN_ATTRIBUTE_NAME.test(name)) {\r\n throw new TypeError(`Invalid boolean attribute name: ${name}`);\r\n }\r\n\r\n const attribute: BooleanAttributeValue = {\r\n [BOOLEAN_ATTRIBUTE_MARKER]: true,\r\n enabled: Boolean(enabled),\r\n name,\r\n };\r\n\r\n return Object.freeze(attribute);\r\n};\r\n\r\n/**\r\n * Tagged template literal for creating HTML strings.\r\n *\r\n * This function handles interpolation of values into HTML templates,\r\n * converting null/undefined to empty strings.\r\n *\r\n * @param strings - Template literal string parts\r\n * @param values - Interpolated values\r\n * @returns Combined HTML string\r\n *\r\n * @example\r\n * ```ts\r\n * const name = 'World';\r\n * const greeting = html`<h1>Hello, ${name}!</h1>`;\r\n * // Result: '<h1>Hello, World!</h1>'\r\n * ```\r\n */\r\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): string => {\r\n return strings.reduce(\r\n (acc, part, index) => `${acc}${part}${stringifyTemplateValue(values[index])}`,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Escapes HTML entities in interpolated values for XSS prevention.\r\n * Use this when you need to safely embed user content in templates.\r\n *\r\n * @param strings - Template literal string parts\r\n * @param values - Interpolated values to escape\r\n * @returns Branded escaped HTML string safe for bQuery template composition\r\n *\r\n * @example\r\n * ```ts\r\n * const userInput = '<script>alert(\"xss\")</script>';\r\n * const safe = safeHtml`<div>${userInput}</div>`;\r\n * // Result: '<div>&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;</div>'\r\n * ```\r\n */\r\nexport const safeHtml = (strings: TemplateStringsArray, ...values: unknown[]): SanitizedHtml => {\r\n const escape = (value: unknown): string => {\r\n if (isTrustedHtml(value)) return unwrapTrustedHtml(value);\r\n return escapeTemplateValue(value);\r\n };\r\n\r\n return toSanitizedHtml(\r\n strings.reduce(\r\n (acc, part, index) => `${acc}${part}${index < values.length ? escape(values[index]) : ''}`,\r\n ''\r\n )\r\n );\r\n};\r\n","/**\r\n * Default component library based on native Web Components.\r\n *\r\n * @module bquery/component\r\n */\r\n\r\nimport { getBqueryConfig } from '../platform/config';\r\nimport { escapeHtml } from '../security';\r\nimport { component } from './component';\r\nimport { html } from './html';\r\n\r\n/** Options for registering the default component library. */\r\nexport interface DefaultComponentLibraryOptions {\r\n /** Prefix used for all registered component tags. Defaults to `bq`. */\r\n prefix?: string;\r\n}\r\n\r\n/** Tag names returned by registerDefaultComponents(). */\r\nexport interface RegisteredDefaultComponents {\r\n /** Button component tag name. */\r\n button: string;\r\n /** Card component tag name. */\r\n card: string;\r\n /** Input component tag name. */\r\n input: string;\r\n /** Textarea component tag name. */\r\n textarea: string;\r\n /** Checkbox component tag name. */\r\n checkbox: string;\r\n}\r\n\r\nconst baseStyles = `\r\n :host {\r\n color: inherit;\r\n font: inherit;\r\n }\r\n`;\r\n\r\nconst controlStyles = `\r\n ${baseStyles}\r\n .field {\r\n display: inline-flex;\r\n flex-direction: column;\r\n gap: 0.375rem;\r\n width: 100%;\r\n }\r\n .label {\r\n color: #334155;\r\n font-size: 0.875rem;\r\n font-weight: 600;\r\n }\r\n .control {\r\n border: 1px solid #cbd5e1;\r\n border-radius: 0.75rem;\r\n box-sizing: border-box;\r\n font: inherit;\r\n min-height: 2.75rem;\r\n outline: none;\r\n padding: 0.75rem 0.875rem;\r\n width: 100%;\r\n background: #fff;\r\n color: #0f172a;\r\n transition: border-color 160ms ease, box-shadow 160ms ease;\r\n }\r\n .control:focus {\r\n border-color: #2563eb;\r\n box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);\r\n }\r\n .control:disabled {\r\n background: #f8fafc;\r\n color: #94a3b8;\r\n cursor: not-allowed;\r\n }\r\n`;\r\n\r\nconst escapeProp = (value: string): string => escapeHtml(value);\r\n\r\nconst handlerStore = new WeakMap<HTMLElement, Record<string, EventListener>>();\r\n\r\nconst readHandler = (element: HTMLElement, key: string): EventListener | undefined => {\r\n return handlerStore.get(element)?.[key];\r\n};\r\n\r\nconst storeHandler = (element: HTMLElement, key: string, value: EventListener): void => {\r\n const handlers = handlerStore.get(element) ?? {};\r\n handlers[key] = value;\r\n handlerStore.set(element, handlers);\r\n};\r\n\r\n/**\r\n * Detect a value-only input update, patch the live control in place, and\r\n * return whether the component can skip a full shadow DOM re-render.\r\n *\r\n * @param element - The host custom element whose shadow DOM is being updated\r\n * @param newProps - The next reflected input props for the pending update\r\n * @param oldProps - The previous reflected input props from the last render\r\n */\r\nconst canSkipInputRender = (\r\n element: HTMLElement,\r\n newProps: {\r\n label: string;\r\n type: string;\r\n value: string;\r\n placeholder: string;\r\n name: string;\r\n disabled: boolean;\r\n },\r\n oldProps: {\r\n label: string;\r\n type: string;\r\n value: string;\r\n placeholder: string;\r\n name: string;\r\n disabled: boolean;\r\n }\r\n): boolean => {\r\n if (oldProps.label !== newProps.label) return false;\r\n if (oldProps.type !== newProps.type) return false;\r\n if (oldProps.placeholder !== newProps.placeholder) return false;\r\n if (oldProps.name !== newProps.name) return false;\r\n if (oldProps.disabled !== newProps.disabled) return false;\r\n\r\n // Verify shadow DOM still matches expected non-value props before skipping re-render\r\n const shadowRoot = element.shadowRoot;\r\n if (!shadowRoot) return false;\r\n\r\n const labelEl = shadowRoot.querySelector('.label');\r\n if ((labelEl?.textContent ?? '') !== newProps.label) return false;\r\n\r\n const control = shadowRoot.querySelector('input.control') as HTMLInputElement | null;\r\n if (!control) return false;\r\n\r\n if (control.type !== newProps.type) return false;\r\n if (control.placeholder !== newProps.placeholder) return false;\r\n if (control.name !== newProps.name) return false;\r\n if (control.disabled !== newProps.disabled) return false;\r\n\r\n if (control.value !== newProps.value) {\r\n control.value = newProps.value;\r\n }\r\n\r\n return true;\r\n};\r\n\r\n/**\r\n * Detect a value-only textarea update, patch the live control in place, and\r\n * return whether the component can skip a full shadow DOM re-render.\r\n *\r\n * @param element - The host custom element whose shadow DOM is being updated\r\n * @param newProps - The next reflected textarea props for the pending update\r\n * @param oldProps - The previous reflected textarea props from the last render\r\n */\r\nconst canSkipTextareaRender = (\r\n element: HTMLElement,\r\n newProps: {\r\n label: string;\r\n value: string;\r\n placeholder: string;\r\n name: string;\r\n rows: number;\r\n disabled: boolean;\r\n },\r\n oldProps: {\r\n label: string;\r\n value: string;\r\n placeholder: string;\r\n name: string;\r\n rows: number;\r\n disabled: boolean;\r\n }\r\n): boolean => {\r\n if (oldProps.label !== newProps.label) return false;\r\n if (oldProps.placeholder !== newProps.placeholder) return false;\r\n if (oldProps.name !== newProps.name) return false;\r\n if (oldProps.rows !== newProps.rows) return false;\r\n if (oldProps.disabled !== newProps.disabled) return false;\r\n\r\n // Verify shadow DOM still matches expected non-value props before skipping re-render\r\n const shadowRoot = element.shadowRoot;\r\n if (!shadowRoot) return false;\r\n\r\n const labelEl = shadowRoot.querySelector('.label');\r\n if ((labelEl?.textContent ?? '') !== newProps.label) return false;\r\n\r\n const control = shadowRoot.querySelector(\r\n 'textarea.control'\r\n ) as HTMLTextAreaElement | null;\r\n if (!control) return false;\r\n\r\n if (control.placeholder !== newProps.placeholder) return false;\r\n if (control.name !== newProps.name) return false;\r\n if (Number(control.rows) !== newProps.rows) return false;\r\n if (control.disabled !== newProps.disabled) return false;\r\n\r\n if (control.value !== newProps.value) {\r\n control.value = newProps.value;\r\n }\r\n return true;\r\n};\r\n\r\nconst renderTextareaControl = (props: {\r\n value: string;\r\n placeholder: string;\r\n name: string;\r\n rows: number;\r\n disabled: boolean;\r\n}): string => {\r\n return [\r\n '<textarea',\r\n ' part=\"control\"',\r\n ' class=\"control\"',\r\n ` placeholder=\"${escapeProp(props.placeholder)}\"`,\r\n ` name=\"${escapeProp(props.name)}\"`,\r\n ` rows=\"${props.rows}\"`,\r\n props.disabled ? ' disabled' : '',\r\n `>${escapeProp(props.value)}</textarea>`,\r\n ].join('');\r\n};\r\n\r\n/**\r\n * Register a default set of foundational UI components.\r\n *\r\n * The library is intentionally small and dependency-free, providing common\r\n * primitives that can be themed via shadow parts and CSS custom properties.\r\n *\r\n * @param options - Optional registration settings such as a custom tag prefix\r\n * @returns The registered tag names for each component\r\n */\r\nexport const registerDefaultComponents = (\r\n options: DefaultComponentLibraryOptions = {}\r\n): RegisteredDefaultComponents => {\r\n const prefix = options.prefix ?? getBqueryConfig().components?.prefix ?? 'bq';\r\n const tags: RegisteredDefaultComponents = {\r\n button: `${prefix}-button`,\r\n card: `${prefix}-card`,\r\n input: `${prefix}-input`,\r\n textarea: `${prefix}-textarea`,\r\n checkbox: `${prefix}-checkbox`,\r\n };\r\n\r\n component<{\r\n label: string;\r\n variant: string;\r\n size: string;\r\n type: string;\r\n disabled: boolean;\r\n }>(tags.button, {\r\n props: {\r\n label: { type: String, default: '' },\r\n variant: { type: String, default: 'primary' },\r\n size: { type: String, default: 'md' },\r\n type: { type: String, default: 'button' },\r\n disabled: { type: Boolean, default: false },\r\n },\r\n styles: `\r\n ${baseStyles}\r\n button {\r\n appearance: none;\r\n border: 0;\r\n border-radius: 999px;\r\n cursor: pointer;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n font: inherit;\r\n font-weight: 600;\r\n gap: 0.5rem;\r\n min-height: 2.5rem;\r\n padding: 0.65rem 1rem;\r\n transition: transform 160ms ease, opacity 160ms ease, background 160ms ease;\r\n background: #2563eb;\r\n color: #fff;\r\n }\r\n button[data-variant='secondary'] {\r\n background: #e2e8f0;\r\n color: #0f172a;\r\n }\r\n button[data-size='sm'] {\r\n min-height: 2.125rem;\r\n padding: 0.5rem 0.875rem;\r\n }\r\n button[data-size='lg'] {\r\n min-height: 3rem;\r\n padding: 0.875rem 1.25rem;\r\n }\r\n button:hover:not(:disabled) {\r\n transform: translateY(-1px);\r\n }\r\n button:disabled {\r\n cursor: not-allowed;\r\n opacity: 0.6;\r\n }\r\n `,\r\n render: ({ props }) => html`\r\n <button\r\n part=\"button\"\r\n type=\"${escapeProp(props.type)}\"\r\n data-variant=\"${escapeProp(props.variant)}\"\r\n data-size=\"${escapeProp(props.size)}\"\r\n ${props.disabled ? 'disabled' : ''}\r\n >\r\n <slot>${escapeProp(props.label)}</slot>\r\n </button>\r\n `,\r\n });\r\n\r\n component<{ title: string; footer: string; elevated: boolean }>(tags.card, {\r\n props: {\r\n title: { type: String, default: '' },\r\n footer: { type: String, default: '' },\r\n elevated: { type: Boolean, default: true },\r\n },\r\n styles: `\r\n ${baseStyles}\r\n article {\r\n background: #fff;\r\n border: 1px solid #e2e8f0;\r\n border-radius: 1rem;\r\n box-shadow: 0 10px 25px rgba(15, 23, 42, 0.08);\r\n color: #0f172a;\r\n display: block;\r\n padding: 1rem;\r\n }\r\n article[data-elevated='false'] {\r\n box-shadow: none;\r\n }\r\n header, footer {\r\n color: #475569;\r\n font-size: 0.95rem;\r\n font-weight: 600;\r\n }\r\n header {\r\n margin-bottom: 0.75rem;\r\n }\r\n footer {\r\n margin-top: 0.75rem;\r\n }\r\n `,\r\n render: ({ props }) => html`\r\n <article part=\"card\" data-elevated=\"${String(props.elevated)}\">\r\n ${props.title ? `<header part=\"header\">${escapeProp(props.title)}</header>` : ''}\r\n <section part=\"body\"><slot></slot></section>\r\n ${props.footer ? `<footer part=\"footer\">${escapeProp(props.footer)}</footer>` : ''}\r\n </article>\r\n `,\r\n });\r\n\r\n component<{\r\n label: string;\r\n type: string;\r\n value: string;\r\n placeholder: string;\r\n name: string;\r\n disabled: boolean;\r\n }>(tags.input, {\r\n props: {\r\n label: { type: String, default: '' },\r\n type: { type: String, default: 'text' },\r\n value: { type: String, default: '' },\r\n placeholder: { type: String, default: '' },\r\n name: { type: String, default: '' },\r\n disabled: { type: Boolean, default: false },\r\n },\r\n styles: controlStyles,\r\n /**\r\n * Skip the full shadow DOM re-render when only the reflected input value\r\n * changed, because the live control has already been patched in place.\r\n */\r\n beforeUpdate(newProps, oldProps) {\r\n if (canSkipInputRender(this, newProps, oldProps)) {\r\n return false;\r\n }\r\n return true;\r\n },\r\n connected() {\r\n const handleInput = (event: Event) => {\r\n const target = event.target as HTMLInputElement | null;\r\n if (!target?.matches('input')) return;\r\n event.stopPropagation();\r\n this.setAttribute('value', target.value);\r\n this.dispatchEvent(\r\n new CustomEvent('input', {\r\n detail: { value: target.value },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n };\r\n storeHandler(this, '__bqueryInputHandler', handleInput);\r\n this.shadowRoot?.addEventListener('input', handleInput);\r\n },\r\n disconnected() {\r\n const handleInput = readHandler(this, '__bqueryInputHandler');\r\n if (handleInput) {\r\n this.shadowRoot?.removeEventListener('input', handleInput);\r\n }\r\n },\r\n render: ({ props }) => html`\r\n <label part=\"field\" class=\"field\">\r\n ${props.label ? `<span part=\"label\" class=\"label\">${escapeProp(props.label)}</span>` : ''}\r\n <input\r\n part=\"control\"\r\n class=\"control\"\r\n type=\"${escapeProp(props.type)}\"\r\n value=\"${escapeProp(props.value)}\"\r\n placeholder=\"${escapeProp(props.placeholder)}\"\r\n name=\"${escapeProp(props.name)}\"\r\n ${props.disabled ? 'disabled' : ''}\r\n />\r\n </label>\r\n `,\r\n });\r\n\r\n component<{\r\n label: string;\r\n value: string;\r\n placeholder: string;\r\n name: string;\r\n rows: number;\r\n disabled: boolean;\r\n }>(tags.textarea, {\r\n props: {\r\n label: { type: String, default: '' },\r\n value: { type: String, default: '' },\r\n placeholder: { type: String, default: '' },\r\n name: { type: String, default: '' },\r\n rows: { type: Number, default: 4 },\r\n disabled: { type: Boolean, default: false },\r\n },\r\n styles: `${controlStyles}\r\n textarea.control {\r\n min-height: 6rem;\r\n resize: vertical;\r\n }\r\n `,\r\n /**\r\n * Skip the full shadow DOM re-render when only the reflected textarea value\r\n * changed, because the live control has already been patched in place.\r\n */\r\n beforeUpdate(newProps, oldProps) {\r\n if (canSkipTextareaRender(this, newProps, oldProps)) {\r\n return false;\r\n }\r\n return true;\r\n },\r\n connected() {\r\n const handleInput = (event: Event) => {\r\n const target = event.target as HTMLTextAreaElement | null;\r\n if (!target?.matches('textarea')) return;\r\n event.stopPropagation();\r\n this.setAttribute('value', target.value);\r\n this.dispatchEvent(\r\n new CustomEvent('input', {\r\n detail: { value: target.value },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n };\r\n storeHandler(this, '__bqueryTextareaHandler', handleInput);\r\n this.shadowRoot?.addEventListener('input', handleInput);\r\n },\r\n disconnected() {\r\n const handleInput = readHandler(this, '__bqueryTextareaHandler');\r\n if (handleInput) {\r\n this.shadowRoot?.removeEventListener('input', handleInput);\r\n }\r\n },\r\n render: ({ props }) => html`\r\n <label part=\"field\" class=\"field\">\r\n ${props.label ? `<span part=\"label\" class=\"label\">${escapeProp(props.label)}</span>` : ''}\r\n ${renderTextareaControl(props)}\r\n </label>\r\n `,\r\n });\r\n\r\n component<{ label: string; checked: boolean; disabled: boolean }>(tags.checkbox, {\r\n props: {\r\n label: { type: String, default: '' },\r\n checked: { type: Boolean, default: false },\r\n disabled: { type: Boolean, default: false },\r\n },\r\n styles: `\r\n ${baseStyles}\r\n label {\r\n align-items: center;\r\n color: #0f172a;\r\n cursor: pointer;\r\n display: inline-flex;\r\n gap: 0.625rem;\r\n }\r\n input {\r\n accent-color: #2563eb;\r\n block-size: 1rem;\r\n inline-size: 1rem;\r\n }\r\n input:disabled {\r\n cursor: not-allowed;\r\n }\r\n `,\r\n connected() {\r\n const handleChange = (event: Event) => {\r\n const target = event.target as HTMLInputElement | null;\r\n if (!target?.matches('input[type=\"checkbox\"]')) return;\r\n event.stopPropagation();\r\n if (target.checked) {\r\n this.setAttribute('checked', 'true');\r\n } else {\r\n this.removeAttribute('checked');\r\n }\r\n this.dispatchEvent(\r\n new CustomEvent('change', {\r\n detail: { checked: target.checked },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n };\r\n storeHandler(this, '__bqueryCheckboxHandler', handleChange);\r\n this.shadowRoot?.addEventListener('change', handleChange);\r\n },\r\n disconnected() {\r\n const handleChange = readHandler(this, '__bqueryCheckboxHandler');\r\n if (handleChange) {\r\n this.shadowRoot?.removeEventListener('change', handleChange);\r\n }\r\n },\r\n render: ({ props }) => html`\r\n <label part=\"label\">\r\n <input\r\n part=\"control\"\r\n type=\"checkbox\"\r\n ${props.checked ? 'checked' : ''}\r\n ${props.disabled ? 'disabled' : ''}\r\n />\r\n <span part=\"text\"><slot>${escapeProp(props.label)}</slot></span>\r\n </label>\r\n `,\r\n });\r\n\r\n return tags;\r\n};\r\n","/**\r\n * Reduced motion detection and global toggle helpers.\r\n *\r\n * @module bquery/motion\r\n */\r\n\r\n/**\r\n * Global override for reduced motion preference.\r\n * When `null`, the system preference is used.\r\n * When `true`, reduced motion is forced on.\r\n * When `false`, reduced motion is forced off.\r\n *\r\n * @internal\r\n */\r\nlet reducedMotionOverride: boolean | null = null;\r\n\r\n/**\r\n * Check whether reduced motion should be applied.\r\n *\r\n * Returns the global override if set via {@link setReducedMotion},\r\n * otherwise checks the user's system preference.\r\n *\r\n * @returns `true` if reduced motion should be applied\r\n *\r\n * @example\r\n * ```ts\r\n * if (prefersReducedMotion()) {\r\n * // skip animation\r\n * }\r\n * ```\r\n */\r\nexport const prefersReducedMotion = (): boolean => {\r\n if (reducedMotionOverride !== null) {\r\n return reducedMotionOverride;\r\n }\r\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\r\n return false;\r\n }\r\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n};\r\n\r\n/**\r\n * Programmatically override the reduced motion preference globally.\r\n *\r\n * When set to `true`, all motion functions that respect reduced motion\r\n * will skip animations. When set to `false`, animations run regardless\r\n * of system settings. Pass `null` to restore system-preference detection.\r\n *\r\n * @param override - `true` to force reduced motion, `false` to force\r\n * full motion, or `null` to use system preference\r\n *\r\n * @example\r\n * ```ts\r\n * // Force all animations to be instant\r\n * setReducedMotion(true);\r\n *\r\n * // Re-enable animations regardless of system\r\n * setReducedMotion(false);\r\n *\r\n * // Restore system preference\r\n * setReducedMotion(null);\r\n * ```\r\n */\r\nexport const setReducedMotion = (override: boolean | null): void => {\r\n reducedMotionOverride = override;\r\n};\r\n","/**\n * Web Animations helpers.\n *\n * @module bquery/motion\n */\n\nimport { prefersReducedMotion } from './reduced-motion';\nimport type { AnimateOptions } from './types';\n\n/** @internal */\nconst isStyleValue = (value: unknown): value is string | number =>\n typeof value === 'string' || typeof value === 'number';\n\n/**\n * Convert camelCase property names to kebab-case for CSS.\n * @internal\n */\nconst toKebabCase = (str: string): string => {\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n};\n\n/** @internal */\nexport const applyFinalKeyframeStyles = (\n element: Element,\n keyframes: Keyframe[] | PropertyIndexedKeyframes\n): void => {\n const htmlElement = element as HTMLElement;\n const style = htmlElement.style;\n\n if (Array.isArray(keyframes)) {\n const last = keyframes[keyframes.length - 1];\n if (!last) return;\n for (const [prop, value] of Object.entries(last)) {\n if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;\n if (isStyleValue(value)) {\n // Convert camelCase to kebab-case for CSS properties\n const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);\n style.setProperty(cssProp, String(value));\n }\n }\n return;\n }\n\n for (const [prop, value] of Object.entries(keyframes)) {\n if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;\n const finalValue = Array.isArray(value) ? value[value.length - 1] : value;\n if (isStyleValue(finalValue)) {\n // Convert camelCase to kebab-case for CSS properties\n const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);\n style.setProperty(cssProp, String(finalValue));\n }\n }\n};\n\n/**\n * Animate an element using the Web Animations API with reduced-motion fallback.\n *\n * @param element - Element to animate\n * @param config - Animation configuration\n * @returns Promise that resolves when animation completes\n *\n * @example\n * ```ts\n * await animate(element, {\n * keyframes: [{ opacity: 0 }, { opacity: 1 }],\n * options: { duration: 200, easing: 'ease-out' },\n * });\n * ```\n */\nexport const animate = (element: Element, config: AnimateOptions): Promise<void> => {\n const { keyframes, options, commitStyles = true, respectReducedMotion = true, onFinish } = config;\n\n if (respectReducedMotion && prefersReducedMotion()) {\n if (commitStyles) {\n applyFinalKeyframeStyles(element, keyframes);\n }\n onFinish?.();\n return Promise.resolve();\n }\n\n const htmlElement = element as HTMLElement;\n if (typeof htmlElement.animate !== 'function') {\n if (commitStyles) {\n applyFinalKeyframeStyles(element, keyframes);\n }\n onFinish?.();\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n const animation = htmlElement.animate(keyframes, options);\n let finalized = false;\n const finalize = () => {\n if (finalized) return;\n finalized = true;\n if (commitStyles) {\n if (typeof animation.commitStyles === 'function') {\n animation.commitStyles();\n } else {\n applyFinalKeyframeStyles(element, keyframes);\n }\n }\n animation.cancel();\n onFinish?.();\n resolve();\n };\n\n animation.onfinish = finalize;\n if (animation.finished) {\n animation.finished.then(finalize).catch(finalize);\n }\n });\n};\n","/**\n * Easing helpers.\n *\n * @module bquery/motion\n */\n\nimport type { EasingFunction } from './types';\n\nconst clamp = (value: number) => Math.min(1, Math.max(0, value));\n\nexport const linear: EasingFunction = (t) => clamp(t);\nexport const easeInQuad: EasingFunction = (t) => clamp(t * t);\nexport const easeOutQuad: EasingFunction = (t) => clamp(1 - (1 - t) * (1 - t));\nexport const easeInOutQuad: EasingFunction = (t) =>\n clamp(t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2);\nexport const easeInCubic: EasingFunction = (t) => clamp(t * t * t);\nexport const easeOutCubic: EasingFunction = (t) => clamp(1 - Math.pow(1 - t, 3));\nexport const easeInOutCubic: EasingFunction = (t) =>\n clamp(t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2);\nexport const easeOutBack: EasingFunction = (t) => {\n const c1 = 1.70158;\n const c3 = c1 + 1;\n return clamp(1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2));\n};\nexport const easeOutExpo: EasingFunction = (t) => clamp(t === 1 ? 1 : 1 - Math.pow(2, -10 * t));\n\n/**\n * Named easing presets.\n */\nexport const easingPresets = {\n linear,\n easeInQuad,\n easeOutQuad,\n easeInOutQuad,\n easeInCubic,\n easeOutCubic,\n easeInOutCubic,\n easeOutBack,\n easeOutExpo,\n};\n","/**\n * FLIP animation helpers.\n *\n * @module bquery/motion\n */\n\nimport type { ElementBounds, FlipGroupOptions, FlipOptions } from './types';\n\n/**\n * Capture the current bounds of an element for FLIP animation.\n *\n * @param element - The DOM element to measure\n * @returns The element's current position and size\n */\nexport const capturePosition = (element: Element): ElementBounds => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Perform a FLIP (First, Last, Invert, Play) animation.\n * Animates an element from its captured position to its current position.\n *\n * @param element - The element to animate\n * @param firstBounds - The previously captured bounds\n * @param options - Animation configuration\n * @returns Promise that resolves when animation completes\n *\n * @example\n * ```ts\n * const first = capturePosition(element);\n * // ... DOM changes that move the element ...\n * await flip(element, first, { duration: 300 });\n * ```\n */\nexport const flip = (\n element: Element,\n firstBounds: ElementBounds,\n options: FlipOptions = {}\n): Promise<void> => {\n const { duration = 300, easing = 'ease-out', onComplete } = options;\n\n // Last: Get current position\n const lastBounds = capturePosition(element);\n\n // Skip animation if element has zero dimensions (avoid division by zero)\n if (lastBounds.width === 0 || lastBounds.height === 0) {\n onComplete?.();\n return Promise.resolve();\n }\n\n // Invert: Calculate the delta\n const deltaX = firstBounds.left - lastBounds.left;\n const deltaY = firstBounds.top - lastBounds.top;\n const deltaW = firstBounds.width / lastBounds.width;\n const deltaH = firstBounds.height / lastBounds.height;\n\n // Skip animation if no change\n if (deltaX === 0 && deltaY === 0 && deltaW === 1 && deltaH === 1) {\n onComplete?.();\n return Promise.resolve();\n }\n\n const htmlElement = element as HTMLElement;\n\n // Feature check: fallback if Web Animations API is unavailable\n if (typeof htmlElement.animate !== 'function') {\n onComplete?.();\n return Promise.resolve();\n }\n\n // Apply inverted transform\n htmlElement.style.transform = `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`;\n htmlElement.style.transformOrigin = 'top left';\n\n // Force reflow\n void htmlElement.offsetHeight;\n\n // Play: Animate back to current position\n return new Promise((resolve) => {\n const animation = htmlElement.animate(\n [\n {\n transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`,\n },\n { transform: 'translate(0, 0) scale(1, 1)' },\n ],\n { duration, easing, fill: 'forwards' }\n );\n\n let finalized = false;\n const finalize = () => {\n if (finalized) return;\n finalized = true;\n htmlElement.style.transform = '';\n htmlElement.style.transformOrigin = '';\n onComplete?.();\n resolve();\n };\n\n animation.onfinish = finalize;\n // Handle cancel/rejection via the finished promise\n if (animation.finished) {\n animation.finished.then(finalize).catch(finalize);\n }\n });\n};\n\n/**\n * FLIP helper for animating a list of elements.\n * Useful for reordering lists with smooth animations.\n *\n * @param elements - Array of elements to animate\n * @param performUpdate - Function that performs the DOM update\n * @param options - Animation configuration\n *\n * @example\n * ```ts\n * await flipList(listItems, () => {\n * container.appendChild(container.firstChild); // Move first to last\n * });\n * ```\n */\nexport const flipList = async (\n elements: Element[],\n performUpdate: () => void,\n options: FlipOptions = {}\n): Promise<void> => {\n await flipElements(elements, performUpdate, options);\n};\n\n/**\n * FLIP helper with optional stagger support.\n *\n * @param elements - Array of elements to animate\n * @param performUpdate - Function that performs the DOM update\n * @param options - Animation configuration\n */\nexport const flipElements = async (\n elements: Element[],\n performUpdate: () => void,\n options: FlipGroupOptions = {}\n): Promise<void> => {\n const { stagger, ...flipOptions } = options;\n\n // First: Capture all positions\n const positions = new Map<Element, ElementBounds>();\n for (const el of elements) {\n positions.set(el, capturePosition(el));\n }\n\n // Perform DOM update\n performUpdate();\n\n const total = elements.length;\n\n // Animate each element\n const animations = elements.map((el, index) => {\n const first = positions.get(el);\n if (!first) return Promise.resolve();\n const delay = stagger ? stagger(index, total) : 0;\n if (delay > 0) {\n return new Promise((resolve) => setTimeout(resolve, delay)).then(() =>\n flip(el, first, flipOptions)\n );\n }\n return flip(el, first, flipOptions);\n });\n\n await Promise.all(animations);\n};\n","/**\n * Keyframe presets.\n *\n * @module bquery/motion\n */\n\n/**\n * Common keyframe presets for quick animations.\n */\nexport const keyframePresets = {\n fadeIn: (from = 0, to = 1): Keyframe[] => [{ opacity: from }, { opacity: to }],\n fadeOut: (from = 1, to = 0): Keyframe[] => [{ opacity: from }, { opacity: to }],\n slideInUp: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateY(${distance}px)` },\n { opacity: 1, transform: 'translateY(0)' },\n ],\n slideInDown: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateY(-${distance}px)` },\n { opacity: 1, transform: 'translateY(0)' },\n ],\n slideInLeft: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateX(${distance}px)` },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n slideInRight: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateX(-${distance}px)` },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n scaleIn: (from = 0.95, to = 1): Keyframe[] => [\n { opacity: 0, transform: `scale(${from})` },\n { opacity: 1, transform: `scale(${to})` },\n ],\n scaleOut: (from = 1, to = 0.95): Keyframe[] => [\n { opacity: 1, transform: `scale(${from})` },\n { opacity: 0, transform: `scale(${to})` },\n ],\n pop: (from = 0.9, mid = 1.02, to = 1): Keyframe[] => [\n { opacity: 0, transform: `scale(${from})` },\n { opacity: 1, transform: `scale(${mid})`, offset: 0.6 },\n { opacity: 1, transform: `scale(${to})` },\n ],\n rotateIn: (degrees = 6): Keyframe[] => [\n { opacity: 0, transform: `rotate(${degrees}deg) scale(0.98)` },\n { opacity: 1, transform: 'rotate(0deg) scale(1)' },\n ],\n};\n","/**\r\n * FLIP-based morph animation between two element states.\r\n *\r\n * @module bquery/motion\r\n */\r\n\r\nimport { prefersReducedMotion } from './reduced-motion';\r\nimport type { MorphOptions } from './types';\r\n\r\n/**\r\n * Perform a FLIP-based morph animation between two elements.\r\n *\r\n * Captures the bounding rect of the `from` element, hides it, shows the\r\n * `to` element, then animates the `to` element from the `from` position\r\n * using CSS transforms and opacity.\r\n *\r\n * @param from - The source element (will be hidden at the end)\r\n * @param to - The destination element (will be shown and animated into place)\r\n * @param options - Morph animation options\r\n * @returns Promise that resolves when the morph completes\r\n *\r\n * @example\r\n * ```ts\r\n * const card = document.querySelector('.card');\r\n * const detail = document.querySelector('.detail');\r\n * await morphElement(card, detail, { duration: 400, easing: 'ease-out' });\r\n * ```\r\n */\r\nexport const morphElement = (\r\n from: Element,\r\n to: Element,\r\n options: MorphOptions = {}\r\n): Promise<void> => {\r\n const { duration = 300, easing = 'ease', respectReducedMotion = true, onComplete } = options;\r\n\r\n const fromEl = from as HTMLElement;\r\n const toEl = to as HTMLElement;\r\n\r\n if (\r\n typeof window === 'undefined' ||\r\n typeof document === 'undefined' ||\r\n typeof fromEl.getBoundingClientRect !== 'function' ||\r\n typeof toEl.getBoundingClientRect !== 'function' ||\r\n typeof fromEl.style === 'undefined' ||\r\n typeof toEl.style === 'undefined'\r\n ) {\r\n onComplete?.();\r\n return Promise.resolve();\r\n }\r\n\r\n // Capture FIRST position of source element\r\n const firstRect = from.getBoundingClientRect();\r\n\r\n // Ensure destination is visible so we can measure it\r\n const previousDisplay = toEl.style.display;\r\n const previousVisibility = toEl.style.visibility;\r\n const previousTransform = toEl.style.transform;\r\n const previousOpacity = toEl.style.opacity;\r\n const computedDisplay =\r\n typeof getComputedStyle === 'function'\r\n ? getComputedStyle(toEl).display\r\n : previousDisplay || 'block';\r\n // Prefer an explicit inline display, otherwise fall back to the current computed\r\n // display, and finally to `block` so hidden destinations remain measurable.\r\n const forcedDisplay =\r\n computedDisplay === 'none' ? 'block' : previousDisplay || computedDisplay || 'block';\r\n const restoreAnimatedInlineStyles = () => {\r\n toEl.style.transform = previousTransform;\r\n toEl.style.opacity = previousOpacity;\r\n };\r\n\r\n toEl.style.visibility = 'hidden';\r\n toEl.style.display = forcedDisplay;\r\n\r\n // Capture LAST position of destination element\r\n const lastRect = to.getBoundingClientRect();\r\n\r\n // Restore visibility (it will be animated in)\r\n toEl.style.visibility = previousVisibility;\r\n\r\n // Hide source, show destination\r\n fromEl.style.display = 'none';\r\n if (computedDisplay === 'none') {\r\n toEl.style.display = forcedDisplay;\r\n } else if (previousDisplay === 'none') {\r\n toEl.style.display = '';\r\n } else {\r\n toEl.style.display = previousDisplay;\r\n }\r\n\r\n // If reduced motion is preferred, skip the animation\r\n if (respectReducedMotion && prefersReducedMotion()) {\r\n restoreAnimatedInlineStyles();\r\n onComplete?.();\r\n return Promise.resolve();\r\n }\r\n\r\n // Calculate the transform inversion (FLIP: Invert)\r\n const dx = firstRect.left - lastRect.left;\r\n const dy = firstRect.top - lastRect.top;\r\n const sx = firstRect.width / (lastRect.width || 1);\r\n const sy = firstRect.height / (lastRect.height || 1);\r\n\r\n // If no visual change, skip animation\r\n if (dx === 0 && dy === 0 && sx === 1 && sy === 1) {\r\n restoreAnimatedInlineStyles();\r\n onComplete?.();\r\n return Promise.resolve();\r\n }\r\n\r\n const keyframes: Keyframe[] = [\r\n {\r\n transform: `translate(${dx}px, ${dy}px) scale(${sx}, ${sy})`,\r\n opacity: '0.5',\r\n },\r\n {\r\n transform: 'translate(0, 0) scale(1, 1)',\r\n opacity: '1',\r\n },\r\n ];\r\n\r\n // Check if animate API is available\r\n if (typeof toEl.animate !== 'function') {\r\n restoreAnimatedInlineStyles();\r\n onComplete?.();\r\n return Promise.resolve();\r\n }\r\n\r\n return new Promise<void>((resolve) => {\r\n const animation = toEl.animate(keyframes, {\r\n duration,\r\n easing,\r\n fill: 'forwards',\r\n });\r\n\r\n let finalized = false;\r\n const finalize = () => {\r\n if (finalized) return;\r\n finalized = true;\r\n restoreAnimatedInlineStyles();\r\n animation.cancel();\r\n onComplete?.();\r\n resolve();\r\n };\r\n\r\n animation.onfinish = finalize;\r\n if (animation.finished) {\r\n animation.finished.then(finalize).catch(finalize);\r\n }\r\n });\r\n};\r\n","/**\r\n * Scroll-linked parallax effect.\r\n *\r\n * @module bquery/motion\r\n */\r\n\r\nimport { prefersReducedMotion } from './reduced-motion';\r\nimport type { ParallaxCleanup, ParallaxOptions } from './types';\r\n\r\n/**\r\n * Apply a scroll-linked parallax effect to an element.\r\n *\r\n * The element's position is translated based on the scroll position\r\n * multiplied by the speed factor. A speed of `0.5` means the element\r\n * moves at half the scroll speed (classic background parallax).\r\n *\r\n * @param element - The element to apply the parallax effect to\r\n * @param options - Parallax configuration\r\n * @returns A cleanup function that removes the scroll listener\r\n *\r\n * @example\r\n * ```ts\r\n * const cleanup = parallax(document.querySelector('.hero-bg')!, {\r\n * speed: 0.3,\r\n * direction: 'vertical',\r\n * });\r\n *\r\n * // Later, remove the effect:\r\n * cleanup();\r\n * ```\r\n */\r\nexport const parallax = (element: Element, options: ParallaxOptions = {}): ParallaxCleanup => {\r\n if (\r\n typeof window === 'undefined' ||\r\n typeof window.addEventListener !== 'function' ||\r\n typeof window.removeEventListener !== 'function' ||\r\n typeof requestAnimationFrame !== 'function' ||\r\n typeof cancelAnimationFrame !== 'function'\r\n ) {\r\n return () => {};\r\n }\r\n\r\n const { speed = 0.5, direction = 'vertical', respectReducedMotion = true } = options;\r\n\r\n const el = element as HTMLElement;\r\n const previousTransform = el.style.transform;\r\n\r\n // If reduced motion is preferred, don't apply parallax\r\n if (respectReducedMotion && prefersReducedMotion()) {\r\n return () => {};\r\n }\r\n\r\n let ticking = false;\r\n let destroyed = false;\r\n let frameId: number | null = null;\r\n\r\n const cleanup = (): void => {\r\n if (destroyed) return;\r\n destroyed = true;\r\n window.removeEventListener('scroll', onScroll);\r\n if (frameId !== null) {\r\n cancelAnimationFrame(frameId);\r\n frameId = null;\r\n }\r\n ticking = false;\r\n el.style.transform = previousTransform;\r\n };\r\n\r\n const updatePosition = () => {\r\n if (destroyed) return;\r\n\r\n // Re-check reduced motion on each frame (in case toggle changed)\r\n if (respectReducedMotion && prefersReducedMotion()) {\r\n cleanup();\r\n return;\r\n }\r\n\r\n const scrollY = window.scrollY;\r\n const scrollX = window.scrollX;\r\n\r\n let tx = 0;\r\n let ty = 0;\r\n\r\n if (direction === 'vertical' || direction === 'both') {\r\n ty = scrollY * speed;\r\n }\r\n if (direction === 'horizontal' || direction === 'both') {\r\n tx = scrollX * speed;\r\n }\r\n\r\n const parallaxTransform = `translate3d(${tx}px, ${ty}px, 0)`;\r\n el.style.transform = previousTransform\r\n ? `${previousTransform} ${parallaxTransform}`\r\n : parallaxTransform;\r\n };\r\n\r\n const onScroll = () => {\r\n if (destroyed) return;\r\n if (respectReducedMotion && prefersReducedMotion()) {\r\n cleanup();\r\n return;\r\n }\r\n if (!ticking) {\r\n ticking = true;\r\n frameId = requestAnimationFrame(() => {\r\n frameId = null;\r\n updatePosition();\r\n ticking = false;\r\n });\r\n }\r\n };\r\n\r\n // Apply initial position\r\n updatePosition();\r\n\r\n // Listen to scroll events\r\n window.addEventListener('scroll', onScroll, { passive: true });\r\n\r\n return cleanup;\r\n};\r\n","/**\n * Scroll-triggered animation helpers.\n *\n * @module bquery/motion\n */\n\nimport { animate } from './animate';\nimport type { ScrollAnimateCleanup, ScrollAnimateOptions } from './types';\n\nconst resolveElements = (elements: Element | Iterable<Element> | ArrayLike<Element>): Element[] => {\n if (typeof Element !== 'undefined' && elements instanceof Element) return [elements];\n return Array.from(elements as Iterable<Element>);\n};\n\n/**\n * Animate elements when they enter the viewport.\n *\n * @param elements - Target element(s)\n * @param options - Scroll animation configuration\n * @returns Cleanup function to disconnect observers\n */\nexport const scrollAnimate = (\n elements: Element | Iterable<Element> | ArrayLike<Element>,\n options: ScrollAnimateOptions\n): ScrollAnimateCleanup => {\n const targets = resolveElements(elements);\n if (!targets.length) return () => undefined;\n\n const { root = null, rootMargin, threshold, once = true, onEnter, ...animationConfig } = options;\n\n if (typeof IntersectionObserver === 'undefined') {\n targets.forEach((element) => {\n onEnter?.(element);\n void animate(element, animationConfig);\n });\n return () => undefined;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (!entry.isIntersecting) return;\n const element = entry.target as Element;\n onEnter?.(element);\n void animate(element, animationConfig);\n if (once) {\n observer.unobserve(element);\n }\n });\n },\n { root, rootMargin, threshold }\n );\n\n targets.forEach((element) => observer.observe(element));\n\n return () => observer.disconnect();\n};\n","/**\n * Spring physics helpers.\n *\n * @module bquery/motion\n */\n\nimport type { Spring, SpringConfig } from './types';\n\n/**\n * Default spring configuration values.\n */\nconst DEFAULT_SPRING_CONFIG: Required<SpringConfig> = {\n stiffness: 100,\n damping: 10,\n mass: 1,\n precision: 0.01,\n};\n\n/**\n * Create a spring-based animation for smooth, physics-based motion.\n *\n * Uses variable frame rate timing based on `requestAnimationFrame` timestamps\n * to ensure consistent animation speed across different devices and frame rates.\n * Large time deltas (e.g., from tab backgrounding) are clamped to maintain\n * simulation stability.\n *\n * @param initialValue - Starting value for the spring\n * @param config - Spring physics configuration\n * @returns Spring instance for controlling the animation\n *\n * @example\n * ```ts\n * const x = spring(0, { stiffness: 120, damping: 14 });\n * x.onChange((value) => {\n * element.style.transform = `translateX(${value}px)`;\n * });\n * await x.to(100);\n * ```\n */\nexport const spring = (initialValue: number, config: SpringConfig = {}): Spring => {\n const { stiffness, damping, mass, precision } = {\n ...DEFAULT_SPRING_CONFIG,\n ...config,\n };\n\n let current = initialValue;\n let velocity = 0;\n let target = initialValue;\n let animationFrame: number | null = null;\n let resolvePromise: (() => void) | null = null;\n let lastTime: number | null = null;\n const listeners = new Set<(value: number) => void>();\n\n const notifyListeners = () => {\n for (const listener of listeners) {\n listener(current);\n }\n };\n\n const step = (timestamp: number) => {\n // Calculate time delta (in seconds) from last frame\n // If this is the first frame, use a sensible default (1/60s)\n // This ensures the animation speed is independent of frame rate\n const deltaTime = lastTime !== null ? (timestamp - lastTime) / 1000 : 1 / 60;\n // Clamp large deltas to prevent instability (e.g. tab backgrounding)\n // Maximum delta of 1/30s (~33ms) keeps simulation stable\n const clampedDelta = Math.min(deltaTime, 1 / 30);\n lastTime = timestamp;\n\n // Spring physics calculation\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n velocity += acceleration * clampedDelta;\n current += velocity * clampedDelta;\n\n notifyListeners();\n\n // Check if spring has settled\n if (Math.abs(velocity) < precision && Math.abs(displacement) < precision) {\n current = target;\n velocity = 0;\n animationFrame = null;\n notifyListeners();\n resolvePromise?.();\n resolvePromise = null;\n return;\n }\n\n animationFrame = requestAnimationFrame(step);\n };\n\n return {\n to(newTarget: number): Promise<void> {\n target = newTarget;\n\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n }\n\n // Resolve any pending promise from a previous to() call\n // This ensures all returned promises eventually settle\n resolvePromise?.();\n\n // Reset lastTime to ensure clean start for new animation\n lastTime = null;\n\n return new Promise((resolve) => {\n resolvePromise = resolve;\n animationFrame = requestAnimationFrame(step);\n });\n },\n\n current(): number {\n return current;\n },\n\n stop(): void {\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n animationFrame = null;\n }\n velocity = 0;\n lastTime = null;\n resolvePromise?.();\n resolvePromise = null;\n },\n\n onChange(callback: (value: number) => void): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n};\n\n/**\n * Preset spring configurations for common use cases.\n */\nexport const springPresets = {\n /** Gentle, slow-settling spring */\n gentle: { stiffness: 80, damping: 15 } as SpringConfig,\n /** Responsive, snappy spring */\n snappy: { stiffness: 200, damping: 20 } as SpringConfig,\n /** Bouncy, playful spring */\n bouncy: { stiffness: 300, damping: 8 } as SpringConfig,\n /** Stiff, quick spring with minimal overshoot */\n stiff: { stiffness: 400, damping: 30 } as SpringConfig,\n};\n","/**\n * Stagger helpers.\n *\n * @module bquery/motion\n */\n\nimport type { StaggerFunction, StaggerOptions } from './types';\n\n/**\n * Create a staggered delay function for list animations.\n *\n * @param step - Delay between items in milliseconds\n * @param options - Stagger configuration\n * @returns Function that returns delay for a given index\n *\n * @example\n * ```ts\n * const delay = stagger(50, { from: 'center' });\n * delay(0, 3); // 50\n * delay(1, 3); // 0\n * ```\n */\nexport const stagger = (step: number, options: StaggerOptions = {}): StaggerFunction => {\n const { start = 0, from = 'start', easing } = options;\n\n return (index: number, total = 0): number => {\n const origin =\n typeof from === 'number'\n ? from\n : from === 'center'\n ? (total - 1) / 2\n : from === 'end'\n ? total - 1\n : 0;\n\n const distance = Math.abs(index - origin);\n const maxDistance = total > 1 ? Math.max(origin, total - 1 - origin) : 1;\n const normalized = maxDistance === 0 ? 0 : distance / maxDistance;\n const eased = easing ? easing(normalized) * maxDistance : distance;\n\n return start + eased * step;\n };\n};\n","/**\n * Timeline and sequence helpers.\n *\n * @module bquery/motion\n */\n\nimport { animate, applyFinalKeyframeStyles } from './animate';\nimport { prefersReducedMotion } from './reduced-motion';\nimport type {\n SequenceOptions,\n SequenceStep,\n TimelineConfig,\n TimelineControls,\n TimelineStep,\n} from './types';\n\nconst resolveTimeValue = (value?: number | string): number => {\n if (typeof value === 'number') return value;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed.endsWith('ms')) {\n const parsed = Number.parseFloat(trimmed.slice(0, -2));\n return Number.isFinite(parsed) ? parsed : 0;\n }\n if (trimmed.endsWith('s')) {\n const parsed = Number.parseFloat(trimmed.slice(0, -1));\n return Number.isFinite(parsed) ? parsed * 1000 : 0;\n }\n const parsed = Number.parseFloat(trimmed);\n return Number.isFinite(parsed) ? parsed : 0;\n }\n return 0;\n};\n\nconst resolveAt = (at: TimelineStep['at'], previousEnd: number): number => {\n if (typeof at === 'number') return at;\n if (typeof at === 'string') {\n const match = /^([+-])=(\\d+(?:\\.\\d+)?)$/.exec(at);\n if (match) {\n const delta = Number.parseFloat(match[2]);\n if (!Number.isFinite(delta)) return previousEnd;\n return match[1] === '+' ? previousEnd + delta : previousEnd - delta;\n }\n }\n return previousEnd;\n};\n\nconst normalizeDuration = (options?: KeyframeAnimationOptions): number => {\n const baseDuration = resolveTimeValue(options?.duration as number | string | undefined);\n const endDelay = resolveTimeValue(options?.endDelay as number | string | undefined);\n const rawIterations = options?.iterations ?? 1;\n\n // Handle infinite iterations - treat as a special case with a very large duration\n // In practice, infinite iterations shouldn't be used in timelines as they never end\n if (rawIterations === Infinity) {\n // Return a large sentinel value - timeline calculations will be incorrect,\n // but this at least prevents NaN/Infinity from breaking scheduling\n return Number.MAX_SAFE_INTEGER;\n }\n\n // Per Web Animations spec, iterations must be a non-negative number\n // Treat negative as 0 (only endDelay duration)\n const iterations = Math.max(0, rawIterations);\n\n // Total duration = (baseDuration * iterations) + endDelay\n // Note: endDelay is applied once at the end, after all iterations\n return baseDuration * iterations + endDelay;\n};\n\nconst scheduleSteps = (steps: TimelineStep[]) => {\n let previousEnd = 0;\n return steps.map((step) => {\n const baseStart = resolveAt(step.at, previousEnd);\n const stepDelay = resolveTimeValue(step.options?.delay as number | string | undefined);\n const start = Math.max(0, baseStart + stepDelay);\n const duration = normalizeDuration(step.options);\n const end = start + duration;\n previousEnd = Math.max(previousEnd, end);\n return { step, start, end, duration };\n });\n};\n\n/**\n * Run a list of animations sequentially.\n *\n * @param steps - Steps to run in order\n * @param options - Sequence configuration\n */\nexport const sequence = async (\n steps: SequenceStep[],\n options: SequenceOptions = {}\n): Promise<void> => {\n const { stagger, onFinish } = options;\n const total = steps.length;\n\n for (let index = 0; index < steps.length; index += 1) {\n const step = steps[index];\n const delay = stagger ? stagger(index, total) : 0;\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n await animate(step.target, step);\n }\n\n onFinish?.();\n};\n\n/**\n * Create a timeline controller for multiple animations.\n *\n * @param initialSteps - Steps for the timeline\n * @param config - Timeline configuration\n */\nexport const timeline = (\n initialSteps: TimelineStep[] = [],\n config: TimelineConfig = {}\n): TimelineControls => {\n const steps = [...initialSteps];\n const listeners = new Set<() => void>();\n let animations: Array<{ animation: Animation; step: TimelineStep; start: number }> = [];\n let totalDuration = 0;\n let reducedMotionApplied = false;\n let finalized = false;\n\n const { commitStyles = true, respectReducedMotion = true, onFinish } = config;\n\n const finalize = () => {\n if (finalized) return;\n finalized = true;\n\n if (commitStyles) {\n for (const item of animations) {\n const { animation, step } = item;\n if (typeof animation.commitStyles === 'function') {\n animation.commitStyles();\n } else {\n applyFinalKeyframeStyles(step.target, step.keyframes);\n }\n animation.cancel();\n }\n }\n\n listeners.forEach((listener) => listener());\n onFinish?.();\n };\n\n const buildAnimations = () => {\n animations.forEach(({ animation }) => animation.cancel());\n animations = [];\n finalized = false;\n\n const schedule = scheduleSteps(steps);\n totalDuration = schedule.length ? Math.max(...schedule.map((item) => item.end)) : 0;\n\n if (respectReducedMotion && prefersReducedMotion()) {\n if (commitStyles) {\n schedule.forEach(({ step }) => applyFinalKeyframeStyles(step.target, step.keyframes));\n }\n reducedMotionApplied = true;\n return;\n }\n\n // Check if Web Animations API is available on all targets\n const animateUnavailable = schedule.some(\n ({ step }) => typeof (step.target as HTMLElement).animate !== 'function'\n );\n if (animateUnavailable) {\n if (commitStyles) {\n schedule.forEach(({ step }) => applyFinalKeyframeStyles(step.target, step.keyframes));\n }\n reducedMotionApplied = true;\n return;\n }\n\n reducedMotionApplied = false;\n animations = schedule.map(({ step, start }) => {\n const { delay: _delay, ...options } = step.options ?? {};\n const animation = step.target.animate(step.keyframes, {\n ...options,\n delay: start,\n fill: options.fill ?? 'both',\n });\n return { animation, step, start };\n });\n };\n\n return {\n add(step: TimelineStep): void {\n steps.push(step);\n },\n\n duration(): number {\n if (!steps.length) return 0;\n if (!animations.length) {\n const schedule = scheduleSteps(steps);\n return Math.max(...schedule.map((item) => item.end));\n }\n return totalDuration;\n },\n\n async play(): Promise<void> {\n buildAnimations();\n\n if (reducedMotionApplied || animations.length === 0) {\n finalize();\n return;\n }\n\n const finishPromises = animations.map((item) =>\n item.animation.finished.catch(() => undefined)\n );\n await Promise.all(finishPromises);\n finalize();\n },\n\n pause(): void {\n if (reducedMotionApplied) return;\n animations.forEach(({ animation }) => animation.pause());\n },\n\n resume(): void {\n if (reducedMotionApplied) return;\n animations.forEach(({ animation }) => animation.play());\n },\n\n stop(): void {\n animations.forEach(({ animation }) => animation.cancel());\n animations = [];\n reducedMotionApplied = false;\n },\n\n seek(time: number): void {\n if (reducedMotionApplied) return;\n animations.forEach(({ animation }) => {\n // currentTime is measured from the beginning of the animation including delay,\n // so we set it directly to the requested timeline time\n animation.currentTime = time;\n });\n },\n\n onFinish(callback: () => void): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n};\n","/**\n * View transition helpers.\n *\n * @module bquery/motion\n */\n\nimport type { TransitionOptions } from './types';\nimport { prefersReducedMotion } from './reduced-motion';\nimport { getBqueryConfig } from '../platform/config';\n\n/** Extended document type with View Transitions API */\ntype DocumentWithTransition = Document & {\n startViewTransition?: (callback: () => void | Promise<void>) => {\n finished: Promise<void>;\n ready: Promise<void>;\n updateCallbackDone: Promise<void>;\n skipTransition?: () => void;\n types?: {\n add: (type: string) => void;\n };\n };\n};\n\nconst sanitizeTokens = (tokens?: string[]): string[] =>\n (tokens ?? []).map((token) => token.trim()).filter((token) => token.length > 0);\n\n/**\n * Execute a DOM update with view transition animation.\n * Falls back to immediate update when View Transitions API is unavailable.\n *\n * @param updateOrOptions - Update function or options object\n * @returns Promise that resolves when transition completes\n *\n * @example\n * ```ts\n * await transition(() => {\n * $('#content').text('Updated');\n * });\n * ```\n */\nexport const transition = async (\n updateOrOptions: (() => void | Promise<void>) | TransitionOptions\n): Promise<void> => {\n const config = getBqueryConfig().transitions;\n const options: TransitionOptions =\n typeof updateOrOptions === 'function'\n ? {\n update: updateOrOptions,\n classes: config?.classes,\n types: config?.types,\n skipOnReducedMotion: config?.skipOnReducedMotion,\n }\n : {\n ...updateOrOptions,\n classes: updateOrOptions.classes ?? config?.classes,\n types: updateOrOptions.types ?? config?.types,\n skipOnReducedMotion: updateOrOptions.skipOnReducedMotion ?? config?.skipOnReducedMotion,\n };\n const update = options.update;\n\n // SSR/non-DOM environment fallback\n if (typeof document === 'undefined') {\n await update();\n return;\n }\n\n const doc = document as DocumentWithTransition;\n const root = document.documentElement;\n const classes = sanitizeTokens(options.classes);\n const types = sanitizeTokens(options.types);\n\n if (!doc.startViewTransition || (options.skipOnReducedMotion && prefersReducedMotion())) {\n await update();\n options.onFinish?.();\n return;\n }\n\n classes.forEach((className: string) => root.classList.add(className));\n\n try {\n const viewTransition = doc.startViewTransition(() => update());\n const transitionTypes = viewTransition.types;\n\n if (transitionTypes) {\n for (const type of types) {\n transitionTypes.add(type);\n }\n }\n\n await viewTransition.ready;\n options.onReady?.();\n await viewTransition.finished;\n options.onFinish?.();\n } finally {\n classes.forEach((className: string) => root.classList.remove(className));\n }\n};\n","/**\r\n * Character-by-character typewriter text animation.\r\n *\r\n * @module bquery/motion\r\n */\r\n\r\nimport { prefersReducedMotion } from './reduced-motion';\r\nimport type { TypewriterControls, TypewriterOptions } from './types';\r\n\r\n/**\r\n * Animate text appearing character by character in an element.\r\n *\r\n * @param element - The element to type text into\r\n * @param text - The text to display\r\n * @param options - Typewriter configuration\r\n * @returns Controls with `.stop()` to cancel and `.done` promise\r\n *\r\n * @example\r\n * ```ts\r\n * const tw = typewriter(\r\n * document.querySelector('#output')!,\r\n * 'Hello, world!',\r\n * { speed: 80, cursor: true },\r\n * );\r\n *\r\n * // Wait for it to finish:\r\n * await tw.done;\r\n *\r\n * // Or cancel early:\r\n * tw.stop();\r\n * ```\r\n */\r\nexport const typewriter = (\r\n element: HTMLElement,\r\n text: string,\r\n options: TypewriterOptions = {}\r\n): TypewriterControls => {\r\n const {\r\n speed = 50,\r\n delay = 0,\r\n cursor = false,\r\n cursorChar = '|',\r\n loop = false,\r\n loopDelay = 1000,\r\n respectReducedMotion = true,\r\n onComplete,\r\n } = options;\r\n\r\n if (typeof document === 'undefined') {\r\n return {\r\n stop: () => {},\r\n done: Promise.resolve(),\r\n };\r\n }\r\n\r\n const el = element;\r\n let stopped = false;\r\n let timer: ReturnType<typeof setTimeout> | null = null;\r\n let cursorEl: HTMLSpanElement | null = null;\r\n let cursorTimer: ReturnType<typeof setInterval> | null = null;\r\n let resolvePromise: (() => void) | null = null;\r\n\r\n // Add cursor element if enabled\r\n const setupCursor = () => {\r\n if (!cursor) return;\r\n cursorEl = document.createElement('span');\r\n cursorEl.setAttribute('aria-hidden', 'true');\r\n cursorEl.textContent = cursorChar;\r\n el.appendChild(cursorEl);\r\n\r\n // Blink the cursor\r\n let visible = true;\r\n cursorTimer = setInterval(() => {\r\n if (cursorEl) {\r\n visible = !visible;\r\n cursorEl.style.opacity = visible ? '1' : '0';\r\n }\r\n }, 530);\r\n };\r\n\r\n const removeCursor = () => {\r\n if (cursorTimer !== null) {\r\n clearInterval(cursorTimer);\r\n cursorTimer = null;\r\n }\r\n if (cursorEl && cursorEl.parentNode) {\r\n cursorEl.parentNode.removeChild(cursorEl);\r\n cursorEl = null;\r\n }\r\n };\r\n\r\n const stop = () => {\r\n if (stopped) return;\r\n stopped = true;\r\n if (timer !== null) {\r\n clearTimeout(timer);\r\n timer = null;\r\n }\r\n removeCursor();\r\n // Resolve the done promise so callers awaiting it are unblocked\r\n resolvePromise?.();\r\n resolvePromise = null;\r\n };\r\n\r\n // If reduced motion, show text instantly\r\n if (respectReducedMotion && prefersReducedMotion()) {\r\n el.textContent = text;\r\n onComplete?.();\r\n return {\r\n stop: () => {},\r\n done: Promise.resolve(),\r\n };\r\n }\r\n\r\n const done = new Promise<void>((resolve) => {\r\n resolvePromise = resolve;\r\n\r\n const typeLoop = () => {\r\n let charIndex = 0;\r\n el.textContent = '';\r\n setupCursor();\r\n const textNode = document.createTextNode('');\r\n\r\n if (cursorEl) {\r\n el.insertBefore(textNode, cursorEl);\r\n } else {\r\n el.appendChild(textNode);\r\n }\r\n\r\n const typeNextChar = () => {\r\n if (stopped) {\r\n return;\r\n }\r\n if (charIndex < text.length) {\r\n textNode.data = text.slice(0, charIndex + 1);\r\n charIndex++;\r\n timer = setTimeout(typeNextChar, speed);\r\n } else {\r\n // Typing complete for this iteration\r\n onComplete?.();\r\n\r\n if (loop && !stopped) {\r\n timer = setTimeout(() => {\r\n if (!stopped) {\r\n removeCursor();\r\n typeLoop();\r\n }\r\n }, loopDelay);\r\n } else {\r\n removeCursor();\r\n resolve();\r\n resolvePromise = null;\r\n }\r\n }\r\n };\r\n\r\n timer = setTimeout(typeNextChar, delay);\r\n };\r\n\r\n typeLoop();\r\n });\r\n\r\n return { stop, done };\r\n};\r\n","/**\n * Storage Buckets API wrapper.\n * Provides a simplified interface for storing blobs and binary data.\n * Falls back to IndexedDB when Storage Buckets API is not available.\n */\n\n/**\n * Bucket interface for blob storage operations.\n */\nexport interface Bucket {\n /**\n * Store a blob in the bucket.\n * @param key - Unique identifier for the blob\n * @param data - Blob data to store\n */\n put(key: string, data: Blob): Promise<void>;\n\n /**\n * Retrieve a blob from the bucket.\n * @param key - Blob identifier\n * @returns The stored blob or null if not found\n */\n get(key: string): Promise<Blob | null>;\n\n /**\n * Remove a blob from the bucket.\n * @param key - Blob identifier\n */\n remove(key: string): Promise<void>;\n\n /**\n * List all keys in the bucket.\n * @returns Array of blob keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * IndexedDB-based bucket implementation.\n * Used as fallback when Storage Buckets API is unavailable.\n */\nclass IndexedDBBucket implements Bucket {\n private dbPromise: Promise<IDBDatabase> | null = null;\n private readonly storeName = 'blobs';\n\n constructor(private readonly bucketName: string) {}\n\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n const dbName = `bquery-bucket-${this.bucketName}`;\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(dbName, 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.storeName, mode);\n const store = tx.objectStore(this.storeName);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async put(key: string, data: Blob): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(data, key));\n }\n\n async get(key: string): Promise<Blob | null> {\n const result = await this.withStore<Blob | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Bucket manager for creating and accessing storage buckets.\n */\nexport const buckets = {\n /**\n * Open or create a storage bucket.\n * @param name - Bucket name\n * @returns Bucket instance for blob operations\n */\n async open(name: string): Promise<Bucket> {\n // Storage Buckets API is experimental; use IndexedDB fallback\n return new IndexedDBBucket(name);\n },\n};\n","/**\n * Cache Storage API wrapper.\n * Provides a simplified interface for caching responses and assets.\n */\n\n/**\n * Cache handle interface for managing cached resources.\n */\nexport interface CacheHandle {\n /**\n * Add a resource to the cache by URL.\n * Fetches the resource and stores the response.\n * @param url - URL to fetch and cache\n */\n add(url: string): Promise<void>;\n\n /**\n * Add multiple resources to the cache.\n * @param urls - Array of URLs to fetch and cache\n */\n addAll(urls: string[]): Promise<void>;\n\n /**\n * Store a custom response in the cache.\n * @param url - URL key for the cached response\n * @param response - Response object to cache\n */\n put(url: string, response: Response): Promise<void>;\n\n /**\n * Retrieve a cached response.\n * @param url - URL to look up\n * @returns Cached Response or undefined if not found\n */\n match(url: string): Promise<Response | undefined>;\n\n /**\n * Remove a cached response.\n * @param url - URL to remove from cache\n * @returns True if the entry was deleted\n */\n remove(url: string): Promise<boolean>;\n\n /**\n * Get all cached request URLs.\n * @returns Array of cached URLs\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Internal cache handle implementation.\n */\nclass CacheHandleImpl implements CacheHandle {\n constructor(private readonly cache: Cache) {}\n\n async add(url: string): Promise<void> {\n await this.cache.add(url);\n }\n\n async addAll(urls: string[]): Promise<void> {\n await this.cache.addAll(urls);\n }\n\n async put(url: string, response: Response): Promise<void> {\n await this.cache.put(url, response);\n }\n\n async match(url: string): Promise<Response | undefined> {\n return this.cache.match(url);\n }\n\n async remove(url: string): Promise<boolean> {\n return this.cache.delete(url);\n }\n\n async keys(): Promise<string[]> {\n const requests = await this.cache.keys();\n return requests.map((req) => req.url);\n }\n}\n\n/**\n * Cache manager for accessing the Cache Storage API.\n */\nexport const cache = {\n /**\n * Check if Cache Storage API is supported.\n * @returns True if caches API is available\n */\n isSupported(): boolean {\n return 'caches' in window;\n },\n\n /**\n * Open or create a named cache.\n * @param name - Cache name\n * @returns CacheHandle for cache operations\n */\n async open(name: string): Promise<CacheHandle> {\n if (!this.isSupported()) {\n throw new Error('bQuery: Cache Storage API not supported');\n }\n const c = await caches.open(name);\n return new CacheHandleImpl(c);\n },\n\n /**\n * Delete a named cache.\n * @param name - Cache name to delete\n * @returns True if the cache was deleted\n */\n async delete(name: string): Promise<boolean> {\n if (!this.isSupported()) {\n return false;\n }\n return caches.delete(name);\n },\n\n /**\n * List all cache names.\n * @returns Array of cache names\n */\n async keys(): Promise<string[]> {\n if (!this.isSupported()) {\n return [];\n }\n return caches.keys();\n },\n};\n","/**\n * Reactive cookie helpers.\n *\n * @module bquery/platform\n */\n\nimport { effect, signal, type Signal } from '../reactive/signal';\nimport { getBqueryConfig } from './config';\n\n/** Options for useCookie(). */\nexport interface UseCookieOptions<T> {\n /** Default value when the cookie is not present. */\n defaultValue?: T;\n /** Cookie path. Defaults to the global config or `/`. */\n path?: string;\n /** Optional cookie domain. */\n domain?: string;\n /** Cookie SameSite attribute. */\n sameSite?: 'Strict' | 'Lax' | 'None';\n /** Whether the cookie should be marked secure. */\n secure?: boolean;\n /** Cookie expiry date. */\n expires?: Date;\n /** Cookie max-age in seconds. */\n maxAge?: number;\n /** Automatically persist signal updates back to document.cookie. */\n watch?: boolean;\n /** Serialize a value before writing it into the cookie. */\n serialize?: (value: T) => string;\n /** Deserialize a cookie string into a typed value. */\n deserialize?: (value: string) => T;\n}\n\nconst readCookie = (name: string): string | null => {\n if (typeof document === 'undefined') return null;\n\n const prefix = `${encodeURIComponent(name)}=`;\n const segments = document.cookie ? document.cookie.split(';') : [];\n\n for (const segment of segments) {\n const normalizedSegment = segment.trim();\n if (normalizedSegment.startsWith(prefix)) {\n const rawValue = normalizedSegment.slice(prefix.length);\n try {\n return decodeURIComponent(rawValue);\n } catch {\n return rawValue;\n }\n }\n }\n\n return null;\n};\n\nconst requiresJsonParsing = (value: string): boolean => {\n const normalized = value.trim();\n return normalized.startsWith('{') || normalized.startsWith('[') || normalized.startsWith('\"');\n};\n\nconst removeCookie = (\n name: string,\n options: Pick<UseCookieOptions<unknown>, 'path' | 'domain' | 'sameSite' | 'secure'>\n): void => {\n if (typeof document === 'undefined') return;\n\n const segments = [`${encodeURIComponent(name)}=`, 'Expires=Thu, 01 Jan 1970 00:00:00 GMT'];\n\n if (options.path) segments.push(`Path=${options.path}`);\n if (options.domain) segments.push(`Domain=${options.domain}`);\n if (options.sameSite) segments.push(`SameSite=${options.sameSite}`);\n if (options.secure) segments.push('Secure');\n\n document.cookie = segments.join('; ');\n};\n\nconst writeCookie = <T>(name: string, value: T, options: UseCookieOptions<T>): void => {\n if (typeof document === 'undefined') return;\n\n const serialized = options.serialize\n ? options.serialize(value)\n : typeof value === 'string'\n ? value\n : JSON.stringify(value);\n\n const segments = [`${encodeURIComponent(name)}=${encodeURIComponent(serialized)}`];\n\n if (options.path) segments.push(`Path=${options.path}`);\n if (options.domain) segments.push(`Domain=${options.domain}`);\n if (typeof options.maxAge === 'number') segments.push(`Max-Age=${options.maxAge}`);\n if (options.expires) segments.push(`Expires=${options.expires.toUTCString()}`);\n if (options.sameSite) segments.push(`SameSite=${options.sameSite}`);\n if (options.secure) segments.push('Secure');\n\n document.cookie = segments.join('; ');\n};\n\n/**\n * Create a reactive cookie signal.\n *\n * @template T - Cookie value type\n * @param name - Cookie name\n * @param options - Read/write configuration for the cookie\n * @returns Reactive signal representing the cookie value\n *\n * @example\n * ```ts\n * const theme = useCookie('theme', { defaultValue: 'light' });\n * theme.value = 'dark';\n * ```\n */\nexport const useCookie = <T>(name: string, options: UseCookieOptions<T> = {}): Signal<T | null> => {\n const cookieConfig = getBqueryConfig().cookies;\n const resolvedOptions: UseCookieOptions<T> = {\n path: cookieConfig?.path ?? '/',\n sameSite: cookieConfig?.sameSite ?? 'Lax',\n secure: cookieConfig?.secure ?? false,\n watch: true,\n ...options,\n };\n\n if (resolvedOptions.sameSite === 'None') {\n resolvedOptions.secure = true;\n }\n\n const raw = readCookie(name);\n let initialValue = (resolvedOptions.defaultValue ?? null) as T | null;\n\n if (raw !== null) {\n try {\n initialValue = resolvedOptions.deserialize\n ? resolvedOptions.deserialize(raw)\n : requiresJsonParsing(raw)\n ? (JSON.parse(raw) as T)\n : ((raw as T) ?? initialValue);\n } catch (error) {\n console.warn(`bQuery: Failed to deserialize cookie \"${name}\", using raw string value`, error);\n initialValue = (raw as T) ?? initialValue;\n }\n }\n\n const cookie = signal<T | null>(initialValue);\n\n if (typeof document === 'undefined' || resolvedOptions.watch === false) {\n return cookie;\n }\n\n let initialized = false;\n effect(() => {\n const nextValue = cookie.value;\n\n if (!initialized) {\n initialized = true;\n return;\n }\n\n if (nextValue == null) {\n removeCookie(name, resolvedOptions);\n return;\n }\n\n writeCookie(name, nextValue, resolvedOptions);\n });\n\n return cookie;\n};\n","/**\n * Web Notifications API wrapper.\n * Provides a simplified interface for browser notifications.\n */\n\n/**\n * Notification options matching the standard NotificationOptions interface.\n */\nexport interface NotificationOptions {\n /** Body text of the notification */\n body?: string;\n /** Icon URL for the notification */\n icon?: string;\n /** Badge icon for mobile devices */\n badge?: string;\n /** Tag for grouping notifications */\n tag?: string;\n /** Whether to require user interaction */\n requireInteraction?: boolean;\n /** Vibration pattern for mobile devices */\n vibrate?: number[];\n /** Additional data attached to the notification */\n data?: unknown;\n}\n\n/**\n * Notifications manager providing a clean interface for web notifications.\n */\nexport const notifications = {\n /**\n * Check if notifications are supported.\n * @returns True if Notification API is available\n */\n isSupported(): boolean {\n return 'Notification' in window;\n },\n\n /**\n * Get current permission status.\n * @returns Current permission state\n */\n getPermission(): NotificationPermission {\n if (!this.isSupported()) return 'denied';\n return Notification.permission;\n },\n\n /**\n * Request notification permission from the user.\n * @returns Promise resolving to the permission result\n */\n async requestPermission(): Promise<NotificationPermission> {\n if (!this.isSupported()) {\n return 'denied';\n }\n\n if (Notification.permission === 'granted') {\n return 'granted';\n }\n\n if (Notification.permission === 'denied') {\n return 'denied';\n }\n\n return Notification.requestPermission();\n },\n\n /**\n * Send a notification.\n * Requires 'granted' permission.\n * @param title - Notification title\n * @param options - Optional notification settings\n * @returns The Notification instance or null if not permitted\n */\n send(title: string, options?: NotificationOptions): Notification | null {\n if (!this.isSupported()) {\n console.warn('bQuery: Notifications not supported in this browser');\n return null;\n }\n\n if (Notification.permission !== 'granted') {\n console.warn('bQuery: Notification permission not granted');\n return null;\n }\n\n return new Notification(title, options);\n },\n};\n","/**\n * Accessibility live-region announcer helpers.\n *\n * @module bquery/platform\n */\n\nimport { effect, signal, type Signal } from '../reactive/signal';\nimport { getBqueryConfig } from './config';\n\n/** Options for creating an announcer. */\nexport interface UseAnnouncerOptions {\n /** Live region politeness. */\n politeness?: 'polite' | 'assertive';\n /** Whether the live region should be atomic. */\n atomic?: boolean;\n /** Delay before applying the message. */\n delay?: number;\n /** Delay after which the message is cleared automatically. */\n clearDelay?: number;\n /** Optional element id for the live region. */\n id?: string;\n /** Optional CSS class name. */\n className?: string;\n /** Optional container used to append the live region. */\n container?: HTMLElement;\n}\n\n/** Runtime options for a single announcement. */\nexport interface AnnounceOptions {\n /** Override politeness for this specific announcement. */\n politeness?: 'polite' | 'assertive';\n /** Override the message delay for this specific announcement. */\n delay?: number;\n /** Override the auto-clear delay for this specific announcement. */\n clearDelay?: number;\n}\n\n/** Returned announcer API. */\nexport interface AnnouncerHandle {\n /** The live region element or null outside the DOM. */\n element: HTMLElement | null;\n /** Reactive message signal. */\n message: Signal<string>;\n /** Announce a message to assistive technologies. */\n announce: (value: string, options?: AnnounceOptions) => void;\n /** Clear the current announcement. */\n clear: () => void;\n /** Remove the live region if it was created by this announcer. */\n destroy: () => void;\n}\n\nconst visuallyHiddenStyle = [\n 'position:absolute',\n 'width:1px',\n 'height:1px',\n 'padding:0',\n 'margin:-1px',\n 'overflow:hidden',\n 'clip:rect(0, 0, 0, 0)',\n 'white-space:nowrap',\n 'border:0',\n].join(';');\n\n/**\n * Create or reuse an accessible live region.\n *\n * @param options - Live region configuration\n * @returns An announcer handle with announce(), clear(), and destroy()\n *\n * @example\n * ```ts\n * const announcer = useAnnouncer();\n * announcer.announce('Saved successfully');\n * ```\n */\nexport const useAnnouncer = (options: UseAnnouncerOptions = {}): AnnouncerHandle => {\n const defaults = getBqueryConfig().announcer;\n const resolvedOptions: Required<\n Pick<UseAnnouncerOptions, 'politeness' | 'atomic' | 'delay' | 'clearDelay'>\n > &\n UseAnnouncerOptions = {\n politeness: defaults?.politeness ?? 'polite',\n atomic: defaults?.atomic ?? true,\n delay: defaults?.delay ?? 16,\n clearDelay: defaults?.clearDelay ?? 1000,\n ...options,\n };\n\n const message = signal('');\n\n if (typeof document === 'undefined') {\n return {\n element: null,\n message,\n announce(value: string) {\n message.value = value;\n },\n clear() {\n message.value = '';\n },\n destroy() {\n message.value = '';\n },\n };\n }\n\n const existing = resolvedOptions.id ? document.getElementById(resolvedOptions.id) : null;\n const element = (existing ?? document.createElement('div')) as HTMLElement;\n const created = !existing;\n\n if (resolvedOptions.id) {\n element.id = resolvedOptions.id;\n }\n\n if (resolvedOptions.className) {\n element.className = resolvedOptions.className;\n }\n\n element.setAttribute('aria-live', resolvedOptions.politeness);\n element.setAttribute('aria-atomic', String(resolvedOptions.atomic));\n element.setAttribute('role', resolvedOptions.politeness === 'assertive' ? 'alert' : 'status');\n element.setAttribute('data-bquery-announcer', 'true');\n if (!element.getAttribute('style')) {\n element.setAttribute('style', visuallyHiddenStyle);\n }\n\n if (created) {\n const parent = resolvedOptions.container ?? document.body ?? document.documentElement;\n if (!parent) {\n return {\n element: null,\n message,\n announce(value: string) {\n message.value = value;\n },\n clear() {\n message.value = '';\n },\n destroy() {\n message.value = '';\n },\n };\n }\n parent.appendChild(element);\n }\n\n const disposeMessageEffect = effect(() => {\n element.textContent = message.value;\n });\n\n let messageTimer: ReturnType<typeof setTimeout> | undefined;\n let clearTimer: ReturnType<typeof setTimeout> | undefined;\n let destroyed = false;\n\n const clearTimers = (): void => {\n if (messageTimer) {\n clearTimeout(messageTimer);\n messageTimer = undefined;\n }\n if (clearTimer) {\n clearTimeout(clearTimer);\n clearTimer = undefined;\n }\n };\n\n const clear = (): void => {\n if (destroyed) return;\n clearTimers();\n message.value = '';\n };\n\n const announce = (value: string, announceOptions: AnnounceOptions = {}): void => {\n if (destroyed) return;\n const politeness = announceOptions.politeness ?? resolvedOptions.politeness;\n const delay = announceOptions.delay ?? resolvedOptions.delay;\n const clearDelay = announceOptions.clearDelay ?? resolvedOptions.clearDelay;\n\n clearTimers();\n\n element.setAttribute('aria-live', politeness);\n element.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');\n message.value = '';\n\n messageTimer = setTimeout(() => {\n if (destroyed) return;\n message.value = value;\n if (clearDelay > 0) {\n clearTimer = setTimeout(() => {\n if (destroyed) return;\n message.value = '';\n }, clearDelay);\n }\n }, delay);\n };\n\n const destroy = (): void => {\n if (destroyed) return;\n destroyed = true;\n clearTimers();\n message.value = '';\n disposeMessageEffect();\n if (created) {\n element.remove();\n }\n };\n\n return { element, message, announce, clear, destroy };\n};\n","/**\n * Document title and meta helpers.\n *\n * @module bquery/platform\n */\n\nimport { getBqueryConfig } from './config';\n\n/** Meta tag definition. */\nexport interface PageMetaTag {\n /** Standard meta name attribute. */\n name?: string;\n /** Open Graph / custom property attribute. */\n property?: string;\n /** http-equiv attribute. */\n httpEquiv?: string;\n /** Meta tag content. */\n content: string;\n}\n\n/** Link tag definition. */\nexport interface PageLinkTag {\n /** Link relation. */\n rel: string;\n /** Link URL. */\n href: string;\n /** Optional type attribute. */\n type?: string;\n /** Optional media query. */\n media?: string;\n /** Optional crossOrigin attribute. */\n crossOrigin?: 'anonymous' | 'use-credentials';\n}\n\n/** Page metadata definition. */\nexport interface PageMetaDefinition {\n /** Document title. */\n title?: string;\n /** Convenience shortcut for the description meta tag. */\n description?: string;\n /** Additional meta tags. */\n meta?: PageMetaTag[];\n /** Additional link tags. */\n link?: PageLinkTag[];\n /** Attributes applied to the html element. */\n htmlAttributes?: Record<string, string>;\n /** Attributes applied to the body element. */\n bodyAttributes?: Record<string, string>;\n}\n\n/** Cleanup function returned by definePageMeta(). */\nexport type PageMetaCleanup = () => void;\n\nconst setAttributes = (target: HTMLElement, attributes: Record<string, string>): (() => void) => {\n const previousValues = new Map<string, string | null>();\n\n for (const [name, value] of Object.entries(attributes)) {\n previousValues.set(name, target.getAttribute(name));\n target.setAttribute(name, value);\n }\n\n return () => {\n for (const [name, value] of previousValues.entries()) {\n if (value == null) {\n target.removeAttribute(name);\n } else {\n target.setAttribute(name, value);\n }\n }\n };\n};\n\nconst createElement = <T extends 'meta' | 'link'>(\n tagName: T,\n attributes: Record<string, string | undefined>\n): HTMLElementTagNameMap[T] => {\n const element = document.createElement(tagName);\n element.setAttribute('data-bquery-page-meta', 'true');\n\n for (const [name, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n element.setAttribute(name, value);\n }\n }\n\n return element;\n};\n\n/**\n * Apply document metadata for the current page.\n *\n * @param definition - Title, meta tags, link tags, and document attributes\n * @returns Cleanup function that restores the previous document state\n *\n * @example\n * ```ts\n * const cleanup = definePageMeta({\n * title: 'Dashboard',\n * description: 'Overview of your account',\n * });\n * ```\n */\nexport const definePageMeta = (definition: PageMetaDefinition): PageMetaCleanup => {\n if (typeof document === 'undefined') {\n return () => {};\n }\n\n const config = getBqueryConfig().pageMeta;\n const title = definition.title\n ? config?.titleTemplate\n ? config.titleTemplate(definition.title)\n : definition.title\n : undefined;\n\n const inserted: HTMLElement[] = [];\n const restoreFns: Array<() => void> = [];\n const previousTitle = document.title;\n\n if (title !== undefined) {\n document.title = title;\n }\n\n const metaEntries = [...(definition.meta ?? [])];\n if (definition.description) {\n metaEntries.unshift({ name: 'description', content: definition.description });\n }\n\n for (const entry of metaEntries) {\n const meta = createElement('meta', {\n name: entry.name,\n property: entry.property,\n 'http-equiv': entry.httpEquiv,\n content: entry.content,\n });\n document.head.appendChild(meta);\n inserted.push(meta);\n }\n\n for (const entry of definition.link ?? []) {\n const link = createElement('link', {\n rel: entry.rel,\n href: entry.href,\n type: entry.type,\n media: entry.media,\n crossorigin: entry.crossOrigin,\n });\n document.head.appendChild(link);\n inserted.push(link);\n }\n\n if (definition.htmlAttributes) {\n restoreFns.push(setAttributes(document.documentElement, definition.htmlAttributes));\n }\n\n if (definition.bodyAttributes && document.body) {\n restoreFns.push(setAttributes(document.body, definition.bodyAttributes));\n }\n\n return () => {\n document.title = previousTitle;\n for (const restore of restoreFns.reverse()) {\n restore();\n }\n for (const element of inserted) {\n element.remove();\n }\n };\n};\n","/**\n * Unified storage adapters for web platform storage APIs.\n * Provides a consistent, promise-based interface with predictable errors.\n */\n\n/**\n * Common interface for all storage adapters.\n * All methods return promises for a unified async API.\n */\nexport interface StorageAdapter {\n /**\n * Retrieve a value by key.\n * @param key - The storage key\n * @returns The stored value or null if not found\n */\n get<T>(key: string): Promise<T | null>;\n\n /**\n * Store a value by key.\n * @param key - The storage key\n * @param value - The value to store\n */\n set<T>(key: string, value: T): Promise<void>;\n\n /**\n * Remove a value by key.\n * @param key - The storage key\n */\n remove(key: string): Promise<void>;\n\n /**\n * Clear all stored values.\n */\n clear(): Promise<void>;\n\n /**\n * Get all storage keys.\n * @returns Array of all keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Abstract base class for web storage adapters (localStorage/sessionStorage).\n * Implements DRY principle by sharing common logic.\n */\nabstract class WebStorageAdapter implements StorageAdapter {\n constructor(protected readonly storage: Storage) {}\n\n async get<T>(key: string): Promise<T | null> {\n const raw = this.storage.getItem(key);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return raw as unknown as T;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n const serialized = typeof value === 'string' ? value : JSON.stringify(value);\n this.storage.setItem(key, serialized);\n }\n\n async remove(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n\n async keys(): Promise<string[]> {\n const result: string[] = [];\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i);\n if (key !== null) {\n result.push(key);\n }\n }\n return result;\n }\n}\n\n/**\n * localStorage adapter with async interface.\n */\nclass LocalStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(localStorage);\n }\n}\n\n/**\n * sessionStorage adapter with async interface.\n */\nclass SessionStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(sessionStorage);\n }\n}\n\n/**\n * IndexedDB configuration options.\n */\nexport interface IndexedDBOptions {\n /** Database name */\n name: string;\n /** Object store name */\n store: string;\n /** Database version (optional) */\n version?: number;\n}\n\n/**\n * IndexedDB key-value adapter.\n * Wraps IndexedDB with a simple key-value interface.\n */\nclass IndexedDBAdapter implements StorageAdapter {\n private dbPromise: Promise<IDBDatabase> | null = null;\n\n constructor(private readonly options: IndexedDBOptions) {}\n\n /**\n * Opens or creates the IndexedDB database.\n */\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.options.name, this.options.version ?? 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.options.store)) {\n db.createObjectStore(this.options.store);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n /**\n * Executes a transaction on the object store.\n */\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.options.store, mode);\n const store = tx.objectStore(this.options.store);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async get<T>(key: string): Promise<T | null> {\n const result = await this.withStore<T | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(value, key));\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async clear(): Promise<void> {\n await this.withStore('readwrite', (store) => store.clear());\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Storage factory providing access to different storage adapters.\n */\nexport const storage = {\n /**\n * Create a localStorage adapter.\n * @returns StorageAdapter wrapping localStorage\n */\n local(): StorageAdapter {\n return new LocalStorageAdapter();\n },\n\n /**\n * Create a sessionStorage adapter.\n * @returns StorageAdapter wrapping sessionStorage\n */\n session(): StorageAdapter {\n return new SessionStorageAdapter();\n },\n\n /**\n * Create an IndexedDB adapter with key-value interface.\n * @param options - Database and store configuration\n * @returns StorageAdapter wrapping IndexedDB\n */\n indexedDB(options: IndexedDBOptions): StorageAdapter {\n return new IndexedDBAdapter(options);\n },\n};\n","/**\n * Internal router state (active router and current route signal).\n * @module bquery/router\n */\n\nimport { computed, signal, type ReadonlySignal, type Signal } from '../reactive/index';\nimport type { Route, Router } from './types';\n\n// ============================================================================\n// Internal State\n// ============================================================================\n\n/** @internal */\nlet activeRouter: Router | null = null;\n\n/** @internal */\nexport const routeSignal: Signal<Route> = signal<Route>({\n path: '',\n params: {},\n query: {},\n matched: null,\n hash: '',\n});\n\n/**\n * Reactive signal containing the current route.\n *\n * @example\n * ```ts\n * import { currentRoute } from 'bquery/router';\n * import { effect } from 'bquery/reactive';\n *\n * effect(() => {\n * document.title = `Page: ${currentRoute.value.path}`;\n * });\n * ```\n */\nexport const currentRoute: ReadonlySignal<Route> = computed(() => routeSignal.value);\n\n/** @internal */\nexport const getActiveRouter = (): Router | null => activeRouter;\n\n/** @internal */\nexport const setActiveRouter = (router: Router | null): void => {\n activeRouter = router;\n};\n","/**\n * Navigation helpers and global router access.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\n\n/**\n * Navigates to a new path.\n *\n * @param path - The path to navigate to\n * @param options - Navigation options\n *\n * @example\n * ```ts\n * import { navigate } from 'bquery/router';\n *\n * // Push to history\n * await navigate('/dashboard');\n *\n * // Replace current entry\n * await navigate('/login', { replace: true });\n * ```\n */\nexport const navigate = async (\n path: string,\n options: { replace?: boolean } = {}\n): Promise<void> => {\n const activeRouter = getActiveRouter();\n if (!activeRouter) {\n throw new Error('bQuery router: No router initialized. Call createRouter() first.');\n }\n\n await activeRouter[options.replace ? 'replace' : 'push'](path);\n};\n\n/**\n * Programmatically go back in history.\n *\n * @example\n * ```ts\n * import { back } from 'bquery/router';\n * back();\n * ```\n */\nexport const back = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.back();\n } else {\n history.back();\n }\n};\n\n/**\n * Programmatically go forward in history.\n *\n * @example\n * ```ts\n * import { forward } from 'bquery/router';\n * forward();\n * ```\n */\nexport const forward = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.forward();\n } else {\n history.forward();\n }\n};\n","/**\r\n * `<bq-link>` custom element for declarative SPA navigation.\r\n *\r\n * Exposes an accessible custom element that behaves like a link for\r\n * client-side routing. Automatically toggles an active class when the\r\n * target path matches the current route.\r\n *\r\n * @module bquery/router\r\n *\r\n * @example\r\n * ```html\r\n * <bq-link to=\"/\">Home</bq-link>\r\n * <bq-link to=\"/about\" active-class=\"selected\">About</bq-link>\r\n * <bq-link to=\"/settings\" replace exact>Settings</bq-link>\r\n * ```\r\n */\r\n\r\nimport { effect, type CleanupFn } from '../reactive/index';\r\nimport { navigate } from './navigation';\r\nimport { getActiveRouter, routeSignal } from './state';\r\n\r\n/**\r\n * Default CSS class applied when the link's target path is active.\r\n * @internal\r\n */\r\nconst DEFAULT_ACTIVE_CLASS = 'active';\r\n\r\n/** @internal */\r\nconst tokenizeClassNames = (value: string): string[] => {\r\n return value\r\n .split(/\\s+/)\r\n .map((token) => token.trim())\r\n .filter((token) => token.length > 0);\r\n};\r\n\r\n/** @internal SSR-safe base class for environments without HTMLElement. */\r\nconst BQ_LINK_BASE =\r\n typeof HTMLElement !== 'undefined' ? HTMLElement : (class {} as unknown as typeof HTMLElement);\r\n\r\n/**\r\n * `<bq-link>` — A navigation custom element for bQuery routers.\r\n *\r\n * Attributes:\r\n * - `to` — Target path (required). Example: `to=\"/dashboard\"`.\r\n * - `replace` — If present, replaces the current history entry instead of pushing.\r\n * - `exact` — If present, the active class is only applied on an exact path match.\r\n * - `active-class` — CSS class added when the route is active (default: `'active'`).\r\n *\r\n * The custom element itself acts as the interactive link target using\r\n * `role=\"link\"` and keyboard handling. It does not render a native `<a>`,\r\n * so browser-native link affordances like context-menu \"open in new tab\"\r\n * are not provided automatically.\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerBqLink } from '@bquery/bquery/router';\r\n *\r\n * // Register the <bq-link> element (idempotent)\r\n * registerBqLink();\r\n *\r\n * // Then use in HTML:\r\n * // <bq-link to=\"/about\">About</bq-link>\r\n * ```\r\n */\r\nexport class BqLinkElement extends BQ_LINK_BASE {\r\n /** @internal */\r\n private _cleanup: CleanupFn | null = null;\r\n\r\n /** @internal */\r\n private _trackedActiveClasses = new Map<string, boolean>();\r\n\r\n static get observedAttributes(): string[] {\r\n return ['to', 'replace', 'exact', 'active-class'];\r\n }\r\n\r\n /** The target path for navigation. */\r\n get to(): string {\r\n const to = this.getAttribute('to');\r\n return to == null || to.trim() === '' ? '/' : to;\r\n }\r\n\r\n set to(value: string) {\r\n this.setAttribute('to', value);\r\n }\r\n\r\n /** Whether to replace the current history entry. */\r\n get replace(): boolean {\r\n return this.hasAttribute('replace');\r\n }\r\n\r\n set replace(value: boolean) {\r\n if (value) {\r\n this.setAttribute('replace', '');\r\n } else {\r\n this.removeAttribute('replace');\r\n }\r\n }\r\n\r\n /** Whether to match the path exactly for active class. */\r\n get exact(): boolean {\r\n return this.hasAttribute('exact');\r\n }\r\n\r\n set exact(value: boolean) {\r\n if (value) {\r\n this.setAttribute('exact', '');\r\n } else {\r\n this.removeAttribute('exact');\r\n }\r\n }\r\n\r\n /** CSS class applied when the route is active. */\r\n get activeClass(): string {\r\n return this.getAttribute('active-class') ?? DEFAULT_ACTIVE_CLASS;\r\n }\r\n\r\n set activeClass(value: string) {\r\n this.setAttribute('active-class', value);\r\n }\r\n\r\n /** @internal */\r\n connectedCallback(): void {\r\n // Set role for accessibility if not an <a> already\r\n if (!this.getAttribute('role')) {\r\n this.setAttribute('role', 'link');\r\n }\r\n\r\n // Make focusable if not already\r\n if (!this.hasAttribute('tabindex')) {\r\n this.setAttribute('tabindex', '0');\r\n }\r\n\r\n // Attach click handler\r\n this.addEventListener('click', this._handleClick);\r\n this.addEventListener('keydown', this._handleKeydown);\r\n\r\n // Set up reactive active-class tracking\r\n this._setupActiveTracking();\r\n }\r\n\r\n /** @internal */\r\n disconnectedCallback(): void {\r\n this.removeEventListener('click', this._handleClick);\r\n this.removeEventListener('keydown', this._handleKeydown);\r\n\r\n if (this._cleanup) {\r\n this._cleanup();\r\n this._cleanup = null;\r\n }\r\n\r\n this._clearTrackedActiveClasses();\r\n }\r\n\r\n /** @internal */\r\n attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void {\r\n // Re-setup active tracking when relevant attributes change\r\n if (name === 'to' || name === 'exact' || name === 'active-class') {\r\n if (this.isConnected) {\r\n this._setupActiveTracking();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Sets up the reactive effect that toggles the active CSS class\r\n * based on the current route.\r\n * @internal\r\n */\r\n private _setupActiveTracking(): void {\r\n // Clean up previous effect\r\n if (this._cleanup) {\r\n this._cleanup();\r\n this._cleanup = null;\r\n }\r\n\r\n this._clearTrackedActiveClasses();\r\n\r\n const targetPath = this.to;\r\n const exactMatch = this.exact;\r\n const cssClasses = tokenizeClassNames(this.activeClass);\r\n this._trackedActiveClasses = new Map(\r\n cssClasses.map((cssClass) => [cssClass, this.classList.contains(cssClass)])\r\n );\r\n\r\n this._cleanup = effect(() => {\r\n const current = routeSignal.value.path;\r\n const isMatch = exactMatch\r\n ? current === targetPath\r\n : targetPath === '/'\r\n ? current === '/'\r\n : current === targetPath ||\r\n current.startsWith(targetPath.endsWith('/') ? targetPath : targetPath + '/');\r\n\r\n for (const cssClass of cssClasses) {\r\n const wasPresentInitially = this._trackedActiveClasses.get(cssClass) ?? false;\r\n this.classList.toggle(cssClass, isMatch || wasPresentInitially);\r\n }\r\n\r\n // Update aria-current for accessibility\r\n if (isMatch) {\r\n this.setAttribute('aria-current', 'page');\r\n } else {\r\n this.removeAttribute('aria-current');\r\n }\r\n });\r\n }\r\n\r\n /** @internal */\r\n private _clearTrackedActiveClasses(): void {\r\n for (const [cssClass, wasPresentInitially] of this._trackedActiveClasses) {\r\n this.classList.toggle(cssClass, wasPresentInitially);\r\n }\r\n this._trackedActiveClasses.clear();\r\n }\r\n\r\n /**\r\n * Handles click events for SPA navigation.\r\n * @internal\r\n */\r\n private _handleClick = (e: Event): void => {\r\n if (!(e instanceof MouseEvent)) return;\r\n if (e.defaultPrevented) return;\r\n if (e.button !== 0) return; // Only left clicks\r\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;\r\n\r\n e.preventDefault();\r\n this._navigate();\r\n };\r\n\r\n /**\r\n * Handles keyboard activation (Enter).\r\n * @internal\r\n */\r\n private _handleKeydown = (e: Event): void => {\r\n if (e instanceof KeyboardEvent && e.key === 'Enter') {\r\n e.preventDefault();\r\n this._navigate();\r\n }\r\n };\r\n\r\n /**\r\n * Performs the actual navigation.\r\n * @internal\r\n */\r\n private _navigate(): void {\r\n const targetPath = this.to;\r\n if (!targetPath) return;\r\n if (!getActiveRouter()) return;\r\n\r\n void navigate(targetPath, { replace: this.replace }).catch((err) => {\r\n console.error('bq-link: Navigation failed:', err);\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Registers the `<bq-link>` custom element.\r\n *\r\n * This function is idempotent — calling it multiple times is safe.\r\n * The element is registered under the tag name `bq-link`.\r\n *\r\n * @example\r\n * ```ts\r\n * import { registerBqLink } from '@bquery/bquery/router';\r\n *\r\n * registerBqLink();\r\n *\r\n * // Now use <bq-link to=\"/about\">About</bq-link> in HTML\r\n * ```\r\n */\r\nexport const registerBqLink = (): void => {\r\n if (\r\n typeof HTMLElement !== 'undefined' &&\r\n typeof customElements !== 'undefined' &&\r\n !customElements.get('bq-link')\r\n ) {\r\n customElements.define('bq-link', BqLinkElement);\r\n }\r\n};\r\n","/**\n * Link helpers for client-side navigation.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\nimport { navigate } from './navigation';\n\n// ============================================================================\n// Router Link Helper\n// ============================================================================\n\n/**\n * Creates click handler for router links.\n * Attach to anchor elements to enable client-side navigation.\n *\n * @param path - Target path\n * @param options - Navigation options\n * @returns Click event handler\n *\n * @example\n * ```ts\n * import { link } from 'bquery/router';\n * import { $ } from 'bquery/core';\n *\n * $('#nav-home').on('click', link('/'));\n * $('#nav-about').on('click', link('/about'));\n * ```\n */\nexport const link = (path: string, options: { replace?: boolean } = {}): ((e: Event) => void) => {\n return (e: Event) => {\n e.preventDefault();\n void navigate(path, options).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n};\n\n/**\n * Intercepts all link clicks within a container for client-side routing.\n * Only intercepts links with matching origins and no target attribute.\n *\n * @param container - The container element to intercept links in\n * @returns Cleanup function to remove the listener\n *\n * @example\n * ```ts\n * import { interceptLinks } from 'bquery/router';\n *\n * // Intercept all links in the app\n * const cleanup = interceptLinks(document.body);\n *\n * // Later, remove the interceptor\n * cleanup();\n * ```\n */\nexport const interceptLinks = (container?: Element): (() => void) => {\n // Provide safe default in DOM environments only\n const targetContainer = container ?? (typeof document !== 'undefined' ? document.body : null);\n if (!targetContainer) {\n // No container available (SSR or invalid input)\n return () => undefined;\n }\n\n const handler = (e: Event) => {\n // Only intercept standard left-clicks without modifier keys\n if (!(e instanceof MouseEvent)) return;\n if (e.defaultPrevented) return; // Already handled\n if (e.button !== 0) return; // Not left-click (middle-click opens new tab, right-click shows context menu)\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; // Modifier keys (Ctrl/Cmd-click = new tab)\n\n // Guard against non-Element targets and non-DOM environments\n if (typeof Element === 'undefined' || !(e.target instanceof Element)) return;\n const target = e.target as HTMLElement;\n const anchor = target.closest('a');\n\n if (!anchor) return;\n\n // Cross-realm compatible anchor check: use owner document's constructor if available\n const anchorWindow = anchor.ownerDocument.defaultView;\n const AnchorConstructor = anchorWindow?.HTMLAnchorElement ?? HTMLAnchorElement;\n if (!(anchor instanceof AnchorConstructor)) return;\n\n if (anchor.target) return; // Has target attribute\n if (anchor.hasAttribute('download')) return;\n if (typeof window === 'undefined') return; // Non-window environment\n if (anchor.origin !== window.location.origin) return; // External link\n\n // Get active router config to handle base paths correctly.\n // If no router is active, proceed with no base/hash; navigate() will throw a\n // \"No router initialized\" error, which is caught and logged below.\n const router = getActiveRouter();\n if (!router) {\n // No active router - trigger navigate(), allowing its error to be logged here\n e.preventDefault();\n void navigate(anchor.pathname + anchor.search + anchor.hash).catch((err) => {\n console.error('Navigation failed:', err);\n });\n return;\n }\n\n const base = router.base;\n const useHash = router.hash;\n\n // Detect hash-routing mode: links written as href=\"#/page\"\n // In this case, anchor.hash contains the route path\n let path: string;\n if (useHash && anchor.hash && anchor.hash.startsWith('#/')) {\n // Hash-routing mode: extract path from the hash\n // e.g., href=\"#/page?foo=bar\" → path = \"/page?foo=bar\"\n path = anchor.hash.slice(1); // Remove leading #\n } else {\n // History mode: use pathname + search + hash\n // Strip base from pathname to avoid duplication (router.push() re-adds it)\n let pathname = anchor.pathname;\n if (base && base !== '/' && pathname.startsWith(base)) {\n pathname = pathname.slice(base.length) || '/';\n }\n path = pathname + anchor.search + anchor.hash;\n }\n\n e.preventDefault();\n void navigate(path).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n\n targetContainer.addEventListener('click', handler);\n return () => targetContainer.removeEventListener('click', handler);\n};\n","/**\r\n * Query string helpers.\r\n * @module bquery/router\r\n */\r\n\r\nimport { isPrototypePollutionKey } from '../core/utils/object';\r\n\r\n/**\r\n * Parses query string into an object.\r\n * Single values are stored as strings, duplicate keys become arrays.\r\n * @internal\r\n *\r\n * @example\r\n * parseQuery('?foo=1') // { foo: '1' }\r\n * parseQuery('?tag=a&tag=b') // { tag: ['a', 'b'] }\r\n * parseQuery('?x=1&y=2&x=3') // { x: ['1', '3'], y: '2' }\r\n */\r\nexport const parseQuery = (search: string): Record<string, string | string[]> => {\r\n const query: Record<string, string | string[]> = {};\r\n const params = new URLSearchParams(search);\r\n\r\n params.forEach((value, key) => {\r\n if (isPrototypePollutionKey(key)) return;\r\n const existing = query[key];\r\n if (existing === undefined) {\r\n // First occurrence: store as string\r\n query[key] = value;\r\n } else if (Array.isArray(existing)) {\r\n // Already an array: append\r\n existing.push(value);\r\n } else {\r\n // Second occurrence: convert to array\r\n query[key] = [existing, value];\r\n }\r\n });\r\n\r\n return query;\r\n};\r\n","/**\r\n * Shared helpers for validating and normalizing route param constraints.\r\n * @internal\r\n */\r\n\r\nconst MAX_ROUTE_CONSTRAINT_CACHE_SIZE = 128;\r\nconst normalizedConstraintCache = new Map<string, string>();\r\nconst compiledConstraintRegexCache = new Map<string, RegExp>();\r\n\r\nconst setBoundedCacheEntry = <T>(cache: Map<string, T>, key: string, value: T): void => {\r\n if (cache.has(key)) {\r\n cache.delete(key);\r\n }\r\n\r\n cache.set(key, value);\r\n\r\n if (cache.size <= MAX_ROUTE_CONSTRAINT_CACHE_SIZE) {\r\n return;\r\n }\r\n\r\n const oldestKey = cache.keys().next().value;\r\n if (oldestKey !== undefined) {\r\n cache.delete(oldestKey);\r\n }\r\n};\r\n\r\n/**\r\n * Detects potentially super-linear (ReDoS) patterns caused by quantified\r\n * groups that already contain inner quantifiers, such as `(a+)+` or `(a*)*`.\r\n * @internal\r\n */\r\nconst hasNestedQuantifier = (pattern: string): boolean => {\r\n const groupQuantifierStack: boolean[] = [];\r\n let inCharClass = false;\r\n\r\n for (let i = 0; i < pattern.length; i++) {\r\n const ch = pattern[i];\r\n\r\n if (ch === '\\\\' && i + 1 < pattern.length) {\r\n i++;\r\n continue;\r\n }\r\n\r\n if (ch === '[' && !inCharClass) {\r\n inCharClass = true;\r\n continue;\r\n }\r\n if (ch === ']' && inCharClass) {\r\n inCharClass = false;\r\n continue;\r\n }\r\n if (inCharClass) continue;\r\n\r\n if (ch === '(') {\r\n groupQuantifierStack.push(false);\r\n continue;\r\n }\r\n\r\n if (ch === ')') {\r\n const groupHasInnerQuantifier = groupQuantifierStack.pop() ?? false;\r\n // Check if the closing paren is followed by a quantifier\r\n const next = pattern[i + 1];\r\n if (groupHasInnerQuantifier && (next === '+' || next === '*' || next === '?' || next === '{')) {\r\n return true;\r\n }\r\n if (groupHasInnerQuantifier && groupQuantifierStack.length > 0) {\r\n groupQuantifierStack[groupQuantifierStack.length - 1] = true;\r\n }\r\n continue;\r\n }\r\n\r\n if (groupQuantifierStack.length > 0) {\r\n if (ch === '?' && i > 0 && pattern[i - 1] === '(') {\r\n continue;\r\n }\r\n\r\n if (ch === '+' || ch === '*' || ch === '?' || ch === '{') {\r\n groupQuantifierStack[groupQuantifierStack.length - 1] = true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n};\r\n\r\nconst normalizeConstraintCaptures = (constraint: string): string => {\r\n let normalized = '';\r\n let inCharacterClass = false;\r\n\r\n for (let i = 0; i < constraint.length; i++) {\r\n const char = constraint[i];\r\n\r\n if (char === '\\\\' && i + 1 < constraint.length) {\r\n if (!inCharacterClass && constraint[i + 1] >= '1' && constraint[i + 1] <= '9') {\r\n throw new Error(\r\n `bQuery router: Route constraints cannot use backreferences: \"${constraint}\".`\r\n );\r\n }\r\n\r\n if (!inCharacterClass && constraint[i + 1] === 'k' && constraint[i + 2] === '<') {\r\n throw new Error(\r\n `bQuery router: Route constraints cannot use backreferences: \"${constraint}\".`\r\n );\r\n }\r\n\r\n normalized += char + constraint[i + 1];\r\n i++;\r\n continue;\r\n }\r\n\r\n if (char === '[' && !inCharacterClass) {\r\n inCharacterClass = true;\r\n normalized += char;\r\n continue;\r\n }\r\n\r\n if (char === ']' && inCharacterClass) {\r\n inCharacterClass = false;\r\n normalized += char;\r\n continue;\r\n }\r\n\r\n if (!inCharacterClass && char === '(') {\r\n if (i + 1 < constraint.length && constraint[i + 1] === '?') {\r\n if (constraint[i + 2] === '<') {\r\n if (constraint[i + 3] === '=' || constraint[i + 3] === '!') {\r\n normalized += '(';\r\n continue;\r\n }\r\n\r\n const namedCaptureEnd = constraint.indexOf('>', i + 3);\r\n if (namedCaptureEnd === -1) {\r\n throw new Error(\r\n `bQuery router: Invalid route constraint named capture group: \"${constraint}\".`\r\n );\r\n }\r\n normalized += '(?:';\r\n i = namedCaptureEnd;\r\n continue;\r\n }\r\n\r\n normalized += '(';\r\n continue;\r\n }\r\n\r\n normalized += '(?:';\r\n continue;\r\n }\r\n\r\n normalized += char;\r\n }\r\n\r\n return normalized;\r\n};\r\n\r\nexport const getNormalizedRouteConstraint = (constraint: string): string => {\r\n const cached = normalizedConstraintCache.get(constraint);\r\n if (cached !== undefined) {\r\n return cached;\r\n }\r\n\r\n const normalized = normalizeConstraintCaptures(constraint);\r\n setBoundedCacheEntry(normalizedConstraintCache, constraint, normalized);\r\n return normalized;\r\n};\r\n\r\nexport const getRouteConstraintRegex = (constraint: string): RegExp => {\r\n const normalizedConstraint = getNormalizedRouteConstraint(constraint);\r\n const cached = compiledConstraintRegexCache.get(normalizedConstraint);\r\n if (cached) {\r\n return cached;\r\n }\r\n\r\n if (hasNestedQuantifier(normalizedConstraint)) {\r\n throw new Error(\r\n `bQuery router: Route constraint contains a potentially catastrophic (ReDoS) pattern. Nested quantifiers are not allowed: \"${constraint}\".`\r\n );\r\n }\r\n\r\n try {\r\n const compiled = new RegExp(`^(?:${normalizedConstraint})$`);\r\n setBoundedCacheEntry(compiledConstraintRegexCache, normalizedConstraint, compiled);\r\n return compiled;\r\n } catch (error) {\r\n if (error instanceof SyntaxError) {\r\n throw new Error(\r\n `bQuery router: Invalid route constraint regex \"${constraint}\": ${error.message}`\r\n );\r\n }\r\n throw error;\r\n }\r\n};\r\n\r\nexport const routeConstraintMatches = (constraint: string, value: string): boolean => {\r\n return getRouteConstraintRegex(constraint).test(value);\r\n};\r\n\r\nexport const clearRouteConstraintCache = (): void => {\r\n normalizedConstraintCache.clear();\r\n compiledConstraintRegexCache.clear();\r\n};\r\n","/**\r\n * Shared helpers for parsing route path params and constraints.\r\n * @internal\r\n */\r\n\r\n/** Validates whether a character can start a route param name. @internal */\r\nexport const isParamStart = (char: string | undefined): boolean =>\r\n char !== undefined &&\r\n ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char === '_');\r\n\r\n/** Validates whether a character can appear after the start of a route param name. @internal */\r\nexport const isParamChar = (char: string | undefined): boolean =>\r\n isParamStart(char) || (char !== undefined && char >= '0' && char <= '9');\r\n\r\n/** Reads a route param constraint while preserving escaped chars and nested groups. @internal */\r\nexport const readConstraint = (\r\n path: string,\r\n startIndex: number\r\n): { constraint: string; endIndex: number } | null => {\r\n let depth = 1;\r\n let constraint = '';\r\n let i = startIndex + 1;\r\n let inCharacterClass = false;\r\n\r\n while (i < path.length) {\r\n const char = path[i];\r\n\r\n if (char === '\\\\' && i + 1 < path.length) {\r\n constraint += char + path[i + 1];\r\n i += 2;\r\n continue;\r\n }\r\n\r\n if (char === '[' && !inCharacterClass) {\r\n inCharacterClass = true;\r\n } else if (char === ']' && inCharacterClass) {\r\n inCharacterClass = false;\r\n } else if (!inCharacterClass && char === '(') {\r\n depth++;\r\n } else if (!inCharacterClass && char === ')') {\r\n depth--;\r\n if (depth === 0) {\r\n return { constraint, endIndex: i + 1 };\r\n }\r\n }\r\n\r\n constraint += char;\r\n i++;\r\n }\r\n\r\n return null;\r\n};\r\n","/**\r\n * Route matching helpers.\r\n * @module bquery/router\r\n */\r\n\r\nimport { parseQuery } from './query';\r\nimport { getNormalizedRouteConstraint, getRouteConstraintRegex } from './constraints';\r\nimport { isParamChar, isParamStart, readConstraint } from './path-pattern';\r\nimport type { Route, RouteDefinition } from './types';\r\n\r\nconst readConstraintOrThrow = (\r\n path: string,\r\n startIndex: number\r\n): { constraint: string; endIndex: number } => {\r\n const parsedConstraint = readConstraint(path, startIndex);\r\n if (!parsedConstraint) {\r\n throw new Error(\r\n `bQuery router: Invalid route param constraint syntax in path \"${path}\" at index ${startIndex}.`\r\n );\r\n }\r\n return parsedConstraint;\r\n};\r\n\r\ntype RouteParamDescriptor = {\r\n name: string;\r\n constraint?: string;\r\n nextIndex: number;\r\n};\r\n\r\nconst validatedRoutePathCache = new Set<string>();\r\n\r\nconst readParamDescriptor = (path: string, index: number): RouteParamDescriptor | null => {\r\n if (path[index] !== ':' || !isParamStart(path[index + 1])) {\r\n return null;\r\n }\r\n\r\n let nameEnd = index + 2;\r\n while (nameEnd < path.length && isParamChar(path[nameEnd])) {\r\n nameEnd++;\r\n }\r\n\r\n let nextIndex = nameEnd;\r\n let constraint: string | undefined;\r\n\r\n if (path[nameEnd] === '(') {\r\n const parsedConstraint = readConstraintOrThrow(path, nameEnd);\r\n constraint = parsedConstraint.constraint;\r\n nextIndex = parsedConstraint.endIndex;\r\n }\r\n\r\n return {\r\n name: path.slice(index + 1, nameEnd),\r\n constraint,\r\n nextIndex,\r\n };\r\n};\r\n\r\nconst validateRoutePathPattern = (path: string): void => {\r\n if (validatedRoutePathCache.has(path)) {\r\n return;\r\n }\r\n\r\n for (let i = 0; i < path.length; ) {\r\n const char = path[i];\r\n\r\n if (char === ':' && isParamStart(path[i + 1])) {\r\n const param = readParamDescriptor(path, i);\r\n if (param?.constraint) {\r\n getNormalizedRouteConstraint(param.constraint);\r\n }\r\n i = param?.nextIndex ?? i + 1;\r\n continue;\r\n }\r\n\r\n i++;\r\n }\r\n\r\n validatedRoutePathCache.add(path);\r\n};\r\n\r\nconst findSegmentBoundary = (value: string, startIndex: number): number => {\r\n const slashIndex = value.indexOf('/', startIndex);\r\n return slashIndex === -1 ? value.length : slashIndex;\r\n};\r\n\r\nconst readNextStaticChunk = (path: string, startIndex: number): string => {\r\n let chunkEnd = startIndex;\r\n\r\n while (chunkEnd < path.length) {\r\n if (path[chunkEnd] === '*') {\r\n break;\r\n }\r\n\r\n if (path[chunkEnd] === ':' && isParamStart(path[chunkEnd + 1])) {\r\n break;\r\n }\r\n\r\n chunkEnd++;\r\n }\r\n\r\n return path.slice(startIndex, chunkEnd);\r\n};\r\n\r\nconst findAnchoredCandidateEnds = (\r\n actualPath: string,\r\n startIndex: number,\r\n limit: number,\r\n nextStaticChunk: string\r\n): number[] => {\r\n const candidates: number[] = [];\r\n let searchIndex = startIndex;\r\n\r\n while (searchIndex <= limit) {\r\n const candidateEnd = actualPath.indexOf(nextStaticChunk, searchIndex);\r\n if (candidateEnd === -1 || candidateEnd > limit) {\r\n break;\r\n }\r\n\r\n candidates.push(candidateEnd);\r\n searchIndex = candidateEnd + 1;\r\n }\r\n\r\n return candidates.reverse();\r\n};\r\n\r\nconst matchPathPattern = (routePath: string, actualPath: string): Record<string, string> | null => {\r\n // Memoization keeps wildcard/param backtracking linear for repeated subproblems\r\n // within a single route/path match attempt.\r\n const memo = new Map<string, Record<string, string> | null>();\r\n\r\n const matchFrom = (routeIndex: number, pathIndex: number): Record<string, string> | null => {\r\n const memoKey = `${routeIndex}:${pathIndex}`;\r\n if (memo.has(memoKey)) {\r\n return memo.get(memoKey) ?? null;\r\n }\r\n\r\n if (routeIndex === routePath.length) {\r\n const result = pathIndex === actualPath.length ? {} : null;\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n\r\n const routeChar = routePath[routeIndex];\r\n\r\n if (routeChar === '*') {\r\n if (routeIndex === routePath.length - 1) {\r\n const result = {};\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n\r\n const nextStaticChunk = readNextStaticChunk(routePath, routeIndex + 1);\r\n const anchoredCandidateEnds =\r\n nextStaticChunk.length > 0\r\n ? findAnchoredCandidateEnds(actualPath, pathIndex, actualPath.length, nextStaticChunk)\r\n : null;\r\n\r\n const iterateCandidateEnds = anchoredCandidateEnds\r\n ? (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (const candidateEnd of anchoredCandidateEnds) {\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n }\r\n : (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (let candidateEnd = actualPath.length; candidateEnd >= pathIndex; candidateEnd--) {\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n };\r\n\r\n const wildcardMatch = iterateCandidateEnds((candidateEnd) => {\r\n const suffixMatch = matchFrom(routeIndex + 1, candidateEnd);\r\n if (suffixMatch) {\r\n memo.set(memoKey, suffixMatch);\r\n return suffixMatch;\r\n }\r\n return null;\r\n });\r\n\r\n if (wildcardMatch) {\r\n return wildcardMatch;\r\n }\r\n\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n const param = readParamDescriptor(routePath, routeIndex);\r\n if (param) {\r\n const constraintRegex = param.constraint\r\n ? getRouteConstraintRegex(param.constraint)\r\n : undefined;\r\n const candidateLimit = param.constraint\r\n ? actualPath.length\r\n : findSegmentBoundary(actualPath, pathIndex);\r\n const nextStaticChunk = readNextStaticChunk(routePath, param.nextIndex);\r\n const anchoredCandidateEnds =\r\n nextStaticChunk.length > 0\r\n ? findAnchoredCandidateEnds(actualPath, pathIndex, candidateLimit, nextStaticChunk)\r\n : null;\r\n\r\n const iterateCandidateEnds = anchoredCandidateEnds\r\n ? (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (const candidateEnd of anchoredCandidateEnds) {\r\n if (candidateEnd <= pathIndex) {\r\n continue;\r\n }\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n }\r\n : (callback: (candidateEnd: number) => Record<string, string> | null) => {\r\n for (let candidateEnd = candidateLimit; candidateEnd > pathIndex; candidateEnd--) {\r\n const result = callback(candidateEnd);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n return null;\r\n };\r\n\r\n const paramMatch = iterateCandidateEnds((candidateEnd) => {\r\n const candidateValue = actualPath.slice(pathIndex, candidateEnd);\r\n\r\n if (constraintRegex) {\r\n if (!constraintRegex.test(candidateValue)) {\r\n return null;\r\n }\r\n }\r\n\r\n const suffixMatch = matchFrom(param.nextIndex, candidateEnd);\r\n if (suffixMatch) {\r\n const result = {\r\n [param.name]: candidateValue,\r\n ...suffixMatch,\r\n };\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n return null;\r\n });\r\n\r\n if (paramMatch) {\r\n return paramMatch;\r\n }\r\n\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n if (pathIndex >= actualPath.length || routeChar !== actualPath[pathIndex]) {\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n const result = matchFrom(routeIndex + 1, pathIndex + 1);\r\n memo.set(memoKey, result);\r\n return result;\r\n };\r\n\r\n return matchFrom(0, 0);\r\n};\r\n\r\n/**\r\n * Matches a path against route definitions and extracts params.\r\n * @internal\r\n */\r\nexport const matchRoute = (\r\n path: string,\r\n routes: RouteDefinition[]\r\n): { matched: RouteDefinition; params: Record<string, string> } | null => {\r\n for (const route of routes) {\r\n validateRoutePathPattern(route.path);\r\n const params = matchPathPattern(route.path, path);\r\n if (params) {\r\n return { matched: route, params };\r\n }\r\n }\r\n\r\n return null;\r\n};\r\n\r\n/**\r\n * Creates a Route object from the current URL.\r\n * @internal\r\n */\r\nexport const createRoute = (\r\n pathname: string,\r\n search: string,\r\n hash: string,\r\n routes: RouteDefinition[]\r\n): Route => {\r\n const result = matchRoute(pathname, routes);\r\n\r\n return {\r\n path: pathname,\r\n params: result?.params ?? {},\r\n query: parseQuery(search),\r\n matched: result?.matched ?? null,\r\n hash: hash.replace(/^#/, ''),\r\n };\r\n};\r\n","/**\r\n * Router utilities.\r\n * @module bquery/router\r\n */\r\n\r\nimport { computed, type ReadonlySignal } from '../reactive/index';\r\nimport { getRouteConstraintRegex } from './constraints';\r\nimport { isParamChar, isParamStart, readConstraint } from './path-pattern';\r\nimport { getActiveRouter, routeSignal } from './state';\r\nimport type { RouteDefinition } from './types';\r\n\r\n// ============================================================================\r\n// Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Flattens nested routes into a single array with full paths.\r\n * Does NOT include the router base - base is only for browser history.\r\n * @internal\r\n */\r\nexport const flattenRoutes = (routes: RouteDefinition[], parentPath = ''): RouteDefinition[] => {\r\n const result: RouteDefinition[] = [];\r\n\r\n for (const route of routes) {\r\n const fullPath = route.path === '*' ? '*' : `${parentPath}${route.path}`.replace(/\\/+/g, '/');\r\n\r\n result.push({\r\n ...route,\r\n path: fullPath,\r\n });\r\n\r\n if (route.children) {\r\n result.push(...flattenRoutes(route.children, fullPath));\r\n }\r\n }\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Resolves a route by name and params.\r\n *\r\n * @param name - The route name\r\n * @param params - Route params to interpolate\r\n * @returns The resolved path\r\n * @throws {Error} If no router is initialized, the route name is unknown,\r\n * a required path param is missing from `params`, a param value does not satisfy\r\n * its route regex constraint, or a route param constraint has invalid syntax\r\n *\r\n * @example\r\n * ```ts\r\n * import { resolve } from 'bquery/router';\r\n *\r\n * const path = resolve('user', { id: '42' });\r\n * // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }\r\n * ```\r\n */\r\nexport const resolve = (name: string, params: Record<string, string> = {}): string => {\r\n const activeRouter = getActiveRouter();\r\n if (!activeRouter) {\r\n throw new Error('bQuery router: No router initialized.');\r\n }\r\n\r\n const route = activeRouter.routes.find((r) => r.name === name);\r\n if (!route) {\r\n throw new Error(`bQuery router: Route \"${name}\" not found.`);\r\n }\r\n\r\n let path = '';\r\n for (let i = 0; i < route.path.length; ) {\r\n if (route.path[i] === ':' && isParamStart(route.path[i + 1])) {\r\n let nameEnd = i + 2;\r\n while (nameEnd < route.path.length && isParamChar(route.path[nameEnd])) {\r\n nameEnd++;\r\n }\r\n\r\n let nextIndex = nameEnd;\r\n let constraint: string | null = null;\r\n if (route.path[nameEnd] === '(') {\r\n const parsedConstraint = readConstraint(route.path, nameEnd);\r\n if (!parsedConstraint) {\r\n throw new Error(\r\n `bQuery router: Invalid constraint syntax in path \"${route.path}\" for route \"${name}\".`\r\n );\r\n }\r\n constraint = parsedConstraint.constraint;\r\n nextIndex = parsedConstraint.endIndex;\r\n }\r\n\r\n const key = route.path.slice(i + 1, nameEnd);\r\n const value = params[key];\r\n if (value === undefined) {\r\n throw new Error(`bQuery router: Missing required param \"${key}\" for route \"${name}\".`);\r\n }\r\n if (constraint && !getRouteConstraintRegex(constraint).test(value)) {\r\n throw new Error(\r\n `bQuery router: Param \"${key}\" with value \"${value}\" does not satisfy the route constraint \"${constraint}\" for route \"${name}\".`\r\n );\r\n }\r\n\r\n path += encodeURIComponent(value);\r\n i = nextIndex;\r\n continue;\r\n }\r\n\r\n path += route.path[i];\r\n i++;\r\n }\r\n\r\n return path;\r\n};\r\n\r\n/**\r\n * Checks if a path matches the current route.\r\n *\r\n * @param path - Path to check\r\n * @param exact - Whether to match exactly (default: false)\r\n * @returns True if the path matches\r\n *\r\n * @example\r\n * ```ts\r\n * import { isActive } from 'bquery/router';\r\n *\r\n * if (isActive('/dashboard')) {\r\n * // Highlight nav item\r\n * }\r\n * ```\r\n */\r\nexport const isActive = (path: string, exact = false): boolean => {\r\n const current = routeSignal.value.path;\r\n return exact ? current === path : current.startsWith(path);\r\n};\r\n\r\n/**\r\n * Creates a computed signal that checks if a path is active.\r\n *\r\n * @param path - Path to check\r\n * @param exact - Whether to match exactly\r\n * @returns A reactive signal\r\n *\r\n * @example\r\n * ```ts\r\n * import { isActiveSignal } from 'bquery/router';\r\n * import { effect } from 'bquery/reactive';\r\n *\r\n * const dashboardActive = isActiveSignal('/dashboard');\r\n * effect(() => {\r\n * navItem.classList.toggle('active', dashboardActive.value);\r\n * });\r\n * ```\r\n */\r\nexport const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {\r\n return computed(() => {\r\n const current = routeSignal.value.path;\r\n return exact ? current === path : current.startsWith(path);\r\n });\r\n};\r\n","/**\r\n * Router creation and lifecycle management.\r\n * @module bquery/router\r\n */\r\n\r\nimport { isPrototypePollutionKey } from '../core/utils/object';\r\nimport { createRoute } from './match';\r\nimport { currentRoute, getActiveRouter, routeSignal, setActiveRouter } from './state';\r\nimport type { NavigationGuard, Route, Router, RouterOptions } from './types';\r\nimport { flattenRoutes } from './utils';\r\n\r\n// ============================================================================\r\n// Router Creation\r\n// ============================================================================\r\n\r\nconst MAX_SCROLL_POSITION_ENTRIES = 100;\r\n\r\nconst sanitizeHistoryState = (state: Record<string, unknown>): Record<string, unknown> => {\r\n const sanitized: Record<string, unknown> = {};\r\n\r\n for (const [key, value] of Object.entries(state)) {\r\n if (isPrototypePollutionKey(key)) continue;\r\n sanitized[key] = value;\r\n }\r\n\r\n return sanitized;\r\n};\r\n\r\n/**\r\n * Creates and initializes a router instance.\r\n *\r\n * @param options - Router configuration\r\n * @returns The router instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createRouter } from 'bquery/router';\r\n *\r\n * const router = createRouter({\r\n * routes: [\r\n * { path: '/', component: () => import('./pages/Home') },\r\n * { path: '/about', component: () => import('./pages/About') },\r\n * { path: '/user/:id(\\\\d+)', component: () => import('./pages/User') },\r\n * { path: '/old-page', redirectTo: '/new-page' },\r\n * { path: '*', component: () => import('./pages/NotFound') },\r\n * ],\r\n * base: '/app',\r\n * scrollRestoration: true,\r\n * });\r\n *\r\n * router.beforeEach((to, from) => {\r\n * if (to.path === '/admin' && !isAuthenticated()) {\r\n * return false; // Cancel navigation\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const createRouter = (options: RouterOptions): Router => {\r\n // Clean up any existing router to prevent guard leakage\r\n const existingRouter = getActiveRouter();\r\n if (existingRouter) {\r\n existingRouter.destroy();\r\n }\r\n\r\n const { routes, base = '', hash: useHash = false, scrollRestoration = false } = options;\r\n\r\n // Instance-specific guards and hooks (not shared globally)\r\n const beforeGuards: NavigationGuard[] = [];\r\n const afterHooks: Array<(to: Route, from: Route) => void> = [];\r\n\r\n // Flatten nested routes (base-relative, not including the base path)\r\n const flatRoutes = flattenRoutes(routes);\r\n\r\n // Scroll position storage keyed by history state id\r\n const scrollPositions = new Map<string, { x: number; y: number }>();\r\n let currentScrollKey = '0';\r\n let scrollKeyCounter = 0;\r\n let previousScrollRestoration: History['scrollRestoration'] | null = null;\r\n\r\n // Enable manual scroll restoration if scrollRestoration is configured\r\n if (scrollRestoration && typeof history !== 'undefined' && 'scrollRestoration' in history) {\r\n previousScrollRestoration = history.scrollRestoration;\r\n if (history.scrollRestoration !== 'manual') {\r\n history.scrollRestoration = 'manual';\r\n }\r\n\r\n const state =\r\n history.state && typeof history.state === 'object'\r\n ? (history.state as Record<string, unknown>)\r\n : {};\r\n\r\n if (typeof state.__bqScrollKey !== 'string') {\r\n const currentUrl = useHash\r\n ? window.location.hash || '#/'\r\n : `${window.location.pathname}${window.location.search}${window.location.hash}`;\r\n history.replaceState({ ...state, __bqScrollKey: currentScrollKey }, '', currentUrl);\r\n }\r\n }\r\n\r\n /**\r\n * Generates a unique key for the current history entry.\r\n * @internal\r\n */\r\n const getScrollKey = (): string => {\r\n return (history.state && history.state.__bqScrollKey) || currentScrollKey;\r\n };\r\n\r\n /**\r\n * Generates a unique key for a new history entry.\r\n * @internal\r\n */\r\n const createScrollKey = (): string => `${Date.now()}-${scrollKeyCounter++}`;\r\n\r\n /**\r\n * Saves current scroll position for the current history entry.\r\n * @internal\r\n */\r\n const saveScrollPosition = (key = getScrollKey()): void => {\r\n if (!scrollRestoration) return;\r\n if (scrollPositions.has(key)) {\r\n // Refresh the insertion order so pruning behaves like an LRU cache.\r\n scrollPositions.delete(key);\r\n }\r\n scrollPositions.set(key, { x: window.scrollX, y: window.scrollY });\r\n while (scrollPositions.size > MAX_SCROLL_POSITION_ENTRIES) {\r\n const oldestKey = scrollPositions.keys().next().value as string | undefined;\r\n if (oldestKey === undefined) {\r\n break;\r\n }\r\n scrollPositions.delete(oldestKey);\r\n }\r\n };\r\n\r\n /**\r\n * Restores scroll position for the current history entry.\r\n * @internal\r\n */\r\n const restoreScrollPosition = (key = getScrollKey()): void => {\r\n if (!scrollRestoration) return;\r\n const pos = scrollPositions.get(key);\r\n if (pos) {\r\n window.scrollTo(pos.x, pos.y);\r\n } else {\r\n window.scrollTo(0, 0);\r\n }\r\n };\r\n\r\n /**\r\n * Builds history state for canceled navigations without dropping\r\n * the scroll restoration key for the current entry.\r\n * @internal\r\n */\r\n const getRestoreHistoryState = (): Record<string, unknown> => {\r\n const state =\r\n history.state && typeof history.state === 'object'\r\n ? { ...(history.state as Record<string, unknown>) }\r\n : {};\r\n\r\n if (scrollRestoration) {\r\n state.__bqScrollKey = currentScrollKey;\r\n }\r\n\r\n return state;\r\n };\r\n\r\n /**\r\n * Gets the current path from the URL.\r\n */\r\n const getCurrentPath = (): { pathname: string; search: string; hash: string } => {\r\n if (useHash) {\r\n const hashPath = window.location.hash.slice(1) || '/';\r\n // In hash routing, URL structure is #/path?query#fragment\r\n // Extract hash fragment first (after the second #)\r\n const [pathWithQuery, hashPart = ''] = hashPath.split('#');\r\n // Then extract query from the path\r\n const [pathname, search = ''] = pathWithQuery.split('?');\r\n return {\r\n pathname,\r\n search: search ? `?${search}` : '',\r\n hash: hashPart ? `#${hashPart}` : '',\r\n };\r\n }\r\n\r\n let pathname = window.location.pathname;\r\n if (base && (pathname === base || pathname.startsWith(base + '/'))) {\r\n pathname = pathname.slice(base.length) || '/';\r\n }\r\n\r\n return {\r\n pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n };\r\n };\r\n\r\n /**\r\n * Updates the route signal with current URL state.\r\n */\r\n const syncRoute = (): void => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const newRoute = createRoute(pathname, search, hash, flatRoutes);\r\n routeSignal.value = newRoute;\r\n };\r\n\r\n /**\r\n * Performs navigation with guards.\r\n */\r\n const performNavigation = async (\r\n path: string,\r\n method: 'pushState' | 'replaceState',\r\n visitedPaths: Set<string> = new Set()\r\n ): Promise<void> => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const from = createRoute(pathname, search, hash, flatRoutes);\r\n\r\n // Parse the target path\r\n const url = new URL(path, window.location.origin);\r\n const resolvedPath = `${url.pathname}${url.search}${url.hash}`;\r\n if (visitedPaths.has(resolvedPath)) {\r\n throw new Error(`bQuery router: redirect loop detected for path \"${resolvedPath}\"`);\r\n }\r\n visitedPaths.add(resolvedPath);\r\n const to = createRoute(url.pathname, url.search, url.hash, flatRoutes);\r\n\r\n // Check for redirectTo on the matched route\r\n if (to.matched?.redirectTo) {\r\n // Navigate to the redirect target instead\r\n await performNavigation(to.matched.redirectTo, method, visitedPaths);\r\n return;\r\n }\r\n\r\n // Run route-level beforeEnter guard\r\n if (to.matched?.beforeEnter) {\r\n const result = await to.matched.beforeEnter(to, from);\r\n if (result === false) {\r\n return; // Cancel navigation\r\n }\r\n }\r\n\r\n // Run beforeEach guards\r\n for (const guard of beforeGuards) {\r\n const result = await guard(to, from);\r\n if (result === false) {\r\n return; // Cancel navigation\r\n }\r\n }\r\n\r\n // Save scroll position before navigation\r\n saveScrollPosition();\r\n\r\n // Update browser history\r\n const existingScrollKey = scrollRestoration ? getScrollKey() : undefined;\r\n const scrollKey =\r\n method === 'replaceState' && existingScrollKey ? existingScrollKey : createScrollKey();\r\n const fullPath = useHash ? `#${path}` : `${base}${path}`;\r\n const baseState =\r\n scrollRestoration && history.state && typeof history.state === 'object'\r\n ? sanitizeHistoryState(history.state as Record<string, unknown>)\r\n : {};\r\n const state = scrollRestoration ? { ...baseState, __bqScrollKey: scrollKey } : {};\r\n history[method](state, '', fullPath);\r\n currentScrollKey = scrollKey;\r\n\r\n // Update route signal\r\n syncRoute();\r\n\r\n // Scroll to top on push navigation\r\n if (scrollRestoration && method === 'pushState') {\r\n window.scrollTo(0, 0);\r\n }\r\n\r\n // Run afterEach hooks\r\n for (const hook of afterHooks) {\r\n hook(routeSignal.value, from);\r\n }\r\n };\r\n\r\n /**\r\n * Handle popstate events (back/forward).\r\n */\r\n const handlePopState = async (event: PopStateEvent): Promise<void> => {\r\n const { pathname, search, hash } = getCurrentPath();\r\n const from = routeSignal.value;\r\n const to = createRoute(pathname, search, hash, flatRoutes);\r\n\r\n // Check for redirectTo on the matched route\r\n if (to.matched?.redirectTo) {\r\n await performNavigation(to.matched.redirectTo, 'replaceState');\r\n return;\r\n }\r\n\r\n // Run route-level beforeEnter guard\r\n if (to.matched?.beforeEnter) {\r\n const result = await to.matched.beforeEnter(to, from);\r\n if (result === false) {\r\n // Restore previous state with full URL (including query/hash)\r\n const queryString = new URLSearchParams(\r\n Object.entries(from.query).flatMap(([key, value]) =>\r\n Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]\r\n )\r\n ).toString();\r\n const searchStr = queryString ? `?${queryString}` : '';\r\n const hashStr = from.hash ? `#${from.hash}` : '';\r\n const restorePath = useHash\r\n ? `#${from.path}${searchStr}${hashStr}`\r\n : `${base}${from.path}${searchStr}${hashStr}`;\r\n history.replaceState(getRestoreHistoryState(), '', restorePath);\r\n return;\r\n }\r\n }\r\n\r\n // Run beforeEach guards (supports async guards)\r\n for (const guard of beforeGuards) {\r\n const result = await guard(to, from);\r\n if (result === false) {\r\n // Restore previous state with full URL (including query/hash)\r\n const queryString = new URLSearchParams(\r\n Object.entries(from.query).flatMap(([key, value]) =>\r\n Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]\r\n )\r\n ).toString();\r\n const search = queryString ? `?${queryString}` : '';\r\n const hash = from.hash ? `#${from.hash}` : '';\r\n const restorePath = useHash\r\n ? `#${from.path}${search}${hash}`\r\n : `${base}${from.path}${search}${hash}`;\r\n history.replaceState(getRestoreHistoryState(), '', restorePath);\r\n return;\r\n }\r\n }\r\n\r\n // Save scroll position of the page we're leaving\r\n saveScrollPosition(currentScrollKey);\r\n\r\n // Update scroll key from history state\r\n currentScrollKey =\r\n (event.state as { __bqScrollKey?: string } | null)?.__bqScrollKey ?? getScrollKey();\r\n\r\n syncRoute();\r\n\r\n // Restore scroll position for the entry we're navigating to\r\n restoreScrollPosition(currentScrollKey);\r\n\r\n for (const hook of afterHooks) {\r\n hook(routeSignal.value, from);\r\n }\r\n };\r\n\r\n // Attach popstate listener\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n // Initialize route\r\n syncRoute();\r\n\r\n const router: Router = {\r\n push: (path: string) => performNavigation(path, 'pushState'),\r\n replace: (path: string) => performNavigation(path, 'replaceState'),\r\n back: () => history.back(),\r\n forward: () => history.forward(),\r\n go: (delta: number) => history.go(delta),\r\n\r\n beforeEach: (guard: NavigationGuard) => {\r\n beforeGuards.push(guard);\r\n return () => {\r\n const index = beforeGuards.indexOf(guard);\r\n if (index > -1) beforeGuards.splice(index, 1);\r\n };\r\n },\r\n\r\n afterEach: (hook: (to: Route, from: Route) => void) => {\r\n afterHooks.push(hook);\r\n return () => {\r\n const index = afterHooks.indexOf(hook);\r\n if (index > -1) afterHooks.splice(index, 1);\r\n };\r\n },\r\n\r\n currentRoute,\r\n routes: flatRoutes,\r\n base,\r\n hash: useHash,\r\n\r\n destroy: () => {\r\n window.removeEventListener('popstate', handlePopState);\r\n beforeGuards.length = 0;\r\n afterHooks.length = 0;\r\n scrollPositions.clear();\r\n // Restore the previous scroll restoration mode on destroy\r\n if (\r\n previousScrollRestoration !== null &&\r\n typeof history !== 'undefined' &&\r\n 'scrollRestoration' in history\r\n ) {\r\n history.scrollRestoration = previousScrollRestoration;\r\n }\r\n setActiveRouter(null);\r\n },\r\n };\r\n\r\n setActiveRouter(router);\r\n return router;\r\n};\r\n","/**\r\n * Reactive route composable.\r\n * @module bquery/router\r\n */\r\n\r\nimport { computed, type ReadonlySignal } from '../reactive/index';\r\nimport { routeSignal } from './state';\r\nimport type { Route, RouteDefinition } from './types';\r\n\r\n// ============================================================================\r\n// useRoute Composable\r\n// ============================================================================\r\n\r\n/**\r\n * Return type for {@link useRoute}.\r\n * Provides reactive access to individual route properties.\r\n */\r\nexport type UseRouteReturn = {\r\n /** Full reactive route object */\r\n route: ReadonlySignal<Route>;\r\n /** Reactive current path */\r\n path: ReadonlySignal<string>;\r\n /** Reactive route params */\r\n params: ReadonlySignal<Record<string, string>>;\r\n /** Reactive query params */\r\n query: ReadonlySignal<Record<string, string | string[]>>;\r\n /** Reactive hash fragment (without #) */\r\n hash: ReadonlySignal<string>;\r\n /** Reactive matched route definition */\r\n matched: ReadonlySignal<RouteDefinition | null>;\r\n};\r\n\r\nconst route = computed(() => routeSignal.value);\r\nconst path = computed(() => route.value.path);\r\nconst params = computed(() => route.value.params);\r\nconst query = computed(() => route.value.query);\r\nconst hash = computed(() => route.value.hash);\r\nconst matched = computed(() => route.value.matched);\r\n\r\nconst routeHandle: UseRouteReturn = { route, path, params, query, hash, matched };\r\n\r\n/**\r\n * Returns reactive access to the current route, params, query, and hash.\r\n *\r\n * Each property is a readonly computed signal that updates automatically\r\n * when the route changes. This is useful for fine-grained reactivity\r\n * where you only need to subscribe to specific route parts.\r\n *\r\n * @returns An object with reactive route properties\r\n *\r\n * @example\r\n * ```ts\r\n * import { useRoute } from '@bquery/bquery/router';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const { path, params, query, hash } = useRoute();\r\n *\r\n * effect(() => {\r\n * console.log('Path:', path.value);\r\n * console.log('Params:', params.value);\r\n * console.log('Query:', query.value);\r\n * console.log('Hash:', hash.value);\r\n * });\r\n * ```\r\n */\r\nexport const useRoute = (): UseRouteReturn => {\r\n return routeHandle;\r\n};\r\n","/**\n * Devtools integration for stores.\n * @internal\n */\n\ndeclare global {\n interface Window {\n __BQUERY_DEVTOOLS__?: {\n stores: Map<string, unknown>;\n onStoreCreated?: (id: string, store: unknown) => void;\n onStateChange?: (id: string, state: unknown) => void;\n };\n }\n}\n\nexport type DevtoolsHook = {\n stores: Map<string, unknown>;\n onStoreCreated?: (id: string, store: unknown) => void;\n onStateChange?: (id: string, state: unknown) => void;\n};\n\nconst ensureDevtools = (): DevtoolsHook | undefined => {\n if (typeof window === 'undefined') return undefined;\n if (!window.__BQUERY_DEVTOOLS__) {\n window.__BQUERY_DEVTOOLS__ = { stores: new Map() };\n }\n return window.__BQUERY_DEVTOOLS__;\n};\n\nexport const registerDevtoolsStore = (id: string, store: unknown): void => {\n const devtools = ensureDevtools();\n if (!devtools) return;\n devtools.stores.set(id, store);\n devtools.onStoreCreated?.(id, store);\n};\n\nexport const unregisterDevtoolsStore = (id: string): void => {\n if (typeof window === 'undefined' || !window.__BQUERY_DEVTOOLS__) return;\n window.__BQUERY_DEVTOOLS__.stores.delete(id);\n};\n\nexport const notifyDevtoolsStateChange = (id: string, state: unknown): void => {\n if (typeof window === 'undefined') return;\n window.__BQUERY_DEVTOOLS__?.onStateChange?.(id, state);\n};\n","/**\n * Store plugins API.\n */\n\nimport type { Store, StoreDefinition, StorePlugin } from './types';\n\n/** @internal Registered plugins */\nconst plugins: StorePlugin[] = [];\n\n/**\n * Registers a plugin that extends all stores.\n *\n * @param plugin - The plugin function\n */\nexport const registerPlugin = (plugin: StorePlugin): void => {\n plugins.push(plugin);\n};\n\n/** @internal */\nexport const applyPlugins = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n store: Store<any, any, any>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: StoreDefinition<any, any, any>\n): void => {\n for (const plugin of plugins) {\n const extension = plugin({ store, options });\n if (extension) {\n Object.assign(store, extension);\n }\n }\n};\n","/**\n * Store registry utilities.\n */\n\nimport { unregisterDevtoolsStore } from './devtools';\nimport type { Store } from './types';\n\n/** @internal Registry of all stores for devtools */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst storeRegistry = new Map<string, Store<any, any, any>>();\n\n/** @internal */\nexport const hasStore = (id: string): boolean => storeRegistry.has(id);\n\n/** @internal */\nexport const registerStore = (\n id: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n store: Store<any, any, any>\n): void => {\n storeRegistry.set(id, store);\n};\n\n/**\n * Retrieves an existing store by its ID.\n *\n * @param id - The store identifier\n * @returns The store instance or undefined if not found\n */\nexport const getStore = <T = unknown>(id: string): T | undefined => {\n return storeRegistry.get(id) as T | undefined;\n};\n\n/**\n * Lists all registered store IDs.\n *\n * @returns Array of store IDs\n */\nexport const listStores = (): string[] => {\n return Array.from(storeRegistry.keys());\n};\n\n/**\n * Removes a store from the registry.\n *\n * @param id - The store identifier\n */\nexport const destroyStore = (id: string): void => {\n storeRegistry.delete(id);\n unregisterDevtoolsStore(id);\n};\n","/**\r\n * Internal utilities for the store module.\r\n * @internal\r\n */\r\n\r\nimport { detectDevEnvironment } from '../core/env';\r\n\r\n/**\r\n * Check if a value is a plain object (not array, null, Date, etc.).\r\n * @internal\r\n */\r\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\r\n return (\r\n value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype\r\n );\r\n};\r\n\r\n/**\r\n * Deep clones an object. Used for deep reactivity support.\r\n * @internal\r\n */\r\nexport const deepClone = <T>(obj: T): T => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(deepClone) as T;\r\n }\r\n\r\n if (obj instanceof Date) {\r\n return new Date(obj.getTime()) as T;\r\n }\r\n\r\n if (obj instanceof Map) {\r\n return new Map(Array.from(obj.entries()).map(([k, v]) => [k, deepClone(v)])) as T;\r\n }\r\n\r\n if (obj instanceof Set) {\r\n return new Set(Array.from(obj).map(deepClone)) as T;\r\n }\r\n\r\n const cloned = {} as T;\r\n for (const key of Object.keys(obj)) {\r\n (cloned as Record<string, unknown>)[key] = deepClone((obj as Record<string, unknown>)[key]);\r\n }\r\n return cloned;\r\n};\r\n\r\n/**\r\n * Compares two values for deep equality.\r\n * @internal\r\n */\r\nexport const deepEqual = (a: unknown, b: unknown): boolean => {\r\n if (a === b) return true;\r\n if (a === null || b === null) return false;\r\n if (typeof a !== 'object' || typeof b !== 'object') return false;\r\n\r\n if (a instanceof Date && b instanceof Date) {\r\n return a.getTime() === b.getTime();\r\n }\r\n\r\n if (a instanceof Map && b instanceof Map) {\r\n if (a.size !== b.size) return false;\r\n for (const [key, value] of a.entries()) {\r\n if (!b.has(key) || !deepEqual(value, b.get(key))) return false;\r\n }\r\n return true;\r\n }\r\n\r\n if (a instanceof Set && b instanceof Set) {\r\n if (a.size !== b.size) return false;\r\n for (const value of a.values()) {\r\n let found = false;\r\n for (const candidate of b.values()) {\r\n if (deepEqual(value, candidate)) {\r\n found = true;\r\n break;\r\n }\r\n }\r\n if (!found) return false;\r\n }\r\n return true;\r\n }\r\n\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n if (a.length !== b.length) return false;\r\n return a.every((item, i) => deepEqual(item, b[i]));\r\n }\r\n\r\n if (Array.isArray(a) !== Array.isArray(b)) return false;\r\n\r\n const keysA = Object.keys(a as object);\r\n const keysB = Object.keys(b as object);\r\n\r\n if (keysA.length !== keysB.length) return false;\r\n\r\n return keysA.every((key) =>\r\n deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])\r\n );\r\n};\r\n\r\n/**\r\n * Detects if nested objects were mutated but the reference stayed the same.\r\n * Returns the keys where nested mutations were detected.\r\n * @internal\r\n */\r\nexport const detectNestedMutations = <S extends Record<string, unknown>>(\r\n before: S,\r\n after: S,\r\n signalValues: Map<keyof S, unknown>\r\n): Array<keyof S> => {\r\n const mutatedKeys: Array<keyof S> = [];\r\n\r\n for (const key of Object.keys(after) as Array<keyof S>) {\r\n const beforeValue = before[key];\r\n const afterValue = after[key];\r\n const signalValue = signalValues.get(key);\r\n\r\n // Check if it's the same reference but content changed\r\n if (\r\n signalValue === afterValue &&\r\n isPlainObject(beforeValue) &&\r\n isPlainObject(afterValue) &&\r\n !deepEqual(beforeValue, afterValue)\r\n ) {\r\n mutatedKeys.push(key);\r\n }\r\n }\r\n\r\n return mutatedKeys;\r\n};\r\n\r\n/** @internal Returns whether development warnings should be enabled */\r\nexport const isDev = (): boolean => detectDevEnvironment();\r\n","/**\r\n * Store creation logic.\r\n */\r\n\r\nimport { isPromise } from '../core/utils/type-guards';\r\nimport {\r\n batch,\r\n computed,\r\n signal,\r\n untrack,\r\n type ReadonlySignal,\r\n type Signal,\r\n} from '../reactive/index';\r\nimport { notifyDevtoolsStateChange, registerDevtoolsStore } from './devtools';\r\nimport { applyPlugins } from './plugins';\r\nimport { getStore, hasStore, registerStore } from './registry';\r\nimport type {\r\n ActionContext,\r\n Getters,\r\n OnActionCallback,\r\n Store,\r\n StoreDefinition,\r\n StoreSubscriber,\r\n} from './types';\r\nimport { deepClone, detectNestedMutations, isDev } from './utils';\r\n\r\n/**\r\n * Creates a reactive store with state, getters, and actions.\r\n *\r\n * @template S - State type\r\n * @template G - Getters type\r\n * @template A - Actions type\r\n * @param definition - Store definition\r\n * @returns The reactive store instance\r\n */\r\nexport const createStore = <\r\n S extends Record<string, unknown>,\r\n G extends Record<string, unknown> = Record<string, never>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\r\n>(\r\n definition: StoreDefinition<S, G, A>\r\n): Store<S, G, A> => {\r\n const { id, state: stateFactory, getters = {} as Getters<S, G>, actions = {} as A } = definition;\r\n\r\n // Check for duplicate store IDs\r\n if (hasStore(id)) {\r\n console.warn(`bQuery store: Store \"${id}\" already exists. Returning existing instance.`);\r\n return getStore(id) as Store<S, G, A>;\r\n }\r\n\r\n // Create initial state\r\n const initialState = stateFactory();\r\n\r\n // Create signals for each state property\r\n const stateSignals = new Map<keyof S, Signal<unknown>>();\r\n for (const key of Object.keys(initialState) as Array<keyof S>) {\r\n stateSignals.set(key, signal(initialState[key]));\r\n }\r\n\r\n // Subscribers for $subscribe\r\n const subscribers: Array<StoreSubscriber<S>> = [];\r\n\r\n // Action lifecycle hooks for $onAction\r\n const actionListeners: Array<OnActionCallback<S, G, A>> = [];\r\n\r\n const reportOnActionError = (\r\n phase: 'listener' | 'after' | 'onError',\r\n actionName: string,\r\n error: unknown\r\n ): void => {\r\n if (!isDev() || typeof console === 'undefined' || typeof console.error !== 'function') return;\r\n console.error(\r\n `[bQuery store \"${id}\"] Error in $onAction ${phase} for action \"${actionName}\"`,\r\n error\r\n );\r\n };\r\n\r\n const warnedAsyncOnActionListeners = new WeakSet<OnActionCallback<S, G, A>>();\r\n\r\n const warnAsyncOnActionListener = (\r\n listener: OnActionCallback<S, G, A>,\r\n actionName: string\r\n ): void => {\r\n if (!isDev() || typeof console === 'undefined' || typeof console.warn !== 'function') return;\r\n if (warnedAsyncOnActionListeners.has(listener)) return;\r\n warnedAsyncOnActionListeners.add(listener);\r\n console.warn(\r\n `[bQuery store \"${id}\"] Async $onAction listener detected for action \"${actionName}\". If it awaits, register after()/onError() before the first await; late registrations will not affect the current action.`\r\n );\r\n };\r\n\r\n /**\r\n * Executes an action observer callback without allowing observer failures to\r\n * affect the action result. Handles both synchronous exceptions and async\r\n * rejections, routing all failures through the standard $onAction logger.\r\n *\r\n * @internal\r\n */\r\n const runOnActionCallback = (\r\n phase: 'listener' | 'after' | 'onError',\r\n actionName: string,\r\n callback: () => unknown,\r\n listener?: OnActionCallback<S, G, A>\r\n ): void => {\r\n try {\r\n const result = callback();\r\n if (isPromise(result)) {\r\n if (phase === 'listener' && listener) {\r\n warnAsyncOnActionListener(listener, actionName);\r\n }\r\n void result.catch((error) => {\r\n reportOnActionError(phase, actionName, error);\r\n });\r\n }\r\n } catch (error) {\r\n reportOnActionError(phase, actionName, error);\r\n }\r\n };\r\n\r\n /**\r\n * Gets the current state.\r\n *\r\n * For subscriber notifications (where a plain object snapshot is needed),\r\n * this creates a shallow copy. For internal reads, use stateProxy directly.\r\n *\r\n * **Note:** Returns a shallow snapshot. Nested object mutations will NOT\r\n * trigger reactive updates. This differs from frameworks like Pinia that\r\n * use deep reactivity. To update nested state, replace the entire object.\r\n *\r\n * Uses `untrack()` to prevent accidental dependency tracking when called\r\n * from within reactive contexts (e.g., `effect()` or `computed()`).\r\n *\r\n * @internal\r\n */\r\n const getCurrentState = (): S =>\r\n untrack(() => {\r\n return { ...stateProxy };\r\n });\r\n\r\n /**\r\n * Notifies subscribers of state changes.\r\n * Short-circuits if there are no subscribers and devtools aren't active\r\n * to avoid unnecessary snapshot overhead.\r\n * @internal\r\n */\r\n const notifySubscribers = (): void => {\r\n // Early return if no subscribers and no devtools hook\r\n const hasDevtools =\r\n typeof window !== 'undefined' &&\r\n typeof window.__BQUERY_DEVTOOLS__?.onStateChange === 'function';\r\n if (subscribers.length === 0 && !hasDevtools) {\r\n return;\r\n }\r\n\r\n const currentState = getCurrentState();\r\n for (const callback of subscribers) {\r\n callback(currentState);\r\n }\r\n\r\n notifyDevtoolsStateChange(id, currentState);\r\n };\r\n\r\n /**\r\n * Cached state proxy that lazily reads signal values.\r\n * Uses a Proxy to avoid creating new objects on each access.\r\n *\r\n * **Note:** This returns a shallow snapshot of the state. Nested object\r\n * mutations will NOT trigger reactive updates. For nested reactivity,\r\n * replace the entire object or use signals for nested properties.\r\n *\r\n * @internal\r\n */\r\n const stateProxy = new Proxy({} as S, {\r\n get: (_, prop: string | symbol) => {\r\n const key = prop as keyof S;\r\n if (stateSignals.has(key)) {\r\n return stateSignals.get(key)!.value;\r\n }\r\n return undefined;\r\n },\r\n ownKeys: () => Array.from(stateSignals.keys()) as string[],\r\n getOwnPropertyDescriptor: (_, prop) => {\r\n if (stateSignals.has(prop as keyof S)) {\r\n return { enumerable: true, configurable: true };\r\n }\r\n return undefined;\r\n },\r\n has: (_, prop) => stateSignals.has(prop as keyof S),\r\n });\r\n\r\n // Create computed getters\r\n const getterComputed = new Map<keyof G, ReadonlySignal<unknown>>();\r\n\r\n // Build the store proxy\r\n const store = {} as Store<S, G, A>;\r\n\r\n // Define state properties with getters/setters\r\n for (const key of Object.keys(initialState) as Array<keyof S>) {\r\n Object.defineProperty(store, key, {\r\n get: () => stateSignals.get(key)!.value,\r\n set: (value: unknown) => {\r\n stateSignals.get(key)!.value = value;\r\n notifySubscribers();\r\n },\r\n enumerable: true,\r\n configurable: false,\r\n });\r\n }\r\n\r\n // Define getters as computed properties\r\n for (const key of Object.keys(getters) as Array<keyof G>) {\r\n const getterFn = getters[key];\r\n\r\n // Create computed that reads from state signals via proxy (more efficient)\r\n const computedGetter = computed(() => {\r\n const state = stateProxy;\r\n // For getter dependencies, pass a proxy that reads from computed getters\r\n const getterProxy = new Proxy({} as G, {\r\n get: (_, prop: string | symbol) => {\r\n const propKey = prop as keyof G;\r\n if (getterComputed.has(propKey)) {\r\n return getterComputed.get(propKey)!.value;\r\n }\r\n return undefined;\r\n },\r\n });\r\n return getterFn(state, getterProxy);\r\n });\r\n\r\n getterComputed.set(key, computedGetter as unknown as ReadonlySignal<unknown>);\r\n\r\n Object.defineProperty(store, key, {\r\n get: () => computedGetter.value,\r\n enumerable: true,\r\n configurable: false,\r\n });\r\n }\r\n\r\n // Bind actions to the store context, with $onAction lifecycle support\r\n for (const key of Object.keys(actions) as Array<keyof A>) {\r\n const actionFn = actions[key];\r\n const actionName = key as keyof A & string;\r\n\r\n // Wrap action to enable 'this' binding and $onAction hooks\r\n (store as Record<string, unknown>)[actionName] = function (...args: unknown[]) {\r\n // Create a context that allows 'this.property' access\r\n const context = new Proxy(store, {\r\n get: (target, prop) => {\r\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\r\n return stateSignals.get(prop as keyof S)!.value;\r\n }\r\n return (target as Record<string, unknown>)[prop as string];\r\n },\r\n set: (target, prop, value) => {\r\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\r\n stateSignals.get(prop as keyof S)!.value = value;\r\n notifySubscribers();\r\n return true;\r\n }\r\n // Allow non-state property assignments (e.g., temporary variables in actions)\r\n // by delegating to the target object rather than returning false\r\n return Reflect.set(target, prop, value);\r\n },\r\n });\r\n\r\n // Run $onAction hooks if any listeners are registered\r\n if (actionListeners.length === 0) {\r\n return actionFn.apply(context, args);\r\n }\r\n\r\n const afterHooks: Array<(result: unknown) => void> = [];\r\n const errorHooks: Array<(error: unknown) => void> = [];\r\n const listenerSnapshot = [...actionListeners];\r\n\r\n const listenerContext = {\r\n name: actionName,\r\n store,\r\n args: args as Parameters<A[typeof actionName]>,\r\n after: (callback: (result: Awaited<ReturnType<A[typeof actionName]>>) => void) => {\r\n afterHooks.push((result) =>\r\n callback(result as Awaited<ReturnType<A[typeof actionName]>>)\r\n );\r\n },\r\n onError: (callback: (error: unknown) => void) => {\r\n errorHooks.push(callback);\r\n },\r\n } satisfies ActionContext<S, G, A, typeof actionName>;\r\n\r\n // Notify all action listeners (before phase)\r\n for (const listener of listenerSnapshot) {\r\n runOnActionCallback('listener', actionName, () => listener(listenerContext), listener);\r\n }\r\n\r\n let result: unknown;\r\n try {\r\n result = actionFn.apply(context, args);\r\n } catch (error) {\r\n for (const hook of errorHooks) {\r\n runOnActionCallback('onError', actionName, () => hook(error));\r\n }\r\n throw error;\r\n }\r\n\r\n // Handle async actions (promises)\r\n if (isPromise(result)) {\r\n return result.then(\r\n (resolved) => {\r\n for (const hook of afterHooks) {\r\n runOnActionCallback('after', actionName, () => hook(resolved));\r\n }\r\n return resolved;\r\n },\r\n (error) => {\r\n for (const hook of errorHooks) {\r\n runOnActionCallback('onError', actionName, () => hook(error));\r\n }\r\n throw error;\r\n }\r\n );\r\n }\r\n\r\n // Sync action — run after hooks immediately\r\n for (const hook of afterHooks) {\r\n runOnActionCallback('after', actionName, () => hook(result));\r\n }\r\n return result;\r\n };\r\n }\r\n\r\n // Add store utility methods\r\n Object.defineProperties(store, {\r\n $id: {\r\n value: id,\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $reset: {\r\n value: () => {\r\n const fresh = stateFactory();\r\n batch(() => {\r\n for (const [key, sig] of stateSignals) {\r\n sig.value = fresh[key];\r\n }\r\n });\r\n notifySubscribers();\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $subscribe: {\r\n value: (callback: StoreSubscriber<S>) => {\r\n subscribers.push(callback);\r\n return () => {\r\n const index = subscribers.indexOf(callback);\r\n if (index > -1) subscribers.splice(index, 1);\r\n };\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $onAction: {\r\n value: (callback: OnActionCallback<S, G, A>) => {\r\n actionListeners.push(callback);\r\n return () => {\r\n const index = actionListeners.indexOf(callback);\r\n if (index > -1) actionListeners.splice(index, 1);\r\n };\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $patch: {\r\n value: (partial: Partial<S> | ((state: S) => void)) => {\r\n batch(() => {\r\n if (typeof partial === 'function') {\r\n // Capture state before mutation for nested mutation detection\r\n const devMode = isDev();\r\n const stateBefore = devMode ? deepClone(getCurrentState()) : null;\r\n const signalValuesBefore = devMode\r\n ? new Map(Array.from(stateSignals.entries()).map(([k, s]) => [k, s.value]))\r\n : null;\r\n\r\n // Mutation function\r\n const state = getCurrentState();\r\n partial(state);\r\n\r\n // Detect nested mutations in development mode\r\n if (devMode && stateBefore && signalValuesBefore) {\r\n const mutatedKeys = detectNestedMutations(stateBefore, state, signalValuesBefore);\r\n if (mutatedKeys.length > 0) {\r\n console.warn(\r\n `[bQuery store \"${id}\"] Nested mutation detected in $patch() for keys: ${mutatedKeys\r\n .map(String)\r\n .join(', ')}.\\n` +\r\n 'Nested object mutations do not trigger reactive updates because the store uses shallow reactivity.\\n' +\r\n 'To fix this, either:\\n' +\r\n ' 1. Replace the entire object: state.user = { ...state.user, name: \"New\" }\\n' +\r\n ' 2. Use $patchDeep() for automatic deep cloning\\n' +\r\n 'See: https://bquery.dev/guide/store#deep-reactivity'\r\n );\r\n }\r\n }\r\n\r\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = value;\r\n }\r\n }\r\n } else {\r\n // Partial object\r\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = value;\r\n }\r\n }\r\n }\r\n });\r\n notifySubscribers();\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $patchDeep: {\r\n value: (partial: Partial<S> | ((state: S) => void)) => {\r\n batch(() => {\r\n if (typeof partial === 'function') {\r\n // Deep clone state before mutation to ensure new references\r\n const state = deepClone(getCurrentState());\r\n partial(state);\r\n\r\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = value;\r\n }\r\n }\r\n } else {\r\n // Deep clone each value in partial to ensure new references\r\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\r\n if (stateSignals.has(key)) {\r\n stateSignals.get(key)!.value = deepClone(value);\r\n }\r\n }\r\n }\r\n });\r\n notifySubscribers();\r\n },\r\n writable: false,\r\n enumerable: false,\r\n },\r\n $state: {\r\n get: () => getCurrentState(),\r\n enumerable: false,\r\n },\r\n });\r\n\r\n // Register store\r\n registerStore(id, store);\r\n\r\n // Apply plugins\r\n applyPlugins(store, definition);\r\n\r\n // Notify devtools\r\n registerDevtoolsStore(id, store);\r\n\r\n return store;\r\n};\r\n","/**\n * Mapping helpers for store state and actions.\n */\n\n/**\n * Maps store state properties to a reactive object for use in components.\n *\n * @param store - The store instance\n * @param keys - State keys to map\n * @returns Object with mapped properties\n */\nexport const mapState = <S extends Record<string, unknown>, K extends keyof S>(\n store: S,\n keys: K[]\n): Pick<S, K> => {\n const mapped = {} as Pick<S, K>;\n\n for (const key of keys) {\n Object.defineProperty(mapped, key, {\n get: () => store[key],\n enumerable: true,\n });\n }\n\n return mapped;\n};\n\n/**\n * Maps store getters to a reactive object for use in components.\n *\n * @param store - The store instance\n * @param keys - Getter keys to map\n * @returns Object with mapped getters\n */\nexport const mapGetters = <G extends Record<string, unknown>, K extends keyof G>(\n store: G,\n keys: K[]\n): Pick<G, K> => {\n const mapped = {} as Pick<G, K>;\n\n for (const key of keys) {\n Object.defineProperty(mapped, key, {\n get: () => store[key],\n enumerable: true,\n });\n }\n\n return mapped;\n};\n\n/**\n * Maps store actions to an object for easier destructuring.\n *\n * @param store - The store instance\n * @param keys - Action keys to map\n * @returns Object with mapped actions\n */\nexport const mapActions = <\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any>,\n K extends keyof A,\n>(\n store: A,\n keys: K[]\n): Pick<A, K> => {\n const mapped = {} as Pick<A, K>;\n\n for (const key of keys) {\n (mapped as Record<string, unknown>)[key as string] = (...args: unknown[]) =>\n (store[key] as (...args: unknown[]) => unknown)(...args);\n }\n\n return mapped;\n};\n","/**\r\n * Store persistence helpers.\r\n */\r\n\r\nimport { isPrototypePollutionKey } from '../core/utils/object';\r\nimport { createStore } from './create-store';\r\nimport { isDev } from './utils';\r\nimport type { PersistedStoreOptions, StorageBackend, Store, StoreDefinition } from './types';\r\n\r\n/** @internal Version key suffix */\r\nconst VERSION_SUFFIX = '__version';\r\n\r\n/** @internal Default JSON serializer */\r\nconst defaultSerializer = {\r\n serialize: (state: unknown) => JSON.stringify(state),\r\n deserialize: (raw: string) => JSON.parse(raw) as unknown,\r\n};\r\n\r\n/** @internal Check whether a value can be merged into store state. */\r\nconst isPersistedStateObject = (value: unknown): value is Record<string, unknown> => {\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\r\n\r\n const prototype = Object.getPrototypeOf(value);\r\n return prototype === null || Object.getPrototypeOf(prototype) === null;\r\n};\r\n\r\n/**\r\n * Applies persisted state onto the default state while ignoring dangerous\r\n * prototype-pollution keys such as `__proto__`, `constructor`, and `prototype`.\r\n *\r\n * @internal\r\n */\r\nconst mergePersistedState = <S extends Record<string, unknown>>(\r\n defaultState: S,\r\n persisted: Record<string, unknown>\r\n): S => {\r\n const merged = { ...defaultState };\r\n for (const [key, value] of Object.entries(persisted)) {\r\n if (isPrototypePollutionKey(key)) continue;\r\n if (!Object.prototype.hasOwnProperty.call(defaultState, key)) continue;\r\n merged[key as keyof S] = value as S[keyof S];\r\n }\r\n return merged;\r\n};\r\n\r\n/** @internal Resolve the default storage backend safely. */\r\nconst getDefaultStorage = (): StorageBackend | undefined => {\r\n try {\r\n return globalThis.localStorage;\r\n } catch {\r\n return undefined;\r\n }\r\n};\r\n\r\n/**\r\n * Creates a store with automatic persistence.\r\n *\r\n * Supports configurable storage backends, custom serializers, and schema\r\n * versioning with migration functions. All options are optional and\r\n * backward-compatible with the simple `(definition, storageKey?)` signature.\r\n *\r\n * @param definition - Store definition\r\n * @param options - Persistence options or a plain string storage key for backward compatibility\r\n * @returns The reactive store instance\r\n *\r\n * @example Basic usage (localStorage + JSON)\r\n * ```ts\r\n * const store = createPersistedStore({\r\n * id: 'settings',\r\n * state: () => ({ theme: 'dark' }),\r\n * });\r\n * ```\r\n *\r\n * @example With sessionStorage and custom key\r\n * ```ts\r\n * const store = createPersistedStore(\r\n * { id: 'session', state: () => ({ token: '' }) },\r\n * { key: 'my-session', storage: sessionStorage },\r\n * );\r\n * ```\r\n *\r\n * @example With versioning and migration\r\n * ```ts\r\n * const store = createPersistedStore(\r\n * { id: 'app', state: () => ({ name: '', theme: 'auto' }) },\r\n * {\r\n * version: 2,\r\n * migrate: (old, v) => {\r\n * if (v < 2) return { ...old, theme: 'auto' };\r\n * return old;\r\n * },\r\n * },\r\n * );\r\n * ```\r\n */\r\nexport const createPersistedStore = <\r\n S extends Record<string, unknown>,\r\n G extends Record<string, unknown> = Record<string, never>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\r\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\r\n>(\r\n definition: StoreDefinition<S, G, A>,\r\n options?: PersistedStoreOptions | string\r\n): Store<S, G, A> => {\r\n // Normalize options — a plain string is treated as the storage key for backward compatibility\r\n const opts: PersistedStoreOptions =\r\n typeof options === 'string' ? { key: options } : (options ?? {});\r\n\r\n const key = opts.key ?? `bquery-store-${definition.id}`;\r\n const storage = opts.storage ?? getDefaultStorage();\r\n const serializer = opts.serializer ?? defaultSerializer;\r\n const version = opts.version;\r\n const migrate = opts.migrate;\r\n const versionKey = key + VERSION_SUFFIX;\r\n let shouldPersistInitialVersion = storage !== undefined && version !== undefined;\r\n let pendingVersionWrite = false;\r\n let canRetryPendingVersionAfterCreate = false;\r\n\r\n const tryPersistVersion = (warningMessage?: string): boolean => {\r\n if (!storage || version === undefined) return false;\r\n\r\n try {\r\n storage.setItem(versionKey, String(version));\r\n return true;\r\n } catch (error) {\r\n if (\r\n warningMessage &&\r\n isDev() &&\r\n typeof console !== 'undefined' &&\r\n typeof console.warn === 'function'\r\n ) {\r\n console.warn(warningMessage, error);\r\n }\r\n return false;\r\n }\r\n };\r\n\r\n const originalStateFactory = definition.state;\r\n\r\n const wrappedDefinition: StoreDefinition<S, G, A> = {\r\n ...definition,\r\n state: () => {\r\n const defaultState = originalStateFactory();\r\n\r\n if (!storage) return defaultState;\r\n\r\n try {\r\n const saved = storage.getItem(key);\r\n if (!saved) return defaultState;\r\n\r\n const deserialized = serializer.deserialize(saved);\r\n if (!isPersistedStateObject(deserialized)) {\r\n return defaultState;\r\n }\r\n\r\n let persisted = deserialized;\r\n\r\n // Handle versioning & migration\r\n if (version !== undefined && migrate) {\r\n const rawVersion = storage.getItem(versionKey);\r\n const parsedVersion = rawVersion !== null ? Number(rawVersion) : 0;\r\n const oldVersion = Number.isFinite(parsedVersion) ? parsedVersion : 0;\r\n\r\n if (oldVersion !== version) {\r\n shouldPersistInitialVersion = false;\r\n pendingVersionWrite = true;\r\n const migrated = migrate(persisted, oldVersion);\r\n if (!isPersistedStateObject(migrated)) {\r\n return defaultState;\r\n }\r\n persisted = migrated;\r\n\r\n let migratedStatePersisted = false;\r\n // Save the migrated state and version immediately when possible.\r\n // If the state write fails, never advance the version key.\r\n try {\r\n storage.setItem(key, serializer.serialize(persisted));\r\n migratedStatePersisted = true;\r\n canRetryPendingVersionAfterCreate = true;\r\n } catch (e) {\r\n // Migration will re-run on next load, but state is still usable\r\n if (\r\n isDev() &&\r\n typeof console !== 'undefined' &&\r\n typeof console.warn === 'function'\r\n ) {\r\n console.warn(\r\n `[bQuery store \"${definition.id}\"] Failed to persist migrated state:`,\r\n e\r\n );\r\n }\r\n }\r\n\r\n if (\r\n migratedStatePersisted &&\r\n tryPersistVersion(\r\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version:`\r\n )\r\n ) {\r\n pendingVersionWrite = false;\r\n }\r\n } else {\r\n shouldPersistInitialVersion = false;\r\n }\r\n }\r\n\r\n return mergePersistedState(defaultState, persisted);\r\n } catch {\r\n // Ignore parse errors\r\n return defaultState;\r\n }\r\n },\r\n };\r\n\r\n const store = createStore(wrappedDefinition);\r\n\r\n // Persist the version number on first creation\r\n if (shouldPersistInitialVersion && storage) {\r\n tryPersistVersion();\r\n } else if (\r\n pendingVersionWrite &&\r\n canRetryPendingVersionAfterCreate &&\r\n tryPersistVersion(\r\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version after store creation:`\r\n )\r\n ) {\r\n pendingVersionWrite = false;\r\n }\r\n\r\n // Subscribe to save changes\r\n store.$subscribe((state) => {\r\n if (!storage) return;\r\n try {\r\n storage.setItem(key, serializer.serialize(state));\r\n if (\r\n pendingVersionWrite &&\r\n tryPersistVersion(\r\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version after a successful state write:`\r\n )\r\n ) {\r\n pendingVersionWrite = false;\r\n }\r\n } catch {\r\n // Ignore quota errors\r\n }\r\n });\r\n\r\n return store;\r\n};\r\n","import { isPrototypePollutionKey } from '../core/utils/object';\r\nimport { isComputed, isSignal, type Signal } from '../reactive/index';\r\nimport type { BindingContext } from './types';\r\n\r\n/** Maximum number of cached expression functions before LRU eviction */\r\nconst MAX_CACHE_SIZE = 500;\r\n\r\n/** Compiled function type for expression evaluation */\r\ntype CompiledFn = (ctx: BindingContext) => unknown;\r\n\r\n/**\r\n * Simple LRU cache for compiled expression functions.\r\n * Uses Map's insertion order to track recency - accessed items are re-inserted.\r\n * @internal\r\n */\r\nclass LRUCache {\r\n private cache = new Map<string, CompiledFn>();\r\n private maxSize: number;\r\n\r\n constructor(maxSize: number) {\r\n this.maxSize = maxSize;\r\n }\r\n\r\n get(key: string): CompiledFn | undefined {\r\n const value = this.cache.get(key);\r\n if (value !== undefined) {\r\n // Move to end (most recently used) by re-inserting\r\n this.cache.delete(key);\r\n this.cache.set(key, value);\r\n }\r\n return value;\r\n }\r\n\r\n set(key: string, value: CompiledFn): void {\r\n // Delete first if exists to update insertion order\r\n if (this.cache.has(key)) {\r\n this.cache.delete(key);\r\n } else if (this.cache.size >= this.maxSize) {\r\n // Evict oldest (first) entry\r\n const oldest = this.cache.keys().next().value;\r\n if (oldest !== undefined) {\r\n this.cache.delete(oldest);\r\n }\r\n }\r\n this.cache.set(key, value);\r\n }\r\n\r\n clear(): void {\r\n this.cache.clear();\r\n }\r\n\r\n get size(): number {\r\n return this.cache.size;\r\n }\r\n}\r\n\r\n/** LRU cache for compiled evaluate functions, keyed by expression string */\r\nconst evaluateCache = new LRUCache(MAX_CACHE_SIZE);\r\n\r\n/** LRU cache for compiled evaluateRaw functions, keyed by expression string */\r\nconst evaluateRawCache = new LRUCache(MAX_CACHE_SIZE);\r\n\r\n/**\r\n * Clears all cached compiled expression functions.\r\n * Call this when unmounting views or to free memory after heavy template usage.\r\n *\r\n * @example\r\n * ```ts\r\n * import { clearExpressionCache } from 'bquery/view';\r\n *\r\n * // After destroying a view or when cleaning up\r\n * clearExpressionCache();\r\n * ```\r\n */\r\nexport const clearExpressionCache = (): void => {\r\n evaluateCache.clear();\r\n evaluateRawCache.clear();\r\n};\r\n\r\n/**\r\n * Creates a proxy that lazily unwraps signals/computed only when accessed.\r\n * This avoids subscribing to signals that aren't referenced in the expression.\r\n * @internal\r\n */\r\nconst createLazyContext = (context: BindingContext): BindingContext =>\r\n new Proxy(context, {\r\n get(target, prop: string | symbol) {\r\n // Only handle string keys for BindingContext indexing\r\n if (typeof prop !== 'string') {\r\n return Reflect.get(target, prop);\r\n }\r\n const value = target[prop];\r\n // Auto-unwrap signals/computed only when actually accessed\r\n if (isSignal(value) || isComputed(value)) {\r\n return (value as Signal<unknown>).value;\r\n }\r\n return value;\r\n },\r\n has(target, prop: string | symbol) {\r\n // Required for `with` statement to resolve identifiers correctly\r\n if (typeof prop !== 'string') {\r\n return Reflect.has(target, prop);\r\n }\r\n return prop in target;\r\n },\r\n });\r\n\r\n/**\r\n * Evaluates an expression in the given context using `new Function()`.\r\n *\r\n * Signals and computed values in the context are lazily unwrapped only when\r\n * accessed by the expression, avoiding unnecessary subscriptions to unused values.\r\n *\r\n * @security **WARNING:** This function uses dynamic code execution via `new Function()`.\r\n * - NEVER pass expressions derived from user input or untrusted sources\r\n * - Expressions should only come from developer-controlled templates\r\n * - Malicious expressions can access and exfiltrate context data\r\n * - Consider this equivalent to `eval()` in terms of security implications\r\n *\r\n * @internal\r\n */\r\nexport const evaluate = <T = unknown>(expression: string, context: BindingContext): T => {\r\n try {\r\n // Create a proxy that lazily unwraps signals/computed on access\r\n const lazyContext = createLazyContext(context);\r\n\r\n // Use cached function or compile and cache a new one\r\n let fn = evaluateCache.get(expression);\r\n if (!fn) {\r\n // Use `with` to enable direct property access from proxy scope.\r\n // Note: `new Function()` runs in non-strict mode, so `with` is allowed.\r\n fn = new Function('$ctx', `with($ctx) { return (${expression}); }`) as (\r\n ctx: BindingContext\r\n ) => unknown;\r\n evaluateCache.set(expression, fn);\r\n }\r\n return fn(lazyContext) as T;\r\n } catch (error) {\r\n console.error(`bQuery view: Error evaluating \"${expression}\"`, error);\r\n return undefined as T;\r\n }\r\n};\r\n\r\n/**\r\n * Evaluates an expression and returns the raw value (for signal access).\r\n *\r\n * @security **WARNING:** Uses dynamic code execution. See {@link evaluate} for security notes.\r\n * @internal\r\n */\r\nexport const evaluateRaw = <T = unknown>(expression: string, context: BindingContext): T => {\r\n try {\r\n // Use cached function or compile and cache a new one\r\n let fn = evaluateRawCache.get(expression);\r\n if (!fn) {\r\n // Use `with` to enable direct property access from context scope.\r\n // Unlike `evaluate`, we don't use a lazy proxy - values are accessed directly.\r\n fn = new Function('$ctx', `with($ctx) { return (${expression}); }`) as (\r\n ctx: BindingContext\r\n ) => unknown;\r\n evaluateRawCache.set(expression, fn);\r\n }\r\n return fn(context) as T;\r\n } catch (error) {\r\n console.error(`bQuery view: Error evaluating \"${expression}\"`, error);\r\n return undefined as T;\r\n }\r\n};\r\n\r\n/**\r\n * Parses object expression like \"{ active: isActive, disabled: !enabled }\".\r\n * Handles nested structures like function calls, arrays, and template literals.\r\n * @internal\r\n */\r\nexport const parseObjectExpression = (expression: string): Record<string, string> => {\r\n const result: Record<string, string> = {};\r\n\r\n // Remove outer braces and trim\r\n const inner = expression\r\n .trim()\r\n .replace(/^\\{|\\}$/g, '')\r\n .trim();\r\n if (!inner) return result;\r\n\r\n // Split by comma at depth 0, respecting strings and nesting\r\n const parts: string[] = [];\r\n let current = '';\r\n let depth = 0;\r\n let inString: string | null = null;\r\n\r\n for (let i = 0; i < inner.length; i++) {\r\n const char = inner[i];\r\n\r\n // Handle string literals: count consecutive backslashes before a quote\r\n // to correctly distinguish escaped quotes from end-of-string\r\n if (char === '\"' || char === \"'\" || char === '`') {\r\n let backslashCount = 0;\r\n let j = i - 1;\r\n while (j >= 0 && inner[j] === '\\\\') {\r\n backslashCount++;\r\n j--;\r\n }\r\n // Quote is escaped only if preceded by an odd number of backslashes\r\n if (backslashCount % 2 === 0) {\r\n if (inString === null) {\r\n inString = char;\r\n } else if (inString === char) {\r\n inString = null;\r\n }\r\n }\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Skip if inside string\r\n if (inString !== null) {\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Track nesting depth for parentheses, brackets, and braces\r\n if (char === '(' || char === '[' || char === '{') {\r\n depth++;\r\n current += char;\r\n } else if (char === ')' || char === ']' || char === '}') {\r\n depth--;\r\n current += char;\r\n } else if (char === ',' && depth === 0) {\r\n // Top-level comma - split point\r\n parts.push(current.trim());\r\n current = '';\r\n } else {\r\n current += char;\r\n }\r\n }\r\n\r\n // Add the last part\r\n if (current.trim()) {\r\n parts.push(current.trim());\r\n }\r\n\r\n // Parse each part to extract key and value\r\n for (const part of parts) {\r\n // Find the first colon at depth 0 (to handle ternary operators in values)\r\n let colonIndex = -1;\r\n let partDepth = 0;\r\n let partInString: string | null = null;\r\n\r\n for (let i = 0; i < part.length; i++) {\r\n const char = part[i];\r\n\r\n if (char === '\"' || char === \"'\" || char === '`') {\r\n let backslashCount = 0;\r\n let j = i - 1;\r\n while (j >= 0 && part[j] === '\\\\') {\r\n backslashCount++;\r\n j--;\r\n }\r\n if (backslashCount % 2 === 0) {\r\n if (partInString === null) {\r\n partInString = char;\r\n } else if (partInString === char) {\r\n partInString = null;\r\n }\r\n }\r\n continue;\r\n }\r\n\r\n if (partInString !== null) continue;\r\n\r\n if (char === '(' || char === '[' || char === '{') {\r\n partDepth++;\r\n } else if (char === ')' || char === ']' || char === '}') {\r\n partDepth--;\r\n } else if (char === ':' && partDepth === 0) {\r\n colonIndex = i;\r\n break;\r\n }\r\n }\r\n\r\n if (colonIndex > -1) {\r\n const key = part\r\n .slice(0, colonIndex)\r\n .trim()\r\n .replace(/^['\"]|['\"]$/g, '');\r\n if (isPrototypePollutionKey(key)) continue;\r\n const value = part.slice(colonIndex + 1).trim();\r\n result[key] = value;\r\n }\r\n }\r\n\r\n return result;\r\n};\r\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-bind:attr directive - attribute binding.\n * @internal\n */\nexport const handleBind = (attrName: string): DirectiveHandler => {\n return (el, expression, context, cleanups) => {\n const cleanup = effect(() => {\n const value = evaluate(expression, context);\n if (value == null || value === false) {\n el.removeAttribute(attrName);\n } else if (value === true) {\n el.setAttribute(attrName, '');\n } else {\n el.setAttribute(attrName, String(value));\n }\n });\n cleanups.push(cleanup);\n };\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate, parseObjectExpression } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-class directive - dynamic class binding.\n * Tracks previously added classes to ensure proper cleanup when expressions change.\n * @internal\n */\nexport const handleClass: DirectiveHandler = (el, expression, context, cleanups) => {\n // Track classes added by this directive to clean them up on re-evaluation\n let previousClasses: Set<string> = new Set();\n\n const cleanup = effect(() => {\n const newClasses: Set<string> = new Set();\n\n if (expression.trimStart().startsWith('{')) {\n // Object syntax: { active: isActive, disabled: !enabled }\n const classMap = parseObjectExpression(expression);\n for (const [className, conditionExpr] of Object.entries(classMap)) {\n const condition = evaluate<boolean>(conditionExpr, context);\n el.classList.toggle(className, Boolean(condition));\n // Track class regardless of condition - toggle handles add/remove\n newClasses.add(className);\n }\n } else if (/^\\s*\\[/.test(expression)) {\n // Array literal syntax: [class1, class2]\n const classes = evaluate<string[]>(expression, context);\n if (Array.isArray(classes)) {\n for (const cls of classes) {\n if (cls) {\n el.classList.add(cls);\n newClasses.add(cls);\n }\n }\n }\n } else {\n // Single expression returning string or array\n const result = evaluate<string | string[]>(expression, context);\n if (typeof result === 'string') {\n result.split(/\\s+/).forEach((cls) => {\n if (cls) {\n el.classList.add(cls);\n newClasses.add(cls);\n }\n });\n } else if (Array.isArray(result)) {\n result.forEach((cls) => {\n if (cls) {\n el.classList.add(cls);\n newClasses.add(cls);\n }\n });\n }\n }\n\n // Remove classes that were previously added but are no longer in the new set\n // This keeps directive-managed classes in sync across all syntax forms and provides\n // defensive cleanup behavior for edge cases (e.g. external classList changes)\n for (const cls of previousClasses) {\n if (!newClasses.has(cls)) {\n el.classList.remove(cls);\n }\n }\n\n previousClasses = newClasses;\n });\n\n cleanups.push(cleanup);\n};\n","import { effect, signal, type CleanupFn, type Signal } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { BindingContext, DirectiveHandler } from '../types';\n\ntype ProcessElementFn = (\n el: Element,\n context: BindingContext,\n prefix: string,\n cleanups: CleanupFn[]\n) => void;\n\ntype ProcessChildrenFn = (\n el: Element,\n context: BindingContext,\n prefix: string,\n cleanups: CleanupFn[]\n) => void;\n\n/**\n * Represents a rendered item in bq-for with its DOM element and associated cleanup functions.\n * @internal\n */\ntype RenderedItem = {\n key: unknown;\n element: Element;\n cleanups: CleanupFn[];\n item: unknown;\n index: number;\n itemSignal: Signal<unknown>; // Reactive item value for item-dependent bindings\n indexSignal: Signal<number> | null; // Reactive index for index-dependent bindings\n};\n\n/**\n * Extracts a key from an item using the key expression or falls back to index.\n * @internal\n */\nconst getItemKey = (\n item: unknown,\n index: number,\n keyExpression: string | null,\n itemName: string,\n indexName: string | undefined,\n context: BindingContext\n): unknown => {\n if (!keyExpression) {\n return index; // Fallback to index-based keying\n }\n\n const keyContext: BindingContext = {\n ...context,\n [itemName]: item,\n };\n if (indexName) {\n keyContext[indexName] = index;\n }\n\n return evaluate(keyExpression, keyContext);\n};\n\n/**\n * Handles bq-for directive - list rendering with keyed reconciliation.\n *\n * Supports optional `:key` attribute for efficient DOM reuse:\n * ```html\n * <li bq-for=\"item in items\" :key=\"item.id\">...</li>\n * ```\n *\n * Without a key, falls back to index-based tracking (less efficient for reordering).\n *\n * @internal\n */\nexport const createForHandler = (options: {\n prefix: string;\n processElement: ProcessElementFn;\n processChildren: ProcessChildrenFn;\n}): DirectiveHandler => {\n const { prefix, processElement, processChildren } = options;\n\n return (el, expression, context, cleanups) => {\n const parent = el.parentNode;\n if (!parent) return;\n\n // Parse expression: \"item in items\" or \"(item, index) in items\"\n // Use \\S.* instead of .+ to prevent ReDoS by requiring non-whitespace start\n const match = expression.match(/^\\(?(\\w+)(?:\\s*,\\s*(\\w+))?\\)?\\s+in\\s+(\\S.*)$/);\n if (!match) {\n console.error(`bQuery view: Invalid bq-for expression \"${expression}\"`);\n return;\n }\n\n const [, itemName, indexName, listExpression] = match;\n\n // Extract :key attribute if present\n const keyExpression = el.getAttribute(':key') || el.getAttribute(`${prefix}-key`);\n\n const template = el.cloneNode(true) as Element;\n template.removeAttribute(`${prefix}-for`);\n template.removeAttribute(':key');\n template.removeAttribute(`${prefix}-key`);\n\n // Create placeholder comment\n const placeholder = document.createComment(`bq-for: ${expression}`);\n parent.replaceChild(placeholder, el);\n\n // Track rendered items by key for reconciliation\n let renderedItemsMap = new Map<unknown, RenderedItem>();\n let renderedOrder: unknown[] = [];\n\n /**\n * Creates a new DOM element for an item.\n */\n const createItemElement = (item: unknown, index: number, key: unknown): RenderedItem => {\n const clone = template.cloneNode(true) as Element;\n const itemCleanups: CleanupFn[] = [];\n\n // Create reactive signals for item and index\n const itemSig = signal(item);\n const indexSig = indexName ? signal(index) : null;\n\n const childContext: BindingContext = {\n ...context,\n [itemName]: itemSig,\n };\n if (indexName && indexSig) {\n childContext[indexName] = indexSig;\n }\n\n // Process bindings on the clone\n processElement(clone, childContext, prefix, itemCleanups);\n processChildren(clone, childContext, prefix, itemCleanups);\n\n return {\n key,\n element: clone,\n cleanups: itemCleanups,\n item,\n index,\n itemSignal: itemSig,\n indexSignal: indexSig,\n };\n };\n\n /**\n * Removes a rendered item and cleans up its effects.\n */\n const removeItem = (rendered: RenderedItem): void => {\n for (const cleanup of rendered.cleanups) {\n cleanup();\n }\n rendered.element.remove();\n };\n\n /**\n * Updates an existing item's data and index when reused.\n * Updates the reactive signals so bindings re-render.\n */\n const updateItem = (rendered: RenderedItem, newItem: unknown, newIndex: number): void => {\n // Update item if it changed\n if (!Object.is(rendered.item, newItem)) {\n rendered.item = newItem;\n rendered.itemSignal.value = newItem;\n }\n\n // Update index if it changed\n if (rendered.index !== newIndex) {\n rendered.index = newIndex;\n if (rendered.indexSignal) {\n rendered.indexSignal.value = newIndex;\n }\n }\n };\n\n const cleanup = effect(() => {\n const list = evaluate<unknown[]>(listExpression, context);\n\n if (!Array.isArray(list)) {\n // Clear all if list is invalid\n for (const rendered of renderedItemsMap.values()) {\n removeItem(rendered);\n }\n renderedItemsMap.clear();\n renderedOrder = [];\n return;\n }\n\n // Build new key order and detect changes\n const newKeys: unknown[] = [];\n const newItemsByKey = new Map<unknown, { item: unknown; index: number }>();\n const seenKeys = new Set<unknown>();\n\n list.forEach((item, index) => {\n let key = getItemKey(item, index, keyExpression, itemName, indexName, context);\n\n // Detect duplicate keys - warn developer and fall back to unique composite key\n if (seenKeys.has(key)) {\n console.warn(\n `bq-for: Duplicate key \"${String(key)}\" detected at index ${index}. ` +\n `Falling back to index-based key for this item. ` +\n `Ensure :key expressions produce unique values for each item.`\n );\n // Create a unique composite key to avoid corrupting rendered output\n key = { __bqDuplicateKey: key, __bqIndex: index };\n }\n seenKeys.add(key);\n\n newKeys.push(key);\n newItemsByKey.set(key, { item, index });\n });\n\n // Identify items to remove (in old but not in new)\n const keysToRemove: unknown[] = [];\n for (const key of renderedOrder) {\n if (!newItemsByKey.has(key)) {\n keysToRemove.push(key);\n }\n }\n\n // Remove deleted items\n for (const key of keysToRemove) {\n const rendered = renderedItemsMap.get(key);\n if (rendered) {\n removeItem(rendered);\n renderedItemsMap.delete(key);\n }\n }\n\n // Process new list: create new items, update indices, reorder\n const newRenderedMap = new Map<unknown, RenderedItem>();\n let lastInsertedElement: Element | Comment = placeholder;\n\n for (let i = 0; i < newKeys.length; i++) {\n const key = newKeys[i];\n const { item, index } = newItemsByKey.get(key)!;\n let rendered = renderedItemsMap.get(key);\n\n if (rendered) {\n // Reuse existing element\n updateItem(rendered, item, index);\n newRenderedMap.set(key, rendered);\n\n // Check if element needs to be moved\n const currentNext: ChildNode | null = lastInsertedElement.nextSibling;\n if (currentNext !== rendered.element) {\n // Move element to correct position\n lastInsertedElement.after(rendered.element);\n }\n lastInsertedElement = rendered.element;\n } else {\n // Create new element\n rendered = createItemElement(item, index, key);\n newRenderedMap.set(key, rendered);\n\n // Insert at correct position\n lastInsertedElement.after(rendered.element);\n lastInsertedElement = rendered.element;\n }\n }\n\n // Update tracking state\n renderedItemsMap = newRenderedMap;\n renderedOrder = newKeys;\n });\n\n // When the bq-for itself is cleaned up, also cleanup all rendered items\n cleanups.push(() => {\n cleanup();\n for (const rendered of renderedItemsMap.values()) {\n for (const itemCleanup of rendered.cleanups) {\n itemCleanup();\n }\n }\n renderedItemsMap.clear();\n });\n };\n};\n","import { effect } from '../../reactive/index';\nimport { sanitizeHtml } from '../../security/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-html directive - sets innerHTML (sanitized by default).\n * @internal\n */\nexport const handleHtml = (sanitize: boolean): DirectiveHandler => {\n return (el, expression, context, cleanups) => {\n const cleanup = effect(() => {\n const value = evaluate<string>(expression, context);\n const html = String(value ?? '');\n el.innerHTML = sanitize ? sanitizeHtml(html) : html;\n });\n cleanups.push(cleanup);\n };\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-if directive - conditional rendering.\n * @internal\n */\nexport const handleIf: DirectiveHandler = (el, expression, context, cleanups) => {\n const placeholder = document.createComment(`bq-if: ${expression}`);\n\n // Store original element state\n let isInserted = true;\n\n const cleanup = effect(() => {\n const condition = evaluate<boolean>(expression, context);\n\n if (condition && !isInserted) {\n // Insert element using replaceWith to handle moved elements\n placeholder.replaceWith(el);\n isInserted = true;\n } else if (!condition && isInserted) {\n // Remove element using replaceWith to handle moved elements\n el.replaceWith(placeholder);\n isInserted = false;\n }\n });\n\n cleanups.push(cleanup);\n};\n","import { effect, isSignal, type Signal } from '../../reactive/index';\nimport { evaluateRaw } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-model directive - two-way binding.\n * @internal\n */\nexport const handleModel: DirectiveHandler = (el, expression, context, cleanups) => {\n const input = el as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n const rawValue = evaluateRaw<Signal<unknown>>(expression, context);\n\n if (!isSignal(rawValue)) {\n console.warn(`bQuery view: bq-model requires a signal, got \"${expression}\"`);\n return;\n }\n\n const sig = rawValue as Signal<unknown>;\n\n // Initial value sync\n const isCheckbox = input.type === 'checkbox';\n const isRadio = input.type === 'radio';\n\n const updateInput = () => {\n if (isCheckbox) {\n (input as HTMLInputElement).checked = Boolean(sig.value);\n } else if (isRadio) {\n (input as HTMLInputElement).checked = sig.value === input.value;\n } else {\n input.value = String(sig.value ?? '');\n }\n };\n\n // Effect to sync signal -> input\n const cleanup = effect(() => {\n updateInput();\n });\n cleanups.push(cleanup);\n\n // Event listener to sync input -> signal\n const eventType = input.tagName === 'SELECT' ? 'change' : 'input';\n const handler = () => {\n if (isCheckbox) {\n sig.value = (input as HTMLInputElement).checked;\n } else if (isRadio) {\n if ((input as HTMLInputElement).checked) {\n sig.value = input.value;\n }\n } else {\n sig.value = input.value;\n }\n };\n\n input.addEventListener(eventType, handler);\n cleanups.push(() => input.removeEventListener(eventType, handler));\n};\n","import { evaluateRaw } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-on:event directive - event binding.\n * @internal\n */\nexport const handleOn = (eventName: string): DirectiveHandler => {\n return (el, expression, context, cleanups) => {\n const handler = (event: Event) => {\n // Add $event to context for expression evaluation\n const eventContext = { ...context, $event: event, $el: el };\n\n // Check if expression contains a function call (has parentheses)\n // If not, it might be a plain function reference like \"handleClick\"\n // Note: Method references like \"handlers.onClick\" will lose their receiver\n // when auto-invoked. For methods, use explicit calls: \"handlers.onClick($event)\"\n const containsCall = expression.includes('(');\n\n if (!containsCall) {\n // Evaluate the expression - if it returns a function, invoke it with $event\n const result = evaluateRaw<unknown>(expression, eventContext);\n if (typeof result === 'function') {\n // Auto-invoke with event. Note: `this` will be undefined for method references.\n // For proper method binding, use explicit syntax: \"obj.method($event)\"\n result(event);\n return;\n }\n // If not a function, the expression was already evaluated (e.g., \"count.value++\")\n return;\n }\n\n // Otherwise evaluate as expression using evaluateRaw to allow signal mutations\n // (e.g., \"count.value++\" or \"handleClick($event)\")\n evaluateRaw(expression, eventContext);\n };\n\n el.addEventListener(eventName, handler);\n cleanups.push(() => el.removeEventListener(eventName, handler));\n };\n};\n","import { isSignal, type Signal } from '../../reactive/index';\nimport { evaluateRaw } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Checks if an object has a writable `value` property.\n * Returns true if `value` is an own data property or an accessor with a setter.\n * @internal\n */\nfunction hasWritableValue(obj: object): obj is { value: Element | null } {\n const descriptor = Object.getOwnPropertyDescriptor(obj, 'value');\n if (!descriptor) return false;\n // Data property: check writable flag\n if ('value' in descriptor) return descriptor.writable === true;\n // Accessor property: check for setter\n return typeof descriptor.set === 'function';\n}\n\n/**\n * Handles bq-ref directive - element reference.\n * @internal\n */\nexport const handleRef: DirectiveHandler = (el, expression, context, cleanups) => {\n const rawValue = evaluateRaw<Signal<Element | null> | { value: Element | null }>(\n expression,\n context\n );\n\n if (isSignal(rawValue)) {\n rawValue.value = el;\n cleanups.push(() => {\n rawValue.value = null;\n });\n } else if (typeof rawValue === 'object' && rawValue !== null && hasWritableValue(rawValue)) {\n // Object with writable .value property (e.g., { value: null })\n rawValue.value = el;\n cleanups.push(() => {\n rawValue.value = null;\n });\n }\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-show directive - toggle visibility.\n * @internal\n */\nexport const handleShow: DirectiveHandler = (el, expression, context, cleanups) => {\n const htmlEl = el as HTMLElement;\n // Capture the computed display value to properly restore visibility.\n // If inline display is 'none' or empty, we need to use the computed value.\n // Use ownerDocument.defaultView for cross-document/iframe compatibility.\n let originalDisplay = htmlEl.style.display;\n if (!originalDisplay || originalDisplay === 'none') {\n const computed = htmlEl.ownerDocument.defaultView?.getComputedStyle(htmlEl).display ?? '';\n originalDisplay = computed !== 'none' ? computed : '';\n }\n\n const cleanup = effect(() => {\n const condition = evaluate<boolean>(expression, context);\n htmlEl.style.display = condition ? originalDisplay : 'none';\n });\n\n cleanups.push(cleanup);\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate, parseObjectExpression } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-style directive - dynamic style binding.\n * @internal\n */\nexport const handleStyle: DirectiveHandler = (el, expression, context, cleanups) => {\n const htmlEl = el as HTMLElement;\n let appliedStyles: Set<string> = new Set();\n\n const cleanup = effect(() => {\n const newStyles = new Set<string>();\n\n if (expression.trimStart().startsWith('{')) {\n const styleMap = parseObjectExpression(expression);\n for (const [prop, valueExpr] of Object.entries(styleMap)) {\n const value = evaluate<string>(valueExpr, context);\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\n htmlEl.style.setProperty(cssProp, String(value ?? ''));\n newStyles.add(cssProp);\n }\n } else {\n const result = evaluate<Record<string, string>>(expression, context);\n if (result && typeof result === 'object') {\n for (const [prop, value] of Object.entries(result)) {\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\n htmlEl.style.setProperty(cssProp, String(value ?? ''));\n newStyles.add(cssProp);\n }\n }\n }\n\n // Remove styles that were previously applied but are no longer present\n for (const cssProp of appliedStyles) {\n if (!newStyles.has(cssProp)) {\n htmlEl.style.removeProperty(cssProp);\n }\n }\n\n // Update the set of applied styles\n appliedStyles = newStyles;\n });\n\n cleanups.push(cleanup);\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-text directive - sets text content.\n * @internal\n */\nexport const handleText: DirectiveHandler = (el, expression, context, cleanups) => {\n const cleanup = effect(() => {\n const value = evaluate(expression, context);\n el.textContent = String(value ?? '');\n });\n cleanups.push(cleanup);\n};\n","import type { DirectiveHandler } from './types';\r\n\r\n/**\r\n * Function signature used to resolve custom directives without coupling the\r\n * view pipeline directly to the plugin module.\r\n * @internal\r\n */\r\nexport type CustomDirectiveResolver = (name: string) => DirectiveHandler | undefined;\r\n\r\nlet customDirectiveResolver: CustomDirectiveResolver | null = null;\r\n\r\n/**\r\n * Registers the resolver used by the view pipeline for custom directives.\r\n *\r\n * Pass `null` to unregister the current resolver and reset to the default behavior.\r\n * @internal\r\n */\r\nexport const registerCustomDirectiveResolver = (\r\n resolver: CustomDirectiveResolver | null\r\n): void => {\r\n customDirectiveResolver = resolver;\r\n};\r\n\r\n/**\r\n * Returns a custom directive handler when one is registered.\r\n * @internal\r\n */\r\nexport const getCustomDirective = (name: string): DirectiveHandler | undefined => {\r\n return customDirectiveResolver ? customDirectiveResolver(name) : undefined;\r\n};\r\n","import type { CleanupFn } from '../reactive/index';\r\nimport { detectDevEnvironment } from '../core/env';\r\nimport { getCustomDirective } from './custom-directives';\r\nimport type { BindingContext, DirectiveHandler } from './types';\r\n\r\nexport type DirectiveHandlers = {\r\n text: DirectiveHandler;\r\n html: DirectiveHandler;\r\n if: DirectiveHandler;\r\n show: DirectiveHandler;\r\n class: DirectiveHandler;\r\n style: DirectiveHandler;\r\n model: DirectiveHandler;\r\n ref: DirectiveHandler;\r\n for: DirectiveHandler;\r\n bind: (attrName: string) => DirectiveHandler;\r\n on: (eventName: string) => DirectiveHandler;\r\n};\r\n\r\n/**\r\n * Processes a single element for directives.\r\n * @internal\r\n */\r\nexport const processElement = (\r\n el: Element,\r\n context: BindingContext,\r\n prefix: string,\r\n cleanups: CleanupFn[],\r\n handlers: DirectiveHandlers\r\n): void => {\r\n const attributes = Array.from(el.attributes);\r\n\r\n for (const attr of attributes) {\r\n const { name: attributeName, value } = attr;\r\n\r\n if (!attributeName.startsWith(`${prefix}-`)) continue;\r\n\r\n const directive = attributeName.slice(prefix.length + 1); // Remove prefix and dash\r\n\r\n // Handle bq-for specially (creates new scope)\r\n if (directive === 'for') {\r\n handlers.for(el, value, context, cleanups);\r\n return; // Don't process children, bq-for handles it\r\n }\r\n\r\n // Handle other directives\r\n if (directive === 'text') {\r\n handlers.text(el, value, context, cleanups);\r\n } else if (directive === 'html') {\r\n handlers.html(el, value, context, cleanups);\r\n } else if (directive === 'if') {\r\n handlers.if(el, value, context, cleanups);\r\n } else if (directive === 'show') {\r\n handlers.show(el, value, context, cleanups);\r\n } else if (directive === 'class') {\r\n handlers.class(el, value, context, cleanups);\r\n } else if (directive === 'style') {\r\n handlers.style(el, value, context, cleanups);\r\n } else if (directive === 'model') {\r\n handlers.model(el, value, context, cleanups);\r\n } else if (directive === 'ref') {\r\n handlers.ref(el, value, context, cleanups);\r\n } else if (directive.startsWith('bind:')) {\r\n const attrName = directive.slice(5);\r\n handlers.bind(attrName)(el, value, context, cleanups);\r\n } else if (directive.startsWith('on:')) {\r\n const eventName = directive.slice(3);\r\n handlers.on(eventName)(el, value, context, cleanups);\r\n } else {\r\n // Check for custom directives registered via plugins\r\n const customHandler = getCustomDirective(directive);\r\n if (customHandler) {\r\n customHandler(el, value, context, cleanups);\r\n } else if (\r\n detectDevEnvironment() &&\r\n typeof console !== 'undefined' &&\r\n typeof console.warn === 'function'\r\n ) {\r\n console.warn(\r\n `[bQuery][view] Unknown directive \"${attributeName}\" (parsed as \"${directive}\") on <${el.tagName.toLowerCase()}>. This may be a typo or a missing custom directive registration.`\r\n );\r\n }\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Recursively processes children of an element.\r\n * @internal\r\n */\r\nexport const processChildren = (\r\n el: Element,\r\n context: BindingContext,\r\n prefix: string,\r\n cleanups: CleanupFn[],\r\n handlers: DirectiveHandlers\r\n): void => {\r\n const children = Array.from(el.children);\r\n for (const child of children) {\r\n // Skip if element has bq-for (handled separately)\r\n if (!child.hasAttribute(`${prefix}-for`)) {\r\n processElement(child, context, prefix, cleanups, handlers);\r\n processChildren(child, context, prefix, cleanups, handlers);\r\n } else {\r\n processElement(child, context, prefix, cleanups, handlers);\r\n }\r\n }\r\n};\r\n","import type { CleanupFn } from '../reactive/index';\nimport {\n createForHandler,\n handleBind,\n handleClass,\n handleHtml,\n handleIf,\n handleModel,\n handleOn,\n handleRef,\n handleShow,\n handleStyle,\n handleText,\n} from './directives/index';\nimport { processChildren, processElement, type DirectiveHandlers } from './process';\nimport type { BindingContext, MountOptions, View } from './types';\n\n/**\n * Mounts a reactive view to an element.\n *\n * @param selector - CSS selector or Element\n * @param context - Binding context with signals, computed, and functions\n * @param options - Mount options\n * @returns The mounted View instance\n *\n * @security **WARNING:** Directive expressions (bq-text, bq-if, bq-on, etc.) are evaluated\n * using `new Function()` at runtime. This means:\n * - Template attributes must come from trusted sources only\n * - NEVER load templates containing bq-* attributes from user input or untrusted APIs\n * - If you must use external templates, validate/sanitize attribute values first\n *\n * @example\n * ```ts\n * import { mount } from 'bquery/view';\n * import { signal, computed } from 'bquery/reactive';\n *\n * const name = signal('World');\n * const greeting = computed(() => `Hello, ${name.value}!`);\n * const items = signal([\n * { id: 1, text: 'Item 1' },\n * { id: 2, text: 'Item 2' },\n * ]);\n *\n * const view = mount('#app', {\n * name,\n * greeting,\n * items,\n * addItem: () => {\n * items.value = [...items.value, { id: Date.now(), text: 'New Item' }];\n * },\n * });\n *\n * // Later, cleanup\n * view.destroy();\n * ```\n */\nexport const mount = (\n selector: string | Element,\n context: BindingContext,\n options: MountOptions = {}\n): View => {\n const { prefix = 'bq', sanitize = true } = options;\n\n const el = typeof selector === 'string' ? document.querySelector(selector) : selector;\n\n if (!el) {\n throw new Error(`bQuery view: Element \"${selector}\" not found.`);\n }\n\n // Reject if root element has bq-for directive\n // bq-for replaces the element with a placeholder comment, which would leave View.el detached\n if (el.hasAttribute(`${prefix}-for`)) {\n throw new Error(\n `bQuery view: Cannot mount on element with ${prefix}-for directive. ` +\n `Wrap the ${prefix}-for element in a container instead.`\n );\n }\n\n const cleanups: CleanupFn[] = [];\n\n const handlers: DirectiveHandlers = {\n text: handleText,\n html: handleHtml(sanitize),\n if: handleIf,\n show: handleShow,\n class: handleClass,\n style: handleStyle,\n model: handleModel,\n ref: handleRef,\n for: createForHandler({\n prefix,\n processElement: (node, nodeContext, nodePrefix, nodeCleanups) =>\n processElement(node, nodeContext, nodePrefix, nodeCleanups, handlers),\n processChildren: (node, nodeContext, nodePrefix, nodeCleanups) =>\n processChildren(node, nodeContext, nodePrefix, nodeCleanups, handlers),\n }),\n bind: handleBind,\n on: handleOn,\n };\n\n const processWithHandlers = (\n node: Element,\n nodeContext: BindingContext,\n nodeCleanups: CleanupFn[]\n ) => {\n // Check if element has bq-for before processing\n // bq-for replaces the element and handles its children internally\n const hasFor = node.hasAttribute(`${prefix}-for`);\n\n processElement(node, nodeContext, prefix, nodeCleanups, handlers);\n\n // Skip processChildren if bq-for was on this element - it handles children itself\n if (!hasFor) {\n processChildren(node, nodeContext, prefix, nodeCleanups, handlers);\n }\n };\n\n // Process the root element and its children\n processWithHandlers(el, context, cleanups);\n\n return {\n el,\n context,\n\n update: (newContext: Partial<BindingContext>) => {\n Object.assign(context, newContext);\n },\n\n destroy: () => {\n for (const cleanup of cleanups) {\n cleanup();\n }\n cleanups.length = 0;\n },\n };\n};\n\n/**\n * Creates a reactive template function.\n *\n * @param template - HTML template string\n * @returns A function that creates a mounted element with the given context\n *\n * @example\n * ```ts\n * import { createTemplate } from 'bquery/view';\n * import { signal } from 'bquery/reactive';\n *\n * const TodoItem = createTemplate(`\n * <li bq-class=\"{ completed: done }\">\n * <input type=\"checkbox\" bq-model=\"done\" />\n * <span bq-text=\"text\"></span>\n * </li>\n * `);\n *\n * const item = TodoItem({\n * done: signal(false),\n * text: 'Buy groceries',\n * });\n *\n * document.querySelector('#list').append(item.el);\n * ```\n */\nexport const createTemplate = (\n template: string,\n options: MountOptions = {}\n): ((context: BindingContext) => View) => {\n return (context: BindingContext) => {\n const container = document.createElement('div');\n container.innerHTML = template.trim();\n\n const el = container.firstElementChild;\n if (!el) {\n throw new Error('bQuery view: Template must contain a single root element.');\n }\n\n // We know at least one element exists (firstElementChild is not null above)\n // Reject if there are multiple root elements\n if (container.childElementCount > 1) {\n throw new Error(\n `bQuery view: Template must contain exactly one root element, found ${container.childElementCount}.`\n );\n }\n\n const { prefix = 'bq' } = options;\n // Reject templates with bq-for or bq-if on the root element\n // These directives replace the element with a placeholder comment, which would leave View.el detached\n // Since processing happens while el is still in the temporary container, the placeholder\n // would remain there while view.el is inserted elsewhere, causing desync on future toggles\n if (el.hasAttribute(`${prefix}-for`) || el.hasAttribute(`${prefix}-if`)) {\n const directive = el.hasAttribute(`${prefix}-for`) ? 'for' : 'if';\n throw new Error(\n `bQuery view: Template root element cannot have ${prefix}-${directive} directive. ` +\n `Wrap the ${prefix}-${directive} element in a container instead.`\n );\n }\n\n return mount(el, context, options);\n };\n};\n","/**\r\n * Reactive form creation and management.\r\n *\r\n * @module bquery/forms\r\n */\r\n\r\nimport { computed, signal } from '../reactive/index';\r\nimport { isPromise } from '../core/utils/type-guards';\r\nimport type {\r\n CrossFieldValidator,\r\n FieldConfig,\r\n Form,\r\n FormConfig,\r\n FormErrors,\r\n FormField,\r\n FormFields,\r\n ValidationResult,\r\n Validator,\r\n} from './types';\r\n\r\n/**\r\n * Determines whether a validator returned a valid result.\r\n * @internal\r\n */\r\nconst isValid = (result: ValidationResult): boolean => result === true || result === undefined;\r\n\r\n/**\r\n * Runs a single validator, normalising sync and async results.\r\n * @internal\r\n */\r\nconst runValidator = async <T>(validator: Validator<T>, value: T): Promise<string | undefined> => {\r\n const result = validator(value);\r\n const resolved = isPromise(result) ? await result : result;\r\n return isValid(resolved) ? undefined : (resolved as string);\r\n};\r\n\r\n/**\r\n * Creates a reactive form field from its configuration.\r\n * @internal\r\n */\r\nconst createField = <T>(config: FieldConfig<T>): FormField<T> => {\r\n const initial = config.initialValue;\r\n const value = signal<T>(initial);\r\n const error = signal('');\r\n const isTouched = signal(false);\r\n\r\n const isDirty = computed(() => !Object.is(value.value, initial));\r\n const isPristine = computed(() => !isDirty.value);\r\n\r\n return {\r\n value,\r\n error,\r\n isDirty,\r\n isTouched,\r\n isPristine,\r\n touch: () => {\r\n isTouched.value = true;\r\n },\r\n reset: () => {\r\n value.value = initial;\r\n error.value = '';\r\n isTouched.value = false;\r\n },\r\n };\r\n};\r\n\r\n/**\r\n * Validates a single field against its validators.\r\n * Sets the field's error signal.\r\n *\r\n * @returns The first error message, or an empty string if valid.\r\n * @internal\r\n */\r\nconst validateSingleField = async <T>(\r\n field: FormField<T>,\r\n validators: Validator<T>[] | undefined\r\n): Promise<string> => {\r\n if (!validators || validators.length === 0) {\r\n field.error.value = '';\r\n return '';\r\n }\r\n\r\n for (const validator of validators) {\r\n const errorMsg = await runValidator(validator, field.value.value);\r\n if (errorMsg) {\r\n field.error.value = errorMsg;\r\n return errorMsg;\r\n }\r\n }\r\n\r\n field.error.value = '';\r\n return '';\r\n};\r\n\r\n/**\r\n * Creates a fully reactive form with field-level validation,\r\n * dirty/touched tracking, cross-field validation, and submission handling.\r\n *\r\n * Each field's `value`, `error`, `isDirty`, `isTouched`, and `isPristine`\r\n * are reactive signals/computed values that can be used in effects, computed\r\n * values, or directly read/written.\r\n *\r\n * @template T - Shape of the form values (e.g. `{ name: string; age: number }`)\r\n * @param config - Form configuration with field definitions, validators, and submit handler\r\n * @returns A reactive {@link Form} instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createForm, required, email, min } from '@bquery/bquery/forms';\r\n *\r\n * const form = createForm({\r\n * fields: {\r\n * name: { initialValue: '', validators: [required()] },\r\n * email: { initialValue: '', validators: [required(), email()] },\r\n * age: { initialValue: 0, validators: [min(18, 'Must be 18+')] },\r\n * },\r\n * onSubmit: async (values) => {\r\n * await fetch('/api/register', {\r\n * method: 'POST',\r\n * body: JSON.stringify(values),\r\n * });\r\n * },\r\n * });\r\n *\r\n * // Read reactive state\r\n * console.log(form.isValid.value); // true (initially, before validation runs)\r\n * console.log(form.fields.name.value.value); // ''\r\n *\r\n * // Update a field\r\n * form.fields.name.value.value = 'Ada';\r\n *\r\n * // Validate and submit\r\n * await form.handleSubmit();\r\n * ```\r\n */\r\nexport const createForm = <T extends Record<string, unknown>>(config: FormConfig<T>): Form<T> => {\r\n // Build reactive field objects\r\n const fieldEntries = Object.entries(config.fields) as [\r\n keyof T & string,\r\n FieldConfig<T[keyof T]>,\r\n ][];\r\n\r\n const fields = {} as FormFields<T>;\r\n const errors = {} as FormErrors<T>;\r\n\r\n for (const [name, fieldConfig] of fieldEntries) {\r\n const field = createField(fieldConfig as FieldConfig<T[typeof name]>);\r\n (fields as Record<string, FormField>)[name] = field;\r\n (errors as Record<string, typeof field.error>)[name] = field.error;\r\n }\r\n\r\n const isSubmitting = signal(false);\r\n\r\n // Computed: form is valid when all error signals are empty\r\n const isFormValid = computed(() => {\r\n for (const name of Object.keys(fields)) {\r\n if ((fields as Record<string, FormField>)[name].error.value !== '') {\r\n return false;\r\n }\r\n }\r\n return true;\r\n });\r\n\r\n // Computed: form is dirty when any field is dirty\r\n const isFormDirty = computed(() => {\r\n for (const name of Object.keys(fields)) {\r\n if ((fields as Record<string, FormField>)[name].isDirty.value) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n });\r\n\r\n /**\r\n * Validate a single field by name.\r\n */\r\n const validateField = async (name: keyof T & string): Promise<void> => {\r\n const field = (fields as Record<string, FormField>)[name];\r\n const fieldConfig = (config.fields as Record<string, FieldConfig>)[name];\r\n if (!field || !fieldConfig) return;\r\n await validateSingleField(field, fieldConfig.validators);\r\n };\r\n\r\n /**\r\n * Validate all fields (per-field + cross-field).\r\n * Returns `true` if the entire form is valid.\r\n */\r\n const validate = async (): Promise<boolean> => {\r\n let hasError = false;\r\n\r\n // Per-field validation\r\n for (const [name, fieldConfig] of fieldEntries) {\r\n const field = (fields as Record<string, FormField>)[name];\r\n const error = await validateSingleField(field, (fieldConfig as FieldConfig).validators);\r\n if (error) hasError = true;\r\n }\r\n\r\n // Cross-field validation\r\n if (config.crossValidators && config.crossValidators.length > 0) {\r\n const values = getValues();\r\n for (const crossValidator of config.crossValidators as CrossFieldValidator<T>[]) {\r\n const crossErrors = await crossValidator(values);\r\n if (crossErrors) {\r\n for (const [fieldName, errorMsg] of Object.entries(crossErrors) as [\r\n string,\r\n string | undefined,\r\n ][]) {\r\n if (errorMsg) {\r\n const field = (fields as Record<string, FormField>)[fieldName];\r\n if (field) {\r\n // Only set cross-field error if no per-field error exists\r\n if (field.error.value === '') {\r\n field.error.value = errorMsg;\r\n }\r\n hasError = true;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return !hasError;\r\n };\r\n\r\n /**\r\n * Validate all fields and, if valid, invoke the onSubmit handler.\r\n * Prevents concurrent submissions by setting isSubmitting before validation.\r\n */\r\n const handleSubmit = async (): Promise<void> => {\r\n if (isSubmitting.value) return;\r\n isSubmitting.value = true;\r\n\r\n try {\r\n const valid = await validate();\r\n if (!valid) return;\r\n\r\n if (config.onSubmit) {\r\n await config.onSubmit(getValues());\r\n }\r\n } finally {\r\n isSubmitting.value = false;\r\n }\r\n };\r\n\r\n /**\r\n * Reset every field to its initial value and clear all errors.\r\n */\r\n const reset = (): void => {\r\n for (const name of Object.keys(fields)) {\r\n (fields as Record<string, FormField>)[name].reset();\r\n }\r\n };\r\n\r\n /**\r\n * Return a plain object snapshot of all current field values.\r\n */\r\n const getValues = (): T => {\r\n const values = {} as Record<string, unknown>;\r\n for (const name of Object.keys(fields)) {\r\n values[name] = (fields as Record<string, FormField>)[name].value.value;\r\n }\r\n return values as T;\r\n };\r\n\r\n return {\r\n fields,\r\n errors,\r\n isValid: isFormValid,\r\n isDirty: isFormDirty,\r\n isSubmitting,\r\n handleSubmit,\r\n validateField,\r\n validate,\r\n reset,\r\n getValues,\r\n };\r\n};\r\n","/**\r\n * Built-in validation functions for form fields.\r\n *\r\n * Each factory returns a {@link SyncValidator} that can be passed\r\n * to a field's `validators` array in {@link FormConfig}.\r\n *\r\n * @module bquery/forms\r\n */\r\n\r\nimport type { AsyncValidator, SyncValidator } from './types';\r\n\r\n/**\r\n * Requires a non-empty value.\r\n *\r\n * Fails for `undefined`, `null`, empty strings (after trim), and empty arrays.\r\n *\r\n * @param message - Custom error message (default: `'This field is required'`)\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { required } from '@bquery/bquery/forms';\r\n * const validate = required('Name is required');\r\n * validate(''); // 'Name is required'\r\n * validate('Ada'); // true\r\n * ```\r\n */\r\nexport const required = (message = 'This field is required'): SyncValidator => {\r\n return (value: unknown) => {\r\n if (value == null) return message;\r\n if (typeof value === 'string' && value.trim() === '') return message;\r\n if (Array.isArray(value) && value.length === 0) return message;\r\n return true;\r\n };\r\n};\r\n\r\n/**\r\n * Requires a string to have at least `len` characters.\r\n *\r\n * Non-string values are coerced via `String()` before checking length.\r\n *\r\n * @param len - Minimum length\r\n * @param message - Custom error message\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { minLength } from '@bquery/bquery/forms';\r\n * const validate = minLength(3);\r\n * validate('ab'); // 'Must be at least 3 characters'\r\n * validate('abc'); // true\r\n * ```\r\n */\r\nexport const minLength = (len: number, message?: string): SyncValidator<unknown> => {\r\n const msg = message ?? `Must be at least ${len} characters`;\r\n return (value: unknown) => {\r\n const str = typeof value === 'string' ? value : String(value ?? '');\r\n return str.length >= len ? true : msg;\r\n };\r\n};\r\n\r\n/**\r\n * Requires a string to have at most `len` characters.\r\n *\r\n * Non-string values are coerced via `String()` before checking length.\r\n *\r\n * @param len - Maximum length\r\n * @param message - Custom error message\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { maxLength } from '@bquery/bquery/forms';\r\n * const validate = maxLength(10);\r\n * validate('hello world!!'); // 'Must be at most 10 characters'\r\n * validate('hello'); // true\r\n * ```\r\n */\r\nexport const maxLength = (len: number, message?: string): SyncValidator<unknown> => {\r\n const msg = message ?? `Must be at most ${len} characters`;\r\n return (value: unknown) => {\r\n const str = typeof value === 'string' ? value : String(value ?? '');\r\n return str.length <= len ? true : msg;\r\n };\r\n};\r\n\r\n/**\r\n * Requires a string to match a regular expression pattern.\r\n *\r\n * Non-string values are coerced via `String()` before testing.\r\n *\r\n * @param regex - Pattern to test against\r\n * @param message - Custom error message (default: `'Invalid format'`)\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { pattern } from '@bquery/bquery/forms';\r\n * const validate = pattern(/^\\d+$/, 'Numbers only');\r\n * validate('abc'); // 'Numbers only'\r\n * validate('123'); // true\r\n * ```\r\n */\r\nexport const pattern = (regex: RegExp, message = 'Invalid format'): SyncValidator<unknown> => {\r\n const safeRegex =\r\n regex.global || regex.sticky\r\n ? new RegExp(regex.source, regex.flags.replace(/[gy]/g, ''))\r\n : regex;\r\n\r\n return (value: unknown) => {\r\n const str = typeof value === 'string' ? value : String(value ?? '');\r\n safeRegex.lastIndex = 0;\r\n return safeRegex.test(str) ? true : message;\r\n };\r\n};\r\n\r\n/**\r\n * RFC 5322–simplified email validation.\r\n *\r\n * @param message - Custom error message (default: `'Invalid email address'`)\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { email } from '@bquery/bquery/forms';\r\n * const validate = email();\r\n * validate('nope'); // 'Invalid email address'\r\n * validate('ada@lovelace'); // 'Invalid email address'\r\n * validate('ada@love.co'); // true\r\n * ```\r\n */\r\nexport const email = (message = 'Invalid email address'): SyncValidator<unknown> => {\r\n // Intentionally simple — covers the vast majority of valid addresses\r\n // without re-implementing the full RFC 5322 grammar.\r\n const re = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n return (value: unknown) => {\r\n const str = typeof value === 'string' ? value : String(value ?? '');\r\n if (str === '') return true; // empty is handled by `required`\r\n return re.test(str) ? true : message;\r\n };\r\n};\r\n\r\n/**\r\n * Requires a string to be a valid URL.\r\n *\r\n * Uses the native `URL` constructor for validation.\r\n *\r\n * @param message - Custom error message (default: `'Invalid URL'`)\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { url } from '@bquery/bquery/forms';\r\n * const validate = url();\r\n * validate('not-a-url'); // 'Invalid URL'\r\n * validate('https://example.com'); // true\r\n * ```\r\n */\r\nexport const url = (message = 'Invalid URL'): SyncValidator<unknown> => {\r\n return (value: unknown) => {\r\n const str = typeof value === 'string' ? value : String(value ?? '');\r\n if (str === '') return true; // empty is handled by `required`\r\n try {\r\n new URL(str);\r\n return true;\r\n } catch {\r\n return message;\r\n }\r\n };\r\n};\r\n\r\n/**\r\n * Requires a numeric value to be at least `limit`.\r\n *\r\n * @param limit - Minimum allowed value (inclusive)\r\n * @param message - Custom error message\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { min } from '@bquery/bquery/forms';\r\n * const validate = min(1, 'Must be positive');\r\n * validate(0); // 'Must be positive'\r\n * validate(1); // true\r\n * ```\r\n */\r\nexport const min = (limit: number, message?: string): SyncValidator<unknown> => {\r\n const msg = message ?? `Must be at least ${limit}`;\r\n return (value: unknown) => {\r\n if (value == null) return true;\r\n if (typeof value === 'string' && value.trim() === '') return true;\r\n const num = typeof value === 'number' ? value : Number(value);\r\n return num >= limit ? true : msg;\r\n };\r\n};\r\n\r\n/**\r\n * Requires a numeric value to be at most `limit`.\r\n *\r\n * @param limit - Maximum allowed value (inclusive)\r\n * @param message - Custom error message\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { max } from '@bquery/bquery/forms';\r\n * const validate = max(100, 'Too high');\r\n * validate(101); // 'Too high'\r\n * validate(100); // true\r\n * ```\r\n */\r\nexport const max = (limit: number, message?: string): SyncValidator<unknown> => {\r\n const msg = message ?? `Must be at most ${limit}`;\r\n return (value: unknown) => {\r\n if (value == null) return true;\r\n if (typeof value === 'string' && value.trim() === '') return true;\r\n const num = typeof value === 'number' ? value : Number(value);\r\n return num <= limit ? true : msg;\r\n };\r\n};\r\n\r\n/**\r\n * Creates a custom synchronous validator from any predicate function.\r\n *\r\n * @param fn - Predicate that returns `true` when the value is valid\r\n * @param message - Error message when the predicate returns `false`\r\n * @returns A sync validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { custom } from '@bquery/bquery/forms';\r\n * const isEven = custom((v: number) => v % 2 === 0, 'Must be even');\r\n * isEven(3); // 'Must be even'\r\n * isEven(4); // true\r\n * ```\r\n */\r\nexport const custom = <T = unknown>(\r\n fn: (value: T) => boolean,\r\n message: string\r\n): SyncValidator<T> => {\r\n return (value: T) => (fn(value) ? true : message);\r\n};\r\n\r\n/**\r\n * Creates a custom asynchronous validator.\r\n *\r\n * @param fn - Async predicate that resolves to `true` when valid\r\n * @param message - Error message when the predicate resolves to `false`\r\n * @returns An async validator function\r\n *\r\n * @example\r\n * ```ts\r\n * import { customAsync } from '@bquery/bquery/forms';\r\n * const isUnique = customAsync(\r\n * async (name: string) => !(await checkExists(name)),\r\n * 'Already taken',\r\n * );\r\n * ```\r\n */\r\nexport const customAsync = <T = unknown>(\r\n fn: (value: T) => Promise<boolean>,\r\n message: string\r\n): AsyncValidator<T> => {\r\n return async (value: T) => ((await fn(value)) ? true : message);\r\n};\r\n","/**\r\n * Number and date formatting helpers using Intl APIs.\r\n * @module bquery/i18n\r\n */\r\n\r\nimport type { DateFormatOptions, NumberFormatOptions } from './types';\r\n\r\n/**\r\n * Formats a number using the Intl.NumberFormat API.\r\n *\r\n * @param value - The number to format\r\n * @param locale - The locale code (e.g. 'en-US', 'de-DE')\r\n * @param options - Intl.NumberFormat options\r\n * @returns The formatted number string\r\n *\r\n * @example\r\n * ```ts\r\n * formatNumber(1234.56, 'en-US'); // '1,234.56'\r\n * formatNumber(1234.56, 'de-DE'); // '1.234,56'\r\n * formatNumber(0.42, 'en-US', { style: 'percent' }); // '42%'\r\n * formatNumber(9.99, 'en-US', { style: 'currency', currency: 'USD' }); // '$9.99'\r\n * ```\r\n */\r\nexport const formatNumber = (\r\n value: number,\r\n locale: string,\r\n options?: NumberFormatOptions\r\n): string => {\r\n const { locale: _ignored, ...intlOptions } = options ?? {};\r\n try {\r\n return new Intl.NumberFormat(locale, intlOptions).format(value);\r\n } catch {\r\n // Fall back to basic toString on Intl errors\r\n return String(value);\r\n }\r\n};\r\n\r\n/**\r\n * Formats a date using the Intl.DateTimeFormat API.\r\n *\r\n * @param value - The date to format (Date object or timestamp)\r\n * @param locale - The locale code\r\n * @param options - Intl.DateTimeFormat options\r\n * @returns The formatted date string\r\n *\r\n * @example\r\n * ```ts\r\n * const date = new Date('2026-03-26');\r\n * formatDate(date, 'en-US'); // '3/26/2026'\r\n * formatDate(date, 'de-DE'); // '26.3.2026'\r\n * formatDate(date, 'en-US', { dateStyle: 'long' }); // 'March 26, 2026'\r\n * ```\r\n */\r\nexport const formatDate = (\r\n value: Date | number,\r\n locale: string,\r\n options?: DateFormatOptions\r\n): string => {\r\n const { locale: _ignored, ...intlOptions } = options ?? {};\r\n const date = typeof value === 'number' ? new Date(value) : value;\r\n try {\r\n return new Intl.DateTimeFormat(locale, intlOptions).format(date);\r\n } catch {\r\n // Fall back to toLocaleString on Intl errors\r\n return date.toLocaleString();\r\n }\r\n};\r\n","/**\r\n * Translation resolution helpers.\r\n * @module bquery/i18n\r\n * @internal\r\n */\r\n\r\nimport { isPlainObject, isPrototypePollutionKey, merge } from '../core/utils/object';\r\nimport type { LocaleMessages, TranslateParams } from './types';\r\n\r\n/**\r\n * Resolves a dot-delimited key path against a messages object.\r\n *\r\n * @param messages - The locale messages\r\n * @param key - Dot-delimited key (e.g. 'user.welcome')\r\n * @returns The resolved string, or `undefined` if not found\r\n *\r\n * @internal\r\n */\r\nexport const resolveKey = (messages: LocaleMessages, key: string): string | undefined => {\r\n const parts = key.split('.');\r\n let current: LocaleMessages | string = messages;\r\n\r\n for (const part of parts) {\r\n if (typeof current === 'string') return undefined;\r\n if (current[part] === undefined) return undefined;\r\n current = current[part];\r\n }\r\n\r\n return typeof current === 'string' ? current : undefined;\r\n};\r\n\r\n/**\r\n * Interpolates `{param}` placeholders in a string.\r\n *\r\n * @param template - The template string with `{key}` placeholders\r\n * @param params - Key-value pairs for replacement\r\n * @returns The interpolated string\r\n *\r\n * @example\r\n * ```ts\r\n * interpolate('Hello, {name}!', { name: 'Ada' });\r\n * // → 'Hello, Ada!'\r\n * ```\r\n *\r\n * @internal\r\n */\r\nexport const interpolate = (template: string, params: TranslateParams): string => {\r\n return template.replace(/\\{(\\w+)\\}/g, (match, key: string) => {\r\n if (key in params) {\r\n return String(params[key]);\r\n }\r\n return match; // Leave unmatched placeholders as-is\r\n });\r\n};\r\n\r\n/**\r\n * Selects the correct plural form from a pipe-delimited string.\r\n *\r\n * Supports two formats:\r\n * - **Two forms:** `\"singular | plural\"` — singular when count === 1\r\n * - **Three forms:** `\"zero | one | many\"` — zero when count === 0,\r\n * one when count === 1, many otherwise\r\n *\r\n * The `count` parameter must be present in `params` for pluralization.\r\n * If no `count` param exists or the string has no pipes, the string is\r\n * returned as-is.\r\n *\r\n * @param template - Pipe-delimited plural forms\r\n * @param params - Must include a `count` key for plural selection\r\n * @returns The selected form\r\n *\r\n * @example\r\n * ```ts\r\n * pluralize('{count} item | {count} items', { count: 1 });\r\n * // → '{count} item'\r\n *\r\n * pluralize('no items | {count} item | {count} items', { count: 0 });\r\n * // → 'no items'\r\n * ```\r\n *\r\n * @internal\r\n */\r\nexport const pluralize = (template: string, params: TranslateParams): string => {\r\n if (!template.includes('|')) return template;\r\n if (!('count' in params)) return template;\r\n\r\n const count = Number(params.count);\r\n const forms = template.split('|').map((s) => s.trim());\r\n\r\n if (forms.length === 3) {\r\n // zero | one | many\r\n if (count === 0) return forms[0];\r\n if (count === 1) return forms[1];\r\n return forms[2];\r\n }\r\n\r\n if (forms.length === 2) {\r\n // singular | plural\r\n return count === 1 ? forms[0] : forms[1];\r\n }\r\n\r\n // More than 3 forms: use last form for \"many\"\r\n if (count === 0 && forms.length > 0) return forms[0];\r\n if (count === 1 && forms.length > 1) return forms[1];\r\n return forms[forms.length - 1];\r\n};\r\n\r\n/**\r\n * Full translation pipeline: resolve → pluralize → interpolate.\r\n *\r\n * @param messages - Locale messages\r\n * @param key - Dot-delimited key path\r\n * @param params - Interpolation + pluralization params\r\n * @param fallbackMessages - Optional fallback locale messages\r\n * @returns The translated string, or the key if not found\r\n *\r\n * @internal\r\n */\r\nexport const translate = (\r\n messages: LocaleMessages | undefined,\r\n key: string,\r\n params: TranslateParams,\r\n fallbackMessages?: LocaleMessages\r\n): string => {\r\n let template: string | undefined;\r\n\r\n // Try current locale\r\n if (messages) {\r\n template = resolveKey(messages, key);\r\n }\r\n\r\n // Fallback locale\r\n if (template === undefined && fallbackMessages) {\r\n template = resolveKey(fallbackMessages, key);\r\n }\r\n\r\n // Key not found — return key as-is\r\n if (template === undefined) {\r\n return key;\r\n }\r\n\r\n // Pluralize first, then interpolate\r\n const pluralized = pluralize(template, params);\r\n return interpolate(pluralized, params);\r\n};\r\n\r\n/**\r\n * Deep merges source into target and returns a sanitized, prototype-safe copy.\r\n *\r\n * @param target - Target messages object\r\n * @param source - Source messages to merge\r\n * @returns A new merged, sanitized messages object\r\n *\r\n * @internal\r\n */\r\nexport const deepMerge = (target: LocaleMessages, source: LocaleMessages): LocaleMessages => {\r\n const merged = merge(\r\n target as Record<string, unknown>,\r\n source as Record<string, unknown>\r\n ) as LocaleMessages;\r\n\r\n const cloneSafeMessages = (value: unknown): unknown => {\r\n if (Array.isArray(value)) {\r\n return value.map((entry) => cloneSafeMessages(entry));\r\n }\r\n\r\n if (!isPlainObject(value)) {\r\n return value;\r\n }\r\n\r\n const safeObject = Object.create(null) as Record<string, unknown>;\r\n for (const [key, entry] of Object.entries(value)) {\r\n if (isPrototypePollutionKey(key)) {\r\n continue;\r\n }\r\n safeObject[key] = cloneSafeMessages(entry);\r\n }\r\n return safeObject;\r\n };\r\n\r\n return cloneSafeMessages(merged) as LocaleMessages;\r\n};\r\n","/**\r\n * Core i18n factory function.\r\n * @module bquery/i18n\r\n */\r\n\r\nimport { computed, signal } from '../reactive/index';\r\nimport { isPrototypePollutionKey } from '../core/utils/object';\r\nimport { formatDate, formatNumber } from './formatting';\r\nimport { deepMerge, translate } from './translate';\r\nimport type {\r\n DateFormatOptions,\r\n I18nConfig,\r\n I18nInstance,\r\n LocaleLoader,\r\n LocaleMessages,\r\n Messages,\r\n NumberFormatOptions,\r\n TranslateParams,\r\n} from './types';\r\n\r\n/**\r\n * Creates a reactive internationalization instance.\r\n *\r\n * The returned object provides:\r\n * - `$locale` — a reactive signal for the current locale\r\n * - `t()` — translation with interpolation and pluralization\r\n * - `tc()` — reactive translation that auto-updates on locale change\r\n * - `loadLocale()` — register lazy-loaded locale files\r\n * - `n()` — locale-aware number formatting\r\n * - `d()` — locale-aware date formatting\r\n *\r\n * @param config - Initial configuration\r\n * @returns An i18n instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createI18n } from '@bquery/bquery/i18n';\r\n *\r\n * const i18n = createI18n({\r\n * locale: 'en',\r\n * fallbackLocale: 'en',\r\n * messages: {\r\n * en: {\r\n * greeting: 'Hello, {name}!',\r\n * items: '{count} item | {count} items',\r\n * },\r\n * de: {\r\n * greeting: 'Hallo, {name}!',\r\n * items: '{count} Gegenstand | {count} Gegenstände',\r\n * },\r\n * },\r\n * });\r\n *\r\n * i18n.t('greeting', { name: 'Ada' }); // 'Hello, Ada!'\r\n * i18n.t('items', { count: 3 }); // '3 items'\r\n *\r\n * // Switch locale reactively\r\n * i18n.$locale.value = 'de';\r\n * i18n.t('greeting', { name: 'Ada' }); // 'Hallo, Ada!'\r\n * ```\r\n */\r\nexport const createI18n = (config: I18nConfig): I18nInstance => {\r\n const { locale: initialLocale, messages: initialMessages, fallbackLocale } = config;\r\n\r\n const sanitizeLocaleMessages = (localeMessages: LocaleMessages): LocaleMessages =>\r\n deepMerge(Object.create(null) as LocaleMessages, localeMessages);\r\n\r\n // Deep-clone initial messages to prevent external mutation\r\n const messages = Object.create(null) as Messages;\r\n for (const [loc, msgs] of Object.entries(initialMessages)) {\r\n if (isPrototypePollutionKey(loc)) {\r\n continue;\r\n }\r\n messages[loc] = sanitizeLocaleMessages(msgs);\r\n }\r\n\r\n // Reactive locale signal\r\n const $locale = signal(initialLocale);\r\n\r\n // Lazy-loader registry\r\n const loaders = new Map<string, LocaleLoader>();\r\n\r\n // Track which loaders have been invoked to avoid duplicate loads\r\n const loadedLocales = new Set<string>(Object.keys(messages));\r\n\r\n /**\r\n * Get messages for a locale, or undefined if not loaded.\r\n */\r\n const getMessages = (loc: string): LocaleMessages | undefined => {\r\n if (isPrototypePollutionKey(loc)) {\r\n return undefined;\r\n }\r\n return messages[loc];\r\n };\r\n\r\n /**\r\n * Register a lazy-loader for a locale.\r\n */\r\n const loadLocale = (loc: string, loader: LocaleLoader): void => {\r\n if (isPrototypePollutionKey(loc)) {\r\n return;\r\n }\r\n loaders.set(loc, loader);\r\n };\r\n\r\n /**\r\n * Ensure a locale's messages are loaded.\r\n */\r\n const ensureLocale = async (loc: string): Promise<void> => {\r\n if (isPrototypePollutionKey(loc)) return;\r\n if (loadedLocales.has(loc)) return;\r\n\r\n const loader = loaders.get(loc);\r\n if (!loader) {\r\n throw new Error(`bQuery i18n: No messages or loader registered for locale \"${loc}\".`);\r\n }\r\n\r\n const loaded = await loader();\r\n // Handle both default exports and direct objects\r\n const msgs = (loaded as { default?: LocaleMessages }).default ?? (loaded as LocaleMessages);\r\n messages[loc] = sanitizeLocaleMessages(msgs);\r\n loadedLocales.add(loc);\r\n };\r\n\r\n /**\r\n * Translate a key path.\r\n */\r\n const t = (key: string, params: TranslateParams = {}): string => {\r\n const currentLocale = $locale.value;\r\n const currentMessages = messages[currentLocale];\r\n const fallbackMessages = fallbackLocale ? messages[fallbackLocale] : undefined;\r\n\r\n return translate(currentMessages, key, params, fallbackMessages);\r\n };\r\n\r\n /**\r\n * Reactive translation — returns a computed signal.\r\n */\r\n const tc = (key: string, params: TranslateParams = {}) => {\r\n return computed(() => {\r\n // Reading $locale.value creates a reactive dependency\r\n const currentLocale = $locale.value;\r\n const currentMessages = messages[currentLocale];\r\n const fallbackMessages = fallbackLocale ? messages[fallbackLocale] : undefined;\r\n\r\n return translate(currentMessages, key, params, fallbackMessages);\r\n });\r\n };\r\n\r\n /**\r\n * Format a number with the current (or overridden) locale.\r\n */\r\n const n = (value: number, options?: NumberFormatOptions): string => {\r\n const loc = options?.locale ?? $locale.value;\r\n return formatNumber(value, loc, options);\r\n };\r\n\r\n /**\r\n * Format a date with the current (or overridden) locale.\r\n */\r\n const d = (value: Date | number, options?: DateFormatOptions): string => {\r\n const loc = options?.locale ?? $locale.value;\r\n return formatDate(value, loc, options);\r\n };\r\n\r\n /**\r\n * Merge additional messages into a locale.\r\n */\r\n const mergeMessages = (loc: string, newMessages: LocaleMessages): void => {\r\n if (isPrototypePollutionKey(loc)) {\r\n return;\r\n }\r\n if (!messages[loc]) {\r\n messages[loc] = Object.create(null) as LocaleMessages;\r\n loadedLocales.add(loc);\r\n }\r\n messages[loc] = deepMerge(messages[loc], sanitizeLocaleMessages(newMessages));\r\n };\r\n\r\n /**\r\n * List all available locales (loaded + registered loaders).\r\n */\r\n const availableLocales = (): string[] => {\r\n const locales = new Set<string>([...loadedLocales, ...loaders.keys()]);\r\n return Array.from(locales).sort();\r\n };\r\n\r\n return {\r\n $locale,\r\n t,\r\n tc,\r\n loadLocale,\r\n ensureLocale,\r\n n,\r\n d,\r\n getMessages,\r\n mergeMessages,\r\n availableLocales,\r\n };\r\n};\r\n","/**\r\n * Screen reader announcement utility using ARIA live regions.\r\n *\r\n * Creates and manages off-screen live regions to announce dynamic\r\n * content changes to assistive technologies.\r\n *\r\n * @module bquery/a11y\r\n */\r\n\r\nimport type { AnnouncePriority } from './types';\r\n\r\n/** Cache for live region containers, keyed by priority. */\r\nconst liveRegions = new Map<AnnouncePriority, HTMLElement>();\r\nconst pendingAnnouncements = new Map<AnnouncePriority, ReturnType<typeof setTimeout>>();\r\n\r\n/**\r\n * Delay in milliseconds before updating the live region text.\r\n * This ensures screen readers detect the content change even when\r\n * the same message is announced consecutively — clearing first and\r\n * setting after a short timer delay forces a new live-region mutation event.\r\n * @internal\r\n */\r\nconst ANNOUNCEMENT_DELAY_MS = 50;\r\n\r\n/**\r\n * Gets or creates a visually-hidden ARIA live region for the given priority.\r\n *\r\n * @param priority - The aria-live priority level\r\n * @returns The live region element\r\n * @internal\r\n */\r\nconst getOrCreateLiveRegion = (priority: AnnouncePriority): HTMLElement => {\r\n const existing = liveRegions.get(priority);\r\n if (existing && existing.isConnected) {\r\n return existing;\r\n }\r\n\r\n const el = document.createElement('div');\r\n el.setAttribute('aria-live', priority);\r\n el.setAttribute('aria-atomic', 'true');\r\n el.setAttribute('role', priority === 'assertive' ? 'alert' : 'status');\r\n\r\n // Visually hidden but accessible to screen readers\r\n Object.assign(el.style, {\r\n position: 'absolute',\r\n width: '1px',\r\n height: '1px',\r\n padding: '0',\r\n margin: '-1px',\r\n overflow: 'hidden',\r\n clip: 'rect(0, 0, 0, 0)',\r\n whiteSpace: 'nowrap',\r\n border: '0',\r\n });\r\n\r\n document.body.appendChild(el);\r\n liveRegions.set(priority, el);\r\n\r\n return el;\r\n};\r\n\r\n/**\r\n * Announces a message to screen readers via an ARIA live region.\r\n *\r\n * The message is injected into a visually-hidden live region element.\r\n * Screen readers will pick up the change and announce it to the user.\r\n *\r\n * @param message - The text message to announce\r\n * @param priority - The urgency level: `'polite'` (default) or `'assertive'`\r\n *\r\n * @example\r\n * ```ts\r\n * import { announceToScreenReader } from '@bquery/bquery/a11y';\r\n *\r\n * // Polite announcement (waits for idle)\r\n * announceToScreenReader('3 search results found');\r\n *\r\n * // Assertive announcement (interrupts current speech)\r\n * announceToScreenReader('Error: Please fix the form', 'assertive');\r\n * ```\r\n */\r\nexport const announceToScreenReader = (\r\n message: string,\r\n priority: AnnouncePriority = 'polite'\r\n): void => {\r\n if (!message) return;\r\n if (typeof document === 'undefined' || !document.body) return;\r\n\r\n const region = getOrCreateLiveRegion(priority);\r\n const pendingTimeout = pendingAnnouncements.get(priority);\r\n if (pendingTimeout !== undefined) {\r\n clearTimeout(pendingTimeout);\r\n }\r\n\r\n // Clear first, then set after a short timer delay to ensure screen readers\r\n // detect the change even if the same message is announced twice.\r\n region.textContent = '';\r\n\r\n // Use setTimeout to ensure the DOM update triggers a live region change event\r\n const timeout = setTimeout(() => {\r\n pendingAnnouncements.delete(priority);\r\n if (region.isConnected) {\r\n region.textContent = message;\r\n }\r\n }, ANNOUNCEMENT_DELAY_MS);\r\n\r\n pendingAnnouncements.set(priority, timeout);\r\n};\r\n\r\n/**\r\n * Removes all live region elements created by `announceToScreenReader`.\r\n * Useful for cleanup in tests or when unmounting an application.\r\n *\r\n * @example\r\n * ```ts\r\n * import { clearAnnouncements } from '@bquery/bquery/a11y';\r\n *\r\n * clearAnnouncements();\r\n * ```\r\n */\r\nexport const clearAnnouncements = (): void => {\r\n for (const timeout of pendingAnnouncements.values()) {\r\n clearTimeout(timeout);\r\n }\r\n pendingAnnouncements.clear();\r\n\r\n for (const [, el] of liveRegions) {\r\n el.remove();\r\n }\r\n liveRegions.clear();\r\n};\r\n","/**\r\n * Development-time accessibility audit utility.\r\n *\r\n * Scans DOM elements for common accessibility issues such as missing\r\n * alt text on images, missing labels on form inputs, empty links/buttons,\r\n * and incorrect ARIA usage.\r\n *\r\n * @module bquery/a11y\r\n */\r\n\r\nimport type { AuditFinding, AuditResult, AuditSeverity } from './types';\r\n\r\n/**\r\n * Creates a finding object.\r\n * @internal\r\n */\r\nconst finding = (\r\n severity: AuditSeverity,\r\n message: string,\r\n element: Element,\r\n rule: string\r\n): AuditFinding => ({\r\n severity,\r\n message,\r\n element,\r\n rule,\r\n});\r\n\r\n/**\r\n * Checks images for missing alt attributes.\r\n * @internal\r\n */\r\nconst auditImages = (container: Element): AuditFinding[] => {\r\n const findings: AuditFinding[] = [];\r\n const images = container.querySelectorAll('img');\r\n\r\n for (const img of images) {\r\n if (!img.hasAttribute('alt')) {\r\n findings.push(\r\n finding(\r\n 'error',\r\n 'Image is missing an alt attribute. Add alt=\"\" for decorative images or a descriptive alt text.',\r\n img,\r\n 'img-alt'\r\n )\r\n );\r\n } else if (img.getAttribute('alt') === '' && !img.hasAttribute('role')) {\r\n findings.push(\r\n finding(\r\n 'info',\r\n 'Image has empty alt text. Consider adding role=\"presentation\" if decorative.',\r\n img,\r\n 'img-decorative'\r\n )\r\n );\r\n }\r\n }\r\n\r\n return findings;\r\n};\r\n\r\n/**\r\n * Checks form inputs for missing labels.\r\n * @internal\r\n */\r\nconst auditFormInputs = (container: Element): AuditFinding[] => {\r\n const findings: AuditFinding[] = [];\r\n const inputs = container.querySelectorAll('input, select, textarea');\r\n\r\n for (const input of inputs) {\r\n const type = input.getAttribute('type');\r\n\r\n // Hidden, submit, and button inputs don't need labels\r\n if (type === 'hidden' || type === 'submit' || type === 'button' || type === 'reset') {\r\n continue;\r\n }\r\n\r\n const id = input.getAttribute('id');\r\n const hasLabel = id ? !!container.querySelector(`label[for=\"${id}\"]`) : false;\r\n const hasAriaLabel = input.hasAttribute('aria-label') || input.hasAttribute('aria-labelledby');\r\n const hasTitle = input.hasAttribute('title');\r\n const isWrappedInLabel = input.closest('label') !== null;\r\n\r\n if (!hasLabel && !hasAriaLabel && !hasTitle && !isWrappedInLabel) {\r\n findings.push(\r\n finding(\r\n 'error',\r\n `Form input is missing a label. Add a <label for=\"id\">, aria-label, or aria-labelledby attribute.`,\r\n input,\r\n 'input-label'\r\n )\r\n );\r\n }\r\n }\r\n\r\n return findings;\r\n};\r\n\r\n/**\r\n * Checks for empty interactive elements (buttons, links).\r\n * @internal\r\n */\r\nconst auditInteractiveElements = (container: Element): AuditFinding[] => {\r\n const findings: AuditFinding[] = [];\r\n\r\n // Check buttons\r\n const buttons = container.querySelectorAll('button');\r\n for (const btn of buttons) {\r\n const hasText = (btn.textContent ?? '').trim().length > 0;\r\n const hasAriaLabel = btn.hasAttribute('aria-label') || btn.hasAttribute('aria-labelledby');\r\n const hasTitle = btn.hasAttribute('title');\r\n\r\n if (!hasText && !hasAriaLabel && !hasTitle) {\r\n findings.push(\r\n finding(\r\n 'error',\r\n 'Button has no accessible name. Add text content, aria-label, or title.',\r\n btn,\r\n 'button-name'\r\n )\r\n );\r\n }\r\n }\r\n\r\n // Check links\r\n const links = container.querySelectorAll('a[href]');\r\n for (const link of links) {\r\n const hasText = (link.textContent ?? '').trim().length > 0;\r\n const hasAriaLabel = link.hasAttribute('aria-label') || link.hasAttribute('aria-labelledby');\r\n const hasTitle = link.hasAttribute('title');\r\n const hasImage = link.querySelector('img[alt]') !== null;\r\n\r\n if (!hasText && !hasAriaLabel && !hasTitle && !hasImage) {\r\n findings.push(\r\n finding(\r\n 'error',\r\n 'Link has no accessible name. Add text content, aria-label, or title.',\r\n link,\r\n 'link-name'\r\n )\r\n );\r\n }\r\n }\r\n\r\n return findings;\r\n};\r\n\r\n/**\r\n * Checks heading hierarchy for skipped levels.\r\n * @internal\r\n */\r\nconst auditHeadings = (container: Element): AuditFinding[] => {\r\n const findings: AuditFinding[] = [];\r\n const headings = container.querySelectorAll('h1, h2, h3, h4, h5, h6');\r\n\r\n let previousLevel = 0;\r\n\r\n for (const heading of headings) {\r\n const level = parseInt(heading.tagName.charAt(1), 10);\r\n\r\n if (previousLevel > 0 && level > previousLevel + 1) {\r\n findings.push(\r\n finding(\r\n 'warning',\r\n `Heading level skipped: <${heading.tagName.toLowerCase()}> follows <h${previousLevel}>. Don't skip heading levels.`,\r\n heading,\r\n 'heading-order'\r\n )\r\n );\r\n }\r\n\r\n if ((heading.textContent ?? '').trim().length === 0) {\r\n findings.push(finding('warning', 'Heading element is empty.', heading, 'heading-empty'));\r\n }\r\n\r\n previousLevel = level;\r\n }\r\n\r\n return findings;\r\n};\r\n\r\n/**\r\n * Checks for valid ARIA attribute usage.\r\n * @internal\r\n */\r\nconst auditAria = (container: Element): AuditFinding[] => {\r\n const findings: AuditFinding[] = [];\r\n\r\n // Check aria-labelledby references exist\r\n const labelled = container.querySelectorAll('[aria-labelledby]');\r\n for (const el of labelled) {\r\n const ids = (el.getAttribute('aria-labelledby') ?? '').split(/\\s+/);\r\n for (const id of ids) {\r\n if (id && !document.getElementById(id)) {\r\n findings.push(\r\n finding(\r\n 'error',\r\n `aria-labelledby references \"${id}\" which does not exist in the document.`,\r\n el,\r\n 'aria-labelledby-ref'\r\n )\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Check aria-describedby references exist\r\n const described = container.querySelectorAll('[aria-describedby]');\r\n for (const el of described) {\r\n const ids = (el.getAttribute('aria-describedby') ?? '').split(/\\s+/);\r\n for (const id of ids) {\r\n if (id && !document.getElementById(id)) {\r\n findings.push(\r\n finding(\r\n 'error',\r\n `aria-describedby references \"${id}\" which does not exist in the document.`,\r\n el,\r\n 'aria-describedby-ref'\r\n )\r\n );\r\n }\r\n }\r\n }\r\n\r\n return findings;\r\n};\r\n\r\n/**\r\n * Checks for sufficient document landmarks.\r\n * @internal\r\n */\r\nconst auditLandmarks = (container: Element): AuditFinding[] => {\r\n const findings: AuditFinding[] = [];\r\n\r\n // Only audit the document body or top-level container\r\n if (container === document.body || container === document.documentElement) {\r\n const hasMain = !!container.querySelector('main') || !!container.querySelector('[role=\"main\"]');\r\n\r\n if (!hasMain) {\r\n findings.push(\r\n finding(\r\n 'warning',\r\n 'Page is missing a <main> landmark. Add <main> or role=\"main\" to the primary content area.',\r\n container,\r\n 'landmark-main'\r\n )\r\n );\r\n }\r\n }\r\n\r\n return findings;\r\n};\r\n\r\n/**\r\n * Runs a development-time accessibility audit on a container element.\r\n *\r\n * Checks for common accessibility issues including:\r\n * - Missing alt text on images\r\n * - Missing labels on form inputs\r\n * - Empty buttons and links\r\n * - Heading hierarchy issues\r\n * - Invalid ARIA references\r\n * - Missing document landmarks\r\n *\r\n * This is intended as a development tool — not a replacement for\r\n * manual testing or professional accessibility audits.\r\n *\r\n * @param container - The element to audit (defaults to `document.body`)\r\n * @returns An audit result with findings, counts, and pass/fail status\r\n *\r\n * @example\r\n * ```ts\r\n * import { auditA11y } from '@bquery/bquery/a11y';\r\n *\r\n * const result = auditA11y();\r\n * if (!result.passed) {\r\n * console.warn(`Found ${result.errors} accessibility errors:`);\r\n * for (const f of result.findings) {\r\n * console.warn(`[${f.severity}] ${f.message}`, f.element);\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport const auditA11y = (container?: Element): AuditResult => {\r\n if (typeof document === 'undefined' || !document.body) {\r\n return {\r\n findings: [],\r\n errors: 0,\r\n warnings: 0,\r\n passed: true,\r\n };\r\n }\r\n\r\n const target = container ?? document.body;\r\n\r\n const allFindings: AuditFinding[] = [\r\n ...auditImages(target),\r\n ...auditFormInputs(target),\r\n ...auditInteractiveElements(target),\r\n ...auditHeadings(target),\r\n ...auditAria(target),\r\n ...auditLandmarks(target),\r\n ];\r\n\r\n const errors = allFindings.filter((f) => f.severity === 'error').length;\r\n const warnings = allFindings.filter((f) => f.severity === 'warning').length;\r\n\r\n return {\r\n findings: allFindings,\r\n errors,\r\n warnings,\r\n passed: errors === 0,\r\n };\r\n};\r\n","/**\r\n * Reactive media preference signals for accessibility.\r\n *\r\n * Provides reactive signals that track the user's system-level\r\n * accessibility preferences (reduced motion, color scheme, contrast).\r\n *\r\n * @module bquery/a11y\r\n */\r\n\r\nimport { readonly, signal, type ReadonlySignal } from '../reactive/index';\r\nimport type { ColorScheme, ContrastPreference, MediaPreferenceSignal } from './types';\r\n\r\ntype LegacyMediaQueryList = MediaQueryList & {\r\n addListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\r\n removeListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\r\n};\r\n\r\nconst bindMediaQueryListener = (\r\n mql: MediaQueryList,\r\n handler: (event: MediaQueryListEvent | MediaQueryList) => void\r\n): (() => void) | undefined => {\r\n if (typeof mql.addEventListener === 'function') {\r\n mql.addEventListener('change', handler);\r\n return (): void => {\r\n mql.removeEventListener('change', handler);\r\n };\r\n }\r\n\r\n const legacyMql = mql as LegacyMediaQueryList;\r\n if (typeof legacyMql.addListener === 'function') {\r\n legacyMql.addListener(handler);\r\n return (): void => {\r\n legacyMql.removeListener?.(handler);\r\n };\r\n }\r\n\r\n return undefined;\r\n};\r\n\r\nconst withDestroy = <T>(\r\n signalHandle: ReadonlySignal<T>,\r\n cleanup: () => void\r\n): MediaPreferenceSignal<T> => {\r\n let destroyImpl = cleanup;\r\n const handle = signalHandle as MediaPreferenceSignal<T>;\r\n Object.defineProperty(handle, 'destroy', {\r\n configurable: true,\r\n enumerable: false,\r\n value: (): void => {\r\n const currentDestroy = destroyImpl;\r\n // Make cleanup idempotent so repeated destroy() calls from user code stay safe.\r\n destroyImpl = (): void => {};\r\n currentDestroy();\r\n },\r\n });\r\n return handle;\r\n};\r\n\r\n/**\r\n * Creates a reactive signal that tracks a CSS media query.\r\n *\r\n * @param query - The media query string\r\n * @param initialValue - Fallback value when `matchMedia` is unavailable\r\n * @returns A readonly signal handle that updates when the query match changes\r\n * @internal\r\n */\r\nconst createMediaSignal = (\r\n query: string,\r\n initialValue: boolean\r\n): MediaPreferenceSignal<boolean> => {\r\n const s = signal(initialValue);\r\n let destroy = (): void => {\r\n s.dispose();\r\n };\r\n\r\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\r\n try {\r\n const mql = window.matchMedia(query);\r\n s.value = mql.matches;\r\n\r\n const handler = (e: MediaQueryListEvent | MediaQueryList): void => {\r\n s.value = e.matches;\r\n };\r\n\r\n const cleanupMql = bindMediaQueryListener(mql, handler);\r\n if (cleanupMql) {\r\n destroy = (): void => {\r\n cleanupMql();\r\n s.dispose();\r\n };\r\n }\r\n } catch {\r\n // matchMedia may throw in non-browser environments\r\n }\r\n }\r\n\r\n return withDestroy(readonly(s), destroy);\r\n};\r\n\r\n/**\r\n * Returns a reactive signal indicating whether the user prefers reduced motion.\r\n *\r\n * Tracks the `(prefers-reduced-motion: reduce)` media query. Returns `true`\r\n * when the user has requested reduced motion in their system settings.\r\n *\r\n * @returns A readonly reactive signal handle. Call `destroy()` to remove listeners.\r\n *\r\n * @example\r\n * ```ts\r\n * import { prefersReducedMotion } from '@bquery/bquery/a11y';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const reduced = prefersReducedMotion();\r\n * effect(() => {\r\n * if (reduced.value) {\r\n * console.log('User prefers reduced motion');\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const prefersReducedMotion = (): MediaPreferenceSignal<boolean> => {\r\n return createMediaSignal('(prefers-reduced-motion: reduce)', false);\r\n};\r\n\r\n/**\r\n * Returns a reactive signal tracking the user's preferred color scheme.\r\n *\r\n * Tracks the `(prefers-color-scheme: dark)` media query. Returns `'dark'`\r\n * when the user prefers a dark color scheme, `'light'` otherwise.\r\n *\r\n * @returns A readonly reactive signal handle with `'light'` or `'dark'`\r\n *\r\n * @example\r\n * ```ts\r\n * import { prefersColorScheme } from '@bquery/bquery/a11y';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const scheme = prefersColorScheme();\r\n * effect(() => {\r\n * document.body.dataset.theme = scheme.value;\r\n * });\r\n * ```\r\n */\r\nexport const prefersColorScheme = (): MediaPreferenceSignal<ColorScheme> => {\r\n const s = signal<ColorScheme>('light');\r\n let destroy = (): void => {\r\n s.dispose();\r\n };\r\n\r\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\r\n try {\r\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\r\n s.value = mql.matches ? 'dark' : 'light';\r\n\r\n const handler = (e: MediaQueryListEvent | MediaQueryList): void => {\r\n s.value = e.matches ? 'dark' : 'light';\r\n };\r\n\r\n const cleanupMql = bindMediaQueryListener(mql, handler);\r\n if (cleanupMql) {\r\n destroy = (): void => {\r\n cleanupMql();\r\n s.dispose();\r\n };\r\n }\r\n } catch {\r\n // matchMedia may throw in non-browser environments\r\n }\r\n }\r\n\r\n return withDestroy(readonly(s), destroy);\r\n};\r\n\r\n/**\r\n * Returns a reactive signal tracking the user's contrast preference.\r\n *\r\n * Tracks the `(prefers-contrast)` media query. Returns:\r\n * - `'more'` — user prefers higher contrast\r\n * - `'less'` — user prefers lower contrast\r\n * - `'custom'` — user has set a custom contrast level\r\n * - `'no-preference'` — no explicit preference\r\n *\r\n * @returns A readonly reactive signal handle\r\n *\r\n * @example\r\n * ```ts\r\n * import { prefersContrast } from '@bquery/bquery/a11y';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const contrast = prefersContrast();\r\n * effect(() => {\r\n * if (contrast.value === 'more') {\r\n * document.body.classList.add('high-contrast');\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const prefersContrast = (): MediaPreferenceSignal<ContrastPreference> => {\r\n const s = signal<ContrastPreference>('no-preference');\r\n let destroy = (): void => {\r\n s.dispose();\r\n };\r\n\r\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\r\n let mql: MediaQueryList | undefined;\r\n let mqlLess: MediaQueryList | undefined;\r\n let mqlCustom: MediaQueryList | undefined;\r\n\r\n const update = (): void => {\r\n // Defensive guard for environments where matchMedia setup fails before\r\n // listeners are attached; update() is only expected to run after init.\r\n if (!mql || !mqlLess || !mqlCustom) {\r\n return;\r\n }\r\n\r\n if (mql.matches) {\r\n s.value = 'more';\r\n } else if (mqlLess.matches) {\r\n s.value = 'less';\r\n } else if (mqlCustom.matches) {\r\n s.value = 'custom';\r\n } else {\r\n s.value = 'no-preference';\r\n }\r\n };\r\n\r\n // Listen for changes on the contrast preference variants\r\n try {\r\n mql = window.matchMedia('(prefers-contrast: more)');\r\n mqlLess = window.matchMedia('(prefers-contrast: less)');\r\n mqlCustom = window.matchMedia('(prefers-contrast: custom)');\r\n update();\r\n const cleanupFns = [mql, mqlLess, mqlCustom]\r\n .map((entry) =>\r\n bindMediaQueryListener(entry, () => {\r\n update();\r\n })\r\n )\r\n .filter((cleanup): cleanup is () => void => cleanup !== undefined);\r\n\r\n if (cleanupFns.length > 0) {\r\n destroy = (): void => {\r\n for (const cleanup of cleanupFns) {\r\n cleanup();\r\n }\r\n s.dispose();\r\n };\r\n }\r\n } catch {\r\n // matchMedia may throw in non-browser environments\r\n }\r\n }\r\n\r\n return withDestroy(readonly(s), destroy);\r\n};\r\n","/**\r\n * Roving tab index utility for arrow-key navigation within groups.\r\n *\r\n * Implements the WAI-ARIA roving tabindex pattern: only one item\r\n * in the group has tabindex=\"0\" (the active item), while all others\r\n * have tabindex=\"-1\". Arrow keys move focus between items.\r\n *\r\n * @module bquery/a11y\r\n */\r\n\r\nimport type { RovingTabIndexHandle, RovingTabIndexOptions } from './types';\r\n\r\n/**\r\n * Sets up roving tab index navigation for a group of elements.\r\n *\r\n * Only the active item receives `tabindex=\"0\"`, making it the only\r\n * tabbable element in the group. Arrow keys move focus between items,\r\n * and Home/End jump to the first/last item.\r\n *\r\n * @param container - The parent element containing the navigable items\r\n * @param itemSelector - CSS selector for the navigable items within the container\r\n * @param options - Configuration options\r\n * @returns A handle with `destroy()`, `focusItem()`, and `activeIndex()`\r\n *\r\n * @example\r\n * ```ts\r\n * import { rovingTabIndex } from '@bquery/bquery/a11y';\r\n *\r\n * const toolbar = document.querySelector('[role=\"toolbar\"]');\r\n * const handle = rovingTabIndex(toolbar, 'button', {\r\n * orientation: 'horizontal',\r\n * wrap: true,\r\n * });\r\n *\r\n * // Later, clean up\r\n * handle.destroy();\r\n * ```\r\n */\r\nexport const rovingTabIndex = (\r\n container: HTMLElement,\r\n itemSelector: string,\r\n options: RovingTabIndexOptions = {}\r\n): RovingTabIndexHandle => {\r\n const { wrap = true, orientation = 'vertical', onActivate } = options;\r\n\r\n let currentIndex = 0;\r\n const originalTabIndexes = new Map<HTMLElement, string | null>();\r\n\r\n const getItems = (): HTMLElement[] => {\r\n return Array.from(container.querySelectorAll(itemSelector)) as HTMLElement[];\r\n };\r\n\r\n const trackItems = (items: HTMLElement[]): void => {\r\n for (const item of items) {\r\n if (!originalTabIndexes.has(item)) {\r\n originalTabIndexes.set(item, item.getAttribute('tabindex'));\r\n }\r\n }\r\n };\r\n\r\n const setActiveItem = (index: number): void => {\r\n const items = getItems();\r\n if (items.length === 0) return;\r\n trackItems(items);\r\n\r\n // Clamp index\r\n const clampedIndex = Math.max(0, Math.min(index, items.length - 1));\r\n\r\n // Update tabindex on all items\r\n for (let i = 0; i < items.length; i++) {\r\n items[i].setAttribute('tabindex', i === clampedIndex ? '0' : '-1');\r\n }\r\n\r\n currentIndex = clampedIndex;\r\n items[clampedIndex].focus();\r\n onActivate?.(items[clampedIndex], clampedIndex);\r\n };\r\n\r\n const isRelevantKey = (key: string): boolean => {\r\n if (key === 'Home' || key === 'End') return true;\r\n\r\n switch (orientation) {\r\n case 'horizontal':\r\n return key === 'ArrowLeft' || key === 'ArrowRight';\r\n case 'vertical':\r\n return key === 'ArrowUp' || key === 'ArrowDown';\r\n case 'both':\r\n return (\r\n key === 'ArrowLeft' || key === 'ArrowRight' || key === 'ArrowUp' || key === 'ArrowDown'\r\n );\r\n default:\r\n return false;\r\n }\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent): void => {\r\n if (!isRelevantKey(event.key)) return;\r\n\r\n const items = getItems();\r\n if (items.length === 0) return;\r\n\r\n event.preventDefault();\r\n\r\n let nextIndex = currentIndex;\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n case 'ArrowRight':\r\n nextIndex = currentIndex + 1;\r\n if (nextIndex >= items.length) {\r\n nextIndex = wrap ? 0 : items.length - 1;\r\n }\r\n break;\r\n\r\n case 'ArrowUp':\r\n case 'ArrowLeft':\r\n nextIndex = currentIndex - 1;\r\n if (nextIndex < 0) {\r\n nextIndex = wrap ? items.length - 1 : 0;\r\n }\r\n break;\r\n\r\n case 'Home':\r\n nextIndex = 0;\r\n break;\r\n\r\n case 'End':\r\n nextIndex = items.length - 1;\r\n break;\r\n }\r\n\r\n setActiveItem(nextIndex);\r\n };\r\n\r\n // Initialize: set tabindex on all items\r\n const items = getItems();\r\n trackItems(items);\r\n for (let i = 0; i < items.length; i++) {\r\n items[i].setAttribute('tabindex', i === 0 ? '0' : '-1');\r\n }\r\n\r\n container.addEventListener('keydown', handleKeyDown);\r\n\r\n return {\r\n destroy: () => {\r\n container.removeEventListener('keydown', handleKeyDown);\r\n // Restore original tabindex values\r\n for (const [item, originalTabIndex] of originalTabIndexes) {\r\n if (originalTabIndex === null) {\r\n item.removeAttribute('tabindex');\r\n } else {\r\n item.setAttribute('tabindex', originalTabIndex);\r\n }\r\n }\r\n originalTabIndexes.clear();\r\n },\r\n\r\n focusItem: (index: number) => {\r\n setActiveItem(index);\r\n },\r\n\r\n activeIndex: () => currentIndex,\r\n };\r\n};\r\n","/**\r\n * Auto-generated skip navigation link utility.\r\n *\r\n * Creates a visually-hidden (but keyboard-focusable) \"Skip to content\"\r\n * link that becomes visible on focus, letting keyboard users bypass\r\n * repeated navigation.\r\n *\r\n * @module bquery/a11y\r\n */\r\n\r\nimport type { SkipLinkHandle, SkipLinkOptions } from './types';\r\n\r\n/** Default CSS for the skip link — visually hidden until focused. */\r\nconst DEFAULT_STYLES = `\r\n position: absolute;\r\n top: -9999px;\r\n left: -9999px;\r\n z-index: 999999;\r\n padding: 0.5em 1em;\r\n background: #000;\r\n color: #fff;\r\n font-size: 1rem;\r\n text-decoration: none;\r\n border-radius: 0 0 4px 0;\r\n outline: 2px solid #4A90D9;\r\n outline-offset: 2px;\r\n`;\r\n\r\nconst FOCUSED_STYLES = `\r\n top: 0;\r\n left: 0;\r\n`;\r\n\r\nlet skipTargetIdCounter = 0;\r\nconst generatedSkipTargetRefs = new Map<string, { count: number; target: HTMLElement }>();\r\n\r\nconst hasSkipLinkEnvironment = (): boolean => {\r\n if (typeof document === 'undefined') {\r\n return false;\r\n }\r\n\r\n return (\r\n typeof document.createElement === 'function' &&\r\n typeof document.querySelector === 'function' &&\r\n typeof document.getElementById === 'function' &&\r\n document.body !== null &&\r\n document.body !== undefined\r\n );\r\n};\r\n\r\nconst createNoopSkipLinkHandle = (): SkipLinkHandle => ({\r\n destroy: () => {},\r\n element: null,\r\n});\r\n\r\n/**\r\n * Creates a skip navigation link that jumps to the specified target.\r\n *\r\n * The link is visually hidden by default and becomes visible when\r\n * it receives keyboard focus. This follows the WCAG 2.4.1 \"Bypass Blocks\"\r\n * success criterion.\r\n *\r\n * @param targetSelector - CSS selector for the main content area (e.g. `'#main'`, `'main'`)\r\n * @param options - Configuration options\r\n * @returns A handle with `destroy()` method and reference to the created element\r\n *\r\n * @example\r\n * ```ts\r\n * import { skipLink } from '@bquery/bquery/a11y';\r\n *\r\n * // Creates a \"Skip to main content\" link pointing to <main>\r\n * const handle = skipLink('#main-content');\r\n *\r\n * // Custom text\r\n * const handle2 = skipLink('#content', { text: 'Jump to content' });\r\n *\r\n * // Remove when no longer needed\r\n * handle.destroy();\r\n * ```\r\n */\r\nexport const skipLink = (targetSelector: string, options: SkipLinkOptions = {}): SkipLinkHandle => {\r\n if (!hasSkipLinkEnvironment()) {\r\n return createNoopSkipLinkHandle();\r\n }\r\n\r\n const { text = 'Skip to main content', className = 'bq-skip-link' } = options;\r\n let trackedGeneratedTargetId: string | undefined;\r\n let trackedFocusTarget:\r\n | { target: HTMLElement; hadTabIndex: boolean; previousTabIndex: string | null }\r\n | undefined;\r\n const safeQuerySelector = (selector: string): HTMLElement | null => {\r\n try {\r\n return document.querySelector(selector) as HTMLElement | null;\r\n } catch {\r\n return null;\r\n }\r\n };\r\n const releaseTrackedGeneratedTargetId = (): void => {\r\n if (!trackedGeneratedTargetId) return;\r\n\r\n const entry = generatedSkipTargetRefs.get(trackedGeneratedTargetId);\r\n const remainingRefs = (entry?.count ?? 0) - 1;\r\n if (remainingRefs <= 0) {\r\n generatedSkipTargetRefs.delete(trackedGeneratedTargetId);\r\n if (entry?.target.isConnected && entry.target.id === trackedGeneratedTargetId) {\r\n entry.target.removeAttribute('id');\r\n }\r\n } else {\r\n generatedSkipTargetRefs.set(trackedGeneratedTargetId, {\r\n count: remainingRefs,\r\n target: entry!.target,\r\n });\r\n }\r\n\r\n trackedGeneratedTargetId = undefined;\r\n };\r\n const restoreTrackedFocusTarget = (): void => {\r\n if (!trackedFocusTarget) return;\r\n\r\n const { target, hadTabIndex, previousTabIndex } = trackedFocusTarget;\r\n if (target.isConnected) {\r\n if (hadTabIndex) {\r\n target.setAttribute('tabindex', previousTabIndex ?? '');\r\n } else {\r\n target.removeAttribute('tabindex');\r\n }\r\n }\r\n\r\n trackedFocusTarget = undefined;\r\n };\r\n const ensureTargetFocusable = (target: HTMLElement): void => {\r\n if (trackedFocusTarget?.target === target) {\r\n return;\r\n }\r\n\r\n restoreTrackedFocusTarget();\r\n\r\n if (target.hasAttribute('tabindex')) {\r\n trackedFocusTarget = {\r\n target,\r\n hadTabIndex: true,\r\n previousTabIndex: target.getAttribute('tabindex'),\r\n };\r\n return;\r\n }\r\n\r\n if (target.tabIndex !== -1) {\r\n return;\r\n }\r\n\r\n trackedFocusTarget = {\r\n target,\r\n hadTabIndex: false,\r\n previousTabIndex: null,\r\n };\r\n target.setAttribute('tabindex', '-1');\r\n };\r\n const trackGeneratedTargetId = (target: HTMLElement, id: string): void => {\r\n if (trackedGeneratedTargetId === id) return;\r\n releaseTrackedGeneratedTargetId();\r\n const entry = generatedSkipTargetRefs.get(id);\r\n generatedSkipTargetRefs.set(id, {\r\n count: (entry?.count ?? 0) + 1,\r\n target,\r\n });\r\n trackedGeneratedTargetId = id;\r\n };\r\n const resolveTarget = (): HTMLElement | null => {\r\n if (targetSelector.startsWith('#')) {\r\n const id = targetSelector.slice(1);\r\n const byId = id ? (document.getElementById(id) as HTMLElement | null) : null;\r\n if (byId) {\r\n return byId;\r\n }\r\n\r\n return safeQuerySelector(targetSelector);\r\n }\r\n\r\n const byId = document.getElementById(targetSelector) as HTMLElement | null;\r\n if (byId) {\r\n return byId;\r\n }\r\n\r\n return safeQuerySelector(targetSelector);\r\n };\r\n\r\n const ensureTargetId = (target: HTMLElement): string => {\r\n if (target.id) {\r\n const generatedTarget = generatedSkipTargetRefs.get(target.id);\r\n if (generatedTarget?.target === target) {\r\n trackGeneratedTargetId(target, target.id);\r\n }\r\n return target.id;\r\n }\r\n\r\n let generatedTargetId: string;\r\n do {\r\n skipTargetIdCounter += 1;\r\n generatedTargetId = `bq-skip-target-${skipTargetIdCounter}`;\r\n } while (document.getElementById(generatedTargetId) !== null);\r\n\r\n target.id = generatedTargetId;\r\n trackGeneratedTargetId(target, generatedTargetId);\r\n return generatedTargetId;\r\n };\r\n\r\n const link = document.createElement('a');\r\n const initialTarget = resolveTarget();\r\n link.href = targetSelector.startsWith('#')\r\n ? targetSelector\r\n : initialTarget\r\n ? `#${ensureTargetId(initialTarget)}`\r\n : `#${targetSelector}`;\r\n link.textContent = text;\r\n link.className = className;\r\n link.setAttribute('style', DEFAULT_STYLES);\r\n\r\n link.addEventListener('focus', () => {\r\n link.setAttribute('style', DEFAULT_STYLES + FOCUSED_STYLES);\r\n });\r\n\r\n link.addEventListener('blur', () => {\r\n link.setAttribute('style', DEFAULT_STYLES);\r\n });\r\n\r\n link.addEventListener('click', (e) => {\r\n e.preventDefault();\r\n\r\n const target = resolveTarget();\r\n if (!target) {\r\n return;\r\n }\r\n\r\n link.href = `#${ensureTargetId(target)}`;\r\n // Make the target focusable if it isn't already\r\n ensureTargetFocusable(target);\r\n target.focus();\r\n });\r\n\r\n // Insert as the first child of <body>\r\n if (document.body.firstChild) {\r\n document.body.insertBefore(link, document.body.firstChild);\r\n } else {\r\n document.body.appendChild(link);\r\n }\r\n\r\n return {\r\n destroy: () => {\r\n restoreTrackedFocusTarget();\r\n releaseTrackedGeneratedTargetId();\r\n link.remove();\r\n },\r\n element: link,\r\n };\r\n};\r\n","/**\r\n * Focus trapping utility for modals, dialogs, and popover content.\r\n *\r\n * Constrains keyboard focus within a container so that Tab and Shift+Tab\r\n * cycle only through the container's focusable elements.\r\n *\r\n * @module bquery/a11y\r\n */\r\n\r\nimport type { FocusTrapHandle, TrapFocusOptions } from './types';\r\n\r\n/** Selector for elements that can receive focus. */\r\nconst FOCUSABLE_SELECTOR = [\r\n 'a[href]',\r\n 'button:not([disabled])',\r\n 'input:not([disabled])',\r\n 'select:not([disabled])',\r\n 'textarea:not([disabled])',\r\n '[tabindex]:not([tabindex=\"-1\"])',\r\n '[contenteditable=\"true\"]',\r\n 'details > summary',\r\n 'audio[controls]',\r\n 'video[controls]',\r\n].join(', ');\r\n\r\n/**\r\n * Gets all focusable elements within a container.\r\n *\r\n * @param container - The container element\r\n * @returns Array of focusable elements\r\n * @internal\r\n */\r\nexport const getFocusableElements = (container: Element): HTMLElement[] => {\r\n const elements = Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)) as HTMLElement[];\r\n return elements.filter(\r\n (el) => !el.hasAttribute('disabled') && el.tabIndex !== -1 && el.getClientRects().length > 0\r\n );\r\n};\r\n\r\n/**\r\n * Resolves an element from a string selector or returns the element directly.\r\n * @internal\r\n */\r\nconst resolveElement = (\r\n target: HTMLElement | string | undefined,\r\n container: Element\r\n): HTMLElement | null => {\r\n if (!target) return null;\r\n if (typeof target === 'string') {\r\n return container.querySelector(target) as HTMLElement | null;\r\n }\r\n return target;\r\n};\r\n\r\n/**\r\n * Traps keyboard focus within a container element.\r\n *\r\n * When activated, Tab and Shift+Tab will cycle only through focusable\r\n * elements within the container. Useful for modals, dialogs, and\r\n * dropdown menus.\r\n *\r\n * @param container - The DOM element to trap focus within\r\n * @param options - Configuration options\r\n * @returns A handle with a `release()` method to deactivate the trap\r\n *\r\n * @example\r\n * ```ts\r\n * import { trapFocus } from '@bquery/bquery/a11y';\r\n *\r\n * const dialog = document.querySelector('#my-dialog');\r\n * const trap = trapFocus(dialog, { escapeDeactivates: true });\r\n *\r\n * // Later, release the trap\r\n * trap.release();\r\n * ```\r\n */\r\nexport const trapFocus = (\r\n container: HTMLElement,\r\n options: TrapFocusOptions = {}\r\n): FocusTrapHandle => {\r\n const { escapeDeactivates = true, onEscape, initialFocus, returnFocus } = options;\r\n\r\n if (\r\n typeof document === 'undefined' ||\r\n typeof document.addEventListener !== 'function' ||\r\n typeof document.removeEventListener !== 'function'\r\n ) {\r\n let active = false;\r\n return {\r\n get active() {\r\n return active;\r\n },\r\n release: () => {\r\n active = false;\r\n },\r\n };\r\n }\r\n\r\n const previouslyFocused = document.activeElement as HTMLElement | null;\r\n let active = true;\r\n\r\n const handleKeyDown = (event: KeyboardEvent): void => {\r\n if (!active) return;\r\n\r\n if (event.key === 'Escape' && escapeDeactivates) {\r\n event.preventDefault();\r\n handle.release();\r\n onEscape?.();\r\n return;\r\n }\r\n\r\n if (event.key !== 'Tab') return;\r\n\r\n const focusable = getFocusableElements(container);\r\n if (focusable.length === 0) {\r\n event.preventDefault();\r\n return;\r\n }\r\n\r\n const first = focusable[0];\r\n const last = focusable[focusable.length - 1];\r\n\r\n if (event.shiftKey) {\r\n // Shift+Tab: if at first element, wrap to last\r\n if (document.activeElement === first || !container.contains(document.activeElement)) {\r\n event.preventDefault();\r\n last.focus();\r\n }\r\n } else {\r\n // Tab: if at last element, wrap to first\r\n if (document.activeElement === last || !container.contains(document.activeElement)) {\r\n event.preventDefault();\r\n first.focus();\r\n }\r\n }\r\n };\r\n\r\n // Attach the event listener\r\n document.addEventListener('keydown', handleKeyDown, true);\r\n\r\n // Set initial focus\r\n const initialEl = resolveElement(initialFocus, container);\r\n if (initialEl) {\r\n initialEl.focus();\r\n } else {\r\n const focusable = getFocusableElements(container);\r\n if (focusable.length > 0) {\r\n focusable[0].focus();\r\n }\r\n }\r\n\r\n const handle: FocusTrapHandle = {\r\n get active() {\r\n return active;\r\n },\r\n\r\n release: () => {\r\n if (!active) return;\r\n active = false;\r\n document.removeEventListener('keydown', handleKeyDown, true);\r\n\r\n // Return focus\r\n const returnEl = resolveElement(returnFocus, document.body);\r\n if (returnEl) {\r\n returnEl.focus();\r\n } else if (previouslyFocused && previouslyFocused.focus) {\r\n previouslyFocused.focus();\r\n }\r\n },\r\n };\r\n\r\n return handle;\r\n};\r\n\r\n/**\r\n * Releases a focus trap handle.\r\n * This is a convenience function — in most cases, use the `release()`\r\n * method on the individual trap handle directly.\r\n *\r\n * @deprecated Prefer using the handle returned by `trapFocus()` directly.\r\n */\r\nexport const releaseFocus = (handle: FocusTrapHandle): void => {\r\n handle.release();\r\n};\r\n","/**\r\n * Make an element draggable using pointer events.\r\n *\r\n * Uses Pointer Events (not HTML5 Drag & Drop) for reliable\r\n * cross-platform behavior including touch support.\r\n *\r\n * @module bquery/dnd\r\n */\r\n\r\nimport type {\r\n BoundsRect,\r\n DragBounds,\r\n DragEventData,\r\n DragPosition,\r\n DraggableHandle,\r\n DraggableOptions,\r\n} from './types';\r\n\r\n/** Global registry of active draggable elements for drop zone detection. */\r\nconst activeDrags = new Map<HTMLElement, { element: HTMLElement; position: DragPosition }>();\r\n\r\n/**\r\n * Returns the currently active drag state, if any.\r\n * Used internally by `droppable()` to detect drag interactions.\r\n * @internal\r\n */\r\nexport const getActiveDrag = (): { element: HTMLElement; position: DragPosition } | undefined => {\r\n const entries = Array.from(activeDrags.values());\r\n return entries[entries.length - 1];\r\n};\r\n\r\n/**\r\n * Resolves a `DragBounds` value to an absolute `BoundsRect`.\r\n * @internal\r\n */\r\nconst resolveBounds = (el: HTMLElement, bounds: DragBounds): BoundsRect | null => {\r\n if (typeof bounds === 'object') {\r\n return bounds;\r\n }\r\n\r\n let target: HTMLElement | null = null;\r\n\r\n if (bounds === 'parent') {\r\n target = el.parentElement;\r\n } else {\r\n target = document.querySelector(bounds) as HTMLElement | null;\r\n }\r\n\r\n if (!target) return null;\r\n\r\n const rect = target.getBoundingClientRect();\r\n const elRect = el.getBoundingClientRect();\r\n const rawLeft = parseFloat(el.style.left || '0');\r\n const rawTop = parseFloat(el.style.top || '0');\r\n const leftOffset = Number.isNaN(rawLeft) ? 0 : rawLeft;\r\n const topOffset = Number.isNaN(rawTop) ? 0 : rawTop;\r\n\r\n return {\r\n left: rect.left - elRect.left + leftOffset,\r\n top: rect.top - elRect.top + topOffset,\r\n right: rect.right - elRect.right + leftOffset + (rect.width - elRect.width),\r\n bottom: rect.bottom - elRect.bottom + topOffset + (rect.height - elRect.height),\r\n };\r\n};\r\n\r\n/**\r\n * Clamp a position within bounds.\r\n * @internal\r\n */\r\nconst clampPosition = (pos: DragPosition, bounds: BoundsRect | null): DragPosition => {\r\n if (!bounds) return pos;\r\n return {\r\n x: Math.max(bounds.left, Math.min(bounds.right, pos.x)),\r\n y: Math.max(bounds.top, Math.min(bounds.bottom, pos.y)),\r\n };\r\n};\r\n\r\n/**\r\n * Makes an element draggable using pointer events.\r\n *\r\n * Features:\r\n * - Touch and mouse support via Pointer Events\r\n * - Axis locking (`x`, `y`, or `both`)\r\n * - Bounds constraint (parent, selector, or explicit rect)\r\n * - Optional drag handle\r\n * - Ghost/clone preview during drag\r\n * - Callbacks: `onDragStart`, `onDrag`, `onDragEnd`\r\n *\r\n * @param el - The element to make draggable\r\n * @param options - Configuration options\r\n * @returns A handle with `destroy()`, `disable()`, and `enable()` methods\r\n *\r\n * @example\r\n * ```ts\r\n * import { draggable } from '@bquery/bquery/dnd';\r\n *\r\n * const handle = draggable(document.querySelector('#box'), {\r\n * axis: 'both',\r\n * bounds: 'parent',\r\n * onDragEnd: ({ position }) => {\r\n * console.log('Dropped at', position.x, position.y);\r\n * },\r\n * });\r\n *\r\n * // Later:\r\n * handle.destroy();\r\n * ```\r\n */\r\nexport const draggable = (el: HTMLElement, options: DraggableOptions = {}): DraggableHandle => {\r\n const {\r\n axis = 'both',\r\n bounds,\r\n handle,\r\n ghost = false,\r\n ghostClass = 'bq-drag-ghost',\r\n draggingClass = 'bq-dragging',\r\n onDragStart,\r\n onDrag,\r\n onDragEnd,\r\n } = options;\r\n\r\n let enabled = !options.disabled;\r\n let isDragging = false;\r\n let startPointer: DragPosition = { x: 0, y: 0 };\r\n let currentPosition: DragPosition = { x: 0, y: 0 };\r\n let previousPosition: DragPosition = { x: 0, y: 0 };\r\n let ghostEl: HTMLElement | null = null;\r\n let ghostStartPosition: DragPosition | null = null;\r\n const previousTouchAction = el.style.touchAction;\r\n const previousUserSelect = el.style.userSelect;\r\n\r\n const createEventData = (event: PointerEvent): DragEventData => ({\r\n element: el,\r\n position: { ...currentPosition },\r\n delta: {\r\n x: currentPosition.x - previousPosition.x,\r\n y: currentPosition.y - previousPosition.y,\r\n },\r\n event,\r\n });\r\n\r\n const createGhost = (): HTMLElement => {\r\n const clone = el.cloneNode(true) as HTMLElement;\r\n const rect = el.getBoundingClientRect();\r\n clone.classList.add(ghostClass);\r\n clone.style.position = 'fixed';\r\n clone.style.left = `${rect.left}px`;\r\n clone.style.top = `${rect.top}px`;\r\n clone.style.width = `${rect.width}px`;\r\n clone.style.height = `${rect.height}px`;\r\n clone.style.pointerEvents = 'none';\r\n clone.style.zIndex = '999999';\r\n clone.style.opacity = '0.7';\r\n clone.style.margin = '0';\r\n document.body.appendChild(clone);\r\n return clone;\r\n };\r\n\r\n const removeGhost = (): void => {\r\n if (ghostEl) {\r\n ghostEl.remove();\r\n ghostEl = null;\r\n }\r\n ghostStartPosition = null;\r\n };\r\n\r\n const onPointerDown = (e: PointerEvent): void => {\r\n if (!enabled) return;\r\n\r\n // Check handle constraint\r\n if (handle) {\r\n const target = e.target as Element;\r\n if (!target.closest(handle)) return;\r\n }\r\n\r\n e.preventDefault();\r\n isDragging = true;\r\n startPointer = { x: e.clientX, y: e.clientY };\r\n previousPosition = { ...currentPosition };\r\n\r\n el.classList.add(draggingClass);\r\n el.setPointerCapture(e.pointerId);\r\n\r\n if (ghost) {\r\n const rect = el.getBoundingClientRect();\r\n ghostStartPosition = { x: rect.left, y: rect.top };\r\n ghostEl = createGhost();\r\n }\r\n\r\n // Register in global active drags\r\n activeDrags.set(el, { element: el, position: currentPosition });\r\n\r\n onDragStart?.(createEventData(e));\r\n };\r\n\r\n const onPointerMove = (e: PointerEvent): void => {\r\n if (!isDragging) return;\r\n\r\n e.preventDefault();\r\n previousPosition = { ...currentPosition };\r\n\r\n let newX = currentPosition.x + (e.clientX - startPointer.x);\r\n let newY = currentPosition.y + (e.clientY - startPointer.y);\r\n\r\n // Reset start pointer to current for delta calculation\r\n startPointer = { x: e.clientX, y: e.clientY };\r\n\r\n // Apply axis constraint\r\n if (axis === 'x') newY = currentPosition.y;\r\n if (axis === 'y') newX = currentPosition.x;\r\n\r\n let newPos: DragPosition = { x: newX, y: newY };\r\n\r\n // Apply bounds constraint\r\n if (bounds) {\r\n const resolvedBounds = resolveBounds(el, bounds);\r\n newPos = clampPosition(newPos, resolvedBounds);\r\n }\r\n\r\n currentPosition = newPos;\r\n\r\n // Update active drag position\r\n activeDrags.set(el, { element: el, position: currentPosition });\r\n\r\n // Apply the position\r\n if (ghost && ghostEl) {\r\n const start = ghostStartPosition ?? {\r\n x: el.getBoundingClientRect().left,\r\n y: el.getBoundingClientRect().top,\r\n };\r\n ghostEl.style.left = `${start.x + currentPosition.x}px`;\r\n ghostEl.style.top = `${start.y + currentPosition.y}px`;\r\n } else {\r\n el.style.transform = `translate(${currentPosition.x}px, ${currentPosition.y}px)`;\r\n }\r\n\r\n onDrag?.(createEventData(e));\r\n };\r\n\r\n const onPointerUp = (e: PointerEvent): void => {\r\n if (!isDragging) return;\r\n\r\n isDragging = false;\r\n el.classList.remove(draggingClass);\r\n try {\r\n if (\r\n typeof el.releasePointerCapture === 'function' &&\r\n (typeof el.hasPointerCapture !== 'function' || el.hasPointerCapture(e.pointerId))\r\n ) {\r\n el.releasePointerCapture(e.pointerId);\r\n }\r\n } catch {\r\n // Pointer capture may already be released in some interrupted drag flows.\r\n } finally {\r\n removeGhost();\r\n\r\n // Remove from active drags\r\n activeDrags.delete(el);\r\n\r\n onDragEnd?.(createEventData(e));\r\n }\r\n };\r\n\r\n // Attach listeners\r\n el.addEventListener('pointerdown', onPointerDown);\r\n el.addEventListener('pointermove', onPointerMove);\r\n el.addEventListener('pointerup', onPointerUp);\r\n el.addEventListener('pointercancel', onPointerUp);\r\n\r\n // Prevent default drag behavior\r\n el.style.touchAction = 'none';\r\n el.style.userSelect = 'none';\r\n\r\n return {\r\n destroy: () => {\r\n el.removeEventListener('pointerdown', onPointerDown);\r\n el.removeEventListener('pointermove', onPointerMove);\r\n el.removeEventListener('pointerup', onPointerUp);\r\n el.removeEventListener('pointercancel', onPointerUp);\r\n removeGhost();\r\n activeDrags.delete(el);\r\n el.style.touchAction = previousTouchAction;\r\n el.style.userSelect = previousUserSelect;\r\n el.classList.remove(draggingClass);\r\n },\r\n disable: () => {\r\n enabled = false;\r\n },\r\n enable: () => {\r\n enabled = true;\r\n },\r\n get enabled() {\r\n return enabled;\r\n },\r\n };\r\n};\r\n","/**\r\n * Define drop zones for draggable elements.\r\n *\r\n * Drop zones detect when draggable elements enter, move over,\r\n * leave, or are dropped onto them using pointer event hit-testing.\r\n *\r\n * @module bquery/dnd\r\n */\r\n\r\nimport { getActiveDrag } from './draggable';\r\nimport type { DropEventData, DroppableHandle, DroppableOptions } from './types';\r\n\r\ntype DroppableListener = {\r\n handlePointerMove: (event: PointerEvent) => void;\r\n handlePointerUp: (event: PointerEvent) => void;\r\n};\r\n\r\nconst passivePointerMoveListenerOptions = { passive: true } as const;\r\n\r\nconst droppableListeners = new Set<DroppableListener>();\r\nlet queuedPointerMove: PointerEvent | null = null;\r\nlet pointerMoveFrame: number | null = null;\r\n\r\nconst getDroppableListenersSnapshot = (): DroppableListener[] => Array.from(droppableListeners);\r\n\r\nconst hasDroppableEnvironment = (): boolean => {\r\n return (\r\n typeof document !== 'undefined' &&\r\n typeof document.addEventListener === 'function' &&\r\n typeof document.removeEventListener === 'function' &&\r\n typeof requestAnimationFrame === 'function' &&\r\n typeof cancelAnimationFrame === 'function'\r\n );\r\n};\r\n\r\nconst dispatchPointerMove = (event: PointerEvent): void => {\r\n for (const listener of getDroppableListenersSnapshot()) {\r\n listener.handlePointerMove(event);\r\n }\r\n};\r\n\r\nconst flushPointerMove = (): void => {\r\n pointerMoveFrame = null;\r\n const event = queuedPointerMove;\r\n queuedPointerMove = null;\r\n if (!event) return;\r\n dispatchPointerMove(event);\r\n};\r\n\r\nconst handleDocumentPointerMove = (event: PointerEvent): void => {\r\n queuedPointerMove = event;\r\n if (pointerMoveFrame === null) {\r\n pointerMoveFrame = requestAnimationFrame(flushPointerMove);\r\n }\r\n};\r\n\r\nconst handleDocumentPointerUp = (event: PointerEvent): void => {\r\n if (pointerMoveFrame !== null) {\r\n cancelAnimationFrame(pointerMoveFrame);\r\n pointerMoveFrame = null;\r\n queuedPointerMove = null;\r\n }\r\n\r\n for (const listener of getDroppableListenersSnapshot()) {\r\n listener.handlePointerUp(event);\r\n }\r\n};\r\n\r\nconst registerDroppableListener = (listener: DroppableListener): void => {\r\n if (droppableListeners.size === 0) {\r\n document.addEventListener(\r\n 'pointermove',\r\n handleDocumentPointerMove,\r\n passivePointerMoveListenerOptions\r\n );\r\n document.addEventListener('pointerup', handleDocumentPointerUp);\r\n }\r\n\r\n droppableListeners.add(listener);\r\n};\r\n\r\nconst unregisterDroppableListener = (listener: DroppableListener): void => {\r\n droppableListeners.delete(listener);\r\n\r\n if (droppableListeners.size !== 0) return;\r\n\r\n document.removeEventListener('pointermove', handleDocumentPointerMove);\r\n document.removeEventListener('pointerup', handleDocumentPointerUp);\r\n if (pointerMoveFrame !== null) {\r\n cancelAnimationFrame(pointerMoveFrame);\r\n pointerMoveFrame = null;\r\n }\r\n queuedPointerMove = null;\r\n};\r\n\r\n/**\r\n * Checks whether a dragged element is accepted by the drop zone.\r\n * @internal\r\n */\r\nconst isAccepted = (dragged: HTMLElement, accept: DroppableOptions['accept']): boolean => {\r\n if (!accept) return true;\r\n if (typeof accept === 'string') return dragged.matches(accept);\r\n return accept(dragged);\r\n};\r\n\r\n/**\r\n * Defines an element as a drop zone.\r\n *\r\n * Drop zones respond to draggable elements being moved over them\r\n * by firing callbacks and applying CSS classes. They work with\r\n * the `draggable()` function from this module.\r\n *\r\n * @param el - The drop zone element\r\n * @param options - Configuration options\r\n * @returns A handle with a `destroy()` method\r\n *\r\n * @example\r\n * ```ts\r\n * import { droppable } from '@bquery/bquery/dnd';\r\n *\r\n * const handle = droppable(document.querySelector('#dropzone'), {\r\n * accept: '.draggable-item',\r\n * overClass: 'drop-active',\r\n * onDrop: ({ dragged }) => {\r\n * console.log('Dropped:', dragged);\r\n * },\r\n * });\r\n *\r\n * // Later:\r\n * handle.destroy();\r\n * ```\r\n */\r\nexport const droppable = (el: HTMLElement, options: DroppableOptions = {}): DroppableHandle => {\r\n const {\r\n overClass = 'bq-drop-over',\r\n accept,\r\n onDragEnter,\r\n onDragOver,\r\n onDragLeave,\r\n onDrop,\r\n } = options;\r\n\r\n if (!hasDroppableEnvironment()) {\r\n return {\r\n destroy: () => {},\r\n };\r\n }\r\n\r\n let isOver = false;\r\n let currentDragged: HTMLElement | null = null;\r\n\r\n const createEventData = (dragged: HTMLElement, event: PointerEvent): DropEventData => ({\r\n zone: el,\r\n dragged,\r\n event,\r\n });\r\n\r\n const isPointerInside = (event: PointerEvent): boolean => {\r\n const rect = el.getBoundingClientRect();\r\n return (\r\n event.clientX >= rect.left &&\r\n event.clientX <= rect.right &&\r\n event.clientY >= rect.top &&\r\n event.clientY <= rect.bottom\r\n );\r\n };\r\n\r\n const resolveDraggedElement = (): HTMLElement | null => {\r\n return getActiveDrag()?.element ?? currentDragged;\r\n };\r\n\r\n const clearOverState = (event: PointerEvent, dragged = currentDragged): void => {\r\n if (!isOver) return;\r\n isOver = false;\r\n el.classList.remove(overClass);\r\n if (dragged) {\r\n onDragLeave?.(createEventData(dragged, event));\r\n }\r\n currentDragged = null;\r\n };\r\n\r\n const handlePointerMove = (e: PointerEvent): void => {\r\n const dragged = getActiveDrag()?.element ?? null;\r\n const isInside = isPointerInside(e);\r\n const acceptsDragged = dragged !== null && dragged !== el && isAccepted(dragged, accept);\r\n\r\n if (!acceptsDragged || !isInside) {\r\n clearOverState(e, dragged ?? currentDragged);\r\n return;\r\n }\r\n\r\n if (!isOver) {\r\n isOver = true;\r\n currentDragged = dragged;\r\n el.classList.add(overClass);\r\n onDragEnter?.(createEventData(dragged, e));\r\n } else {\r\n onDragOver?.(createEventData(dragged, e));\r\n }\r\n };\r\n\r\n const handlePointerUp = (e: PointerEvent): void => {\r\n const dragged = resolveDraggedElement();\r\n const isInside = isPointerInside(e);\r\n const acceptsDragged = dragged !== null && dragged !== el && isAccepted(dragged, accept);\r\n\r\n if (isInside && acceptsDragged && dragged) {\r\n onDrop?.(createEventData(dragged, e));\r\n }\r\n\r\n if (isOver) {\r\n isOver = false;\r\n el.classList.remove(overClass);\r\n }\r\n currentDragged = null;\r\n };\r\n\r\n const listener: DroppableListener = { handlePointerMove, handlePointerUp };\r\n registerDroppableListener(listener);\r\n\r\n return {\r\n destroy: () => {\r\n unregisterDroppableListener(listener);\r\n el.classList.remove(overClass);\r\n currentDragged = null;\r\n },\r\n };\r\n};\r\n","/**\r\n * Sortable list with animated reordering via pointer events.\r\n *\r\n * Makes children of a container sortable by dragging. Items are\r\n * rearranged in the DOM with optional CSS animation.\r\n *\r\n * @module bquery/dnd\r\n */\r\n\r\nimport type { SortEventData, SortableHandle, SortableOptions } from './types';\r\n\r\n/**\r\n * Gets the sortable items within a container.\r\n * @internal\r\n */\r\nconst getItems = (container: HTMLElement, selector: string): HTMLElement[] => {\r\n return Array.from(container.querySelectorAll(selector)) as HTMLElement[];\r\n};\r\n\r\n/**\r\n * Finds the closest sortable item to a given Y (or X) position.\r\n * @internal\r\n */\r\nconst getClosestItem = (\r\n items: HTMLElement[],\r\n clientPos: number,\r\n axis: 'x' | 'y',\r\n dragged: HTMLElement\r\n): { element: HTMLElement; index: number } | null => {\r\n let closest: { element: HTMLElement; index: number; distance: number } | null = null;\r\n\r\n for (let i = 0; i < items.length; i++) {\r\n const item = items[i];\r\n if (item === dragged) continue;\r\n\r\n const rect = item.getBoundingClientRect();\r\n const mid = axis === 'y' ? rect.top + rect.height / 2 : rect.left + rect.width / 2;\r\n const distance = clientPos - mid;\r\n\r\n if (\r\n closest === null ||\r\n (distance < 0 && distance > closest.distance) ||\r\n (closest.distance >= 0 && distance < 0 && Math.abs(distance) < Math.abs(closest.distance))\r\n ) {\r\n // Find the item we're just before\r\n if (distance < 0) {\r\n closest = { element: item, index: i, distance };\r\n }\r\n }\r\n }\r\n\r\n return closest ? { element: closest.element, index: closest.index } : null;\r\n};\r\n\r\n/**\r\n * Makes the children of a container sortable by dragging.\r\n *\r\n * Features:\r\n * - Pointer event based (touch + mouse)\r\n * - Animated reordering with configurable duration\r\n * - Axis constraint (vertical or horizontal)\r\n * - Optional drag handle\r\n * - Placeholder element during sort\r\n * - Callbacks: `onSortStart`, `onSortMove`, `onSortEnd`\r\n *\r\n * @param container - The container element whose children will be sortable\r\n * @param options - Configuration options\r\n * @returns A handle with `destroy()`, `disable()`, and `enable()` methods\r\n *\r\n * @example\r\n * ```ts\r\n * import { sortable } from '@bquery/bquery/dnd';\r\n *\r\n * const handle = sortable(document.querySelector('#list'), {\r\n * items: 'li',\r\n * axis: 'y',\r\n * animationDuration: 200,\r\n * onSortEnd: ({ oldIndex, newIndex }) => {\r\n * console.log(`Moved from ${oldIndex} to ${newIndex}`);\r\n * },\r\n * });\r\n *\r\n * // Later:\r\n * handle.destroy();\r\n * ```\r\n */\r\nexport const sortable = (container: HTMLElement, options: SortableOptions = {}): SortableHandle => {\r\n const {\r\n items: itemSelector = ':scope > *',\r\n axis = 'y',\r\n handle,\r\n placeholderClass = 'bq-sort-placeholder',\r\n sortingClass = 'bq-sorting',\r\n animationDuration = 200,\r\n onSortStart,\r\n onSortMove,\r\n onSortEnd,\r\n } = options;\r\n\r\n let enabled = !options.disabled;\r\n let isDragging = false;\r\n let dragItem: HTMLElement | null = null;\r\n let placeholder: HTMLElement | null = null;\r\n let startIndex = -1;\r\n let startPointerY = 0;\r\n let startPointerX = 0;\r\n let itemStartTop = 0;\r\n let itemStartLeft = 0;\r\n\r\n const createEventData = (item: HTMLElement, oldIdx: number, newIdx: number): SortEventData => ({\r\n container,\r\n item,\r\n oldIndex: oldIdx,\r\n newIndex: newIdx,\r\n });\r\n\r\n const onPointerDown = (e: PointerEvent): void => {\r\n if (!enabled) return;\r\n\r\n const target = e.target as HTMLElement;\r\n\r\n // Find the item being dragged\r\n const items = getItems(container, itemSelector);\r\n let item: HTMLElement | null = null;\r\n\r\n for (const it of items) {\r\n if (it.contains(target)) {\r\n item = it;\r\n break;\r\n }\r\n }\r\n\r\n if (!item) return;\r\n\r\n // Check handle constraint\r\n if (handle && !target.closest(handle)) return;\r\n\r\n e.preventDefault();\r\n\r\n isDragging = true;\r\n dragItem = item;\r\n startIndex = items.indexOf(item);\r\n startPointerY = e.clientY;\r\n startPointerX = e.clientX;\r\n\r\n const rect = item.getBoundingClientRect();\r\n itemStartTop = rect.top;\r\n itemStartLeft = rect.left;\r\n\r\n // Create placeholder\r\n placeholder = document.createElement('div');\r\n placeholder.classList.add(placeholderClass);\r\n placeholder.style.width = `${rect.width}px`;\r\n placeholder.style.height = `${rect.height}px`;\r\n placeholder.style.boxSizing = 'border-box';\r\n\r\n // Style the dragged item\r\n item.classList.add(sortingClass);\r\n item.style.position = 'fixed';\r\n item.style.width = `${rect.width}px`;\r\n item.style.height = `${rect.height}px`;\r\n item.style.left = `${rect.left}px`;\r\n item.style.top = `${rect.top}px`;\r\n item.style.zIndex = '999999';\r\n item.style.pointerEvents = 'none';\r\n item.style.margin = '0';\r\n\r\n // Insert placeholder where the item was\r\n item.parentNode?.insertBefore(placeholder, item);\r\n\r\n container.setPointerCapture(e.pointerId);\r\n\r\n onSortStart?.(createEventData(item, startIndex, startIndex));\r\n };\r\n\r\n const onPointerMove = (e: PointerEvent): void => {\r\n if (!isDragging || !dragItem || !placeholder) return;\r\n\r\n e.preventDefault();\r\n\r\n const deltaX = e.clientX - startPointerX;\r\n const deltaY = e.clientY - startPointerY;\r\n\r\n // Move the dragged item\r\n if (axis === 'y') {\r\n dragItem.style.top = `${itemStartTop + deltaY}px`;\r\n } else {\r\n dragItem.style.left = `${itemStartLeft + deltaX}px`;\r\n }\r\n\r\n // Find the closest item to determine insertion point\r\n const items = getItems(container, itemSelector);\r\n const clientPos = axis === 'y' ? e.clientY : e.clientX;\r\n const closest = getClosestItem(items, clientPos, axis, dragItem);\r\n\r\n if (closest) {\r\n // Move placeholder before the closest element\r\n container.insertBefore(placeholder, closest.element);\r\n } else {\r\n // Append to end\r\n container.appendChild(placeholder);\r\n }\r\n\r\n const currentIndex = Array.from(container.children).indexOf(placeholder);\r\n onSortMove?.(createEventData(dragItem, startIndex, currentIndex));\r\n };\r\n\r\n const onPointerUp = (e: PointerEvent): void => {\r\n if (!isDragging || !dragItem || !placeholder) return;\r\n\r\n isDragging = false;\r\n const draggedItem = dragItem;\r\n\r\n // Get final index\r\n const newIndex = Array.from(container.children).indexOf(placeholder);\r\n\r\n // Animate the item back to the placeholder position\r\n const placeholderRect = placeholder.getBoundingClientRect();\r\n const itemRect = draggedItem.getBoundingClientRect();\r\n\r\n if (animationDuration > 0) {\r\n const deltaX = placeholderRect.left - itemRect.left;\r\n const deltaY = placeholderRect.top - itemRect.top;\r\n\r\n draggedItem.style.transition = `transform ${animationDuration}ms ease`;\r\n draggedItem.style.transform = `translate(${deltaX}px, ${deltaY}px)`;\r\n\r\n let finalized = false;\r\n let timeoutId: number | null = null;\r\n const finalize = (): void => {\r\n if (finalized) return;\r\n finalized = true;\r\n if (timeoutId !== null) {\r\n window.clearTimeout(timeoutId);\r\n timeoutId = null;\r\n }\r\n resetDragItem();\r\n onSortEnd?.(createEventData(draggedItem, startIndex, newIndex));\r\n };\r\n timeoutId = window.setTimeout(() => {\r\n finalize();\r\n }, animationDuration + 50);\r\n\r\n draggedItem.addEventListener('transitionend', finalize, { once: true });\r\n } else {\r\n resetDragItem();\r\n onSortEnd?.(createEventData(draggedItem, startIndex, newIndex));\r\n }\r\n\r\n container.releasePointerCapture(e.pointerId);\r\n };\r\n\r\n const resetDragItem = (): void => {\r\n if (!dragItem || !placeholder) return;\r\n\r\n // Insert the real item where the placeholder is\r\n placeholder.parentNode?.insertBefore(dragItem, placeholder);\r\n placeholder.remove();\r\n placeholder = null;\r\n\r\n // Reset styles\r\n dragItem.classList.remove(sortingClass);\r\n dragItem.style.position = '';\r\n dragItem.style.width = '';\r\n dragItem.style.height = '';\r\n dragItem.style.left = '';\r\n dragItem.style.top = '';\r\n dragItem.style.zIndex = '';\r\n dragItem.style.pointerEvents = '';\r\n dragItem.style.margin = '';\r\n dragItem.style.transition = '';\r\n dragItem.style.transform = '';\r\n\r\n dragItem = null;\r\n };\r\n\r\n container.addEventListener('pointerdown', onPointerDown);\r\n container.addEventListener('pointermove', onPointerMove);\r\n container.addEventListener('pointerup', onPointerUp);\r\n container.addEventListener('pointercancel', onPointerUp);\r\n\r\n // Prevent default touch behavior on container\r\n container.style.touchAction = 'none';\r\n\r\n return {\r\n destroy: () => {\r\n container.removeEventListener('pointerdown', onPointerDown);\r\n container.removeEventListener('pointermove', onPointerMove);\r\n container.removeEventListener('pointerup', onPointerUp);\r\n container.removeEventListener('pointercancel', onPointerUp);\r\n container.style.touchAction = '';\r\n\r\n if (isDragging) {\r\n resetDragItem();\r\n }\r\n },\r\n disable: () => {\r\n enabled = false;\r\n },\r\n enable: () => {\r\n enabled = true;\r\n },\r\n get enabled() {\r\n return enabled;\r\n },\r\n };\r\n};\r\n","/**\r\n * Reactive media query matching.\r\n *\r\n * Returns a reactive boolean signal that tracks whether a CSS media query matches.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport { readonly, signal } from '../reactive/index';\r\nimport type { MediaSignalHandle } from './types';\r\n\r\n/**\r\n * Creates a reactive signal that tracks whether a CSS media query matches.\r\n *\r\n * Uses `window.matchMedia()` under the hood and automatically updates\r\n * when the match state changes (e.g., on window resize, device orientation change).\r\n *\r\n * @param query - A valid CSS media query string (e.g., `'(min-width: 768px)'`)\r\n * @returns A readonly reactive signal that is `true` when the query matches,\r\n * plus a `destroy()` method to remove the media query listener\r\n *\r\n * @example\r\n * ```ts\r\n * import { mediaQuery } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const isDark = mediaQuery('(prefers-color-scheme: dark)');\r\n * effect(() => {\r\n * document.body.classList.toggle('dark', isDark.value);\r\n * });\r\n *\r\n * const isWide = mediaQuery('(min-width: 1024px)');\r\n * effect(() => {\r\n * console.log('Wide screen:', isWide.value);\r\n * });\r\n * ```\r\n */\r\nexport const mediaQuery = (query: string): MediaSignalHandle<boolean> => {\r\n const s = signal(false);\r\n let cleanup: (() => void) | undefined;\r\n\r\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\r\n try {\r\n const mql = window.matchMedia(query);\r\n s.value = mql.matches;\r\n\r\n const handler = (e: MediaQueryListEvent): void => {\r\n s.value = e.matches;\r\n };\r\n\r\n if (typeof mql.addEventListener === 'function') {\r\n mql.addEventListener('change', handler);\r\n cleanup = () => {\r\n mql.removeEventListener('change', handler);\r\n };\r\n } else if (\r\n typeof (\r\n mql as MediaQueryList & {\r\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\r\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\r\n }\r\n ).addListener === 'function'\r\n ) {\r\n const legacyMql = mql as MediaQueryList & {\r\n addListener: (listener: (event: MediaQueryListEvent) => void) => void;\r\n removeListener: (listener: (event: MediaQueryListEvent) => void) => void;\r\n };\r\n legacyMql.addListener(handler);\r\n cleanup = () => {\r\n legacyMql.removeListener(handler);\r\n };\r\n }\r\n } catch {\r\n // matchMedia may throw in non-browser environments\r\n }\r\n }\r\n\r\n const ro = readonly(s) as MediaSignalHandle<boolean>;\r\n let destroyed = false;\r\n Object.defineProperty(ro, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n cleanup?.();\r\n s.dispose();\r\n },\r\n });\r\n\r\n return ro;\r\n};\r\n","/**\r\n * Named breakpoint signals.\r\n *\r\n * Defines named breakpoints that return reactive boolean signals,\r\n * making it easy to respond to viewport size changes.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport { readonly, signal } from '../reactive/index';\r\nimport type { BreakpointMap, MediaSignalHandle } from './types';\r\n\r\ntype BreakpointSignals<T extends BreakpointMap> = { [K in keyof T]: MediaSignalHandle<boolean> } & {\r\n destroyAll(): void;\r\n} & ('destroy' extends keyof T ? Record<never, never> : { destroy(): void });\r\n\r\n/**\r\n * Defines named breakpoints and returns reactive boolean signals for each.\r\n *\r\n * Each breakpoint is a minimum-width media query. The returned object maps\r\n * each breakpoint name to a `ReadonlySignal<boolean>` that is `true` when\r\n * the viewport width is at or above the breakpoint value.\r\n *\r\n * @param bp - An object mapping breakpoint names to minimum widths in pixels\r\n * @returns An object with the same keys, each a reactive boolean signal with\r\n * `destroy()`, plus a top-level `destroyAll()` method to clean up all listeners.\r\n * When no breakpoint is named `destroy`, a `destroy()` alias is also provided.\r\n *\r\n * @example\r\n * ```ts\r\n * import { breakpoints } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const bp = breakpoints({ sm: 640, md: 768, lg: 1024, xl: 1280 });\r\n *\r\n * effect(() => {\r\n * if (bp.xl.value) {\r\n * console.log('Extra large viewport');\r\n * } else if (bp.lg.value) {\r\n * console.log('Large viewport');\r\n * } else if (bp.md.value) {\r\n * console.log('Medium viewport');\r\n * } else {\r\n * console.log('Small viewport');\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const breakpoints = <T extends BreakpointMap>(\r\n bp: T\r\n): BreakpointSignals<T> => {\r\n const signals = {} as { [K in keyof T]: MediaSignalHandle<boolean> };\r\n const destroyers: Array<() => void> = [];\r\n\r\n type LegacyMediaQueryList = MediaQueryList & {\r\n addListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\r\n removeListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\r\n };\r\n\r\n for (const key of Object.keys(bp) as Array<keyof T>) {\r\n const width = bp[key];\r\n const s = signal(false);\r\n let cleanup: (() => void) | undefined;\r\n\r\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\r\n try {\r\n const mql = window.matchMedia(`(min-width: ${width}px)`);\r\n s.value = mql.matches;\r\n\r\n const handler = (e: MediaQueryListEvent | MediaQueryList): void => {\r\n s.value = e.matches;\r\n };\r\n\r\n if (typeof mql.addEventListener === 'function') {\r\n mql.addEventListener('change', handler);\r\n cleanup = () => {\r\n mql.removeEventListener('change', handler);\r\n };\r\n } else {\r\n const legacyMql = mql as LegacyMediaQueryList;\r\n if (typeof legacyMql.addListener === 'function') {\r\n legacyMql.addListener(handler);\r\n cleanup = () => {\r\n legacyMql.removeListener?.(handler);\r\n };\r\n }\r\n }\r\n } catch {\r\n // matchMedia may throw in non-browser environments\r\n }\r\n }\r\n\r\n const ro = readonly(s) as MediaSignalHandle<boolean>;\r\n let destroyed = false;\r\n Object.defineProperty(ro, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n cleanup?.();\r\n s.dispose();\r\n },\r\n });\r\n destroyers.push(ro.destroy);\r\n signals[key] = ro;\r\n }\r\n\r\n let destroyed = false;\r\n const result = Object.defineProperty(signals, 'destroyAll', {\r\n enumerable: false,\r\n configurable: true,\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n destroyers.forEach((destroy) => {\r\n destroy();\r\n });\r\n },\r\n }) as BreakpointSignals<T>;\r\n\r\n if (!Object.prototype.hasOwnProperty.call(signals, 'destroy')) {\r\n Object.defineProperty(result, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value: result.destroyAll,\r\n });\r\n }\r\n\r\n return result;\r\n};\r\n","/**\r\n * Reactive viewport dimensions.\r\n *\r\n * Provides a reactive signal tracking the browser viewport's\r\n * width, height, and orientation.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport { readonly, signal } from '../reactive/index';\r\nimport type { ViewportSignal, ViewportState } from './types';\r\n\r\n/**\r\n * Computes orientation from width and height.\r\n * @internal\r\n */\r\nconst getOrientation = (w: number, h: number): 'portrait' | 'landscape' =>\r\n h >= w ? 'portrait' : 'landscape';\r\n\r\n/**\r\n * Returns a reactive signal tracking the current viewport dimensions and orientation.\r\n *\r\n * Updates automatically when the window is resized. Uses `window.innerWidth`\r\n * and `window.innerHeight` under the hood.\r\n *\r\n * @returns A readonly reactive signal with `{ width, height, orientation }`\r\n * and a `destroy()` method to remove the resize listener\r\n *\r\n * @example\r\n * ```ts\r\n * import { useViewport } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const viewport = useViewport();\r\n * effect(() => {\r\n * console.log(`Viewport: ${viewport.value.width}x${viewport.value.height}`);\r\n * console.log(`Orientation: ${viewport.value.orientation}`);\r\n * });\r\n * ```\r\n */\r\nexport const useViewport = (): ViewportSignal => {\r\n const initial: ViewportState = {\r\n width: typeof window !== 'undefined' ? window.innerWidth : 0,\r\n height: typeof window !== 'undefined' ? window.innerHeight : 0,\r\n orientation:\r\n typeof window !== 'undefined'\r\n ? getOrientation(window.innerWidth, window.innerHeight)\r\n : 'portrait',\r\n };\r\n\r\n const s = signal<ViewportState>(initial);\r\n\r\n let cleanup: (() => void) | undefined;\r\n\r\n if (typeof window !== 'undefined') {\r\n const handler = (): void => {\r\n s.value = {\r\n width: window.innerWidth,\r\n height: window.innerHeight,\r\n orientation: getOrientation(window.innerWidth, window.innerHeight),\r\n };\r\n };\r\n\r\n window.addEventListener('resize', handler);\r\n cleanup = () => {\r\n window.removeEventListener('resize', handler);\r\n };\r\n }\r\n\r\n const ro = readonly(s) as ViewportSignal;\r\n let destroyed = false;\r\n Object.defineProperty(ro, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value: (): void => {\r\n if (destroyed) return;\r\n destroyed = true;\r\n cleanup?.();\r\n s.dispose();\r\n },\r\n });\r\n\r\n return ro;\r\n};\r\n","/**\r\n * Reactive network status.\r\n *\r\n * Provides a reactive signal tracking the browser's network connectivity\r\n * and connection quality via the Network Information API.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport { readonly, signal } from '../reactive/index';\r\nimport type { NetworkSignal, NetworkState } from './types';\r\n\r\n/**\r\n * Navigator connection interface for the Network Information API.\r\n * @internal\r\n */\r\ninterface NavigatorConnection extends EventTarget {\r\n effectiveType?: string;\r\n downlink?: number;\r\n rtt?: number;\r\n}\r\n\r\n/**\r\n * Extended Navigator with connection property.\r\n * @internal\r\n */\r\ninterface NavigatorWithConnection extends Navigator {\r\n connection?: NavigatorConnection;\r\n}\r\n\r\n/**\r\n * Reads current network state from browser APIs.\r\n * @internal\r\n */\r\nconst getNetworkState = (): NetworkState => {\r\n const online =\r\n typeof navigator !== 'undefined' && navigator.onLine !== undefined ? navigator.onLine : true;\r\n\r\n const nav = typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;\r\n const conn = nav?.connection;\r\n\r\n return {\r\n online,\r\n effectiveType: conn?.effectiveType ?? 'unknown',\r\n downlink: conn?.downlink ?? 0,\r\n rtt: conn?.rtt ?? 0,\r\n };\r\n};\r\n\r\n/**\r\n * Returns a reactive signal tracking network connectivity and quality.\r\n *\r\n * Tracks whether the browser is online/offline and, where supported,\r\n * the effective connection type, downlink speed, and round-trip time\r\n * via the Network Information API.\r\n *\r\n * @returns A readonly reactive signal with `{ online, effectiveType, downlink, rtt }`\r\n * and a `destroy()` method to remove attached listeners\r\n *\r\n * @example\r\n * ```ts\r\n * import { useNetworkStatus } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const net = useNetworkStatus();\r\n * effect(() => {\r\n * if (!net.value.online) {\r\n * console.warn('You are offline!');\r\n * }\r\n * console.log(`Connection: ${net.value.effectiveType}, RTT: ${net.value.rtt}ms`);\r\n * });\r\n * ```\r\n */\r\nexport const useNetworkStatus = (): NetworkSignal => {\r\n const s = signal<NetworkState>(getNetworkState());\r\n let cleanup: (() => void) | undefined;\r\n\r\n if (typeof window !== 'undefined') {\r\n const update = (): void => {\r\n s.value = getNetworkState();\r\n };\r\n\r\n window.addEventListener('online', update);\r\n window.addEventListener('offline', update);\r\n\r\n const nav =\r\n typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;\r\n if (nav?.connection && typeof nav.connection.addEventListener === 'function') {\r\n nav.connection.addEventListener('change', update);\r\n }\r\n\r\n cleanup = () => {\r\n window.removeEventListener('online', update);\r\n window.removeEventListener('offline', update);\r\n if (nav?.connection && typeof nav.connection.removeEventListener === 'function') {\r\n nav.connection.removeEventListener('change', update);\r\n }\r\n };\r\n }\r\n\r\n const ro = readonly(s) as NetworkSignal;\r\n let destroyed = false;\r\n Object.defineProperty(ro, 'destroy', {\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n cleanup?.();\r\n s.dispose();\r\n },\r\n enumerable: false,\r\n configurable: true,\r\n });\r\n\r\n return ro;\r\n};\r\n","/**\r\n * Reactive battery status.\r\n *\r\n * Provides a reactive signal tracking the device's battery status\r\n * via the Battery Status API.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport { signal, readonly } from '../reactive/index';\r\nimport type { BatterySignal, BatteryState } from './types';\r\n\r\n/**\r\n * BatteryManager interface for the Battery Status API.\r\n * @internal\r\n */\r\ninterface BatteryManager extends EventTarget {\r\n charging: boolean;\r\n chargingTime: number;\r\n dischargingTime: number;\r\n level: number;\r\n}\r\n\r\n/** Default battery state when API is unavailable. */\r\nconst DEFAULT_BATTERY_STATE: BatteryState = {\r\n supported: false,\r\n charging: false,\r\n chargingTime: 0,\r\n dischargingTime: 0,\r\n level: 1,\r\n};\r\n\r\n/**\r\n * Returns a reactive signal tracking the device's battery status.\r\n *\r\n * Uses the Battery Status API (`navigator.getBattery()`) where available.\r\n * Falls back gracefully to a default state with `supported: false` when\r\n * the API is not available.\r\n *\r\n * @returns A readonly reactive signal with battery state and a `destroy()` method\r\n * to remove Battery Status API listeners\r\n *\r\n * @example\r\n * ```ts\r\n * import { useBattery } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const battery = useBattery();\r\n * effect(() => {\r\n * if (battery.value.supported) {\r\n * console.log(`Battery: ${(battery.value.level * 100).toFixed(0)}%`);\r\n * console.log(`Charging: ${battery.value.charging}`);\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const useBattery = (): BatterySignal => {\r\n const s = signal<BatteryState>({ ...DEFAULT_BATTERY_STATE });\r\n let cleanup: (() => void) | undefined;\r\n let destroyed = false;\r\n\r\n if (\r\n typeof navigator !== 'undefined' &&\r\n 'getBattery' in navigator &&\r\n typeof (navigator as Navigator & { getBattery: () => Promise<BatteryManager> }).getBattery ===\r\n 'function'\r\n ) {\r\n const nav = navigator as Navigator & { getBattery: () => Promise<BatteryManager> };\r\n\r\n nav\r\n .getBattery()\r\n .then((battery) => {\r\n if (destroyed) return;\r\n\r\n const update = (): void => {\r\n s.value = {\r\n supported: true,\r\n charging: battery.charging,\r\n chargingTime: battery.chargingTime,\r\n dischargingTime: battery.dischargingTime,\r\n level: battery.level,\r\n };\r\n };\r\n\r\n update();\r\n\r\n battery.addEventListener('chargingchange', update);\r\n battery.addEventListener('chargingtimechange', update);\r\n battery.addEventListener('dischargingtimechange', update);\r\n battery.addEventListener('levelchange', update);\r\n cleanup = () => {\r\n battery.removeEventListener('chargingchange', update);\r\n battery.removeEventListener('chargingtimechange', update);\r\n battery.removeEventListener('dischargingtimechange', update);\r\n battery.removeEventListener('levelchange', update);\r\n };\r\n })\r\n .catch(() => {\r\n // Battery API rejected — keep default state\r\n });\r\n }\r\n\r\n const ro = readonly(s) as BatterySignal;\r\n Object.defineProperty(ro, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n cleanup?.();\r\n s.dispose();\r\n },\r\n });\r\n\r\n return ro;\r\n};\r\n","/**\r\n * Reactive geolocation.\r\n *\r\n * Provides a reactive signal tracking the device's geographic position\r\n * via the Geolocation API.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport { signal, readonly } from '../reactive/index';\r\nimport type { GeolocationOptions, GeolocationSignal, GeolocationState } from './types';\r\n\r\n/** Default geolocation state. */\r\nconst DEFAULT_GEO_STATE: GeolocationState = {\r\n supported: false,\r\n loading: false,\r\n latitude: null,\r\n longitude: null,\r\n accuracy: null,\r\n altitude: null,\r\n altitudeAccuracy: null,\r\n heading: null,\r\n speed: null,\r\n timestamp: null,\r\n error: null,\r\n};\r\n\r\n/**\r\n * Returns a reactive signal tracking the device's geographic position.\r\n *\r\n * Uses the Geolocation API (`navigator.geolocation`) where available.\r\n * Can operate in one-shot mode (default) or continuous watch mode.\r\n *\r\n * @param options - Configuration for the geolocation request\r\n * @returns A readonly reactive signal with position data and loading/error state,\r\n * plus a `destroy()` method to stop an active watcher\r\n *\r\n * @example\r\n * ```ts\r\n * import { useGeolocation } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * // One-shot position\r\n * const geo = useGeolocation();\r\n * effect(() => {\r\n * if (geo.value.loading) return console.log('Getting position...');\r\n * if (geo.value.error) return console.error(geo.value.error);\r\n * console.log(`Lat: ${geo.value.latitude}, Lng: ${geo.value.longitude}`);\r\n * });\r\n *\r\n * // Continuous watch with high accuracy\r\n * const geoWatch = useGeolocation({ watch: true, enableHighAccuracy: true });\r\n * ```\r\n */\r\nexport const useGeolocation = (options: GeolocationOptions = {}): GeolocationSignal => {\r\n const { enableHighAccuracy = false, maximumAge = 0, timeout = Infinity, watch = false } = options;\r\n\r\n const s = signal<GeolocationState>({ ...DEFAULT_GEO_STATE });\r\n\r\n let destroyWatcher: (() => void) | undefined;\r\n\r\n if (typeof navigator !== 'undefined' && 'geolocation' in navigator) {\r\n s.value = { ...DEFAULT_GEO_STATE, supported: true, loading: true };\r\n\r\n const posOptions: PositionOptions = {\r\n enableHighAccuracy,\r\n maximumAge,\r\n timeout: timeout === Infinity ? undefined : timeout,\r\n };\r\n\r\n const onSuccess = (pos: GeolocationPosition): void => {\r\n s.value = {\r\n supported: true,\r\n loading: false,\r\n latitude: pos.coords.latitude,\r\n longitude: pos.coords.longitude,\r\n accuracy: pos.coords.accuracy,\r\n altitude: pos.coords.altitude,\r\n altitudeAccuracy: pos.coords.altitudeAccuracy,\r\n heading: pos.coords.heading,\r\n speed: pos.coords.speed,\r\n timestamp: pos.timestamp,\r\n error: null,\r\n };\r\n };\r\n\r\n const onError = (err: GeolocationPositionError): void => {\r\n s.value = {\r\n ...s.value,\r\n loading: false,\r\n error: err.message,\r\n };\r\n };\r\n\r\n if (watch) {\r\n const watchId = navigator.geolocation.watchPosition(onSuccess, onError, posOptions);\r\n destroyWatcher = () => {\r\n navigator.geolocation.clearWatch(watchId);\r\n };\r\n } else {\r\n navigator.geolocation.getCurrentPosition(onSuccess, onError, posOptions);\r\n }\r\n }\r\n\r\n const ro = readonly(s) as GeolocationSignal;\r\n let destroyed = false;\r\n Object.defineProperty(ro, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n destroyWatcher?.();\r\n s.dispose();\r\n },\r\n });\r\n\r\n return ro;\r\n};\r\n","/**\r\n * Reactive device motion and orientation sensors.\r\n *\r\n * Provides reactive signals for accelerometer, gyroscope, and\r\n * compass data via the DeviceMotion and DeviceOrientation APIs.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport { signal, readonly } from '../reactive/index';\r\nimport type {\r\n DeviceMotionSignal,\r\n DeviceMotionState,\r\n DeviceOrientationSignal,\r\n DeviceOrientationState,\r\n} from './types';\r\n\r\n/** Default device motion state. */\r\nconst DEFAULT_MOTION_STATE: DeviceMotionState = {\r\n acceleration: { x: null, y: null, z: null },\r\n accelerationIncludingGravity: { x: null, y: null, z: null },\r\n rotationRate: { alpha: null, beta: null, gamma: null },\r\n interval: 0,\r\n};\r\n\r\n/** Default device orientation state. */\r\nconst DEFAULT_ORIENTATION_STATE: DeviceOrientationState = {\r\n alpha: null,\r\n beta: null,\r\n gamma: null,\r\n absolute: false,\r\n};\r\n\r\n/**\r\n * Returns a reactive signal tracking device motion (accelerometer + gyroscope).\r\n *\r\n * Uses the `devicemotion` event to provide acceleration, acceleration\r\n * including gravity, and rotation rate data.\r\n *\r\n * @returns A readonly reactive signal with motion sensor data and a `destroy()`\r\n * method to remove the underlying event listener\r\n *\r\n * @example\r\n * ```ts\r\n * import { useDeviceMotion } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const motion = useDeviceMotion();\r\n * effect(() => {\r\n * const { acceleration } = motion.value;\r\n * console.log(`Acceleration: x=${acceleration.x}, y=${acceleration.y}, z=${acceleration.z}`);\r\n * });\r\n * ```\r\n */\r\nexport const useDeviceMotion = (): DeviceMotionSignal => {\r\n const s = signal<DeviceMotionState>({ ...DEFAULT_MOTION_STATE });\r\n let cleanup: (() => void) | undefined;\r\n\r\n if (typeof window !== 'undefined') {\r\n const handler = (e: DeviceMotionEvent): void => {\r\n s.value = {\r\n acceleration: {\r\n x: e.acceleration?.x ?? null,\r\n y: e.acceleration?.y ?? null,\r\n z: e.acceleration?.z ?? null,\r\n },\r\n accelerationIncludingGravity: {\r\n x: e.accelerationIncludingGravity?.x ?? null,\r\n y: e.accelerationIncludingGravity?.y ?? null,\r\n z: e.accelerationIncludingGravity?.z ?? null,\r\n },\r\n rotationRate: {\r\n alpha: e.rotationRate?.alpha ?? null,\r\n beta: e.rotationRate?.beta ?? null,\r\n gamma: e.rotationRate?.gamma ?? null,\r\n },\r\n interval: e.interval ?? 0,\r\n };\r\n };\r\n\r\n window.addEventListener('devicemotion', handler);\r\n cleanup = () => {\r\n window.removeEventListener('devicemotion', handler);\r\n };\r\n }\r\n\r\n const ro = readonly(s) as DeviceMotionSignal;\r\n let destroyed = false;\r\n Object.defineProperty(ro, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n cleanup?.();\r\n s.dispose();\r\n },\r\n });\r\n\r\n return ro;\r\n};\r\n\r\n/**\r\n * Returns a reactive signal tracking device orientation (compass/gyroscope).\r\n *\r\n * Uses the `deviceorientation` event to provide alpha (compass heading),\r\n * beta (front-to-back tilt), and gamma (left-to-right tilt) data.\r\n *\r\n * @returns A readonly reactive signal with orientation data and a `destroy()`\r\n * method to remove the underlying event listener\r\n *\r\n * @example\r\n * ```ts\r\n * import { useDeviceOrientation } from '@bquery/bquery/media';\r\n * import { effect } from '@bquery/bquery/reactive';\r\n *\r\n * const orientation = useDeviceOrientation();\r\n * effect(() => {\r\n * console.log(`Compass heading: ${orientation.value.alpha}°`);\r\n * console.log(`Tilt: ${orientation.value.beta}° / ${orientation.value.gamma}°`);\r\n * });\r\n * ```\r\n */\r\nexport const useDeviceOrientation = (): DeviceOrientationSignal => {\r\n const s = signal<DeviceOrientationState>({ ...DEFAULT_ORIENTATION_STATE });\r\n let cleanup: (() => void) | undefined;\r\n\r\n if (typeof window !== 'undefined') {\r\n const handler = (e: DeviceOrientationEvent): void => {\r\n s.value = {\r\n alpha: e.alpha ?? null,\r\n beta: e.beta ?? null,\r\n gamma: e.gamma ?? null,\r\n absolute: e.absolute ?? false,\r\n };\r\n };\r\n\r\n window.addEventListener('deviceorientation', handler);\r\n cleanup = () => {\r\n window.removeEventListener('deviceorientation', handler);\r\n };\r\n }\r\n\r\n const ro = readonly(s) as DeviceOrientationSignal;\r\n let destroyed = false;\r\n Object.defineProperty(ro, 'destroy', {\r\n enumerable: false,\r\n configurable: true,\r\n value(): void {\r\n if (destroyed) return;\r\n destroyed = true;\r\n cleanup?.();\r\n s.dispose();\r\n },\r\n });\r\n\r\n return ro;\r\n};\r\n","/**\r\n * Async clipboard API wrappers.\r\n *\r\n * Provides simple read/write access to the system clipboard\r\n * via the Async Clipboard API.\r\n *\r\n * @module bquery/media\r\n */\r\n\r\nimport type { ClipboardAPI } from './types';\r\n\r\nconst CLIPBOARD_UNAVAILABLE_ERROR =\r\n 'bQuery media: Clipboard API is unavailable. Use a secure context (HTTPS or localhost) and ensure clipboard permissions or user-activation requirements are met.';\r\n\r\n/**\r\n * Clipboard API wrapper providing simple async read/write access.\r\n *\r\n * Uses the modern Async Clipboard API (`navigator.clipboard`) under the hood.\r\n * Both methods are `Promise`-based and will reject if the API is unavailable\r\n * or permission is denied.\r\n *\r\n * @example\r\n * ```ts\r\n * import { clipboard } from '@bquery/bquery/media';\r\n *\r\n * // Write text to clipboard\r\n * await clipboard.write('Hello, world!');\r\n *\r\n * // Read text from clipboard\r\n * const text = await clipboard.read();\r\n * console.log(text); // \"Hello, world!\"\r\n * ```\r\n */\r\nexport const clipboard: ClipboardAPI = {\r\n /**\r\n * Reads text from the system clipboard.\r\n *\r\n * @returns A promise that resolves with the clipboard text content\r\n * @throws Error if the Clipboard API is not available or permission is denied\r\n *\r\n * @example\r\n * ```ts\r\n * const text = await clipboard.read();\r\n * console.log('Clipboard contains:', text);\r\n * ```\r\n */\r\n read: async (): Promise<string> => {\r\n if (\r\n typeof navigator === 'undefined' ||\r\n !navigator.clipboard ||\r\n typeof navigator.clipboard.readText !== 'function'\r\n ) {\r\n throw new Error(CLIPBOARD_UNAVAILABLE_ERROR);\r\n }\r\n return navigator.clipboard.readText();\r\n },\r\n\r\n /**\r\n * Writes text to the system clipboard.\r\n *\r\n * @param text - The text to write to the clipboard\r\n * @returns A promise that resolves when the text has been written\r\n * @throws Error if the Clipboard API is not available or permission is denied\r\n *\r\n * @example\r\n * ```ts\r\n * await clipboard.write('Copied!');\r\n * ```\r\n */\r\n write: async (text: string): Promise<void> => {\r\n if (\r\n typeof navigator === 'undefined' ||\r\n !navigator.clipboard ||\r\n typeof navigator.clipboard.writeText !== 'function'\r\n ) {\r\n throw new Error(CLIPBOARD_UNAVAILABLE_ERROR);\r\n }\r\n return navigator.clipboard.writeText(text);\r\n },\r\n};\r\n","/**\r\n * Global plugin registry for bQuery.\r\n *\r\n * Provides `use()` to register plugins and query helpers consumed by\r\n * other modules (e.g. the view module reads custom directives from here).\r\n *\r\n * @module bquery/plugin\r\n */\r\n\r\nimport { registerCustomDirectiveResolver } from '../view/custom-directives';\r\nimport type {\r\n BQueryPlugin,\r\n CustomDirective,\r\n CustomDirectiveHandler,\r\n PluginInstallContext,\r\n} from './types';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal registries\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Set of installed plugin names — prevents double-install. */\r\nconst installedPlugins = new Set<string>();\r\n\r\n/** Custom directives contributed by plugins. */\r\nconst customDirectives = new Map<string, CustomDirectiveHandler>();\r\n\r\ntype PendingComponentRegistration = {\r\n tagName: string;\r\n constructor: CustomElementConstructor;\r\n options?: ElementDefinitionOptions;\r\n};\r\n\r\nregisterCustomDirectiveResolver((name) => customDirectives.get(name));\r\n\r\n/**\r\n * Restore the directive registry to a previously captured snapshot.\r\n *\r\n * Used to roll back partial plugin installation when `install()` or staged\r\n * `customElements.define()` calls fail after directives were already registered.\r\n *\r\n * @internal\r\n */\r\nconst restoreDirectiveSnapshot = (\r\n directivesSnapshot: ReadonlyMap<string, CustomDirectiveHandler>\r\n): void => {\r\n customDirectives.clear();\r\n for (const [name, handler] of directivesSnapshot) {\r\n customDirectives.set(name, handler);\r\n }\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Install context factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Build the `PluginInstallContext` handed to each plugin's `install()`.\r\n * @internal\r\n */\r\nconst createInstallContext = (\r\n pendingComponents: PendingComponentRegistration[]\r\n): PluginInstallContext => ({\r\n directive(name: string, handler: CustomDirectiveHandler): void {\r\n if (typeof name !== 'string' || name.length === 0) {\r\n throw new Error('bQuery plugin directive: name must be a non-empty string');\r\n }\r\n if (name.startsWith('bq-')) {\r\n const suggestedName = name.slice(3);\r\n throw new Error(\r\n `bQuery plugin directive: name \"${name}\" must be provided without the \"bq-\" prefix` +\r\n (suggestedName ? ` (use \"${suggestedName}\")` : '')\r\n );\r\n }\r\n if (typeof handler !== 'function') {\r\n throw new Error(`bQuery plugin directive: handler for \"${name}\" must be a function`);\r\n }\r\n if (customDirectives.has(name)) {\r\n throw new Error(`bQuery plugin directive: a directive named \"${name}\" is already registered`);\r\n }\r\n customDirectives.set(name, handler);\r\n },\r\n\r\n component(\r\n tagName: string,\r\n constructor: CustomElementConstructor,\r\n options?: ElementDefinitionOptions\r\n ): void {\r\n if (typeof tagName !== 'string' || tagName.length === 0) {\r\n throw new Error('bQuery plugin component: tagName must be a non-empty string');\r\n }\r\n if (!tagName.includes('-')) {\r\n throw new Error(\r\n `bQuery plugin component: tagName \"${tagName}\" must be a valid custom element name containing a hyphen`\r\n );\r\n }\r\n if (typeof constructor !== 'function') {\r\n throw new Error(`bQuery plugin component: constructor for \"${tagName}\" must be a function`);\r\n }\r\n if (typeof customElements === 'undefined') {\r\n if (typeof console !== 'undefined' && typeof console.warn === 'function') {\r\n console.warn(\r\n `[bQuery] plugin component \"${tagName}\" was not registered because customElements is not available in this environment.`\r\n );\r\n }\r\n return;\r\n }\r\n // Idempotent — skip if already defined or already staged during this install\r\n if (\r\n !customElements.get(tagName) &&\r\n !pendingComponents.some((entry) => entry.tagName === tagName)\r\n ) {\r\n pendingComponents.push({ tagName, constructor, options });\r\n }\r\n },\r\n});\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Register a bQuery plugin.\r\n *\r\n * Plugins are installed at most once (identified by `plugin.name`).\r\n * Duplicate calls with the same name are silently ignored.\r\n *\r\n * @param plugin - The plugin object implementing `{ name, install }`.\r\n * @param options - Optional configuration forwarded to `plugin.install()`.\r\n * @throws If `plugin` is not a valid plugin object.\r\n *\r\n * @example\r\n * ```ts\r\n * import { use } from '@bquery/bquery/plugin';\r\n *\r\n * use({\r\n * name: 'highlight',\r\n * install(ctx) {\r\n * ctx.directive('highlight', (el, expr) => {\r\n * (el as HTMLElement).style.background = String(expr);\r\n * });\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport const use = <TOptions = unknown>(\r\n plugin: BQueryPlugin<TOptions>,\r\n options?: TOptions\r\n): void => {\r\n if (!plugin || typeof plugin !== 'object') {\r\n throw new Error('bQuery plugin: use() expects a plugin object with { name, install }');\r\n }\r\n if (typeof plugin.name !== 'string' || plugin.name.length === 0) {\r\n throw new Error('bQuery plugin: plugin must have a non-empty \"name\" property');\r\n }\r\n if (typeof plugin.install !== 'function') {\r\n throw new Error(`bQuery plugin: plugin \"${plugin.name}\" must have an \"install\" function`);\r\n }\r\n\r\n // Deduplicate\r\n if (installedPlugins.has(plugin.name)) return;\r\n\r\n const pendingComponents: PendingComponentRegistration[] = [];\r\n const ctx = createInstallContext(pendingComponents);\r\n const directivesSnapshot = new Map(customDirectives);\r\n\r\n try {\r\n plugin.install(ctx, options);\r\n } catch (error) {\r\n restoreDirectiveSnapshot(directivesSnapshot);\r\n throw error;\r\n }\r\n\r\n try {\r\n for (const entry of pendingComponents) {\r\n if (!customElements.get(entry.tagName)) {\r\n customElements.define(entry.tagName, entry.constructor, entry.options);\r\n }\r\n }\r\n } catch (error) {\r\n restoreDirectiveSnapshot(directivesSnapshot);\r\n throw error;\r\n }\r\n\r\n installedPlugins.add(plugin.name);\r\n};\r\n\r\n/**\r\n * Check whether a plugin with the given name has been installed.\r\n *\r\n * @param name - The plugin name to check.\r\n * @returns `true` if the plugin was previously installed via `use()`.\r\n *\r\n * @example\r\n * ```ts\r\n * import { isInstalled } from '@bquery/bquery/plugin';\r\n *\r\n * if (!isInstalled('my-plugin')) {\r\n * use(myPlugin);\r\n * }\r\n * ```\r\n */\r\nexport const isInstalled = (name: string): boolean => installedPlugins.has(name);\r\n\r\n/**\r\n * Return a read-only snapshot of all installed plugin names.\r\n *\r\n * @returns Array of plugin name strings.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getInstalledPlugins } from '@bquery/bquery/plugin';\r\n * console.log(getInstalledPlugins()); // ['my-plugin', 'other-plugin']\r\n * ```\r\n */\r\nexport const getInstalledPlugins = (): readonly string[] => [...installedPlugins];\r\n\r\n/**\r\n * Retrieve the handler for a custom directive registered by a plugin.\r\n *\r\n * This is used internally by the view module's `processElement` to\r\n * resolve directives that aren't built-in.\r\n *\r\n * @param name - Directive name **without** prefix (e.g. `'tooltip'`).\r\n * @returns The handler, or `undefined` if none is registered.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getCustomDirective } from '@bquery/bquery/plugin';\r\n * const handler = getCustomDirective('tooltip');\r\n * ```\r\n */\r\nexport const getCustomDirective = (name: string): CustomDirectiveHandler | undefined =>\r\n customDirectives.get(name);\r\n\r\n/**\r\n * Return a read-only snapshot of all registered custom directives.\r\n *\r\n * @returns Array of `{ name, handler }` descriptors.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getCustomDirectives } from '@bquery/bquery/plugin';\r\n * for (const { name, handler } of getCustomDirectives()) {\r\n * console.log(`Directive: bq-${name}`);\r\n * }\r\n * ```\r\n */\r\nexport const getCustomDirectives = (): readonly CustomDirective[] =>\r\n [...customDirectives.entries()].map(([name, handler]) => ({ name, handler }));\r\n\r\n/**\r\n * Reset all plugin registrations.\r\n *\r\n * Clears all installed plugins and custom directives.\r\n *\r\n * This utility is primarily intended for tests and other isolated environments\r\n * that need to reinitialize plugin state between runs.\r\n *\r\n * @example\r\n * ```ts\r\n * import { resetPlugins } from '@bquery/bquery/plugin';\r\n * afterEach(() => resetPlugins());\r\n * ```\r\n */\r\nexport const resetPlugins = (): void => {\r\n installedPlugins.clear();\r\n customDirectives.clear();\r\n};\r\n","/**\r\n * bQuery DevTools — runtime debugging utilities.\r\n *\r\n * Enable devtools to inspect signals, stores, components, and view a\r\n * timeline of reactive events.\r\n *\r\n * @module bquery/devtools\r\n */\r\n\r\nimport type {\r\n ComponentSnapshot,\r\n DevtoolsOptions,\r\n DevtoolsState,\r\n SignalSnapshot,\r\n StoreSnapshot,\r\n TimelineEntry,\r\n TimelineEventType,\r\n} from './types';\r\nimport { listStores as _listStores, getStore as _getStore } from '../store/registry';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Internal state\r\n// ---------------------------------------------------------------------------\r\n\r\nlet _enabled = false;\r\nlet _options: DevtoolsOptions = {};\r\nconst _timeline: TimelineEntry[] = [];\r\n\r\n/** Registered signals keyed by label. */\r\nconst _trackedSignals = new Map<string, { peek: () => unknown; subscriberCount: () => number }>();\r\n\r\n/** Monotonic counter for auto-labelling anonymous signals. */\r\nlet _signalCounter = 0;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Enable / disable\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Enable bQuery development mode.\r\n *\r\n * When enabled the devtools module records timeline events and\r\n * allows inspection of signals, stores, and components.\r\n *\r\n * @param enabled - `true` to enable, `false` to disable.\r\n * @param options - Optional configuration.\r\n *\r\n * @example\r\n * ```ts\r\n * import { enableDevtools } from '@bquery/bquery/devtools';\r\n * enableDevtools(true, { logToConsole: true });\r\n * ```\r\n */\r\nexport const enableDevtools = (enabled: boolean, options?: DevtoolsOptions): void => {\r\n _enabled = enabled;\r\n _options = options ?? {};\r\n\r\n if (!enabled) {\r\n _timeline.length = 0;\r\n _trackedSignals.clear();\r\n _signalCounter = 0;\r\n }\r\n};\r\n\r\n/**\r\n * Returns `true` when devtools are active.\r\n *\r\n * @example\r\n * ```ts\r\n * import { isDevtoolsEnabled } from '@bquery/bquery/devtools';\r\n * if (isDevtoolsEnabled()) { ... }\r\n * ```\r\n */\r\nexport const isDevtoolsEnabled = (): boolean => _enabled;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Signal tracking\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Register a signal for devtools inspection.\r\n *\r\n * @param label - Human-readable label (must be unique).\r\n * @param peek - Returns the signal's value without tracking.\r\n * @param subscriberCount - Returns the current subscriber count.\r\n * @throws If a signal with the same label is already tracked.\r\n *\r\n * @example\r\n * ```ts\r\n * import { trackSignal } from '@bquery/bquery/devtools';\r\n * import { signal } from '@bquery/bquery/reactive';\r\n *\r\n * const count = signal(0);\r\n * trackSignal('count', () => count.peek(), () => 0);\r\n * ```\r\n */\r\nexport const trackSignal = (\r\n label: string,\r\n peek: () => unknown,\r\n subscriberCount: () => number\r\n): void => {\r\n if (!_enabled) return;\r\n if (typeof label !== 'string' || label.length === 0) {\r\n throw new Error('bQuery devtools: trackSignal() requires a non-empty label');\r\n }\r\n _trackedSignals.set(label, { peek, subscriberCount });\r\n};\r\n\r\n/**\r\n * Remove a previously tracked signal.\r\n *\r\n * @param label - The label used during registration.\r\n *\r\n * @example\r\n * ```ts\r\n * import { untrackSignal } from '@bquery/bquery/devtools';\r\n * untrackSignal('count');\r\n * ```\r\n */\r\nexport const untrackSignal = (label: string): void => {\r\n _trackedSignals.delete(label);\r\n};\r\n\r\n/**\r\n * Generate a unique label for anonymous signals.\r\n *\r\n * @returns A label such as `signal_0`, `signal_1`, …\r\n *\r\n * @example\r\n * ```ts\r\n * import { generateSignalLabel } from '@bquery/bquery/devtools';\r\n * const label = generateSignalLabel(); // 'signal_0'\r\n * ```\r\n */\r\nexport const generateSignalLabel = (): string => `signal_${_signalCounter++}`;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Signal inspector\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * List all tracked signals with their current values.\r\n *\r\n * @returns An array of {@link SignalSnapshot} objects.\r\n *\r\n * @example\r\n * ```ts\r\n * import { inspectSignals } from '@bquery/bquery/devtools';\r\n * console.table(inspectSignals());\r\n * ```\r\n */\r\nexport const inspectSignals = (): SignalSnapshot[] => {\r\n const result: SignalSnapshot[] = [];\r\n for (const [label, entry] of _trackedSignals) {\r\n result.push({\r\n label,\r\n value: entry.peek(),\r\n subscriberCount: entry.subscriberCount(),\r\n });\r\n }\r\n return result;\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Store inspector\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * List all stores with their current state.\r\n *\r\n * Reads from the store registry (`listStores` / `getStore`) that is\r\n * already maintained by the store module.\r\n *\r\n * @returns An array of {@link StoreSnapshot} objects.\r\n *\r\n * @example\r\n * ```ts\r\n * import { inspectStores } from '@bquery/bquery/devtools';\r\n * console.table(inspectStores());\r\n * ```\r\n */\r\nexport const inspectStores = (): StoreSnapshot[] => {\r\n try {\r\n const ids: string[] = _listStores();\r\n return ids.map((id: string) => {\r\n const store = _getStore(id) as Record<string, unknown> | undefined;\r\n const state: Record<string, unknown> = {};\r\n if (store && typeof store === 'object' && '$state' in store) {\r\n const raw = (store as { $state: unknown }).$state;\r\n if (raw && typeof raw === 'object') {\r\n Object.assign(state, raw);\r\n }\r\n }\r\n return { id, state };\r\n });\r\n } catch {\r\n return [];\r\n }\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component inspector\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * List all bQuery-registered custom elements visible in the document.\r\n *\r\n * @returns An array of {@link ComponentSnapshot} objects.\r\n *\r\n * @example\r\n * ```ts\r\n * import { inspectComponents } from '@bquery/bquery/devtools';\r\n * console.table(inspectComponents());\r\n * ```\r\n */\r\nexport const inspectComponents = (): ComponentSnapshot[] => {\r\n if (typeof document === 'undefined') return [];\r\n\r\n const result: ComponentSnapshot[] = [];\r\n const seen = new Set<string>();\r\n\r\n // Walk every custom element in the DOM (they must contain a hyphen)\r\n const all = document.querySelectorAll('*');\r\n for (let i = 0; i < all.length; i++) {\r\n const el = all[i];\r\n const tag = el.tagName.toLowerCase();\r\n if (!tag.includes('-')) continue;\r\n if (seen.has(tag)) continue;\r\n\r\n // Only include if registered via customElements\r\n if (typeof customElements !== 'undefined' && customElements.get(tag)) {\r\n seen.add(tag);\r\n const instances = document.querySelectorAll(tag);\r\n result.push({ tagName: tag, instanceCount: instances.length });\r\n }\r\n }\r\n return result;\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Timeline\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Record a timeline event.\r\n *\r\n * This is called internally by bQuery modules (signals, store, router)\r\n * or can be called from user code / plugins to add custom entries.\r\n *\r\n * @param type - The event category.\r\n * @param detail - A human-readable description.\r\n *\r\n * @example\r\n * ```ts\r\n * import { recordEvent } from '@bquery/bquery/devtools';\r\n * recordEvent('signal:update', 'count changed to 5');\r\n * ```\r\n */\r\nexport const recordEvent = (type: TimelineEventType, detail: string): void => {\r\n if (!_enabled) return;\r\n\r\n const entry: TimelineEntry = {\r\n timestamp: Date.now(),\r\n type,\r\n detail,\r\n };\r\n _timeline.push(entry);\r\n\r\n if (_options.logToConsole) {\r\n console.log(`[bq:devtools] ${type} — ${detail}`);\r\n }\r\n};\r\n\r\n/**\r\n * Returns the full timeline log.\r\n *\r\n * @returns A read-only array of {@link TimelineEntry} objects.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getTimeline } from '@bquery/bquery/devtools';\r\n * for (const e of getTimeline()) {\r\n * console.log(e.type, e.detail);\r\n * }\r\n * ```\r\n */\r\nexport const getTimeline = (): readonly TimelineEntry[] => _timeline;\r\n\r\n/**\r\n * Clear all timeline entries.\r\n *\r\n * @example\r\n * ```ts\r\n * import { clearTimeline } from '@bquery/bquery/devtools';\r\n * clearTimeline();\r\n * ```\r\n */\r\nexport const clearTimeline = (): void => {\r\n _timeline.length = 0;\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Combined state\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Returns a snapshot of the full devtools state.\r\n *\r\n * @returns A {@link DevtoolsState} object.\r\n *\r\n * @example\r\n * ```ts\r\n * import { getDevtoolsState } from '@bquery/bquery/devtools';\r\n * const state = getDevtoolsState();\r\n * console.log(state.enabled, state.timeline.length);\r\n * ```\r\n */\r\nexport const getDevtoolsState = (): DevtoolsState => ({\r\n enabled: _enabled,\r\n options: { ..._options },\r\n timeline: [..._timeline],\r\n});\r\n\r\n// ---------------------------------------------------------------------------\r\n// Log helpers (convenience for interactive debugging)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Pretty-print all tracked signals to the console.\r\n *\r\n * @example\r\n * ```ts\r\n * import { logSignals } from '@bquery/bquery/devtools';\r\n * logSignals(); // → table output\r\n * ```\r\n */\r\nexport const logSignals = (): void => {\r\n const signals = inspectSignals();\r\n if (signals.length === 0) {\r\n console.log('[bq:devtools] No tracked signals.');\r\n return;\r\n }\r\n\r\n console.table(signals);\r\n};\r\n\r\n/**\r\n * Pretty-print all stores to the console.\r\n *\r\n * @example\r\n * ```ts\r\n * import { logStores } from '@bquery/bquery/devtools';\r\n * logStores(); // → table output\r\n * ```\r\n */\r\nexport const logStores = (): void => {\r\n const stores = inspectStores();\r\n if (stores.length === 0) {\r\n console.log('[bq:devtools] No stores registered.');\r\n return;\r\n }\r\n\r\n console.table(stores.map((s) => ({ id: s.id, state: JSON.stringify(s.state) })));\r\n};\r\n\r\n/**\r\n * Pretty-print all registered components to the console.\r\n *\r\n * @example\r\n * ```ts\r\n * import { logComponents } from '@bquery/bquery/devtools';\r\n * logComponents(); // → table output\r\n * ```\r\n */\r\nexport const logComponents = (): void => {\r\n const components = inspectComponents();\r\n if (components.length === 0) {\r\n console.log('[bq:devtools] No custom elements found.');\r\n return;\r\n }\r\n\r\n console.table(components);\r\n};\r\n\r\n/**\r\n * Pretty-print the timeline to the console.\r\n *\r\n * @param last - Only show the last N entries (default: all).\r\n *\r\n * @example\r\n * ```ts\r\n * import { logTimeline } from '@bquery/bquery/devtools';\r\n * logTimeline(10);\r\n * ```\r\n */\r\nexport const logTimeline = (last?: number): void => {\r\n const entries = typeof last === 'number' && last > 0 ? _timeline.slice(-last) : _timeline;\r\n if (entries.length === 0) {\r\n console.log('[bq:devtools] Timeline is empty.');\r\n return;\r\n }\r\n\r\n console.table(\r\n entries.map((e) => ({\r\n time: new Date(e.timestamp).toISOString(),\r\n type: e.type,\r\n detail: e.detail,\r\n }))\r\n );\r\n};\r\n","/**\r\n * Testing utilities for bQuery.js.\r\n *\r\n * Provides helpers for mounting components, controlling signals, mocking\r\n * the router, dispatching events, and asserting async conditions — all\r\n * designed for use with `bun:test` and happy-dom.\r\n *\r\n * @module bquery/testing\r\n */\r\n\r\nimport { batch, Signal, signal } from '../reactive/index';\r\nimport { getNormalizedRouteConstraint } from '../router/constraints';\r\nimport type {\r\n FireEventOptions,\r\n MockRouteDefinition,\r\n MockRouter,\r\n MockRouterOptions,\r\n MockSignal,\r\n RenderComponentOptions,\r\n RenderResult,\r\n TestRoute,\r\n WaitForOptions,\r\n} from './types';\r\n\r\n// ============================================================================\r\n// renderComponent\r\n// ============================================================================\r\n\r\nconst isWordChar = (char: string | undefined): boolean =>\r\n char !== undefined &&\r\n ((char >= 'a' && char <= 'z') ||\r\n (char >= 'A' && char <= 'Z') ||\r\n (char >= '0' && char <= '9') ||\r\n char === '_');\r\n\r\nconst readRouteConstraint = (\r\n pattern: string,\r\n startIndex: number\r\n): { constraint: string; endIndex: number } | null => {\r\n let depth = 1;\r\n let constraint = '';\r\n let i = startIndex + 1;\r\n\r\n while (i < pattern.length) {\r\n const char = pattern[i];\r\n\r\n if (char === '\\\\' && i + 1 < pattern.length) {\r\n constraint += char + pattern[i + 1];\r\n i += 2;\r\n continue;\r\n }\r\n\r\n if (char === '(') {\r\n depth++;\r\n } else if (char === ')') {\r\n depth--;\r\n if (depth === 0) {\r\n return { constraint, endIndex: i + 1 };\r\n }\r\n }\r\n\r\n constraint += char;\r\n i++;\r\n }\r\n\r\n return null;\r\n};\r\n\r\nconst routeConstraintRegexCache = new Map<string, RegExp>();\r\n\r\nconst getRouteConstraintRegex = (constraint: string): RegExp => {\r\n const normalized = getNormalizedRouteConstraint(constraint);\r\n const cached = routeConstraintRegexCache.get(normalized);\r\n if (cached) {\r\n return cached;\r\n }\r\n\r\n const compiled = new RegExp(`^(?:${normalized})$`);\r\n routeConstraintRegexCache.set(normalized, compiled);\r\n return compiled;\r\n};\r\n\r\n/**\r\n * Mounts a custom element by tag name for testing and returns a handle\r\n * to interact with it.\r\n *\r\n * The element is created, configured with the given props and slots,\r\n * and appended to the container (defaults to `document.body`). Call\r\n * `unmount()` to remove the element and trigger its `disconnectedCallback`.\r\n *\r\n * @param tagName - The custom element tag name (must already be registered)\r\n * @param options - Props, slots, and container configuration\r\n * @returns A {@link RenderResult} with the element and an unmount function\r\n * @throws {Error} If the tag name is not a valid custom element name\r\n *\r\n * @example\r\n * ```ts\r\n * import { renderComponent } from '@bquery/bquery/testing';\r\n *\r\n * const { el, unmount } = renderComponent('my-counter', {\r\n * props: { start: '5' },\r\n * });\r\n * expect(el.shadowRoot?.textContent).toContain('5');\r\n * unmount();\r\n * ```\r\n */\r\nexport function renderComponent(\r\n tagName: string,\r\n options: RenderComponentOptions = {}\r\n): RenderResult {\r\n if (!tagName || !tagName.includes('-')) {\r\n throw new Error(\r\n `bQuery testing: \"${tagName}\" is not a valid custom element tag name (must contain a hyphen)`\r\n );\r\n }\r\n\r\n const { props, slots, container = document.body } = options;\r\n\r\n const el = document.createElement(tagName);\r\n\r\n // Set attributes (props) before connecting\r\n if (props) {\r\n for (const [key, value] of Object.entries(props)) {\r\n if (value === null || value === undefined) continue;\r\n el.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Inject slot content before connecting so the component can discover it\r\n if (slots) {\r\n if (typeof slots === 'string') {\r\n el.innerHTML = slots;\r\n } else {\r\n const parts: string[] = [];\r\n for (const [slotName, html] of Object.entries(slots)) {\r\n if (slotName === 'default') {\r\n parts.push(html);\r\n } else {\r\n const safeSlotName = slotName\r\n .replace(/&/g, '&amp;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;');\r\n parts.push(`<div slot=\"${safeSlotName}\">${html}</div>`);\r\n }\r\n }\r\n el.innerHTML = parts.join('');\r\n }\r\n }\r\n\r\n // Connect — triggers connectedCallback\r\n container.appendChild(el);\r\n\r\n const unmount = (): void => {\r\n if (el.parentNode) {\r\n el.parentNode.removeChild(el);\r\n }\r\n };\r\n\r\n return { el, unmount };\r\n}\r\n\r\n// ============================================================================\r\n// flushEffects\r\n// ============================================================================\r\n\r\n/**\r\n * Synchronously flushes any pending reactive effects.\r\n *\r\n * In bQuery's reactive system, effects outside of a batch are executed\r\n * synchronously. This helper exists primarily for clarity and for\r\n * flushing effects that may have been deferred inside a batch.\r\n *\r\n * Internally it performs a no-op batch to trigger the flush of any\r\n * pending observers that were queued during a prior `batch()` call.\r\n *\r\n * @example\r\n * ```ts\r\n * import { signal, batch } from '@bquery/bquery/reactive';\r\n * import { flushEffects } from '@bquery/bquery/testing';\r\n *\r\n * const count = signal(0);\r\n * let observed = 0;\r\n * effect(() => { observed = count.value; });\r\n *\r\n * batch(() => { count.value = 42; });\r\n * flushEffects();\r\n * expect(observed).toBe(42);\r\n * ```\r\n */\r\nexport function flushEffects(): void {\r\n // A no-op batch triggers endBatch which flushes any pending observers.\r\n // Since bQuery's effects are synchronous outside of batches, this is\r\n // mainly useful after manual batch calls or micro-task boundaries.\r\n batch(() => {\r\n /* intentionally empty — triggers pending observer flush */\r\n });\r\n}\r\n\r\n// ============================================================================\r\n// mockSignal\r\n// ============================================================================\r\n\r\n/**\r\n * Creates a controllable signal for tests with `set()` and `reset()` helpers.\r\n *\r\n * This is a thin wrapper around `signal()` that records the initial value\r\n * and adds explicit `set()` / `reset()` methods for clearer test intent.\r\n *\r\n * @template T - The type of the signal value\r\n * @param initialValue - The initial value\r\n * @returns A {@link MockSignal} instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { mockSignal } from '@bquery/bquery/testing';\r\n *\r\n * const count = mockSignal(0);\r\n * count.set(5);\r\n * expect(count.value).toBe(5);\r\n * count.reset();\r\n * expect(count.value).toBe(0);\r\n * ```\r\n */\r\nexport function mockSignal<T>(initialValue: T): MockSignal<T> {\r\n const s = signal(initialValue) as Signal<T> & {\r\n set: (value: T) => void;\r\n reset: () => void;\r\n initialValue: T;\r\n };\r\n\r\n Object.defineProperty(s, 'initialValue', {\r\n value: initialValue,\r\n writable: false,\r\n enumerable: true,\r\n });\r\n\r\n s.set = function (value: T): void {\r\n s.value = value;\r\n };\r\n\r\n s.reset = function (): void {\r\n s.value = initialValue;\r\n };\r\n\r\n return s as MockSignal<T>;\r\n}\r\n\r\n// ============================================================================\r\n// mockRouter\r\n// ============================================================================\r\n\r\n/**\r\n * Parses a path string into the route's `path`, `query`, and `hash` parts.\r\n * @internal\r\n */\r\nfunction parsePath(\r\n fullPath: string,\r\n base: string\r\n): { path: string; query: Record<string, string | string[]>; hash: string } {\r\n let working = fullPath;\r\n\r\n // Strip base prefix\r\n if (base && working.startsWith(base)) {\r\n working = working.slice(base.length) || '/';\r\n }\r\n\r\n // Extract hash\r\n let hash = '';\r\n const hashIdx = working.indexOf('#');\r\n if (hashIdx >= 0) {\r\n hash = working.slice(hashIdx + 1);\r\n working = working.slice(0, hashIdx);\r\n }\r\n\r\n // Extract query string\r\n const query: Record<string, string | string[]> = {};\r\n const qIdx = working.indexOf('?');\r\n if (qIdx >= 0) {\r\n const qs = working.slice(qIdx + 1);\r\n working = working.slice(0, qIdx);\r\n for (const pair of qs.split('&')) {\r\n const eqIdx = pair.indexOf('=');\r\n const key = eqIdx >= 0 ? decodeURIComponent(pair.slice(0, eqIdx)) : decodeURIComponent(pair);\r\n const val = eqIdx >= 0 ? decodeURIComponent(pair.slice(eqIdx + 1)) : '';\r\n const existing = query[key];\r\n if (existing !== undefined) {\r\n if (Array.isArray(existing)) {\r\n existing.push(val);\r\n } else {\r\n query[key] = [existing, val];\r\n }\r\n } else {\r\n query[key] = val;\r\n }\r\n }\r\n }\r\n\r\n return { path: working || '/', query, hash };\r\n}\r\n\r\n/**\r\n * Matches a path against a route definition, extracting params.\r\n * @internal\r\n */\r\nfunction matchRoute(\r\n path: string,\r\n routes: MockRouteDefinition[]\r\n): { matched: MockRouteDefinition | null; params: Record<string, string> } {\r\n for (const route of routes) {\r\n const params = matchRoutePattern(route.path, path);\r\n if (params) {\r\n return { matched: route, params };\r\n }\r\n }\r\n return { matched: null, params: {} };\r\n}\r\n\r\n/**\r\n * Builds param matches from a route path pattern without compiling the full path into a regex.\r\n * @internal\r\n */\r\nfunction matchRoutePattern(pattern: string, path: string): Record<string, string> | null {\r\n if (pattern === '*') {\r\n return {};\r\n }\r\n\r\n // Memoization keeps wildcard/param backtracking linear for repeated subproblems\r\n // within a single pattern/path match attempt.\r\n const memo = new Map<string, Record<string, string> | null>();\r\n\r\n const findSegmentBoundary = (value: string, startIndex: number): number => {\r\n const slashIndex = value.indexOf('/', startIndex);\r\n return slashIndex === -1 ? value.length : slashIndex;\r\n };\r\n\r\n const matchFrom = (patternIndex: number, pathIndex: number): Record<string, string> | null => {\r\n const memoKey = `${patternIndex}:${pathIndex}`;\r\n if (memo.has(memoKey)) {\r\n return memo.get(memoKey) ?? null;\r\n }\r\n\r\n if (patternIndex === pattern.length) {\r\n const result = pathIndex === path.length ? {} : null;\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n\r\n const patternChar = pattern[patternIndex];\r\n\r\n if (patternChar === '*') {\r\n for (let candidateEnd = path.length; candidateEnd >= pathIndex; candidateEnd--) {\r\n const suffixMatch = matchFrom(patternIndex + 1, candidateEnd);\r\n if (suffixMatch) {\r\n memo.set(memoKey, suffixMatch);\r\n return suffixMatch;\r\n }\r\n }\r\n\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n if (patternChar === ':' && isWordChar(pattern[patternIndex + 1])) {\r\n let nameEnd = patternIndex + 2;\r\n while (nameEnd < pattern.length && isWordChar(pattern[nameEnd])) {\r\n nameEnd++;\r\n }\r\n\r\n const name = pattern.slice(patternIndex + 1, nameEnd);\r\n let nextPatternIndex = nameEnd;\r\n let constraint: string | undefined;\r\n let catchAll = false;\r\n\r\n if (pattern[nameEnd] === '(') {\r\n const parsedConstraint = readRouteConstraint(pattern, nameEnd);\r\n if (parsedConstraint) {\r\n constraint = parsedConstraint.constraint;\r\n nextPatternIndex = parsedConstraint.endIndex;\r\n }\r\n }\r\n\r\n if (pattern[nextPatternIndex] === '*') {\r\n catchAll = true;\r\n nextPatternIndex++;\r\n }\r\n\r\n const candidateLimit = catchAll\r\n ? path.length\r\n : constraint\r\n ? path.length\r\n : findSegmentBoundary(path, pathIndex);\r\n\r\n for (let candidateEnd = candidateLimit; candidateEnd > pathIndex; candidateEnd--) {\r\n const candidateValue = path.slice(pathIndex, candidateEnd);\r\n if (constraint) {\r\n const constraintRegex = getRouteConstraintRegex(constraint);\r\n if (!constraintRegex.test(candidateValue)) {\r\n continue;\r\n }\r\n }\r\n\r\n const suffixMatch = matchFrom(nextPatternIndex, candidateEnd);\r\n if (suffixMatch) {\r\n const result = {\r\n [name]: candidateValue,\r\n ...suffixMatch,\r\n };\r\n memo.set(memoKey, result);\r\n return result;\r\n }\r\n }\r\n\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n if (pathIndex >= path.length || patternChar !== path[pathIndex]) {\r\n memo.set(memoKey, null);\r\n return null;\r\n }\r\n\r\n const result = matchFrom(patternIndex + 1, pathIndex + 1);\r\n memo.set(memoKey, result);\r\n return result;\r\n };\r\n\r\n return matchFrom(0, 0);\r\n}\r\n\r\n/**\r\n * Creates a lightweight mock router for testing that does not interact\r\n * with the browser History API.\r\n *\r\n * The mock router provides a reactive `currentRoute` signal that updates\r\n * when `push()` or `replace()` is called, making it ideal for testing\r\n * components or logic that depend on route state.\r\n *\r\n * @param options - Mock router configuration\r\n * @returns A {@link MockRouter} instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { mockRouter } from '@bquery/bquery/testing';\r\n *\r\n * const router = mockRouter({\r\n * routes: [\r\n * { path: '/', component: () => null },\r\n * { path: '/user/:id', component: () => null },\r\n * ],\r\n * initialPath: '/',\r\n * });\r\n *\r\n * router.push('/user/42');\r\n * expect(router.currentRoute.value.params.id).toBe('42');\r\n * router.destroy();\r\n * ```\r\n */\r\nexport function mockRouter(options: MockRouterOptions = {}): MockRouter {\r\n const routes = options.routes ?? [{ path: '*', component: () => null }];\r\n const base = options.base ?? '';\r\n const initialPath = options.initialPath ?? '/';\r\n\r\n const resolveRoute = (fullPath: string): TestRoute => {\r\n const { path, query, hash } = parsePath(fullPath, base);\r\n const { matched, params } = matchRoute(path, routes);\r\n return { path, params, query, matched, hash };\r\n };\r\n\r\n const routeSignal = signal<TestRoute>(resolveRoute(initialPath));\r\n\r\n return {\r\n push(path: string): void {\r\n routeSignal.value = resolveRoute(path);\r\n },\r\n replace(path: string): void {\r\n routeSignal.value = resolveRoute(path);\r\n },\r\n get currentRoute(): Signal<TestRoute> {\r\n return routeSignal;\r\n },\r\n get routes(): MockRouteDefinition[] {\r\n return routes;\r\n },\r\n destroy(): void {\r\n routeSignal.dispose();\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// fireEvent\r\n// ============================================================================\r\n\r\n/**\r\n * Dispatches a synthetic event on an element and flushes pending effects.\r\n *\r\n * By default the event bubbles, is cancelable, and is composed (crosses\r\n * shadow DOM boundaries). Pass a `detail` option to create a `CustomEvent`.\r\n *\r\n * @param el - The target element\r\n * @param eventName - The event type (e.g. 'click', 'input', 'my-event')\r\n * @param options - Event configuration\r\n * @returns `true` if the event was not cancelled\r\n *\r\n * @example\r\n * ```ts\r\n * import { fireEvent } from '@bquery/bquery/testing';\r\n *\r\n * const button = document.createElement('button');\r\n * let clicked = false;\r\n * button.addEventListener('click', () => { clicked = true; });\r\n * fireEvent(button, 'click');\r\n * expect(clicked).toBe(true);\r\n * ```\r\n */\r\nexport function fireEvent(el: Element, eventName: string, options: FireEventOptions = {}): boolean {\r\n if (!el) {\r\n throw new Error('bQuery testing: fireEvent requires a valid element');\r\n }\r\n if (!eventName) {\r\n throw new Error('bQuery testing: fireEvent requires an event name');\r\n }\r\n\r\n const { bubbles = true, cancelable = true, composed = true, detail } = options;\r\n\r\n let event: Event;\r\n if (detail !== undefined) {\r\n event = new CustomEvent(eventName, { bubbles, cancelable, composed, detail });\r\n } else {\r\n event = new Event(eventName, { bubbles, cancelable, composed });\r\n }\r\n\r\n const result = el.dispatchEvent(event);\r\n\r\n // Flush any effects triggered by event handlers\r\n flushEffects();\r\n\r\n return result;\r\n}\r\n\r\n// ============================================================================\r\n// waitFor\r\n// ============================================================================\r\n\r\n/**\r\n * Waits for a predicate to return `true`, polling at a configurable interval.\r\n *\r\n * Useful for asserting conditions that depend on asynchronous operations,\r\n * timers, or deferred reactive updates.\r\n *\r\n * @param predicate - A function that returns `true` when the condition is met\r\n * @param options - Timeout and interval configuration\r\n * @returns A promise that resolves when the predicate returns `true`\r\n * @throws {Error} If the predicate does not return `true` within the timeout\r\n *\r\n * @example\r\n * ```ts\r\n * import { waitFor } from '@bquery/bquery/testing';\r\n *\r\n * await waitFor(() => document.querySelector('.loaded') !== null, {\r\n * timeout: 2000,\r\n * });\r\n * ```\r\n */\r\nexport async function waitFor(\r\n predicate: () => boolean | Promise<boolean>,\r\n options: WaitForOptions = {}\r\n): Promise<void> {\r\n if (typeof predicate !== 'function') {\r\n throw new Error('bQuery testing: waitFor requires a predicate function');\r\n }\r\n\r\n const { timeout = 1000, interval = 10 } = options;\r\n const start = Date.now();\r\n\r\n while (true) {\r\n try {\r\n const result = await predicate();\r\n if (result) return;\r\n } catch {\r\n // Predicate threw — treat as not-yet-met and keep polling\r\n }\r\n\r\n if (Date.now() - start >= timeout) {\r\n throw new Error(\r\n `bQuery testing: waitFor timed out after ${timeout}ms — predicate never returned true`\r\n );\r\n }\r\n\r\n await new Promise((resolve) => setTimeout(resolve, interval));\r\n }\r\n}\r\n","/**\r\n * Hydration support for server-rendered DOM.\r\n *\r\n * Enables the client-side view system to reuse existing server-rendered DOM\r\n * elements instead of re-rendering them, by attaching reactive bindings\r\n * to the pre-existing DOM structure.\r\n *\r\n * @module bquery/ssr\r\n */\r\n\r\nimport type { BindingContext, MountOptions, View } from '../view/types';\r\nimport { mount } from '../view/mount';\r\n\r\n/**\r\n * Extended mount options that include hydration mode.\r\n */\r\nexport type HydrateMountOptions = MountOptions & {\r\n /**\r\n * When present, must be `true` so the mount operation reuses existing DOM elements\r\n * instead of re-rendering them. Reactive bindings (effects) are\r\n * still attached so the DOM updates reactively from that point on.\r\n *\r\n * @default true\r\n */\r\n hydrate?: true;\r\n};\r\n\r\n/**\r\n * Mounts a reactive view with optional hydration support.\r\n *\r\n * When `hydrate: true` is set, the existing server-rendered DOM is preserved\r\n * and reactive bindings are attached on top. The DOM is NOT re-rendered;\r\n * instead, effects begin tracking signals so future changes update the DOM.\r\n *\r\n * This is the client-side counterpart to `renderToString()`. The typical flow:\r\n * 1. Server: `renderToString(template, data)` → send HTML to client\r\n * 2. Client: `hydrateMount('#app', reactiveContext, { hydrate: true })`\r\n *\r\n * Under the hood, `hydrateMount` simply delegates to the standard `mount()`\r\n * function. The `mount()` function already processes existing DOM elements\r\n * and attaches reactive effects to them — it does not clear/replace content.\r\n * The `hydrate` flag is a semantic marker indicating developer intent and\r\n * ensures the existing DOM structure is preserved.\r\n *\r\n * @param selector - CSS selector or Element to hydrate\r\n * @param context - Binding context with signals, computed values, and functions\r\n * @param options - Mount options with `hydrate: true`\r\n * @returns The mounted View instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { hydrateMount } from '@bquery/bquery/ssr';\r\n * import { signal, computed } from '@bquery/bquery/reactive';\r\n *\r\n * // Server rendered:\r\n * // <div id=\"app\"><h1>Welcome</h1><p>Hello, World!</p></div>\r\n *\r\n * // Client hydration — attaches reactivity to existing DOM:\r\n * const name = signal('World');\r\n * const greeting = computed(() => `Hello, ${name.value}!`);\r\n *\r\n * const view = hydrateMount('#app', { name, greeting }, { hydrate: true });\r\n *\r\n * // Now updating `name.value` will reactively update the DOM\r\n * name.value = 'Alice'; // <p> updates to \"Hello, Alice!\"\r\n * ```\r\n */\r\nexport const hydrateMount = (\r\n selector: string | Element,\r\n context: BindingContext,\r\n options: HydrateMountOptions = {}\r\n): View => {\r\n const { hydrate = true, ...mountOptions } = options;\r\n\r\n if (!hydrate) {\r\n throw new Error('bQuery ssr: hydrateMount() requires { hydrate: true } when options are provided.');\r\n }\r\n\r\n // Hydration uses the standard mount which processes existing DOM\r\n // and attaches reactive effects without clearing content.\r\n return mount(selector, context, mountOptions);\r\n};\r\n","/**\r\n * Store state serialization for SSR.\r\n *\r\n * Provides utilities to serialize store state into a `<script>` tag\r\n * for client-side hydration, and to deserialize state on the client.\r\n *\r\n * @module bquery/ssr\r\n */\r\n\r\nimport { getStore, listStores } from '../store/index';\r\nimport { isPrototypePollutionKey } from '../core/utils/object';\r\nimport type { DeserializedStoreState, SerializeOptions } from './types';\r\n\r\nconst isStoreStateObject = (value: unknown): value is Record<string, unknown> =>\r\n typeof value === 'object' && value !== null && !Array.isArray(value);\r\n\r\nconst sanitizeHydrationState = (value: Record<string, unknown>): Record<string, unknown> => {\r\n const sanitized: Record<string, unknown> = {};\r\n for (const [key, entryValue] of Object.entries(value)) {\r\n if (isPrototypePollutionKey(key)) continue;\r\n sanitized[key] = entryValue;\r\n }\r\n return sanitized;\r\n};\r\n\r\n/**\r\n * Result of store state serialization.\r\n */\r\nexport type SerializeResult = {\r\n /** JSON string of the state map */\r\n stateJson: string;\r\n /** Complete `<script>` tag ready to embed in HTML */\r\n scriptTag: string;\r\n};\r\n\r\n/**\r\n * Escapes a string for safe embedding in a `<script>` tag.\r\n * Prevents XSS via `</script>` injection and HTML entities.\r\n *\r\n * @internal\r\n */\r\nconst escapeForScript = (str: string): string => {\r\n return str\r\n .replace(/</g, '\\\\u003c')\r\n .replace(/>/g, '\\\\u003e')\r\n .replace(/\\//g, '\\\\u002f')\r\n .replace(/\\u2028/g, '\\\\u2028')\r\n .replace(/\\u2029/g, '\\\\u2029');\r\n};\r\n\r\n/**\r\n * Escapes a string for safe embedding in an HTML attribute value.\r\n * @internal\r\n */\r\nconst escapeForHtmlAttribute = (str: string): string => {\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;');\r\n};\r\n\r\n/**\r\n * Serializes the state of registered stores into a JSON string and\r\n * a `<script>` tag suitable for embedding in server-rendered HTML.\r\n *\r\n * The serialized state can be picked up on the client using\r\n * `deserializeStoreState()` to restore stores to their server-side values.\r\n *\r\n * @param options - Serialization options\r\n * @returns Object with JSON string and ready-to-use script tag\r\n *\r\n * @example\r\n * ```ts\r\n * import { serializeStoreState } from '@bquery/bquery/ssr';\r\n * import { createStore } from '@bquery/bquery/store';\r\n *\r\n * const store = createStore({\r\n * id: 'counter',\r\n * state: () => ({ count: 42 }),\r\n * });\r\n *\r\n * const { scriptTag } = serializeStoreState();\r\n * // '<script id=\"__BQUERY_STORE_STATE__\">window.__BQUERY_INITIAL_STATE__={\"counter\":{\"count\":42}}</script>'\r\n * ```\r\n *\r\n * @example\r\n * ```ts\r\n * // Serialize only specific stores\r\n * const { scriptTag } = serializeStoreState({ storeIds: ['counter'] });\r\n * ```\r\n */\r\nexport const serializeStoreState = (options: SerializeOptions = {}): SerializeResult => {\r\n const {\r\n scriptId = '__BQUERY_STORE_STATE__',\r\n globalKey = '__BQUERY_INITIAL_STATE__',\r\n storeIds,\r\n serialize = JSON.stringify,\r\n } = options;\r\n\r\n if (isPrototypePollutionKey(globalKey)) {\r\n throw new Error(\r\n `serializeStoreState: invalid globalKey \"${globalKey}\" - prototype-pollution keys are not allowed.`\r\n );\r\n }\r\n\r\n if (isPrototypePollutionKey(scriptId)) {\r\n throw new Error(\r\n `serializeStoreState: invalid scriptId \"${scriptId}\" - prototype-pollution keys are not allowed.`\r\n );\r\n }\r\n\r\n const ids = storeIds ?? listStores();\r\n const stateMap = Object.create(null) as Record<string, Record<string, unknown>>;\r\n\r\n for (const id of ids) {\r\n if (isPrototypePollutionKey(id)) {\r\n continue;\r\n }\r\n\r\n const store = getStore<{ $state: Record<string, unknown> }>(id);\r\n if (store) {\r\n stateMap[id] = sanitizeHydrationState(store.$state);\r\n }\r\n }\r\n\r\n const stateJson = serialize(stateMap);\r\n if (typeof stateJson !== 'string') {\r\n throw new Error('serializeStoreState: custom serialize function must return a string.');\r\n }\r\n\r\n if (serialize !== JSON.stringify) {\r\n let parsedStateJson: unknown;\r\n try {\r\n parsedStateJson = JSON.parse(stateJson);\r\n } catch {\r\n throw new Error('serializeStoreState: custom serialize function returned invalid JSON.');\r\n }\r\n\r\n if (!isStoreStateObject(parsedStateJson)) {\r\n throw new Error(\r\n 'serializeStoreState: custom serialize function must return a JSON object string.'\r\n );\r\n }\r\n }\r\n\r\n const escapedJson = escapeForScript(stateJson);\r\n const escapedGlobalKey = escapeForScript(JSON.stringify(globalKey));\r\n const escapedScriptId = escapeForHtmlAttribute(scriptId);\r\n const scriptTag = `<script id=\"${escapedScriptId}\">window[${escapedGlobalKey}]=${escapedJson}</script>`;\r\n\r\n return { stateJson, scriptTag };\r\n};\r\n\r\n/**\r\n * Deserializes store state from the global variable set by the SSR script tag.\r\n *\r\n * Call this on the client before creating stores to pre-populate them with\r\n * server-rendered state. After deserialization, the script tag and global\r\n * variable are cleaned up automatically.\r\n *\r\n * @param globalKey - The global variable name where state was serialized\r\n * @param scriptId - The ID of the SSR script tag to remove after hydration\r\n * @returns The deserialized state map, or an empty object if not found\r\n *\r\n * @example\r\n * ```ts\r\n * import { deserializeStoreState } from '@bquery/bquery/ssr';\r\n *\r\n * // Call before creating stores\r\n * const state = deserializeStoreState();\r\n * // state = { counter: { count: 42 } }\r\n * ```\r\n */\r\nexport const deserializeStoreState = (\r\n globalKey = '__BQUERY_INITIAL_STATE__',\r\n scriptId = '__BQUERY_STORE_STATE__'\r\n): DeserializedStoreState => {\r\n if (isPrototypePollutionKey(globalKey)) {\r\n throw new Error(\r\n `deserializeStoreState: invalid globalKey \"${globalKey}\" - prototype-pollution keys are not allowed.`\r\n );\r\n }\r\n\r\n if (isPrototypePollutionKey(scriptId)) {\r\n throw new Error(\r\n `deserializeStoreState: invalid scriptId \"${scriptId}\" - prototype-pollution keys are not allowed.`\r\n );\r\n }\r\n\r\n if (typeof window === 'undefined') {\r\n return {};\r\n }\r\n\r\n const state = (window as unknown as Record<string, unknown>)[globalKey];\r\n if (!state) {\r\n return {};\r\n }\r\n\r\n // Clean up global variable\r\n try {\r\n delete (window as unknown as Record<string, unknown>)[globalKey];\r\n } catch {\r\n // In strict mode on some environments, delete may fail\r\n (window as unknown as Record<string, unknown>)[globalKey] = undefined;\r\n }\r\n\r\n // Clean up script tag\r\n if (typeof document !== 'undefined' && typeof document.getElementById === 'function') {\r\n const scriptEl = document.getElementById(scriptId);\r\n if (scriptEl) {\r\n scriptEl.remove();\r\n }\r\n }\r\n\r\n if (!isStoreStateObject(state)) {\r\n return {};\r\n }\r\n\r\n for (const value of Object.values(state)) {\r\n if (!isStoreStateObject(value)) {\r\n return {};\r\n }\r\n }\r\n\r\n const sanitizedStateMap = Object.create(null) as DeserializedStoreState;\r\n\r\n for (const [storeId, storeState] of Object.entries(state)) {\r\n if (isPrototypePollutionKey(storeId) || !isStoreStateObject(storeState)) {\r\n continue;\r\n }\r\n\r\n sanitizedStateMap[storeId] = sanitizeHydrationState(storeState);\r\n }\r\n\r\n return sanitizedStateMap;\r\n};\r\n\r\n/**\r\n * Hydrates a store with pre-serialized state from SSR.\r\n *\r\n * If the store exists and has a `$patch` method, this applies the\r\n * deserialized state as a patch. Otherwise, the state is ignored.\r\n *\r\n * @param storeId - The store ID to hydrate\r\n * @param state - The plain state object to apply\r\n *\r\n * @example\r\n * ```ts\r\n * import { hydrateStore, deserializeStoreState } from '@bquery/bquery/ssr';\r\n * import { createStore } from '@bquery/bquery/store';\r\n *\r\n * // 1. Deserialize state from SSR script tag\r\n * const ssrState = deserializeStoreState();\r\n *\r\n * // 2. Create store (gets initial values from factory)\r\n * const store = createStore({\r\n * id: 'counter',\r\n * state: () => ({ count: 0 }),\r\n * });\r\n *\r\n * // 3. Apply SSR state\r\n * if (ssrState.counter) {\r\n * hydrateStore('counter', ssrState.counter);\r\n * }\r\n * // store.count is now 42 (from SSR)\r\n * ```\r\n */\r\nexport const hydrateStore = (storeId: string, state: Record<string, unknown>): void => {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const store = getStore<{ $patch?: (partial: any) => void }>(storeId);\r\n if (store && typeof store.$patch === 'function') {\r\n store.$patch(sanitizeHydrationState(state));\r\n }\r\n};\r\n\r\n/**\r\n * Hydrates all stores at once from a deserialized state map.\r\n *\r\n * Convenience wrapper that calls `hydrateStore` for each entry in the state map.\r\n *\r\n * @param stateMap - Map of store IDs to their state objects\r\n *\r\n * @example\r\n * ```ts\r\n * import { hydrateStores, deserializeStoreState } from '@bquery/bquery/ssr';\r\n *\r\n * const ssrState = deserializeStoreState();\r\n * hydrateStores(ssrState);\r\n * ```\r\n */\r\nexport const hydrateStores = (stateMap: DeserializedStoreState): void => {\r\n for (const [storeId, state] of Object.entries(stateMap)) {\r\n hydrateStore(storeId, state);\r\n }\r\n};\r\n","/**\r\n * SSR rendering utilities.\r\n *\r\n * Server-side renders bQuery templates to HTML strings by evaluating\r\n * directive attributes against a plain data context. Uses a lightweight\r\n * DOM implementation to process templates without a browser.\r\n *\r\n * @module bquery/ssr\r\n */\r\n\r\nimport { isComputed, isSignal, type Signal } from '../reactive/index';\r\nimport { DANGEROUS_PROTOCOLS } from '../security/constants';\r\nimport { sanitizeHtml } from '../security/sanitize';\r\nimport type { BindingContext } from '../view/types';\r\nimport type { RenderOptions, SSRResult } from './types';\r\nimport { serializeStoreState } from './serialize';\r\n\r\nconst VOID_ELEMENTS = new Set([\r\n 'area',\r\n 'base',\r\n 'br',\r\n 'col',\r\n 'embed',\r\n 'hr',\r\n 'img',\r\n 'input',\r\n 'link',\r\n 'meta',\r\n 'param',\r\n 'source',\r\n 'track',\r\n 'wbr',\r\n]);\r\n\r\nconst escapeHtmlText = (value: string): string =>\r\n value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\r\n\r\nconst escapeHtmlAttribute = (value: string): string =>\r\n escapeHtmlText(value).replace(/\"/g, '&quot;');\r\n\r\nconst isUnsafeUrlAttribute = (name: string): boolean => {\r\n const normalized = name.toLowerCase();\r\n return (\r\n normalized === 'href' ||\r\n normalized === 'src' ||\r\n normalized === 'xlink:href' ||\r\n normalized === 'formaction' ||\r\n normalized === 'action' ||\r\n normalized === 'poster' ||\r\n normalized === 'background' ||\r\n normalized === 'cite' ||\r\n normalized === 'data'\r\n );\r\n};\r\n\r\nconst sanitizeUrlForProtocolCheck = (value: string): string =>\r\n value\r\n .trim()\r\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\r\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\r\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\r\n .replace(/\\s+/g, '')\r\n .toLowerCase();\r\n\r\nconst isUnsafeUrlValue = (value: string): boolean => {\r\n const normalized = sanitizeUrlForProtocolCheck(value);\r\n return DANGEROUS_PROTOCOLS.some((protocol) => normalized.startsWith(protocol));\r\n};\r\n\r\nconst serializeSSRNode = (node: Node): string => {\r\n if (node.nodeType === Node.TEXT_NODE) {\r\n return escapeHtmlText(node.textContent ?? '');\r\n }\r\n\r\n if (node.nodeType !== Node.ELEMENT_NODE) {\r\n return '';\r\n }\r\n\r\n const el = node as Element;\r\n const tagName = el.tagName.toLowerCase();\r\n\r\n if (tagName === 'script') {\r\n return '';\r\n }\r\n\r\n let attrs = '';\r\n for (const attr of el.attributes) {\r\n const attrName = attr.name.toLowerCase();\r\n if (attrName.startsWith('on')) {\r\n continue;\r\n }\r\n if (isUnsafeUrlAttribute(attrName) && isUnsafeUrlValue(attr.value)) {\r\n continue;\r\n }\r\n attrs += ` ${attr.name}=\"${escapeHtmlAttribute(attr.value)}\"`;\r\n }\r\n\r\n if (VOID_ELEMENTS.has(tagName)) {\r\n return `<${tagName}${attrs}>`;\r\n }\r\n\r\n let childrenHtml = '';\r\n for (const child of el.childNodes) {\r\n childrenHtml += serializeSSRNode(child);\r\n }\r\n\r\n return `<${tagName}${attrs}>${childrenHtml}</${tagName}>`;\r\n};\r\n\r\n/**\r\n * Unwraps a value — if it's a signal/computed, returns `.value`, otherwise returns as-is.\r\n * @internal\r\n */\r\nconst unwrap = (value: unknown): unknown => {\r\n if (isSignal(value) || isComputed(value)) {\r\n return (value as Signal<unknown>).value;\r\n }\r\n return value;\r\n};\r\n\r\n/**\r\n * Evaluates a simple expression against a context.\r\n * Supports dot-notation property access, negation, ternary, and basic comparisons.\r\n * Unlike the view module's `evaluate()`, this does NOT use `new Function()` —\r\n * it uses a safe subset for SSR to avoid `unsafe-eval` in server environments.\r\n *\r\n * Falls back to `new Function()` for complex expressions.\r\n *\r\n * @internal\r\n */\r\nconst evaluateSSR = <T = unknown>(expression: string, context: BindingContext): T => {\r\n const trimmed = expression.trim();\r\n\r\n // Handle negation: !expr\r\n if (trimmed.startsWith('!')) {\r\n return !evaluateSSR(trimmed.slice(1).trim(), context) as T;\r\n }\r\n\r\n // Handle string literals\r\n if (\r\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) ||\r\n (trimmed.startsWith('\"') && trimmed.endsWith('\"'))\r\n ) {\r\n return trimmed.slice(1, -1) as T;\r\n }\r\n\r\n // Handle numeric literals\r\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\r\n return Number(trimmed) as T;\r\n }\r\n\r\n // Handle boolean literals\r\n if (trimmed === 'true') return true as T;\r\n if (trimmed === 'false') return false as T;\r\n if (trimmed === 'null') return null as T;\r\n if (trimmed === 'undefined') return undefined as T;\r\n\r\n // Handle dot-notation property access: a.b.c\r\n if (/^[\\w$]+(?:\\.[\\w$]+)*$/.test(trimmed)) {\r\n const parts = trimmed.split('.');\r\n let current: unknown = context;\r\n for (const part of parts) {\r\n if (current == null) return undefined as T;\r\n // First level: unwrap signals\r\n if (current === context) {\r\n current = unwrap((current as Record<string, unknown>)[part]);\r\n } else {\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n }\r\n return current as T;\r\n }\r\n\r\n // For complex expressions, fall back to Function-based evaluation\r\n try {\r\n const keys = Object.keys(context);\r\n const values = keys.map((k) => unwrap(context[k]));\r\n const fn = new Function(...keys, `return (${trimmed});`);\r\n return fn(...values) as T;\r\n } catch {\r\n return undefined as T;\r\n }\r\n};\r\n\r\n/**\r\n * Parses a `bq-for` expression like `item in items` or `(item, index) in items`.\r\n * @internal\r\n */\r\nconst parseForExpression = (\r\n expression: string\r\n): { itemName: string; indexName?: string; listExpr: string } | null => {\r\n const match = expression.match(/^\\(?(\\w+)(?:\\s*,\\s*(\\w+))?\\)?\\s+in\\s+(\\S.*)$/);\r\n if (!match) return null;\r\n return {\r\n itemName: match[1],\r\n indexName: match[2] || undefined,\r\n listExpr: match[3].trim(),\r\n };\r\n};\r\n\r\n/**\r\n * Processes an element's SSR directives, modifying it in place.\r\n * Returns `false` if the element should be removed from output (bq-if = false).\r\n * @internal\r\n */\r\nconst processSSRElement = (\r\n el: Element,\r\n context: BindingContext,\r\n prefix: string,\r\n doc: Document\r\n): boolean => {\r\n // Handle bq-if: remove element if condition is falsy\r\n const ifExpr = el.getAttribute(`${prefix}-if`);\r\n if (ifExpr !== null) {\r\n const condition = evaluateSSR<boolean>(ifExpr, context);\r\n if (!condition) {\r\n return false; // Signal to remove this element\r\n }\r\n }\r\n\r\n // Handle bq-show: set display:none if falsy\r\n const showExpr = el.getAttribute(`${prefix}-show`);\r\n if (showExpr !== null) {\r\n const condition = evaluateSSR<boolean>(showExpr, context);\r\n if (!condition) {\r\n const htmlEl = el as unknown as { style?: { display?: string } };\r\n if (htmlEl.style) {\r\n htmlEl.style.display = 'none';\r\n } else {\r\n el.setAttribute('style', 'display: none;');\r\n }\r\n }\r\n }\r\n\r\n // Handle bq-text: set text content\r\n const textExpr = el.getAttribute(`${prefix}-text`);\r\n if (textExpr !== null) {\r\n const value = evaluateSSR(textExpr, context);\r\n el.textContent = String(value ?? '');\r\n }\r\n\r\n // Handle bq-html: sanitize to match client-side default behavior\r\n const htmlExpr = el.getAttribute(`${prefix}-html`);\r\n if (htmlExpr !== null) {\r\n const value = evaluateSSR(htmlExpr, context);\r\n el.innerHTML = String(sanitizeHtml(String(value ?? '')));\r\n }\r\n\r\n // Handle bq-class: add classes\r\n const classExpr = el.getAttribute(`${prefix}-class`);\r\n if (classExpr !== null) {\r\n const trimmedClass = classExpr.trim();\r\n if (trimmedClass.startsWith('{')) {\r\n // Object syntax: { active: isActive, disabled: !enabled }\r\n const inner = trimmedClass.slice(1, -1).trim();\r\n const pairs = inner.split(',');\r\n for (const pair of pairs) {\r\n const colonIdx = pair.indexOf(':');\r\n if (colonIdx > -1) {\r\n const className = pair\r\n .slice(0, colonIdx)\r\n .trim()\r\n .replace(/^['\"]|['\"]$/g, '');\r\n const condExpr = pair.slice(colonIdx + 1).trim();\r\n const condition = evaluateSSR<boolean>(condExpr, context);\r\n if (condition) {\r\n el.classList.add(className);\r\n }\r\n }\r\n }\r\n } else {\r\n const result = evaluateSSR<string | string[]>(classExpr, context);\r\n if (typeof result === 'string') {\r\n result\r\n .split(/\\s+/)\r\n .filter(Boolean)\r\n .forEach((cls) => el.classList.add(cls));\r\n } else if (Array.isArray(result)) {\r\n result.filter(Boolean).forEach((cls) => el.classList.add(cls));\r\n }\r\n }\r\n }\r\n\r\n // Handle bq-style: set inline styles\r\n const styleExpr = el.getAttribute(`${prefix}-style`);\r\n if (styleExpr !== null) {\r\n const result = evaluateSSR<Record<string, string>>(styleExpr, context);\r\n if (result && typeof result === 'object') {\r\n const htmlEl = el as HTMLElement;\r\n for (const [prop, val] of Object.entries(result)) {\r\n // Convert camelCase to kebab-case\r\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\r\n htmlEl.style.setProperty(cssProp, String(val));\r\n }\r\n }\r\n }\r\n\r\n // Handle bq-bind:attr — set arbitrary attributes\r\n const attrs = Array.from(el.attributes);\r\n for (const attr of attrs) {\r\n if (attr.name.startsWith(`${prefix}-bind:`)) {\r\n const attrName = attr.name.slice(`${prefix}-bind:`.length);\r\n const value = evaluateSSR(attr.value, context);\r\n if (value === false || value === null || value === undefined) {\r\n el.removeAttribute(attrName);\r\n } else if (value === true) {\r\n el.setAttribute(attrName, '');\r\n } else {\r\n el.setAttribute(attrName, String(value));\r\n }\r\n }\r\n }\r\n\r\n // Handle bq-for: list rendering\r\n const forExpr = el.getAttribute(`${prefix}-for`);\r\n if (forExpr !== null) {\r\n const parsed = parseForExpression(forExpr);\r\n if (parsed) {\r\n const list = evaluateSSR<unknown[]>(parsed.listExpr, context);\r\n if (Array.isArray(list) && el.parentNode) {\r\n const parent = el.parentNode;\r\n for (let i = 0; i < list.length; i++) {\r\n const item = list[i];\r\n const clone = el.cloneNode(true) as Element;\r\n\r\n // Remove the bq-for attribute from clones\r\n clone.removeAttribute(`${prefix}-for`);\r\n clone.removeAttribute(':key');\r\n clone.removeAttribute(`${prefix}-key`);\r\n\r\n // Create item context\r\n const itemContext: BindingContext = {\r\n ...context,\r\n [parsed.itemName]: item,\r\n };\r\n if (parsed.indexName) {\r\n itemContext[parsed.indexName] = i;\r\n }\r\n\r\n // Recursively process the clone\r\n processSSRElement(clone, itemContext, prefix, doc);\r\n processSSRChildren(clone, itemContext, prefix, doc);\r\n\r\n parent.insertBefore(clone, el);\r\n }\r\n\r\n // Remove the original template element\r\n parent.removeChild(el);\r\n return true; // Already handled children\r\n }\r\n }\r\n }\r\n\r\n return true;\r\n};\r\n\r\n/**\r\n * Recursively processes children of an element for SSR.\r\n * @internal\r\n */\r\nconst processSSRChildren = (\r\n parent: Element,\r\n context: BindingContext,\r\n prefix: string,\r\n doc: Document\r\n): void => {\r\n // Process children in reverse to handle removals safely\r\n const children = Array.from(parent.children);\r\n for (const child of children) {\r\n // Skip bq-for elements — they're handled by parent\r\n if (child.hasAttribute(`${prefix}-for`)) {\r\n // Process the for directive on this element\r\n const keep = processSSRElement(child, context, prefix, doc);\r\n if (!keep) {\r\n child.remove();\r\n }\r\n continue;\r\n }\r\n\r\n const keep = processSSRElement(child, context, prefix, doc);\r\n if (!keep) {\r\n child.remove();\r\n continue;\r\n }\r\n\r\n // Recurse into children\r\n processSSRChildren(child, context, prefix, doc);\r\n }\r\n};\r\n\r\n/**\r\n * Strips all directive attributes (bq-*) from an element and its descendants.\r\n * @internal\r\n */\r\nconst stripDirectiveAttributes = (el: Element, prefix: string): void => {\r\n // Remove directive attributes from this element\r\n const attrs = Array.from(el.attributes);\r\n for (const attr of attrs) {\r\n if (attr.name.startsWith(`${prefix}-`) || attr.name.startsWith(':') || attr.name === ':key') {\r\n el.removeAttribute(attr.name);\r\n }\r\n }\r\n\r\n // Recurse into children\r\n for (const child of Array.from(el.children)) {\r\n stripDirectiveAttributes(child, prefix);\r\n }\r\n};\r\n\r\n/**\r\n * Server-side renders a bQuery template to an HTML string.\r\n *\r\n * Takes an HTML template with bQuery directives (bq-text, bq-if, bq-for, etc.)\r\n * and a data context, then evaluates the directives to produce a static HTML string.\r\n * This HTML can be sent to the client and later hydrated with `mount()` using\r\n * `{ hydrate: true }`.\r\n *\r\n * Supported directives:\r\n * - `bq-text` — Sets text content\r\n * - `bq-html` — Sets innerHTML\r\n * - `bq-if` — Conditional rendering (removes element if falsy)\r\n * - `bq-show` — Toggle visibility via `display: none`\r\n * - `bq-class` — Dynamic class binding (object or expression syntax)\r\n * - `bq-style` — Dynamic inline styles\r\n * - `bq-for` — List rendering\r\n * - `bq-bind:attr` — Dynamic attribute binding\r\n *\r\n * @param template - HTML template string with bq-* directives\r\n * @param data - Plain data object (signals will be unwrapped automatically)\r\n * @param options - Rendering options\r\n * @returns SSR result with HTML string and optional store state\r\n *\r\n * @example\r\n * ```ts\r\n * import { renderToString } from '@bquery/bquery/ssr';\r\n * import { signal } from '@bquery/bquery/reactive';\r\n *\r\n * const result = renderToString(\r\n * '<div><h1 bq-text=\"title\"></h1><p bq-if=\"showBody\">Hello!</p></div>',\r\n * { title: 'Welcome', showBody: true }\r\n * );\r\n *\r\n * console.log(result.html);\r\n * // '<div><h1>Welcome</h1><p>Hello!</p></div>'\r\n * ```\r\n *\r\n * @example\r\n * ```ts\r\n * // With bq-for list rendering\r\n * const result = renderToString(\r\n * '<ul><li bq-for=\"item in items\" bq-text=\"item.name\"></li></ul>',\r\n * { items: [{ name: 'Alice' }, { name: 'Bob' }] }\r\n * );\r\n *\r\n * console.log(result.html);\r\n * // '<ul><li>Alice</li><li>Bob</li></ul>'\r\n * ```\r\n */\r\nexport const renderToString = (\r\n template: string,\r\n data: BindingContext,\r\n options: RenderOptions = {}\r\n): SSRResult => {\r\n const { prefix = 'bq', stripDirectives = false, includeStoreState = false } = options;\r\n\r\n if (!template || typeof template !== 'string') {\r\n throw new Error('bQuery SSR: template must be a non-empty string.');\r\n }\r\n\r\n if (typeof DOMParser === 'undefined') {\r\n throw new Error(\r\n 'bQuery SSR: DOMParser is not available in this environment. Provide a DOMParser-compatible implementation before calling renderToString().'\r\n );\r\n }\r\n\r\n // Create a DOM document for processing\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(template.trim(), 'text/html');\r\n const body = doc.body || doc.documentElement;\r\n\r\n if (!body) {\r\n throw new Error('bQuery SSR: Failed to parse template.');\r\n }\r\n\r\n // Process all children of the body\r\n processSSRChildren(body, data, prefix, doc);\r\n\r\n // Strip directive attributes if requested\r\n if (stripDirectives) {\r\n for (const child of Array.from(body.children)) {\r\n stripDirectiveAttributes(child, prefix);\r\n }\r\n }\r\n\r\n let html = '';\r\n for (const child of body.childNodes) {\r\n html += serializeSSRNode(child);\r\n }\r\n\r\n // Handle store state serialization\r\n let storeState: string | undefined;\r\n if (includeStoreState) {\r\n const storeIds = Array.isArray(includeStoreState) ? includeStoreState : undefined;\r\n storeState = serializeStoreState({ storeIds }).stateJson;\r\n }\r\n\r\n return { html, storeState };\r\n};\r\n"],"mappings":"kRASA,IAAa,GAAc,mBAKd,GAAuB,IAAI,IAAI,CAC1C,IACA,OACA,UACA,UACA,QACA,IACA,MACA,MACA,aACA,KACA,SACA,UACA,OACA,OACA,MACA,WACA,OACA,KACA,MACA,UACA,MACA,MACA,KACA,KACA,KACA,aACA,SACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,SACA,SACA,KACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,OACA,MACA,KACA,WACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,UACA,SACA,QACA,SACA,OACA,SACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,QACA,KACA,QACA,OACA,KACA,IACA,KACA,MACA,MACD,EAMY,GAAiB,IAAI,IAAI,CACpC,SACA,SACA,QACA,WACA,SACA,QACA,SACA,OACA,OACA,QACA,OACA,WAIA,OACA,MACA,gBACA,WACD,EAMY,GAAe,IAAI,IAAI,CAElC,WACA,SACA,WACA,MACA,OACA,SACA,SACA,UACA,YACA,SAEA,QACA,UACA,SACA,OACA,WAEA,SACA,SACA,WACA,OACA,OACA,QACA,SACA,QACA,UAEA,WACA,aACA,aACA,YAEA,YACA,YACA,cACD,EAWY,GAA6B,IAAI,IAAI,CAChD,MACA,QACA,MACA,SACA,SACA,OACA,KACA,OACA,UACA,OACA,MACA,OACA,MACA,SACA,WACA,SACA,QACA,OACA,QACA,SACD,EAKY,GAA0B,CAAC,KAAM,aAAc,SAAU,UAKzD,GAAsB,CAAC,cAAe,QAAS,YAAa,SC7LnE,GAAA,CACJ,EACA,EACA,IACY,CACZ,MAAM,EAAY,EAAK,YAAA,EAGvB,UAAW,KAAU,GACnB,GAAI,EAAU,WAAW,CAAA,EAAS,MAAO,GAO3C,OAHI,GAAkB,EAAU,WAAW,OAAA,GAGvC,EAAU,WAAW,OAAA,EAAiB,GAGnC,EAAW,IAAI,CAAA,GAOlB,GAAkB,GAA2B,CACjD,MAAM,EAAa,EAAM,YAAA,EAAc,KAAA,EACvC,MAAO,CAA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"}
1
+ {"version":3,"file":"full.umd.js","names":[],"sources":["../src/security/constants.ts","../src/security/sanitize-core.ts","../src/security/trusted-html.ts","../src/security/csp.ts","../src/security/trusted-types.ts","../src/security/sanitize.ts","../src/core/shared.ts","../src/core/dom.ts","../src/core/utils/object.ts","../src/core/element.ts","../src/core/collection.ts","../src/core/selector.ts","../src/core/utils/array.ts","../src/core/utils/function.ts","../src/core/utils/misc.ts","../src/core/utils/number.ts","../src/core/utils/string.ts","../src/core/utils/type-guards.ts","../src/core/utils/index.ts","../src/reactive/internals.ts","../src/reactive/batch.ts","../src/platform/config.ts","../src/reactive/scope.ts","../src/reactive/computed.ts","../src/reactive/effect.ts","../src/reactive/core.ts","../src/reactive/untrack.ts","../src/reactive/async-data.ts","../src/reactive/http.ts","../src/reactive/linked.ts","../src/reactive/pagination.ts","../src/reactive/persisted.ts","../src/reactive/polling.ts","../src/reactive/readonly.ts","../src/reactive/rest.ts","../src/reactive/type-guards.ts","../src/reactive/to-value.ts","../src/reactive/watch.ts","../src/reactive/websocket.ts","../src/component/props.ts","../src/core/env.ts","../src/component/scope.ts","../src/component/component.ts","../src/component/html.ts","../src/component/library.ts","../src/motion/reduced-motion.ts","../src/motion/animate.ts","../src/motion/easing.ts","../src/motion/flip.ts","../src/motion/keyframes.ts","../src/motion/morph.ts","../src/motion/parallax.ts","../src/motion/scroll.ts","../src/motion/spring.ts","../src/motion/stagger.ts","../src/motion/timeline.ts","../src/motion/transition.ts","../src/motion/typewriter.ts","../src/platform/buckets.ts","../src/platform/cache.ts","../src/platform/cookies.ts","../src/platform/notifications.ts","../src/platform/announcer.ts","../src/platform/meta.ts","../src/platform/storage.ts","../src/router/state.ts","../src/router/navigation.ts","../src/router/bq-link.ts","../src/router/links.ts","../src/router/query.ts","../src/router/constraints.ts","../src/router/path-pattern.ts","../src/router/match.ts","../src/router/utils.ts","../src/router/router.ts","../src/router/use-route.ts","../src/store/devtools.ts","../src/store/plugins.ts","../src/store/registry.ts","../src/store/utils.ts","../src/store/create-store.ts","../src/store/define-store.ts","../src/store/mapping.ts","../src/store/persisted.ts","../src/store/watch.ts","../src/view/evaluate.ts","../src/view/directives/bind.ts","../src/view/directives/class.ts","../src/view/directives/for.ts","../src/view/directives/html.ts","../src/view/directives/if.ts","../src/view/directives/model.ts","../src/view/directives/on.ts","../src/view/directives/ref.ts","../src/view/directives/show.ts","../src/view/directives/style.ts","../src/view/directives/text.ts","../src/view/custom-directives.ts","../src/view/process.ts","../src/view/mount.ts","../src/forms/create-form.ts","../src/forms/use-field.ts","../src/forms/validators.ts","../src/i18n/formatting.ts","../src/i18n/translate.ts","../src/i18n/i18n.ts","../src/a11y/announce.ts","../src/a11y/audit.ts","../src/a11y/media-preferences.ts","../src/a11y/roving-tab-index.ts","../src/a11y/skip-link.ts","../src/a11y/trap-focus.ts","../src/dnd/draggable.ts","../src/dnd/droppable.ts","../src/dnd/sortable.ts","../src/media/media-query.ts","../src/media/breakpoints.ts","../src/media/viewport.ts","../src/media/network.ts","../src/media/battery.ts","../src/media/geolocation.ts","../src/media/device-sensors.ts","../src/media/clipboard.ts","../src/plugin/registry.ts","../src/devtools/devtools.ts","../src/testing/testing.ts","../src/ssr/hydrate.ts","../src/ssr/serialize.ts","../src/ssr/render.ts"],"sourcesContent":["/**\n * Security constants and safe lists.\n *\n * @module bquery/security\n */\n\n/**\n * Trusted Types policy name.\n */\nexport const POLICY_NAME = 'bquery-sanitizer';\n\n/**\n * Default allowed HTML tags considered safe.\n */\nexport const DEFAULT_ALLOWED_TAGS = new Set([\n 'a',\n 'abbr',\n 'address',\n 'article',\n 'aside',\n 'b',\n 'bdi',\n 'bdo',\n 'blockquote',\n 'br',\n 'button',\n 'caption',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'data',\n 'dd',\n 'del',\n 'details',\n 'dfn',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hgroup',\n 'hr',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'mark',\n 'nav',\n 'ol',\n 'optgroup',\n 'option',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'small',\n 'source',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'u',\n 'ul',\n 'var',\n 'wbr',\n]);\n\n/**\n * Explicitly dangerous tags that should never be allowed.\n * These are checked even if somehow added to allowTags.\n */\nexport const DANGEROUS_TAGS = new Set([\n 'script',\n 'iframe',\n 'frame',\n 'frameset',\n 'object',\n 'embed',\n 'applet',\n 'link',\n 'meta',\n 'style',\n 'base',\n 'template',\n // 'slot' is intentionally excluded here so component shadow markup can opt in\n // via sanitizeHtml(..., { allowTags: ['slot'] }). It remains disallowed by default\n // for general HTML writes, because DEFAULT_ALLOWED_TAGS does not include it.\n 'math',\n 'svg',\n 'foreignobject',\n 'noscript',\n]);\n\n/**\n * Reserved IDs that could cause DOM clobbering attacks.\n * These are prevented to avoid overwriting global browser objects.\n */\nexport const RESERVED_IDS = new Set([\n // Global objects\n 'document',\n 'window',\n 'location',\n 'top',\n 'self',\n 'parent',\n 'frames',\n 'history',\n 'navigator',\n 'screen',\n // Dangerous functions\n 'alert',\n 'confirm',\n 'prompt',\n 'eval',\n 'function',\n // Document properties\n 'cookie',\n 'domain',\n 'referrer',\n 'body',\n 'head',\n 'forms',\n 'images',\n 'links',\n 'scripts',\n // DOM traversal properties\n 'children',\n 'parentnode',\n 'firstchild',\n 'lastchild',\n // Content manipulation\n 'innerhtml',\n 'outerhtml',\n 'textcontent',\n]);\n\n/**\n * Default allowed attributes considered safe.\n * Note: 'style' is excluded by default because inline CSS can be abused for:\n * - UI redressing attacks\n * - Data exfiltration via url() in CSS\n * - CSS injection vectors\n * If you need to allow inline styles, add 'style' to allowAttributes in your\n * sanitizeHtml options, but ensure you implement proper CSS value validation.\n */\nexport const DEFAULT_ALLOWED_ATTRIBUTES = new Set([\n 'alt',\n 'class',\n 'dir',\n 'height',\n 'hidden',\n 'href',\n 'id',\n 'lang',\n 'loading',\n 'name',\n 'rel',\n 'role',\n 'src',\n 'srcset',\n 'tabindex',\n 'target',\n 'title',\n 'type',\n 'width',\n 'aria-*',\n]);\n\n/**\n * Dangerous attribute prefixes to always remove.\n */\nexport const DANGEROUS_ATTR_PREFIXES = ['on', 'formaction', 'xlink:', 'xmlns:'];\n\n/**\n * Dangerous URL protocols to block.\n */\nexport const DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'file:'];\n","/**\n * Core HTML sanitization logic.\n *\n * @module bquery/security\n * @internal\n */\n\nimport {\n DANGEROUS_ATTR_PREFIXES,\n DANGEROUS_PROTOCOLS,\n DANGEROUS_TAGS,\n DEFAULT_ALLOWED_ATTRIBUTES,\n DEFAULT_ALLOWED_TAGS,\n RESERVED_IDS,\n} from './constants';\nimport type { SanitizeOptions } from './types';\n\n/**\n * Check if an attribute name is allowed.\n * @internal\n */\nconst isAllowedAttribute = (\n name: string,\n allowedSet: Set<string>,\n allowDataAttrs: boolean\n): boolean => {\n const lowerName = name.toLowerCase();\n\n // Check dangerous prefixes\n for (const prefix of DANGEROUS_ATTR_PREFIXES) {\n if (lowerName.startsWith(prefix)) return false;\n }\n\n // Check data attributes\n if (allowDataAttrs && lowerName.startsWith('data-')) return true;\n\n // Check aria attributes (allowed by default)\n if (lowerName.startsWith('aria-')) return true;\n\n // Check explicit allow list\n return allowedSet.has(lowerName);\n};\n\n/**\n * Check if an ID/name value could cause DOM clobbering.\n * @internal\n */\nconst isSafeIdOrName = (value: string): boolean => {\n const lowerValue = value.toLowerCase().trim();\n return !RESERVED_IDS.has(lowerValue);\n};\n\n/**\n * Normalize URL by removing control characters, whitespace, and Unicode tricks.\n * Enhanced to prevent various bypass techniques.\n * @internal\n */\nconst normalizeUrl = (value: string): string =>\n value\n // Remove null bytes and control characters\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\n // Remove zero-width characters that could hide malicious content\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\n // Remove escaped Unicode sequences\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\n // Remove whitespace\n .replace(/\\s+/g, '')\n // Normalize case\n .toLowerCase();\n\n/**\n * Check if a URL value is safe.\n * @internal\n */\nconst isSafeUrl = (value: string): boolean => {\n const normalized = normalizeUrl(value);\n for (const protocol of DANGEROUS_PROTOCOLS) {\n if (normalized.startsWith(protocol)) return false;\n }\n return true;\n};\n\n/**\n * Check if a srcset attribute value is safe.\n * srcset contains comma-separated entries of \"url [descriptor]\".\n * Each individual URL must be validated.\n * @internal\n */\nconst isSafeSrcset = (value: string): boolean => {\n const entries = value.split(',');\n for (const entry of entries) {\n const url = entry.trim().split(/\\s+/)[0];\n if (url && !isSafeUrl(url)) return false;\n }\n return true;\n};\n\n/**\n * Check if a URL is external (different origin).\n * @internal\n */\nconst isExternalUrl = (url: string): boolean => {\n try {\n // Normalize URL by trimming whitespace\n const trimmedUrl = url.trim();\n\n // Protocol-relative URLs (//example.com) are always external.\n // CRITICAL: This check must run before the relative-URL check below;\n // otherwise, a protocol-relative URL like \"//evil.com\" would be treated\n // as a non-http(s) relative URL and incorrectly classified as same-origin.\n // Handling them up front guarantees correct security classification.\n if (trimmedUrl.startsWith('//')) {\n return true;\n }\n\n // Normalize URL for case-insensitive protocol checks\n const lowerUrl = trimmedUrl.toLowerCase();\n\n // Check for non-http(s) protocols which are considered external/special\n // (mailto:, tel:, ftp:, etc.)\n const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmedUrl);\n if (hasProtocol && !lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\n // These are special protocols, not traditional \"external\" links\n // but we treat them as external for security consistency\n return true;\n }\n\n // Relative URLs are not external\n if (!lowerUrl.startsWith('http://') && !lowerUrl.startsWith('https://')) {\n return false;\n }\n\n // In non-browser environments (e.g., Node.js), treat all absolute URLs as external\n if (typeof window === 'undefined' || !window.location) {\n return true;\n }\n\n const urlObj = new URL(trimmedUrl, window.location.href);\n return urlObj.origin !== window.location.origin;\n } catch {\n // If URL parsing fails, treat as potentially external for safety\n return true;\n }\n};\n\n/**\n * Parse an HTML string into a Document using DOMParser.\n * This helper is intentionally separated to make the control-flow around HTML parsing\n * explicit for static analysis tools. It should ONLY be called when the input is\n * known to contain HTML syntax (angle brackets).\n *\n * DOMParser creates an inert document where scripts don't execute, making it safe\n * for parsing untrusted HTML that will subsequently be sanitized.\n *\n * @param htmlContent - A string that is known to contain HTML markup (has < or >)\n * @returns The parsed Document\n * @internal\n */\nconst parseHtmlDocument = (htmlContent: string): Document => {\n const parser = new DOMParser();\n // Parse as a full HTML document in an inert context; scripts won't execute\n return parser.parseFromString(htmlContent, 'text/html');\n};\n\n/**\n * Safely parse HTML string into a DocumentFragment using DOMParser.\n * DOMParser is preferred over innerHTML for security as it creates an inert document\n * where scripts don't execute and provides better static analysis recognition.\n *\n * This function includes input normalization to satisfy static analysis tools:\n * - Coerces input to string and trims whitespace\n * - For plain text (no HTML tags), creates a Text node directly without parsing\n * - Only invokes DOMParser for actual HTML-like content via parseHtmlDocument\n *\n * The separation between plain text handling and HTML parsing is intentional:\n * DOM text that contains no HTML syntax is never fed into an HTML parser,\n * preventing \"DOM text reinterpreted as HTML\" issues.\n *\n * @internal\n */\nconst parseHtmlSafely = (html: string): DocumentFragment => {\n // Step 1: Normalize input - coerce to string and trim\n // This defensive check handles edge cases even though TypeScript says it's a string\n const normalizedHtml = (typeof html === 'string' ? html : String(html ?? '')).trim();\n\n // Step 2: Create the fragment that will hold our result\n const fragment = document.createDocumentFragment();\n\n // Step 3: Early return for empty input\n if (normalizedHtml.length === 0) {\n return fragment;\n }\n\n // Step 4: If input contains no angle brackets, it's plain text - no HTML parsing needed.\n // Plain text is handled as a Text node, never passed to an HTML parser.\n // This explicitly prevents \"DOM text reinterpreted as HTML\" for purely textual inputs.\n const containsHtmlSyntax = normalizedHtml.includes('<') || normalizedHtml.includes('>');\n if (!containsHtmlSyntax) {\n fragment.appendChild(document.createTextNode(normalizedHtml));\n return fragment;\n }\n\n // Step 5: Input contains HTML syntax - parse it via the dedicated HTML parsing helper.\n // This separation makes the data-flow explicit: only strings with HTML syntax\n // are passed to DOMParser, satisfying static analysis requirements.\n const doc = parseHtmlDocument(normalizedHtml);\n\n // Move all children from the document body into the fragment.\n // This avoids interpolating untrusted HTML into an outer wrapper string.\n const body = doc.body;\n\n if (!body) {\n return fragment;\n }\n\n while (body.firstChild) {\n fragment.appendChild(body.firstChild);\n }\n\n return fragment;\n};\n\n/**\n * Core sanitization logic (without Trusted Types wrapper).\n * @internal\n */\nexport const sanitizeHtmlCore = (html: string, options: SanitizeOptions = {}): string => {\n const {\n allowTags = [],\n allowAttributes = [],\n allowDataAttributes = true,\n stripAllTags = false,\n } = options;\n\n // Build combined allow sets (excluding dangerous tags even if specified)\n const allowedTags = new Set(\n [...DEFAULT_ALLOWED_TAGS, ...allowTags.map((t) => t.toLowerCase())].filter(\n (tag) => !DANGEROUS_TAGS.has(tag)\n )\n );\n const allowedAttrs = new Set([\n ...DEFAULT_ALLOWED_ATTRIBUTES,\n ...allowAttributes.map((a) => a.toLowerCase()),\n ]);\n\n // Use DOMParser for safe HTML parsing (inert context, no script execution)\n const fragment = parseHtmlSafely(html);\n\n if (stripAllTags) {\n return fragment.textContent ?? '';\n }\n\n // Walk the DOM tree\n const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_ELEMENT);\n\n const toRemove: Element[] = [];\n\n while (walker.nextNode()) {\n const el = walker.currentNode as Element;\n const tagName = el.tagName.toLowerCase();\n\n // Remove explicitly dangerous tags even if in allow list\n if (DANGEROUS_TAGS.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // Remove disallowed tags entirely\n if (!allowedTags.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // Process attributes\n const attrsToRemove: string[] = [];\n for (const attr of Array.from(el.attributes)) {\n const attrName = attr.name.toLowerCase();\n\n // Check if attribute is allowed\n if (!isAllowedAttribute(attrName, allowedAttrs, allowDataAttributes)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Check for DOM clobbering on id and name attributes\n if ((attrName === 'id' || attrName === 'name') && !isSafeIdOrName(attr.value)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Validate URL attributes\n if (\n (attrName === 'href' || attrName === 'src' || attrName === 'action') &&\n !isSafeUrl(attr.value)\n ) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // Validate srcset URLs individually\n if (attrName === 'srcset' && !isSafeSrcset(attr.value)) {\n attrsToRemove.push(attr.name);\n }\n }\n\n // Remove disallowed attributes\n for (const attrName of attrsToRemove) {\n el.removeAttribute(attrName);\n }\n\n // Add rel=\"noopener noreferrer\" to external links for security\n if (tagName === 'a') {\n const href = el.getAttribute('href');\n const target = el.getAttribute('target');\n const hasTargetBlank = target?.toLowerCase() === '_blank';\n const isExternal = href && isExternalUrl(href);\n\n // Add security attributes to links opening in new window or external links\n if (hasTargetBlank || isExternal) {\n const existingRel = el.getAttribute('rel');\n const relValues = new Set(existingRel ? existingRel.split(/\\s+/).filter(Boolean) : []);\n\n // Add noopener and noreferrer\n relValues.add('noopener');\n relValues.add('noreferrer');\n\n el.setAttribute('rel', Array.from(relValues).join(' '));\n }\n }\n }\n\n // Remove disallowed elements\n for (const el of toRemove) {\n el.remove();\n }\n\n // Serialize the sanitized fragment to HTML string.\n // We use a temporary container to get the innerHTML of the fragment.\n const serializeFragment = (frag: DocumentFragment): string => {\n const container = document.createElement('div');\n container.appendChild(frag.cloneNode(true));\n return container.innerHTML;\n };\n\n // Double-parse to prevent mutation XSS (mXSS).\n // Browsers may normalize HTML during serialization in ways that could create\n // new dangerous content when re-parsed. By re-parsing the sanitized output\n // and verifying stability, we ensure the final HTML is safe.\n const firstPass = serializeFragment(fragment);\n\n // Re-parse through DOMParser for mXSS detection.\n // Using DOMParser instead of innerHTML for security.\n const verifyFragment = parseHtmlSafely(firstPass);\n const secondPass = serializeFragment(verifyFragment);\n\n // Verify stability: if content mutates between parses, it indicates mXSS attempt\n if (firstPass !== secondPass) {\n // Content mutated during re-parse - potential mXSS detected.\n // Return safely escaped text content as fallback.\n return fragment.textContent ?? '';\n }\n\n return secondPass;\n};\n","declare const sanitizedHtmlBrand: unique symbol;\nconst trustedHtmlBrand: unique symbol = Symbol('bquery.trusted-html.brand');\nconst TRUSTED_HTML_VALUE = Symbol('bquery.trusted-html');\n\n/**\n * Branded HTML string produced by bQuery's sanitization or escaping template helpers.\n *\n * Values returned from {@link sanitizeHtml} carry sanitized markup. Values returned from\n * {@link safeHtml} preserve the template's static markup while escaping normal interpolations\n * and splicing {@link trusted} fragments verbatim. This brand is not intended for arbitrary\n * strings or manual concatenation outside those helpers.\n */\nexport type SanitizedHtml = string & { readonly [sanitizedHtmlBrand]: true };\n\n/**\n * Marker object that safeHtml can splice into templates without escaping again.\n */\nexport type TrustedHtml = { readonly [trustedHtmlBrand]: true; toString(): string };\n\ntype TrustedHtmlValue = TrustedHtml & { readonly [TRUSTED_HTML_VALUE]: string };\n\n/**\n * Apply the internal {@link SanitizedHtml} brand to helper output.\n *\n * @internal\n */\nexport const toSanitizedHtml = (html: string): SanitizedHtml => html as SanitizedHtml;\n\n/**\n * Mark a sanitized HTML string for verbatim splicing into safeHtml templates.\n *\n * @param html - HTML previously produced by sanitizeHtml, safeHtml, or another trusted bQuery helper\n * @returns Trusted HTML marker object for safeHtml interpolations\n *\n * @example\n * ```ts\n * const badge = trusted(sanitizeHtml('<strong onclick=\"alert(1)\">New</strong>'));\n * const markup = safeHtml`<span>${badge}</span>`;\n * ```\n */\nexport const trusted = (html: SanitizedHtml): TrustedHtml => {\n const value = String(html);\n return Object.freeze({\n [trustedHtmlBrand]: true as const,\n [TRUSTED_HTML_VALUE]: value,\n toString: () => value,\n });\n};\n\n/**\n * Check whether a value is a trusted HTML marker created by trusted().\n *\n * @internal\n */\nexport const isTrustedHtml = (value: unknown): value is TrustedHtml => {\n return (\n typeof value === 'object' &&\n value !== null &&\n trustedHtmlBrand in value &&\n TRUSTED_HTML_VALUE in value\n );\n};\n\n/**\n * Unwrap the raw HTML string stored inside a trusted HTML marker.\n *\n * @internal\n */\nexport const unwrapTrustedHtml = (value: TrustedHtml): string => {\n return (value as TrustedHtmlValue)[TRUSTED_HTML_VALUE];\n};\n","/**\n * Content Security Policy helpers.\n *\n * @module bquery/security\n */\n\n/** Maximum allowed nonce length to prevent memory issues */\nconst MAX_NONCE_LENGTH = 1024;\n\n/** Chunk size for building strings to avoid argument limit in String.fromCharCode */\nconst CHUNK_SIZE = 8192;\n\n/**\n * Generate a nonce for inline scripts/styles.\n * Use with Content-Security-Policy nonce directives.\n *\n * @param length - Nonce length in bytes (default: 16, max: 1024)\n * @returns Cryptographically random nonce string\n * @throws {Error} If crypto.getRandomValues or btoa are not available\n * @throws {RangeError} If length is invalid (negative, non-integer, or exceeds maximum)\n */\nexport const generateNonce = (length: number = 16): string => {\n // Validate length parameter\n if (!Number.isInteger(length) || length < 1) {\n throw new RangeError('generateNonce length must be a positive integer');\n }\n if (length > MAX_NONCE_LENGTH) {\n throw new RangeError(`generateNonce length must not exceed ${MAX_NONCE_LENGTH}`);\n }\n\n // Check for required globals in browser/crypto environments\n if (\n typeof globalThis.crypto === 'undefined' ||\n typeof globalThis.crypto.getRandomValues !== 'function'\n ) {\n throw new Error(\n 'generateNonce requires crypto.getRandomValues (not available in this environment)'\n );\n }\n if (typeof globalThis.btoa !== 'function') {\n throw new Error('generateNonce requires btoa (not available in this environment)');\n }\n\n const array = new Uint8Array(length);\n globalThis.crypto.getRandomValues(array);\n\n // Build string in chunks to avoid argument limit in String.fromCharCode\n let binaryString = '';\n for (let i = 0; i < array.length; i += CHUNK_SIZE) {\n const chunk = array.subarray(i, Math.min(i + CHUNK_SIZE, array.length));\n binaryString += String.fromCharCode(...chunk);\n }\n\n return globalThis.btoa(binaryString).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n};\n\n/**\n * Check if a CSP header is present with specific directive.\n * Useful for feature detection and fallback strategies.\n *\n * @param directive - The CSP directive to check (e.g., 'script-src')\n * @returns True if the directive appears to be enforced\n */\nexport const hasCSPDirective = (directive: string): boolean => {\n // Guard for non-DOM environments (SSR, tests, etc.)\n if (typeof document === 'undefined') {\n return false;\n }\n\n // Check meta tag\n const meta = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\n if (meta) {\n const content = meta.getAttribute('content') ?? '';\n return content.includes(directive);\n }\n return false;\n};\n","/**\n * Trusted Types helpers for CSP compatibility.\n *\n * @module bquery/security\n */\n\nimport { POLICY_NAME } from './constants';\nimport { sanitizeHtmlCore } from './sanitize-core';\nimport type { TrustedHTML, TrustedTypePolicy, TrustedTypesWindow } from './types';\n\n/** Cached Trusted Types policy */\nlet cachedPolicy: TrustedTypePolicy | null = null;\n\n/** Whether policy initialization has been attempted (to avoid retry spam) */\nlet policyInitAttempted = false;\n\n/**\n * Check if Trusted Types API is available.\n * @returns True if Trusted Types are supported\n */\nexport const isTrustedTypesSupported = (): boolean => {\n return (\n typeof window !== 'undefined' &&\n typeof (window as TrustedTypesWindow).trustedTypes !== 'undefined'\n );\n};\n\n/**\n * Get or create the bQuery Trusted Types policy.\n * @returns The Trusted Types policy or null if unsupported\n */\nexport const getTrustedTypesPolicy = (): TrustedTypePolicy | null => {\n if (cachedPolicy) return cachedPolicy;\n if (policyInitAttempted) return null;\n\n if (typeof window === 'undefined') return null;\n\n const win = window as TrustedTypesWindow;\n if (!win.trustedTypes) return null;\n\n policyInitAttempted = true;\n\n try {\n cachedPolicy = win.trustedTypes.createPolicy(POLICY_NAME, {\n createHTML: (input: string) => sanitizeHtmlCore(input),\n });\n return cachedPolicy;\n } catch (error) {\n // Policy may already exist or be blocked by CSP\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.warn(`bQuery: Could not create Trusted Types policy \"${POLICY_NAME}\": ${errorMessage}`);\n return null;\n }\n};\n\n/**\n * Create a Trusted HTML value for use with Trusted Types-enabled sites.\n * Falls back to regular string when Trusted Types are unavailable.\n *\n * @param html - The HTML string to wrap\n * @returns Trusted HTML value or sanitized string\n */\nexport const createTrustedHtml = (html: string): TrustedHTML | string => {\n const policy = getTrustedTypesPolicy();\n if (policy) {\n return policy.createHTML(html);\n }\n return sanitizeHtmlCore(html);\n};\n","/**\n * Security utilities for HTML sanitization.\n * All DOM writes are sanitized by default to prevent XSS attacks.\n *\n * @module bquery/security\n */\n\nimport { sanitizeHtmlCore } from './sanitize-core';\nimport { toSanitizedHtml } from './trusted-html';\nimport type { SanitizedHtml } from './trusted-html';\nimport type { SanitizeOptions } from './types';\nexport { generateNonce } from './csp';\nexport { isTrustedTypesSupported } from './trusted-types';\nexport { trusted } from './trusted-html';\nexport type { SanitizedHtml, TrustedHtml } from './trusted-html';\n\n/**\n * Sanitize HTML string, removing dangerous elements and attributes.\n * Uses Trusted Types when available for CSP compliance.\n *\n * @param html - The HTML string to sanitize\n * @param options - Sanitization options\n * @returns Sanitized HTML string\n *\n * @example\n * ```ts\n * const safe = sanitizeHtml('<div onclick=\"alert(1)\">Hello</div>');\n * // Returns: '<div>Hello</div>'\n * ```\n */\nexport const sanitizeHtml = (html: string, options: SanitizeOptions = {}): SanitizedHtml => {\n return toSanitizedHtml(sanitizeHtmlCore(html, options));\n};\n\n/**\n * Escape HTML entities to prevent XSS.\n * Use this for displaying user content as text.\n *\n * @param text - The text to escape\n * @returns Escaped HTML string\n *\n * @example\n * ```ts\n * escapeHtml('<script>alert(1)</script>');\n * // Returns: '&lt;script&gt;alert(1)&lt;/script&gt;'\n * ```\n */\nexport const escapeHtml = (text: string): string => {\n const escapeMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n '`': '&#x60;',\n };\n return text.replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\n};\n\n/**\n * Strip all HTML tags and return plain text.\n *\n * @param html - The HTML string to strip\n * @returns Plain text content\n */\nexport const stripTags = (html: string): string => {\n return sanitizeHtmlCore(html, { stripAllTags: true });\n};\n\nexport type { SanitizeOptions } from './types';\n","/**\n * Shared helpers for element wrappers.\n */\nexport type ElementList = Element[];\n\nexport const toElementList = (input: Element | ElementList): ElementList =>\n Array.isArray(input) ? input : [input];\n\nexport const applyAll = (elements: ElementList, action: (el: Element) => void) => {\n for (const el of elements) {\n action(el);\n }\n};\n\n/** @internal */\nexport const isHTMLElement = (element: Element | null | undefined): element is HTMLElement => {\n if (!element) {\n return false;\n }\n\n const view = element.ownerDocument?.defaultView;\n const HTMLElementCtor = view?.HTMLElement ?? globalThis.HTMLElement;\n return typeof HTMLElementCtor === 'function' && element instanceof HTMLElementCtor;\n};\n\n/**\n * Gets an element's inner size (content + padding, excluding border and margin).\n *\n * @internal\n */\nexport const getInnerSize = (\n element: Element | null | undefined,\n dimension: 'width' | 'height'\n): number => {\n if (!isHTMLElement(element)) {\n return 0;\n }\n return dimension === 'width' ? element.clientWidth : element.clientHeight;\n};\n\n/**\n * Gets an element's outer size, optionally including margins.\n *\n * @internal\n */\nexport const getOuterSize = (\n element: Element | null | undefined,\n dimension: 'width' | 'height',\n includeMargin: boolean\n): number => {\n if (!isHTMLElement(element)) {\n return 0;\n }\n\n const size = dimension === 'width' ? element.offsetWidth : element.offsetHeight;\n if (!includeMargin) {\n return size;\n }\n\n const view = element.ownerDocument?.defaultView;\n if (!view || typeof view.getComputedStyle !== 'function') {\n return size;\n }\n\n const computedStyle = view.getComputedStyle(element);\n const startMargin = Number.parseFloat(\n computedStyle.getPropertyValue(dimension === 'width' ? 'margin-left' : 'margin-top')\n );\n const endMargin = Number.parseFloat(\n computedStyle.getPropertyValue(dimension === 'width' ? 'margin-right' : 'margin-bottom')\n );\n\n const safeStartMargin = Number.isNaN(startMargin) ? 0 : startMargin;\n const safeEndMargin = Number.isNaN(endMargin) ? 0 : endMargin;\n\n return size + safeStartMargin + safeEndMargin;\n};\n","import { sanitizeHtml } from '../security/sanitize';\nimport { applyAll, toElementList } from './shared';\n\nexport type InsertableContent = string | Element | Element[];\n\nexport const sanitizeContent = (html: string): string => sanitizeHtml(html);\n\nexport const setHtml = (element: Element, html: string): void => {\n element.innerHTML = sanitizeHtml(html);\n};\n\nexport const createElementFromHtml = (html: string): Element => {\n const template = document.createElement('template');\n template.innerHTML = sanitizeHtml(html);\n return template.content.firstElementChild ?? document.createElement('div');\n};\n\nexport const insertContent = (\n target: Element,\n content: InsertableContent,\n position: InsertPosition\n): void => {\n if (typeof content === 'string') {\n target.insertAdjacentHTML(position, sanitizeHtml(content));\n return;\n }\n\n const elements = toElementList(content);\n\n // For positions that insert at the beginning (afterbegin, afterend), reverse\n // the array to maintain the caller's order. For beforeend/beforebegin, keep order.\n const needsReverse = position === 'afterbegin' || position === 'afterend';\n const orderedElements = needsReverse ? elements.slice().reverse() : elements;\n\n applyAll(orderedElements, (el) => {\n target.insertAdjacentElement(position, el);\n });\n};\n","/**\n * Object-focused utility helpers.\n *\n * @module bquery/core/utils/object\n */\n\n/**\n * Checks if a value is a plain object (not null, array, or class instance).\n *\n * @param value - The value to check\n * @returns True if the value is a plain object\n */\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n\n/**\n * Checks if a key could cause prototype pollution.\n * These keys are dangerous when used in object merging operations.\n *\n * @param key - The key to check\n * @returns True if the key is a prototype pollution vector\n *\n * @internal\n */\nexport function isPrototypePollutionKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype';\n}\n\n/**\n * Creates a deep clone using structuredClone if available, otherwise fallback to JSON.\n *\n * @template T - The type of value being cloned\n * @param value - The value to clone\n * @returns A deep copy of the value\n *\n * @remarks\n * When `structuredClone` is available (modern browsers, Node 17+, Bun), this function\n * provides full deep cloning including circular references, Date, Map, Set, ArrayBuffer, etc.\n *\n * **JSON fallback limitations** (older environments without `structuredClone`):\n * - **Throws** on circular references\n * - **Drops** functions, `undefined`, and Symbol properties\n * - **Transforms** Date → ISO string, Map/Set → empty object, BigInt → throws\n * - **Loses** prototype chains and non-enumerable properties\n *\n * For guaranteed safe cloning of arbitrary data, ensure your environment supports\n * `structuredClone` or pre-validate your data structure.\n *\n * @example\n * ```ts\n * const original = { nested: { value: 1 } };\n * const copy = clone(original);\n * copy.nested.value = 2;\n * console.log(original.nested.value); // 1\n * ```\n */\nexport function clone<T>(value: T): T {\n if (typeof structuredClone === 'function') {\n return structuredClone(value);\n }\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\n/**\n * Deep-merges plain objects into a new object.\n * Later sources override earlier ones for primitive values.\n * Objects are recursively merged.\n *\n * @param sources - Objects to merge\n * @returns A new object with all sources merged as an intersection type\n *\n * @remarks\n * This function uses overloads to provide accurate intersection types for up to 5 sources.\n * For more than 5 sources, the return type falls back to `Record<string, unknown>`.\n *\n * Note that deep merging creates a shallow intersection at the type level. Nested objects\n * are merged at runtime, but TypeScript sees them as intersected types which may not\n * perfectly represent the merged structure for deeply nested conflicting types.\n *\n * @example\n * ```ts\n * const result = merge(\n * { a: 1, nested: { x: 1 } },\n * { b: 2, nested: { y: 2 } }\n * );\n * // Result: { a: 1, b: 2, nested: { x: 1, y: 2 } }\n * // Type: { a: number; nested: { x: number } } & { b: number; nested: { y: number } }\n * ```\n *\n * @security This method is protected against prototype pollution attacks.\n * Keys like `__proto__`, `constructor`, and `prototype` are ignored.\n */\nexport function merge<T1 extends Record<string, unknown>>(source1: T1): T1;\nexport function merge<T1 extends Record<string, unknown>, T2 extends Record<string, unknown>>(\n source1: T1,\n source2: T2\n): T1 & T2;\nexport function merge<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n T3 extends Record<string, unknown>,\n>(source1: T1, source2: T2, source3: T3): T1 & T2 & T3;\nexport function merge<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n T3 extends Record<string, unknown>,\n T4 extends Record<string, unknown>,\n>(source1: T1, source2: T2, source3: T3, source4: T4): T1 & T2 & T3 & T4;\nexport function merge<\n T1 extends Record<string, unknown>,\n T2 extends Record<string, unknown>,\n T3 extends Record<string, unknown>,\n T4 extends Record<string, unknown>,\n T5 extends Record<string, unknown>,\n>(source1: T1, source2: T2, source3: T3, source4: T4, source5: T5): T1 & T2 & T3 & T4 & T5;\nexport function merge(...sources: Record<string, unknown>[]): Record<string, unknown>;\nexport function merge(...sources: Record<string, unknown>[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const source of sources) {\n for (const [key, value] of Object.entries(source)) {\n if (isPrototypePollutionKey(key)) continue;\n\n if (isPlainObject(value) && isPlainObject(result[key])) {\n result[key] = merge(\n result[key] as Record<string, unknown>,\n value as Record<string, unknown>\n );\n } else {\n result[key] = value;\n }\n }\n }\n return result;\n}\n\n/**\n * Picks specified keys from an object.\n *\n * @template T - The object type\n * @template K - The key type\n * @param obj - The source object\n * @param keys - Keys to pick\n * @returns A new object with only the specified keys\n *\n * @example\n * ```ts\n * const user = { name: 'John', age: 30, email: 'john@example.com' };\n * pick(user, ['name', 'email']); // { name: 'John', email: 'john@example.com' }\n * ```\n */\nexport function pick<T extends Record<string, unknown>, K extends keyof T>(\n obj: T,\n keys: K[]\n): Pick<T, K> {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in obj) {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\n/**\n * Omits specified keys from an object.\n *\n * @template T - The object type\n * @template K - The key type\n * @param obj - The source object\n * @param keys - Keys to omit\n * @returns A new object without the specified keys\n *\n * @example\n * ```ts\n * const user = { name: 'John', age: 30, password: 'secret' };\n * omit(user, ['password']); // { name: 'John', age: 30 }\n * ```\n */\nexport function omit<T extends Record<string, unknown>, K extends keyof T>(\n obj: T,\n keys: K[]\n): Omit<T, K> {\n const result = { ...obj };\n for (const key of keys) {\n delete result[key];\n }\n return result as Omit<T, K>;\n}\n\n/**\n * Checks if an object has a given own property.\n *\n * @template T - The object type\n * @param obj - The object to check\n * @param key - The property key\n * @returns True if the property exists on the object\n *\n * @example\n * ```ts\n * hasOwn({ a: 1 }, 'a'); // true\n * ```\n */\nexport function hasOwn<T extends object>(obj: T, key: PropertyKey): key is keyof T {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n","import { createElementFromHtml, insertContent, setHtml } from './dom';\nimport { getInnerSize, getOuterSize, isHTMLElement } from './shared';\nimport { isPrototypePollutionKey } from './utils/object';\n\n/**\n * Wrapper for a single DOM element.\n * Provides a chainable, jQuery-like API for DOM manipulation.\n *\n * This class encapsulates a DOM element and provides methods for:\n * - Class manipulation (addClass, removeClass, toggleClass)\n * - Attribute and property access (attr, prop, data)\n * - Content manipulation (text, html, append, prepend)\n * - Style manipulation (css)\n * - Event handling (on, off, once, trigger)\n * - DOM traversal (find, closest, parent, children, siblings)\n *\n * All mutating methods return `this` for method chaining.\n *\n * @example\n * ```ts\n * $('#button')\n * .addClass('active')\n * .css({ color: 'blue' })\n * .on('click', () => console.log('clicked'));\n * ```\n */\n/** Handler signature for delegated events */\ntype DelegatedHandler = (event: Event, target: Element) => void;\n\ntype SerializableFormControl = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\nconst isSerializableFormControl = (element: Element): element is SerializableFormControl => {\n const tagName = element.tagName.toLowerCase();\n return tagName === 'input' || tagName === 'textarea' || tagName === 'select';\n};\n\nconst collectFormEntries = (form: HTMLFormElement): Array<[string, string]> => {\n const entries: Array<[string, string]> = [];\n const elementCtor = form.ownerDocument.defaultView?.Element ?? Element;\n\n for (const control of Array.from(form.elements)) {\n if (!(control instanceof elementCtor) || !isSerializableFormControl(control)) {\n continue;\n }\n\n const name = control.name;\n if (!name || control.disabled || isPrototypePollutionKey(name)) {\n continue;\n }\n\n if (control.tagName.toLowerCase() === 'input') {\n const input = control as HTMLInputElement;\n const type = input.type.toLowerCase();\n\n if (type === 'checkbox' || type === 'radio') {\n if (input.checked) {\n entries.push([name, input.value]);\n }\n continue;\n }\n\n if (\n type === 'file' ||\n type === 'submit' ||\n type === 'button' ||\n type === 'reset' ||\n type === 'image'\n ) {\n continue;\n }\n\n entries.push([name, input.value]);\n continue;\n }\n\n if (control.tagName.toLowerCase() === 'select') {\n const select = control as HTMLSelectElement;\n\n if (select.multiple) {\n for (const option of Array.from(select.selectedOptions)) {\n entries.push([name, option.value]);\n }\n } else {\n entries.push([name, select.value]);\n }\n continue;\n }\n\n entries.push([name, (control as HTMLTextAreaElement).value]);\n }\n\n return entries;\n};\n\nconst getFormEntries = (form: HTMLFormElement): Array<[string, string]> => {\n if (typeof FormData === 'function') {\n try {\n const entries: Array<[string, string]> = [];\n\n for (const [key, value] of new FormData(form).entries()) {\n if (isPrototypePollutionKey(key) || typeof value !== 'string') {\n continue;\n }\n entries.push([key, value]);\n }\n\n // Some environments expose FormData(form) but fail to populate entries for\n // successful controls. Fall back to manual collection only in that zero-entry case.\n return entries.length > 0 ? entries : collectFormEntries(form);\n } catch {\n // Fall back to manual collection when FormData is unavailable for this form\n // or the environment does not fully support constructing it.\n }\n }\n\n return collectFormEntries(form);\n};\n\nexport class BQueryElement {\n /**\n * Stores delegated event handlers for cleanup via undelegate().\n * Key format: `${event}:${selector}`\n * @internal\n */\n private readonly delegatedHandlers = new Map<string, Map<DelegatedHandler, EventListener>>();\n\n /**\n * Creates a new BQueryElement wrapper.\n * @param element - The DOM element to wrap\n */\n constructor(private readonly element: Element) {}\n\n /**\n * Exposes the raw DOM element when direct access is needed.\n * Use sparingly; prefer the wrapper methods for consistency.\n */\n get raw(): Element {\n return this.element;\n }\n\n /**\n * Exposes the underlying DOM element.\n * Provided for spec compatibility and read-only access.\n */\n get node(): Element {\n return this.element;\n }\n\n /** Add one or more classes. */\n addClass(...classNames: string[]): this {\n this.element.classList.add(...classNames);\n return this;\n }\n\n /** Remove one or more classes. */\n removeClass(...classNames: string[]): this {\n this.element.classList.remove(...classNames);\n return this;\n }\n\n /** Toggle a class by name. */\n toggleClass(className: string, force?: boolean): this {\n this.element.classList.toggle(className, force);\n return this;\n }\n\n /** Get or set an attribute. */\n attr(name: string, value?: string): string | this {\n if (value === undefined) {\n return this.element.getAttribute(name) ?? '';\n }\n this.element.setAttribute(name, value);\n return this;\n }\n\n /** Remove an attribute. */\n removeAttr(name: string): this {\n this.element.removeAttribute(name);\n return this;\n }\n\n /** Toggle an attribute on/off. */\n toggleAttr(name: string, force?: boolean): this {\n const hasAttr = this.element.hasAttribute(name);\n const shouldAdd = force ?? !hasAttr;\n if (shouldAdd) {\n this.element.setAttribute(name, '');\n } else {\n this.element.removeAttribute(name);\n }\n return this;\n }\n\n /** Get or set a property. */\n prop<T extends keyof Element>(name: T, value?: Element[T]): Element[T] | this {\n if (value === undefined) {\n return this.element[name];\n }\n this.element[name] = value;\n return this;\n }\n\n /** Read or write data attributes in camelCase. */\n data(name: string, value?: string): string | this {\n const key = name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\n if (value === undefined) {\n return this.element.getAttribute(`data-${key}`) ?? '';\n }\n this.element.setAttribute(`data-${key}`, value);\n return this;\n }\n\n /** Get or set text content. */\n text(value?: string): string | this {\n if (value === undefined) {\n return this.element.textContent ?? '';\n }\n this.element.textContent = value;\n return this;\n }\n\n /** Set HTML content using a sanitized string. */\n /**\n * Sets sanitized HTML content on the element.\n * Uses the security module to sanitize input and prevent XSS attacks.\n *\n * @param value - The HTML string to set (will be sanitized)\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * $('#content').html('<strong>Hello</strong>');\n * ```\n */\n html(value: string): this {\n setHtml(this.element, value);\n return this;\n }\n\n /**\n * Sets HTML content without sanitization.\n * Use only when you trust the HTML source completely.\n *\n * @param value - The raw HTML string to set\n * @returns The instance for method chaining\n *\n * @warning This method bypasses XSS protection. Use with caution.\n */\n htmlUnsafe(value: string): this {\n this.element.innerHTML = value;\n return this;\n }\n\n /**\n * Gets or sets CSS styles on the element.\n *\n * @param property - A CSS property name or an object of property-value pairs\n * @param value - The value when setting a single property\n * @returns The computed style value when getting a single property, or the instance for method chaining when setting\n *\n * @example\n * ```ts\n * // Get a computed style value\n * const color = $('#box').css('color');\n *\n * // Set a single property\n * $('#box').css('color', 'red');\n *\n * // Set multiple properties\n * $('#box').css({ color: 'red', 'font-size': '16px' });\n * ```\n */\n css(property: string): string;\n css(property: string, value: string): this;\n css(property: Record<string, string>): this;\n css(property: string | Record<string, string>, value?: string): string | this {\n if (typeof property === 'string') {\n if (value !== undefined) {\n (this.element as HTMLElement).style.setProperty(property, value);\n return this;\n }\n const view = this.element.ownerDocument?.defaultView;\n if (!view || typeof view.getComputedStyle !== 'function') {\n return '';\n }\n return view.getComputedStyle(this.element).getPropertyValue(property);\n }\n\n for (const [key, val] of Object.entries(property)) {\n (this.element as HTMLElement).style.setProperty(key, val);\n }\n return this;\n }\n\n /**\n * Appends HTML or elements to the end of the element.\n *\n * @param content - HTML string or element(s) to append\n * @returns The instance for method chaining\n */\n append(content: string | Element | Element[]): this {\n this.insertContent(content, 'beforeend');\n return this;\n }\n\n /**\n * Prepends HTML or elements to the beginning of the element.\n *\n * @param content - HTML string or element(s) to prepend\n * @returns The instance for method chaining\n */\n prepend(content: string | Element | Element[]): this {\n this.insertContent(content, 'afterbegin');\n return this;\n }\n\n /**\n * Inserts content before this element.\n *\n * @param content - HTML string or element(s) to insert\n * @returns The instance for method chaining\n */\n before(content: string | Element | Element[]): this {\n this.insertContent(content, 'beforebegin');\n return this;\n }\n\n /**\n * Inserts content after this element.\n *\n * @param content - HTML string or element(s) to insert\n * @returns The instance for method chaining\n */\n after(content: string | Element | Element[]): this {\n this.insertContent(content, 'afterend');\n return this;\n }\n\n /**\n * Wraps the element with the specified wrapper element or tag.\n *\n * @param wrapper - Tag name string or Element to wrap with\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * $('#content').wrap('div'); // Wraps with <div>\n * $('#content').wrap(document.createElement('section'));\n * ```\n */\n wrap(wrapper: string | Element): this {\n const wrapperEl = typeof wrapper === 'string' ? document.createElement(wrapper) : wrapper;\n this.element.parentNode?.insertBefore(wrapperEl, this.element);\n wrapperEl.appendChild(this.element);\n return this;\n }\n\n /**\n * Removes the parent element, keeping this element in its place.\n * Essentially the opposite of wrap().\n *\n * **Important**: This method only moves the current element out of its parent\n * before removing the parent. Any sibling elements will be removed along with\n * the parent. For unwrapping multiple siblings, use a collection: `$$(siblings).unwrap()`.\n *\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * // Before: <div><span id=\"text\">Hello</span></div>\n * $('#text').unwrap();\n * // After: <span id=\"text\">Hello</span>\n * ```\n */\n unwrap(): this {\n const parent = this.element.parentElement;\n if (parent && parent.parentNode) {\n parent.parentNode.insertBefore(this.element, parent);\n parent.remove();\n }\n return this;\n }\n\n /**\n * Replaces this element with new content.\n *\n * @param content - HTML string (sanitized) or Element to replace with\n * @returns A new BQueryElement wrapping the replacement element\n *\n * @example\n * ```ts\n * const newEl = $('#old').replaceWith('<div id=\"new\">Replaced</div>');\n * ```\n */\n replaceWith(content: string | Element): BQueryElement {\n const newEl = typeof content === 'string' ? createElementFromHtml(content) : content;\n this.element.replaceWith(newEl);\n return new BQueryElement(newEl);\n }\n\n /**\n * Removes the element from the DOM while keeping the wrapped node available\n * for later reuse.\n *\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * const item = $('#item').detach();\n * document.body.appendChild(item.raw);\n * ```\n */\n detach(): this {\n return this.remove();\n }\n\n /**\n * Gets the zero-based index of the element among its element siblings.\n *\n * @returns Index within the parent element, or -1 when detached\n *\n * @example\n * ```ts\n * const index = $('#item').index();\n * ```\n */\n index(): number {\n const parent = this.element.parentElement;\n if (!parent) {\n return -1;\n }\n return Array.from(parent.children).indexOf(this.element);\n }\n\n /**\n * Returns all child nodes, including text nodes and comments.\n *\n * @returns Array of child nodes\n *\n * @example\n * ```ts\n * const nodes = $('#content').contents();\n * ```\n */\n contents(): ChildNode[] {\n return Array.from(this.element.childNodes);\n }\n\n /**\n * Gets the nearest positioned ancestor used for offset calculations.\n *\n * @returns The offset parent element, or null when unavailable\n *\n * @example\n * ```ts\n * const parent = $('#item').offsetParent();\n * ```\n */\n offsetParent(): Element | null {\n return isHTMLElement(this.element) ? this.element.offsetParent : null;\n }\n\n /**\n * Gets the current position relative to the offset parent.\n *\n * @returns Position object with top and left coordinates\n *\n * @example\n * ```ts\n * const { top, left } = $('#item').position();\n * ```\n */\n position(): { top: number; left: number } {\n if (!isHTMLElement(this.element)) {\n return { top: 0, left: 0 };\n }\n\n const el = this.element;\n return {\n top: el.offsetTop,\n left: el.offsetLeft,\n };\n }\n\n /**\n * Gets the inner width of the element (content + padding, excluding border).\n *\n * This corresponds to the element's `clientWidth` and mirrors jQuery's\n * `innerWidth()` method.\n *\n * @returns Inner width in pixels, or 0 for non-HTML elements\n *\n * @example\n * ```ts\n * const innerW = $('#panel').innerWidth();\n * ```\n */\n innerWidth(): number {\n return getInnerSize(this.element, 'width');\n }\n\n /**\n * Gets the inner height of the element (content + padding, excluding border).\n *\n * This corresponds to the element's `clientHeight` and mirrors jQuery's\n * `innerHeight()` method.\n *\n * @returns Inner height in pixels, or 0 for non-HTML elements\n *\n * @example\n * ```ts\n * const innerH = $('#panel').innerHeight();\n * ```\n */\n innerHeight(): number {\n return getInnerSize(this.element, 'height');\n }\n\n /**\n * Gets the outer width of the element, optionally including margins.\n *\n * @param includeMargin - When true, include horizontal margins\n * @returns Outer width in pixels\n *\n * @example\n * ```ts\n * const width = $('#panel').outerWidth();\n * const widthWithMargin = $('#panel').outerWidth(true);\n * ```\n */\n outerWidth(includeMargin: boolean = false): number {\n return getOuterSize(this.element, 'width', includeMargin);\n }\n\n /**\n * Gets the outer height of the element, optionally including margins.\n *\n * @param includeMargin - When true, include vertical margins\n * @returns Outer height in pixels\n *\n * @example\n * ```ts\n * const height = $('#panel').outerHeight();\n * const heightWithMargin = $('#panel').outerHeight(true);\n * ```\n */\n outerHeight(includeMargin: boolean = false): number {\n return getOuterSize(this.element, 'height', includeMargin);\n }\n\n /**\n * Scrolls the element into view with configurable behavior.\n *\n * @param options - ScrollIntoView options or boolean for legacy behavior\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * $('#section').scrollTo(); // Smooth scroll\n * $('#section').scrollTo({ behavior: 'instant', block: 'start' });\n * ```\n */\n scrollTo(options: ScrollIntoViewOptions | boolean = { behavior: 'smooth' }): this {\n this.element.scrollIntoView(options);\n return this;\n }\n\n /**\n * Removes the element from the DOM.\n *\n * @returns The instance for method chaining (though element is now detached)\n */\n remove(): this {\n this.element.remove();\n return this;\n }\n\n /**\n * Clears all child nodes from the element.\n *\n * @returns The instance for method chaining\n */\n empty(): this {\n this.element.innerHTML = '';\n return this;\n }\n\n /**\n * Clones the element, optionally with all descendants.\n *\n * @param deep - If true, clone all descendants (default: true)\n * @returns A new BQueryElement wrapping the cloned element\n */\n clone(deep: boolean = true): BQueryElement {\n return new BQueryElement(this.element.cloneNode(deep) as Element);\n }\n\n /**\n * Finds all descendant elements matching the selector.\n *\n * @param selector - CSS selector to match\n * @returns Array of matching elements\n */\n find(selector: string): Element[] {\n return Array.from(this.element.querySelectorAll(selector));\n }\n\n /**\n * Finds the first descendant element matching the selector.\n *\n * @param selector - CSS selector to match\n * @returns The first matching element or null\n */\n findOne(selector: string): Element | null {\n return this.element.querySelector(selector);\n }\n\n /**\n * Finds the closest ancestor matching the selector.\n *\n * @param selector - CSS selector to match\n * @returns The matching ancestor or null\n */\n closest(selector: string): Element | null {\n return this.element.closest(selector);\n }\n\n /**\n * Gets the parent element.\n *\n * @returns The parent element or null\n */\n parent(): Element | null {\n return this.element.parentElement;\n }\n\n /**\n * Gets all child elements.\n *\n * @returns Array of child elements\n */\n children(): Element[] {\n return Array.from(this.element.children);\n }\n\n /**\n * Gets all sibling elements.\n *\n * @returns Array of sibling elements (excluding this element)\n */\n siblings(): Element[] {\n const parent = this.element.parentElement;\n if (!parent) return [];\n return Array.from(parent.children).filter((child) => child !== this.element);\n }\n\n /**\n * Gets the next sibling element.\n *\n * @returns The next sibling element or null\n */\n next(): Element | null {\n return this.element.nextElementSibling;\n }\n\n /**\n * Gets the previous sibling element.\n *\n * @returns The previous sibling element or null\n */\n prev(): Element | null {\n return this.element.previousElementSibling;\n }\n\n /**\n * Adds an event listener.\n *\n * @param event - Event type to listen for\n * @param handler - Event handler function\n * @returns The instance for method chaining\n */\n on(event: string, handler: EventListenerOrEventListenerObject): this {\n this.element.addEventListener(event, handler);\n return this;\n }\n\n /**\n * Adds a one-time event listener that removes itself after firing.\n *\n * @param event - Event type to listen for\n * @param handler - Event handler function\n * @returns The instance for method chaining\n */\n once(event: string, handler: EventListener): this {\n this.element.addEventListener(event, handler, { once: true });\n return this;\n }\n\n /**\n * Removes an event listener.\n *\n * @param event - Event type\n * @param handler - The handler to remove\n * @returns The instance for method chaining\n */\n off(event: string, handler: EventListenerOrEventListenerObject): this {\n this.element.removeEventListener(event, handler);\n return this;\n }\n\n /**\n * Triggers a custom event on the element.\n *\n * @param event - Event type to trigger\n * @param detail - Optional detail data to include with the event\n * @returns The instance for method chaining\n */\n trigger(event: string, detail?: unknown): this {\n this.element.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\n return this;\n }\n\n /**\n * Adds a delegated event listener that only triggers for matching descendants.\n * More efficient than adding listeners to many elements individually.\n *\n * Use `undelegate()` to remove the listener later.\n *\n * @param event - Event type to listen for\n * @param selector - CSS selector to match against event targets\n * @param handler - Event handler function, receives the matched element as context\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * // Instead of adding listeners to each button:\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\n * $('#list').delegate('click', '.item', handler);\n *\n * // Later, remove the delegated listener:\n * $('#list').undelegate('click', '.item', handler);\n * ```\n */\n delegate(\n event: string,\n selector: string,\n handler: (event: Event, target: Element) => void\n ): this {\n const key = `${event}:${selector}`;\n const wrapper: EventListener = (e: Event) => {\n const target = (e.target as Element).closest(selector);\n if (target && this.element.contains(target)) {\n handler(e, target);\n }\n };\n\n // Store the wrapper so it can be removed later\n if (!this.delegatedHandlers.has(key)) {\n this.delegatedHandlers.set(key, new Map());\n }\n this.delegatedHandlers.get(key)!.set(handler, wrapper);\n\n this.element.addEventListener(event, wrapper);\n return this;\n }\n\n /**\n * Removes a delegated event listener previously added with `delegate()`.\n *\n * @param event - Event type that was registered\n * @param selector - CSS selector that was used\n * @param handler - The original handler function passed to delegate()\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\n * $('#list').delegate('click', '.item', handler);\n *\n * // Remove the delegated listener:\n * $('#list').undelegate('click', '.item', handler);\n * ```\n */\n undelegate(\n event: string,\n selector: string,\n handler: (event: Event, target: Element) => void\n ): this {\n const key = `${event}:${selector}`;\n const handlers = this.delegatedHandlers.get(key);\n\n if (handlers) {\n const wrapper = handlers.get(handler);\n if (wrapper) {\n this.element.removeEventListener(event, wrapper);\n handlers.delete(handler);\n\n // Clean up empty maps\n if (handlers.size === 0) {\n this.delegatedHandlers.delete(key);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Checks if the element matches a CSS selector.\n *\n * @param selector - CSS selector to match against\n * @returns True if the element matches the selector\n */\n matches(selector: string): boolean {\n return this.element.matches(selector);\n }\n\n /**\n * Alias for `matches()`. Checks if the element matches a CSS selector.\n *\n * @param selector - CSS selector to match against\n * @returns True if the element matches the selector\n *\n * @example\n * ```ts\n * if ($('#el').is('.active')) {\n * console.log('Element is active');\n * }\n * ```\n */\n is(selector: string): boolean {\n return this.matches(selector);\n }\n\n /**\n * Checks if the element has a specific class.\n *\n * @param className - Class name to check\n * @returns True if the element has the class\n */\n hasClass(className: string): boolean {\n return this.element.classList.contains(className);\n }\n\n /**\n * Shows the element by removing the hidden attribute and setting display.\n *\n * @param display - Optional display value (default: '')\n * @returns The instance for method chaining\n */\n show(display: string = ''): this {\n this.element.removeAttribute('hidden');\n (this.element as HTMLElement).style.display = display;\n return this;\n }\n\n /**\n * Hides the element by setting display to 'none'.\n *\n * @returns The instance for method chaining\n */\n hide(): this {\n (this.element as HTMLElement).style.display = 'none';\n return this;\n }\n\n /**\n * Toggles the visibility of the element.\n *\n * @param force - Optional force show (true) or hide (false)\n * @returns The instance for method chaining\n */\n toggle(force?: boolean): this {\n const isHidden = (this.element as HTMLElement).style.display === 'none';\n const shouldShow = force ?? isHidden;\n return shouldShow ? this.show() : this.hide();\n }\n\n /**\n * Focuses the element.\n *\n * @returns The instance for method chaining\n */\n focus(): this {\n (this.element as HTMLElement).focus();\n return this;\n }\n\n /**\n * Blurs (unfocuses) the element.\n *\n * @returns The instance for method chaining\n */\n blur(): this {\n (this.element as HTMLElement).blur();\n return this;\n }\n\n /**\n * Gets or sets the value of form elements.\n *\n * @param newValue - Optional value to set\n * @returns The current value when getting, or the instance when setting\n */\n val(newValue?: string): string | this {\n const input = this.element as HTMLInputElement;\n if (newValue === undefined) {\n return input.value ?? '';\n }\n input.value = newValue;\n return this;\n }\n\n /**\n * Serializes form data to a plain object.\n * Only works on form elements; returns empty object for non-forms.\n *\n * For security hardening, the returned object uses a null prototype,\n * so inherited members like `hasOwnProperty` are not available directly.\n * Prefer `Object.keys()` or `Object.prototype.hasOwnProperty.call(...)`\n * when checking for fields on the serialized result.\n *\n * @returns Object with form field names as keys and values\n *\n * @example\n * ```ts\n * // For a form with <input name=\"email\" value=\"test@example.com\">\n * const data = $('#myForm').serialize();\n * // { email: 'test@example.com' }\n * Object.prototype.hasOwnProperty.call(data, 'email'); // true\n * ```\n */\n serialize(): Record<string, string | string[]> {\n const form = this.element as HTMLFormElement;\n if (form.tagName.toLowerCase() !== 'form') {\n return {};\n }\n\n const result = Object.create(null) as Record<string, string | string[]>;\n\n for (const [key, value] of getFormEntries(form)) {\n if (Object.prototype.hasOwnProperty.call(result, key)) {\n // Handle multiple values (e.g., checkboxes)\n const existing = result[key];\n if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n result[key] = [existing, value];\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n /**\n * Serializes form data to a URL-encoded query string.\n *\n * @returns URL-encoded string suitable for form submission\n *\n * @example\n * ```ts\n * const queryString = $('#myForm').serializeString();\n * // 'email=test%40example.com&name=John'\n * ```\n */\n serializeString(): string {\n const form = this.element as HTMLFormElement;\n if (form.tagName.toLowerCase() !== 'form') {\n return '';\n }\n\n const params = new URLSearchParams();\n\n for (const [key, value] of getFormEntries(form)) {\n params.append(key, value);\n }\n\n return params.toString();\n }\n\n /**\n * Gets the bounding client rectangle of the element.\n *\n * @returns The element's bounding rectangle\n */\n rect(): DOMRect {\n return this.element.getBoundingClientRect();\n }\n\n /**\n * Gets the offset dimensions (width, height, top, left).\n *\n * @returns Object with offset dimensions\n */\n offset(): { width: number; height: number; top: number; left: number } {\n const el = this.element as HTMLElement;\n return {\n width: el.offsetWidth,\n height: el.offsetHeight,\n top: el.offsetTop,\n left: el.offsetLeft,\n };\n }\n\n /**\n * Internal method to insert content at a specified position.\n * @internal\n */\n private insertContent(content: string | Element | Element[], position: InsertPosition) {\n insertContent(this.element, content, position);\n }\n}\n","import {\n createElementFromHtml,\n insertContent,\n sanitizeContent,\n type InsertableContent,\n} from './dom';\nimport { BQueryElement } from './element';\nimport { applyAll, getInnerSize, getOuterSize, isHTMLElement, toElementList } from './shared';\n\n/** Handler signature for delegated events */\ntype DelegatedHandler = (event: Event, target: Element) => void;\n\n/**\n * Wrapper for multiple DOM elements.\n * Provides batch operations on a collection of elements with chainable API.\n *\n * This class enables jQuery-like operations across multiple elements:\n * - All mutating methods apply to every element in the collection\n * - Getter methods return data from the first element\n * - Supports iteration via forEach, map, filter, and reduce\n *\n * @example\n * ```ts\n * $$('.items')\n * .addClass('highlight')\n * .css({ opacity: '0.8' })\n * .on('click', () => console.log('clicked'));\n * ```\n */\nexport class BQueryCollection {\n /**\n * Stores delegated event handlers for cleanup via undelegate().\n * Outer map: element -> (key -> (handler -> wrapper))\n * Key format: `${event}:${selector}`\n * @internal\n */\n private readonly delegatedHandlers = new WeakMap<\n Element,\n Map<string, Map<DelegatedHandler, EventListener>>\n >();\n\n /**\n * Creates a new collection wrapper.\n * @param elements - Array of DOM elements to wrap\n */\n constructor(public readonly elements: Element[]) {}\n\n /**\n * Gets the number of elements in the collection.\n */\n get length(): number {\n return this.elements.length;\n }\n\n /**\n * Gets the first element in the collection, if any.\n * @internal\n */\n private first(): Element | undefined {\n return this.elements[0];\n }\n\n /**\n * Gets a single element as a BQueryElement wrapper.\n *\n * @param index - Zero-based index of the element\n * @returns BQueryElement wrapper or undefined if out of range\n */\n eq(index: number): BQueryElement | undefined {\n const el = this.elements[index];\n return el ? new BQueryElement(el) : undefined;\n }\n\n /**\n * Gets the first element as a BQueryElement wrapper.\n *\n * @returns BQueryElement wrapper or undefined if empty\n */\n firstEl(): BQueryElement | undefined {\n return this.eq(0);\n }\n\n /**\n * Gets the last element as a BQueryElement wrapper.\n *\n * @returns BQueryElement wrapper or undefined if empty\n */\n lastEl(): BQueryElement | undefined {\n return this.eq(this.elements.length - 1);\n }\n\n /**\n * Iterates over each element in the collection.\n *\n * @param callback - Function to call for each wrapped element\n * @returns The instance for method chaining\n */\n each(callback: (element: BQueryElement, index: number) => void): this {\n this.elements.forEach((element, index) => {\n callback(new BQueryElement(element), index);\n });\n return this;\n }\n\n /**\n * Maps each element to a new value.\n *\n * @param callback - Function to transform each element\n * @returns Array of transformed values\n */\n map<T>(callback: (element: Element, index: number) => T): T[] {\n return this.elements.map(callback);\n }\n\n /**\n * Filters elements based on a predicate.\n *\n * @param predicate - Function to test each element\n * @returns New BQueryCollection with matching elements\n */\n filter(predicate: (element: Element, index: number) => boolean): BQueryCollection {\n return new BQueryCollection(this.elements.filter(predicate));\n }\n\n /**\n * Reduces the collection to a single value.\n *\n * @param callback - Reducer function\n * @param initialValue - Initial accumulator value\n * @returns Accumulated result\n */\n reduce<T>(callback: (accumulator: T, element: Element, index: number) => T, initialValue: T): T {\n return this.elements.reduce(callback, initialValue);\n }\n\n /**\n * Converts the collection to an array of BQueryElement wrappers.\n *\n * @returns Array of BQueryElement instances\n */\n toArray(): BQueryElement[] {\n return this.elements.map((el) => new BQueryElement(el));\n }\n\n /** Add one or more classes to all elements. */\n addClass(...classNames: string[]): this {\n applyAll(this.elements, (el) => el.classList.add(...classNames));\n return this;\n }\n\n /** Remove one or more classes from all elements. */\n removeClass(...classNames: string[]): this {\n applyAll(this.elements, (el) => el.classList.remove(...classNames));\n return this;\n }\n\n /** Toggle a class on all elements. */\n toggleClass(className: string, force?: boolean): this {\n applyAll(this.elements, (el) => el.classList.toggle(className, force));\n return this;\n }\n\n /**\n * Sets an attribute on all elements or gets from first.\n *\n * @param name - Attribute name\n * @param value - Value to set (optional)\n * @returns Attribute value when getting, instance when setting\n */\n attr(name: string, value?: string): string | this {\n if (value === undefined) {\n return this.first()?.getAttribute(name) ?? '';\n }\n applyAll(this.elements, (el) => el.setAttribute(name, value));\n return this;\n }\n\n /**\n * Removes an attribute from all elements.\n *\n * @param name - Attribute name to remove\n * @returns The instance for method chaining\n */\n removeAttr(name: string): this {\n applyAll(this.elements, (el) => el.removeAttribute(name));\n return this;\n }\n\n /** Toggle an attribute on all elements. */\n toggleAttr(name: string, force?: boolean): this {\n applyAll(this.elements, (el) => {\n const hasAttr = el.hasAttribute(name);\n const shouldAdd = force ?? !hasAttr;\n if (shouldAdd) {\n el.setAttribute(name, '');\n } else {\n el.removeAttribute(name);\n }\n });\n return this;\n }\n\n /**\n * Sets text content on all elements or gets from first.\n *\n * @param value - Text to set (optional)\n * @returns Text content when getting, instance when setting\n */\n text(value?: string): string | this {\n if (value === undefined) {\n return this.first()?.textContent ?? '';\n }\n applyAll(this.elements, (el) => {\n el.textContent = value;\n });\n return this;\n }\n\n /**\n * Sets sanitized HTML on all elements or gets from first.\n *\n * @param value - HTML to set (optional, will be sanitized)\n * @returns HTML content when getting, instance when setting\n */\n html(value?: string): string | this {\n if (value === undefined) {\n return this.first()?.innerHTML ?? '';\n }\n const sanitized = sanitizeContent(value);\n applyAll(this.elements, (el) => {\n el.innerHTML = sanitized;\n });\n return this;\n }\n\n /**\n * Sets HTML on all elements without sanitization.\n *\n * @param value - Raw HTML to set\n * @returns The instance for method chaining\n * @warning Bypasses XSS protection\n */\n htmlUnsafe(value: string): this {\n applyAll(this.elements, (el) => {\n el.innerHTML = value;\n });\n return this;\n }\n\n /** Append content to all elements. */\n append(content: InsertableContent): this {\n this.insertAll(content, 'beforeend');\n return this;\n }\n\n /** Prepend content to all elements. */\n prepend(content: InsertableContent): this {\n this.insertAll(content, 'afterbegin');\n return this;\n }\n\n /** Insert content before all elements. */\n before(content: InsertableContent): this {\n this.insertAll(content, 'beforebegin');\n return this;\n }\n\n /** Insert content after all elements. */\n after(content: InsertableContent): this {\n this.insertAll(content, 'afterend');\n return this;\n }\n\n /**\n * Gets or sets CSS styles on all elements.\n * When getting, returns the computed style value from the first element.\n *\n * @param property - Property name or object of properties\n * @param value - Value when setting single property\n * @returns The computed style value when getting, instance when setting\n */\n css(property: string): string;\n css(property: string, value: string): this;\n css(property: Record<string, string>): this;\n css(property: string | Record<string, string>, value?: string): string | this {\n if (typeof property === 'string') {\n if (value !== undefined) {\n applyAll(this.elements, (el) => {\n (el as HTMLElement).style.setProperty(property, value);\n });\n return this;\n }\n const first = this.first();\n if (!first) {\n return '';\n }\n const view = first.ownerDocument?.defaultView;\n if (!view || typeof view.getComputedStyle !== 'function') {\n return '';\n }\n return view.getComputedStyle(first).getPropertyValue(property);\n }\n\n applyAll(this.elements, (el) => {\n for (const [key, val] of Object.entries(property)) {\n (el as HTMLElement).style.setProperty(key, val);\n }\n });\n return this;\n }\n\n /** Wrap each element with a wrapper element or tag. */\n wrap(wrapper: string | Element): this {\n this.elements.forEach((el, index) => {\n const wrapperEl =\n typeof wrapper === 'string'\n ? document.createElement(wrapper)\n : index === 0\n ? wrapper\n : (wrapper.cloneNode(true) as Element);\n el.parentNode?.insertBefore(wrapperEl, el);\n wrapperEl.appendChild(el);\n });\n return this;\n }\n\n /**\n * Remove the parent element of each element, keeping the elements in place.\n *\n * **Important**: This method unwraps ALL children of each parent element,\n * not just the elements in the collection. If you call `unwrap()` on a\n * collection containing only some children of a parent, all siblings will\n * also be unwrapped. This behavior is consistent with jQuery's `.unwrap()`.\n *\n * @returns The collection for chaining\n *\n * @example\n * ```ts\n * // HTML: <div><section><span>A</span><span>B</span></section></div>\n * const spans = $$('span');\n * spans.unwrap(); // Removes <section>, both spans move to <div>\n * // Result: <div><span>A</span><span>B</span></div>\n * ```\n */\n unwrap(): this {\n // Collect unique parent elements to avoid removing the same parent multiple times.\n const parents = new Set<Element>();\n for (const el of this.elements) {\n if (el.parentElement) {\n parents.add(el.parentElement);\n }\n }\n\n // Unwrap each parent once: move all children out, then remove the wrapper.\n parents.forEach((parent) => {\n const grandParent = parent.parentNode;\n if (!grandParent) return;\n\n while (parent.firstChild) {\n grandParent.insertBefore(parent.firstChild, parent);\n }\n\n parent.remove();\n });\n return this;\n }\n\n /** Replace each element with provided content. */\n replaceWith(content: string | Element): BQueryCollection {\n const replacements: Element[] = [];\n this.elements.forEach((el, index) => {\n const replacement =\n typeof content === 'string'\n ? createElementFromHtml(content)\n : index === 0\n ? content\n : (content.cloneNode(true) as Element);\n el.replaceWith(replacement);\n replacements.push(replacement);\n });\n return new BQueryCollection(replacements);\n }\n\n /**\n * Removes all elements from the DOM while keeping the wrapped nodes available\n * for later reuse.\n *\n * @returns The instance for method chaining\n */\n detach(): this {\n return this.remove();\n }\n\n /**\n * Gets the zero-based sibling index of the first element in the collection.\n *\n * @returns Index of the first element, or -1 when unavailable\n */\n index(): number {\n const first = this.first();\n if (!first?.parentElement) {\n return -1;\n }\n return Array.from(first.parentElement.children).indexOf(first);\n }\n\n /**\n * Returns the child nodes of the first element, including text nodes and comments.\n *\n * @returns Array of child nodes from the first element\n */\n contents(): ChildNode[] {\n return Array.from(this.first()?.childNodes ?? []);\n }\n\n /**\n * Gets the offset parent of the first element in the collection.\n *\n * @returns Offset parent element, or null when unavailable\n */\n offsetParent(): Element | null {\n const first = this.first();\n return isHTMLElement(first) ? first.offsetParent : null;\n }\n\n /**\n * Gets the position of the first element relative to its offset parent.\n *\n * @returns Position object with top and left coordinates\n */\n position(): { top: number; left: number } {\n const first = this.first();\n if (!isHTMLElement(first)) {\n return { top: 0, left: 0 };\n }\n\n return {\n top: first.offsetTop,\n left: first.offsetLeft,\n };\n }\n\n /**\n * Gets the inner width of the first element (content + padding, excluding border).\n *\n * @returns Inner width in pixels, or 0 when the collection is empty\n */\n innerWidth(): number {\n return getInnerSize(this.first(), 'width');\n }\n\n /**\n * Gets the inner height of the first element (content + padding, excluding border).\n *\n * @returns Inner height in pixels, or 0 when the collection is empty\n */\n innerHeight(): number {\n return getInnerSize(this.first(), 'height');\n }\n\n /**\n * Gets the outer width of the first element, optionally including margins.\n *\n * @param includeMargin - When true, include horizontal margins\n * @returns Outer width in pixels\n */\n outerWidth(includeMargin: boolean = false): number {\n return getOuterSize(this.first(), 'width', includeMargin);\n }\n\n /**\n * Gets the outer height of the first element, optionally including margins.\n *\n * @param includeMargin - When true, include vertical margins\n * @returns Outer height in pixels\n */\n outerHeight(includeMargin: boolean = false): number {\n return getOuterSize(this.first(), 'height', includeMargin);\n }\n\n /**\n * Shows all elements.\n *\n * @param display - Optional display value (default: '')\n * @returns The instance for method chaining\n */\n show(display: string = ''): this {\n applyAll(this.elements, (el) => {\n el.removeAttribute('hidden');\n (el as HTMLElement).style.display = display;\n });\n return this;\n }\n\n /**\n * Hides all elements.\n *\n * @returns The instance for method chaining\n */\n hide(): this {\n applyAll(this.elements, (el) => {\n (el as HTMLElement).style.display = 'none';\n });\n return this;\n }\n\n /**\n * Adds an event listener to all elements.\n *\n * @param event - Event type\n * @param handler - Event handler\n * @returns The instance for method chaining\n */\n on(event: string, handler: EventListenerOrEventListenerObject): this {\n applyAll(this.elements, (el) => el.addEventListener(event, handler));\n return this;\n }\n\n /**\n * Adds a one-time event listener to all elements.\n *\n * @param event - Event type\n * @param handler - Event handler\n * @returns The instance for method chaining\n */\n once(event: string, handler: EventListener): this {\n applyAll(this.elements, (el) => el.addEventListener(event, handler, { once: true }));\n return this;\n }\n\n /**\n * Removes an event listener from all elements.\n *\n * @param event - Event type\n * @param handler - The handler to remove\n * @returns The instance for method chaining\n */\n off(event: string, handler: EventListenerOrEventListenerObject): this {\n applyAll(this.elements, (el) => el.removeEventListener(event, handler));\n return this;\n }\n\n /**\n * Triggers a custom event on all elements.\n *\n * @param event - Event type\n * @param detail - Optional event detail\n * @returns The instance for method chaining\n */\n trigger(event: string, detail?: unknown): this {\n applyAll(this.elements, (el) => {\n el.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, cancelable: true }));\n });\n return this;\n }\n\n /**\n * Adds a delegated event listener to all elements.\n * Events are delegated to matching descendants.\n *\n * Use `undelegate()` to remove the listener later.\n *\n * @param event - Event type to listen for\n * @param selector - CSS selector to match against event targets\n * @param handler - Event handler function\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\n * $$('.container').delegate('click', '.item', handler);\n *\n * // Later, remove the delegated listener:\n * $$('.container').undelegate('click', '.item', handler);\n * ```\n */\n delegate(\n event: string,\n selector: string,\n handler: (event: Event, target: Element) => void\n ): this {\n const key = `${event}:${selector}`;\n\n applyAll(this.elements, (el) => {\n const wrapper: EventListener = (e: Event) => {\n const target = (e.target as Element).closest(selector);\n if (target && el.contains(target)) {\n handler(e, target);\n }\n };\n\n // Get or create the handler maps for this element\n if (!this.delegatedHandlers.has(el)) {\n this.delegatedHandlers.set(el, new Map());\n }\n const elementHandlers = this.delegatedHandlers.get(el)!;\n\n if (!elementHandlers.has(key)) {\n elementHandlers.set(key, new Map());\n }\n elementHandlers.get(key)!.set(handler, wrapper);\n\n el.addEventListener(event, wrapper);\n });\n\n return this;\n }\n\n /**\n * Removes a delegated event listener previously added with `delegate()`.\n *\n * @param event - Event type that was registered\n * @param selector - CSS selector that was used\n * @param handler - The original handler function passed to delegate()\n * @returns The instance for method chaining\n *\n * @example\n * ```ts\n * const handler = (e, target) => console.log('Clicked:', target.textContent);\n * $$('.container').delegate('click', '.item', handler);\n *\n * // Remove the delegated listener:\n * $$('.container').undelegate('click', '.item', handler);\n * ```\n */\n undelegate(\n event: string,\n selector: string,\n handler: (event: Event, target: Element) => void\n ): this {\n const key = `${event}:${selector}`;\n\n applyAll(this.elements, (el) => {\n const elementHandlers = this.delegatedHandlers.get(el);\n if (!elementHandlers) return;\n\n const handlers = elementHandlers.get(key);\n if (!handlers) return;\n\n const wrapper = handlers.get(handler);\n if (wrapper) {\n el.removeEventListener(event, wrapper);\n handlers.delete(handler);\n\n // Clean up empty maps\n if (handlers.size === 0) {\n elementHandlers.delete(key);\n }\n if (elementHandlers.size === 0) {\n this.delegatedHandlers.delete(el);\n }\n }\n });\n\n return this;\n }\n\n /**\n * Finds all descendant elements matching the selector across all elements\n * in the collection. Returns a new BQueryCollection with the results.\n *\n * @param selector - CSS selector to match\n * @returns A new BQueryCollection with all matching descendants\n *\n * @example\n * ```ts\n * $$('.container').find('.item').addClass('highlight');\n * ```\n */\n find(selector: string): BQueryCollection {\n const seen = new Set<Element>();\n const results: Element[] = [];\n for (const el of this.elements) {\n const found = el.querySelectorAll(selector);\n for (let i = 0; i < found.length; i++) {\n if (!seen.has(found[i])) {\n seen.add(found[i]);\n results.push(found[i]);\n }\n }\n }\n return new BQueryCollection(results);\n }\n\n /**\n * Gets the closest element or ancestor matching a selector for each element in\n * the collection, including the element itself. Duplicates are removed from the\n * result.\n *\n * @param selector - CSS selector to match\n * @returns A new BQueryCollection with matching elements or ancestors\n *\n * @example\n * ```ts\n * $$('.item').closest('.container');\n * ```\n */\n closest(selector: string): BQueryCollection {\n const seen = new Set<Element>();\n const results: Element[] = [];\n for (const el of this.elements) {\n const match = el.closest(selector);\n if (match && !seen.has(match)) {\n seen.add(match);\n results.push(match);\n }\n }\n return new BQueryCollection(results);\n }\n\n /**\n * Gets the parent element of each element in the collection.\n * Duplicates are removed (e.g. siblings sharing a parent).\n *\n * @returns A new BQueryCollection with unique parent elements\n *\n * @example\n * ```ts\n * $$('.item').parent().addClass('has-items');\n * ```\n */\n parent(): BQueryCollection {\n const seen = new Set<Element>();\n const results: Element[] = [];\n for (const el of this.elements) {\n const p = el.parentElement;\n if (p && !seen.has(p)) {\n seen.add(p);\n results.push(p);\n }\n }\n return new BQueryCollection(results);\n }\n\n /**\n * Gets the direct children of every element in the collection.\n * Duplicates are removed from the result.\n *\n * @returns A new BQueryCollection with child elements\n *\n * @example\n * ```ts\n * $$('.list').children().addClass('child');\n * ```\n */\n children(): BQueryCollection {\n const seen = new Set<Element>();\n const results: Element[] = [];\n for (const el of this.elements) {\n for (const child of Array.from(el.children)) {\n if (!seen.has(child)) {\n seen.add(child);\n results.push(child);\n }\n }\n }\n return new BQueryCollection(results);\n }\n\n /**\n * Gets all siblings of every element in the collection (excluding the\n * elements themselves). Duplicates are removed.\n *\n * @returns A new BQueryCollection with sibling elements\n *\n * @example\n * ```ts\n * $$('.active').siblings().removeClass('active');\n * ```\n */\n siblings(): BQueryCollection {\n const selfSet = new Set(this.elements);\n const seen = new Set<Element>();\n const results: Element[] = [];\n for (const el of this.elements) {\n const parent = el.parentElement;\n if (!parent) continue;\n for (const sibling of Array.from(parent.children)) {\n if (!selfSet.has(sibling) && !seen.has(sibling)) {\n seen.add(sibling);\n results.push(sibling);\n }\n }\n }\n return new BQueryCollection(results);\n }\n\n /**\n * Gets the next sibling element of each element in the collection.\n * Elements without a next sibling are skipped.\n *\n * @returns A new BQueryCollection with next sibling elements\n *\n * @example\n * ```ts\n * $$('.current').next().addClass('upcoming');\n * ```\n */\n next(): BQueryCollection {\n const seen = new Set<Element>();\n const results: Element[] = [];\n for (const el of this.elements) {\n const n = el.nextElementSibling;\n if (n && !seen.has(n)) {\n seen.add(n);\n results.push(n);\n }\n }\n return new BQueryCollection(results);\n }\n\n /**\n * Gets the previous sibling element of each element in the collection.\n * Elements without a previous sibling are skipped.\n *\n * @returns A new BQueryCollection with previous sibling elements\n *\n * @example\n * ```ts\n * $$('.current').prev().addClass('previous');\n * ```\n */\n prev(): BQueryCollection {\n const seen = new Set<Element>();\n const results: Element[] = [];\n for (const el of this.elements) {\n const p = el.previousElementSibling;\n if (p && !seen.has(p)) {\n seen.add(p);\n results.push(p);\n }\n }\n return new BQueryCollection(results);\n }\n\n /**\n * Removes all elements from the DOM.\n *\n * @returns The instance for method chaining\n */\n remove(): this {\n applyAll(this.elements, (el) => el.remove());\n return this;\n }\n\n /**\n * Clears all child nodes from all elements.\n *\n * @returns The instance for method chaining\n */\n empty(): this {\n applyAll(this.elements, (el) => {\n el.innerHTML = '';\n });\n return this;\n }\n\n /** @internal */\n private insertAll(content: InsertableContent, position: InsertPosition): void {\n if (typeof content === 'string') {\n // Sanitize once and reuse for all elements\n const sanitized = sanitizeContent(content);\n applyAll(this.elements, (el) => {\n el.insertAdjacentHTML(position, sanitized);\n });\n return;\n }\n\n const elements = toElementList(content);\n this.elements.forEach((el, index) => {\n const nodes =\n index === 0 ? elements : elements.map((node) => node.cloneNode(true) as Element);\n insertContent(el, nodes, position);\n });\n }\n}\n","import { BQueryCollection } from './collection';\nimport { BQueryElement } from './element';\n\n/**\n * Select a single element. Returns a wrapper for chainable operations.\n */\nexport const $ = (selector: string | Element): BQueryElement => {\n if (typeof selector !== 'string') {\n return new BQueryElement(selector);\n }\n const element = document.querySelector(selector);\n if (!element) {\n throw new Error(`bQuery: element not found for selector \"${selector}\"`);\n }\n return new BQueryElement(element);\n};\n\n/**\n * Select multiple elements. Returns a collection wrapper.\n */\nexport const $$ = (selector: string | Element[] | NodeListOf<Element>): BQueryCollection => {\n if (Array.isArray(selector)) {\n return new BQueryCollection(selector);\n }\n if (selector instanceof NodeList) {\n return new BQueryCollection(Array.from(selector));\n }\n return new BQueryCollection(Array.from(document.querySelectorAll(selector)));\n};\n","/**\n * Array-focused utility helpers.\n *\n * @module bquery/core/utils/array\n */\n\n/**\n * Ensures the input is always returned as an array.\n *\n * @template T - The item type\n * @param value - A single value, array, or nullish value\n * @returns An array (empty if nullish)\n *\n * @example\n * ```ts\n * ensureArray('a'); // ['a']\n * ensureArray(['a', 'b']); // ['a', 'b']\n * ensureArray(null); // []\n * ```\n */\nexport function ensureArray<T>(value: T | T[] | null | undefined): T[] {\n if (value == null) return [];\n return Array.isArray(value) ? value : [value];\n}\n\n/**\n * Removes duplicate entries from an array.\n *\n * @template T - The item type\n * @param items - The array to deduplicate\n * @returns A new array with unique items\n *\n * @example\n * ```ts\n * unique([1, 2, 2, 3]); // [1, 2, 3]\n * ```\n */\nexport function unique<T>(items: T[]): T[] {\n return Array.from(new Set(items));\n}\n\n/**\n * Splits an array into chunks of a given size.\n *\n * @template T - The item type\n * @param items - The array to chunk\n * @param size - The maximum size of each chunk\n * @returns An array of chunks\n *\n * @example\n * ```ts\n * chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]\n * ```\n */\nexport function chunk<T>(items: T[], size: number): T[][] {\n if (size <= 0) return [];\n const result: T[][] = [];\n for (let i = 0; i < items.length; i += size) {\n result.push(items.slice(i, i + size));\n }\n return result;\n}\n\n/**\n * Removes falsy values from an array.\n *\n * @template T - The item type\n * @param items - The array to compact\n * @returns A new array without falsy values\n *\n * @example\n * ```ts\n * compact([0, 1, '', 'ok', null]); // [1, 'ok']\n * ```\n */\nexport function compact<T>(items: Array<T | null | undefined | false | 0 | ''>): T[] {\n return items.filter(Boolean) as T[];\n}\n\n/**\n * Flattens a single level of nested arrays.\n *\n * @template T - The item type\n * @param items - The array to flatten\n * @returns A new flattened array\n *\n * @example\n * ```ts\n * flatten([1, [2, 3], 4]); // [1, 2, 3, 4]\n * ```\n */\nexport function flatten<T>(items: Array<T | T[]>): T[] {\n const result: T[] = [];\n for (const item of items) {\n if (Array.isArray(item)) {\n result.push(...item);\n } else {\n result.push(item);\n }\n }\n return result;\n}\n","/**\n * Function-focused utility helpers.\n *\n * @module bquery/core/utils/function\n */\n\n/** A debounced function with a cancel method to clear the pending timeout. */\nexport interface DebouncedFn<TArgs extends unknown[]> {\n (...args: TArgs): void;\n /** Cancels the pending debounced invocation. */\n cancel(): void;\n}\n\n/** A throttled function with a cancel method to reset the throttle timer. */\nexport interface ThrottledFn<TArgs extends unknown[]> {\n (...args: TArgs): void;\n /** Resets the throttle timer, allowing the next call to execute immediately. */\n cancel(): void;\n}\n\n/**\n * Creates a debounced function that delays execution until after\n * the specified delay has elapsed since the last call.\n *\n * @template TArgs - The argument types of the function\n * @param fn - The function to debounce\n * @param delayMs - Delay in milliseconds\n * @returns A debounced version of the function with a `cancel()` method\n *\n * @example\n * ```ts\n * const search = debounce((query: string) => {\n * console.log('Searching:', query);\n * }, 300);\n *\n * search('h');\n * search('he');\n * search('hello'); // Only this call executes after 300ms\n *\n * search('cancel me');\n * search.cancel(); // Cancels the pending invocation\n * ```\n */\nexport function debounce<TArgs extends unknown[]>(\n fn: (...args: TArgs) => void,\n delayMs: number\n): DebouncedFn<TArgs> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const debounced: DebouncedFn<TArgs> = Object.assign(\n (...args: TArgs) => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n timeoutId = setTimeout(() => {\n timeoutId = undefined;\n fn(...args);\n }, delayMs);\n },\n {\n cancel: () => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n timeoutId = undefined;\n }\n },\n }\n );\n return debounced;\n}\n\n/**\n * Creates a throttled function that runs at most once per interval.\n *\n * @template TArgs - The argument types of the function\n * @param fn - The function to throttle\n * @param intervalMs - Minimum interval between calls in milliseconds\n * @returns A throttled version of the function with a `cancel()` method\n *\n * @example\n * ```ts\n * const handleScroll = throttle(() => {\n * console.log('Scroll position:', window.scrollY);\n * }, 100);\n *\n * window.addEventListener('scroll', handleScroll);\n *\n * handleScroll.cancel(); // Resets throttle, next call executes immediately\n * ```\n */\nexport function throttle<TArgs extends unknown[]>(\n fn: (...args: TArgs) => void,\n intervalMs: number\n): ThrottledFn<TArgs> {\n let lastRun = 0;\n const throttled: ThrottledFn<TArgs> = Object.assign(\n (...args: TArgs) => {\n const now = Date.now();\n if (now - lastRun >= intervalMs) {\n lastRun = now;\n fn(...args);\n }\n },\n {\n cancel: () => {\n lastRun = 0;\n },\n }\n );\n return throttled;\n}\n\n/**\n * Ensures a function only runs once. Subsequent calls return the first result.\n *\n * @template TArgs - The argument types of the function\n * @template TResult - The return type of the function\n * @param fn - The function to wrap\n * @returns A function that only runs once\n *\n * @example\n * ```ts\n * const init = once(() => ({ ready: true }));\n * init();\n * init(); // only runs once\n * ```\n */\nexport function once<TArgs extends unknown[], TResult>(\n fn: (...args: TArgs) => TResult\n): (...args: TArgs) => TResult {\n let hasRun = false;\n let result!: TResult;\n return (...args: TArgs) => {\n if (!hasRun) {\n result = fn(...args);\n hasRun = true;\n }\n return result;\n };\n}\n\n/**\n * A no-operation function.\n *\n * @example\n * ```ts\n * noop();\n * ```\n */\nexport function noop(): void {\n // Intentionally empty\n}\n","/**\n * Miscellaneous utility helpers.\n *\n * @module bquery/core/utils/misc\n */\n\n/**\n * Creates a stable unique ID for DOM usage.\n *\n * @param prefix - Optional prefix for the ID (default: 'bQuery')\n * @returns A unique identifier string\n *\n * @example\n * ```ts\n * const id = uid('modal'); // 'modal_x7k2m9p'\n * ```\n */\nexport function uid(prefix = 'bQuery'): string {\n return `${prefix}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\n/**\n * Delays execution for a specified number of milliseconds.\n *\n * @param ms - Milliseconds to delay\n * @returns A promise that resolves after the delay\n *\n * @example\n * ```ts\n * await sleep(1000); // Wait 1 second\n * console.log('Done!');\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Safely parses a JSON string, returning a default value on error.\n *\n * @template T - The expected type of the parsed value\n * @param json - The JSON string to parse\n * @param fallback - The default value if parsing fails\n * @returns The parsed value or the fallback\n *\n * @example\n * ```ts\n * parseJson('{\"name\":\"bQuery\"}', {}); // { name: 'bQuery' }\n * parseJson('invalid', {}); // {}\n * ```\n */\nexport function parseJson<T>(json: string, fallback: T): T {\n try {\n return JSON.parse(json) as T;\n } catch {\n return fallback;\n }\n}\n\n/**\n * Checks for emptiness across common value types.\n *\n * @param value - The value to check\n * @returns True if the value is empty (null, undefined, empty string, empty array, or empty object)\n *\n * @example\n * ```ts\n * isEmpty(''); // true\n * isEmpty([]); // true\n * isEmpty({}); // true\n * isEmpty(null); // true\n * isEmpty('hello'); // false\n * isEmpty([1, 2]); // false\n * ```\n */\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'string') return value.trim().length === 0;\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === 'object') return Object.keys(value as object).length === 0;\n return false;\n}\n","/**\n * Number-focused utility helpers.\n *\n * @module bquery/core/utils/number\n */\n\n/**\n * Generates a random integer between min and max (inclusive).\n *\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns A random integer in the range [min, max]\n *\n * @example\n * ```ts\n * const roll = randomInt(1, 6); // Random dice roll\n * ```\n */\nexport function randomInt(min: number, max: number): number {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n/**\n * Clamps a number between a minimum and maximum value.\n *\n * @param value - The value to clamp\n * @param min - Minimum value\n * @param max - Maximum value\n * @returns The clamped value\n *\n * @example\n * ```ts\n * clamp(150, 0, 100); // 100\n * clamp(-10, 0, 100); // 0\n * clamp(50, 0, 100); // 50\n * ```\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Checks if a number is within a range.\n *\n * @param value - The value to check\n * @param min - Minimum value\n * @param max - Maximum value\n * @param inclusive - Whether the range is inclusive (default: true)\n * @returns True if the value is within the range\n *\n * @example\n * ```ts\n * inRange(5, 1, 10); // true\n * inRange(10, 1, 10, false); // false\n * ```\n */\nexport function inRange(value: number, min: number, max: number, inclusive = true): boolean {\n if (inclusive) return value >= min && value <= max;\n return value > min && value < max;\n}\n\n/**\n * Converts a value to a number with a fallback on NaN.\n *\n * @param value - The value to convert\n * @param fallback - The fallback value if conversion fails (default: 0)\n * @returns The parsed number or the fallback\n *\n * @example\n * ```ts\n * toNumber('42'); // 42\n * toNumber('nope', 10); // 10\n * ```\n */\nexport function toNumber(value: unknown, fallback = 0): number {\n const parsed = typeof value === 'number' ? value : Number(value);\n return Number.isNaN(parsed) ? fallback : parsed;\n}\n","/**\n * String-focused utility helpers.\n *\n * @module bquery/core/utils/string\n */\n\n/**\n * Capitalizes the first letter of a string.\n *\n * @param str - The string to capitalize\n * @returns The capitalized string\n *\n * @example\n * ```ts\n * capitalize('hello'); // 'Hello'\n * ```\n */\nexport function capitalize(str: string): string {\n if (!str) return str;\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Converts a string to kebab-case.\n *\n * @param str - The string to convert\n * @returns The kebab-cased string\n *\n * @example\n * ```ts\n * toKebabCase('myVariableName'); // 'my-variable-name'\n * ```\n */\nexport function toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n}\n\n/**\n * Converts a string to camelCase.\n *\n * @param str - The string to convert\n * @returns The camelCased string\n *\n * @example\n * ```ts\n * toCamelCase('my-variable-name'); // 'myVariableName'\n * ```\n */\nexport function toCamelCase(str: string): string {\n return str\n .replace(/[-_\\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))\n .replace(/^[A-Z]/, (char) => char.toLowerCase());\n}\n\n/**\n * Truncates a string to a maximum length.\n *\n * @param str - The string to truncate\n * @param maxLength - The maximum length\n * @param suffix - The suffix to append when truncating (default: '…')\n * @returns The truncated string\n *\n * @example\n * ```ts\n * truncate('Hello world', 8); // 'Hello w…'\n * ```\n */\nexport function truncate(str: string, maxLength: number, suffix = '…'): string {\n if (maxLength <= 0) return '';\n if (str.length <= maxLength) return str;\n const sliceLength = Math.max(0, maxLength - suffix.length);\n return `${str.slice(0, sliceLength)}${suffix}`;\n}\n\n/**\n * Converts a string to a URL-friendly slug.\n *\n * @param str - The string to slugify\n * @returns The slugified string\n *\n * @example\n * ```ts\n * slugify('Hello, World!'); // 'hello-world'\n * ```\n */\nexport function slugify(str: string): string {\n return str\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^\\w\\s-]/g, '')\n .trim()\n .replace(/[\\s_-]+/g, '-')\n .toLowerCase();\n}\n\n/**\n * Escapes a string for safe usage inside a RegExp.\n *\n * @param str - The string to escape\n * @returns The escaped string\n *\n * @example\n * ```ts\n * escapeRegExp('[a-z]+'); // '\\\\[a-z\\\\]+'\n * ```\n */\nexport function escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","/**\n * Type guard helpers.\n *\n * @module bquery/core/utils/type-guards\n */\n\n/**\n * Checks if a value is a DOM Element.\n *\n * @param value - The value to check\n * @returns True if the value is an Element\n */\nexport function isElement(value: unknown): value is Element {\n return typeof Element !== 'undefined' && value instanceof Element;\n}\n\n/**\n * Checks if a value is a BQueryCollection-like object.\n *\n * @param value - The value to check\n * @returns True if the value has an elements array property\n */\nexport function isCollection(value: unknown): value is { elements: Element[] } {\n return Boolean(value && typeof value === 'object' && 'elements' in (value as object));\n}\n\n/**\n * Checks if a value is a function.\n *\n * @param value - The value to check\n * @returns True if the value is a function\n */\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\n return typeof value === 'function';\n}\n\n/**\n * Checks if a value is a string.\n *\n * @param value - The value to check\n * @returns True if the value is a string\n */\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Checks if a value is a number (excluding NaN).\n *\n * @param value - The value to check\n * @returns True if the value is a valid number\n */\nexport function isNumber(value: unknown): value is number {\n return typeof value === 'number' && !Number.isNaN(value);\n}\n\n/**\n * Checks if a value is a boolean.\n *\n * @param value - The value to check\n * @returns True if the value is a boolean\n */\nexport function isBoolean(value: unknown): value is boolean {\n return typeof value === 'boolean';\n}\n\n/**\n * Checks if a value is an array.\n *\n * @template T - The type of array elements\n * @param value - The value to check\n * @returns True if the value is an array\n */\nexport function isArray<T = unknown>(value: unknown): value is T[] {\n return Array.isArray(value);\n}\n\n/**\n * Checks if a value is a Date instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Date\n */\nexport function isDate(value: unknown): value is Date {\n return value instanceof Date;\n}\n\n/**\n * Checks if a value is a Promise-like object.\n *\n * @param value - The value to check\n * @returns True if the value is a Promise-like object\n */\nexport function isPromise<T = unknown>(value: unknown): value is Promise<T> {\n return Boolean(\n value &&\n (value instanceof Promise ||\n (typeof value === 'object' &&\n 'then' in (value as object) &&\n typeof (value as { then?: unknown }).then === 'function'))\n );\n}\n\n/**\n * Checks if a value is a non-null object.\n *\n * @param value - The value to check\n * @returns True if the value is an object\n */\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n","/**\n * Utility helpers used across the framework.\n * These are intentionally small and framework-agnostic to keep the core tiny.\n *\n * @module bquery/core/utils\n */\n\nexport * from './array';\nexport * from './function';\nexport * from './misc';\nexport * from './number';\nexport * from './object';\nexport * from './string';\nexport * from './type-guards';\n\nimport { chunk, compact, ensureArray, flatten, unique } from './array';\nimport { debounce, noop, once, throttle } from './function';\nimport { isEmpty, parseJson, sleep, uid } from './misc';\nimport { clamp, inRange, randomInt, toNumber } from './number';\nimport { clone, hasOwn, isPlainObject, merge, omit, pick } from './object';\nimport { capitalize, escapeRegExp, slugify, toCamelCase, toKebabCase, truncate } from './string';\nimport {\n isArray,\n isBoolean,\n isCollection,\n isDate,\n isElement,\n isFunction,\n isNumber,\n isObject,\n isPromise,\n isString,\n} from './type-guards';\n\n/**\n * Describes the public shape of the aggregated {@link utils} namespace.\n *\n * Every member maps 1-to-1 to a named export from one of the sub-modules\n * (`array`, `function`, `misc`, `number`, `object`, `string`, `type-guards`).\n *\n * `isPrototypePollutionKey` is intentionally excluded as it is an\n * internal security helper. It remains available as a named export for\n * internal framework use.\n */\nexport interface BQueryUtils {\n // ── object ──────────────────────────────────────────────────────────\n readonly clone: typeof clone;\n readonly merge: typeof merge;\n readonly pick: typeof pick;\n readonly omit: typeof omit;\n readonly hasOwn: typeof hasOwn;\n readonly isPlainObject: typeof isPlainObject;\n\n // ── function ────────────────────────────────────────────────────────\n readonly debounce: typeof debounce;\n readonly throttle: typeof throttle;\n readonly once: typeof once;\n readonly noop: typeof noop;\n\n // ── misc ────────────────────────────────────────────────────────────\n readonly uid: typeof uid;\n readonly isEmpty: typeof isEmpty;\n readonly parseJson: typeof parseJson;\n readonly sleep: typeof sleep;\n\n // ── type-guards ─────────────────────────────────────────────────────\n readonly isElement: typeof isElement;\n readonly isCollection: typeof isCollection;\n readonly isFunction: typeof isFunction;\n readonly isString: typeof isString;\n readonly isNumber: typeof isNumber;\n readonly isBoolean: typeof isBoolean;\n readonly isArray: typeof isArray;\n readonly isDate: typeof isDate;\n readonly isPromise: typeof isPromise;\n readonly isObject: typeof isObject;\n\n // ── number ──────────────────────────────────────────────────────────\n readonly randomInt: typeof randomInt;\n readonly clamp: typeof clamp;\n readonly inRange: typeof inRange;\n readonly toNumber: typeof toNumber;\n\n // ── string ──────────────────────────────────────────────────────────\n readonly capitalize: typeof capitalize;\n readonly toKebabCase: typeof toKebabCase;\n readonly toCamelCase: typeof toCamelCase;\n readonly truncate: typeof truncate;\n readonly slugify: typeof slugify;\n readonly escapeRegExp: typeof escapeRegExp;\n\n // ── array ───────────────────────────────────────────────────────────\n readonly ensureArray: typeof ensureArray;\n readonly unique: typeof unique;\n readonly chunk: typeof chunk;\n readonly compact: typeof compact;\n readonly flatten: typeof flatten;\n}\n\n/**\n * Utility object containing common helper functions.\n * All utilities are designed to be tree-shakeable and have zero dependencies.\n *\n * Note: `isPrototypePollutionKey` is intentionally excluded from this namespace\n * as it is an internal security helper. It remains available as a named export\n * for internal framework use.\n */\nexport const utils: BQueryUtils = {\n clone,\n merge,\n pick,\n omit,\n hasOwn,\n debounce,\n throttle,\n once,\n noop,\n uid,\n isElement,\n isCollection,\n isEmpty,\n isPlainObject,\n isFunction,\n isString,\n isNumber,\n isBoolean,\n isArray,\n isDate,\n isPromise,\n isObject,\n parseJson,\n sleep,\n randomInt,\n clamp,\n inRange,\n toNumber,\n capitalize,\n toKebabCase,\n toCamelCase,\n truncate,\n slugify,\n escapeRegExp,\n ensureArray,\n unique,\n chunk,\n compact,\n flatten,\n};\n","/**\n * Internal reactive plumbing shared across primitives.\n * @internal\n */\n\nexport type Observer = () => void;\nexport type CleanupFn = () => void;\n\n/**\n * Interface for reactive sources (Signals, Computed) that can unsubscribe observers.\n * @internal\n */\nexport interface ReactiveSource {\n unsubscribe(observer: Observer): void;\n}\n\nconst observerStack: Observer[] = [];\nlet batchDepth = 0;\nconst pendingObservers = new Set<Observer>();\n\n// Track dependencies for each observer to enable cleanup\nconst observerDependencies = new WeakMap<Observer, Set<ReactiveSource>>();\n\nexport const track = <T>(observer: Observer, fn: () => T): T => {\n observerStack.push(observer);\n try {\n return fn();\n } finally {\n observerStack.pop();\n }\n};\n\nexport const getCurrentObserver = (): Observer | undefined =>\n observerStack[observerStack.length - 1];\n\n/**\n * Executes a function without exposing the current observer to dependencies.\n * Unlike disabling tracking globally, this still allows nested reactive internals\n * (e.g., computed recomputation) to track their own dependencies.\n * @internal\n */\nexport const withoutCurrentObserver = <T>(fn: () => T): T => {\n // Push undefined to temporarily \"hide\" the current observer\n // This way, Signal.value reads won't link to the previous observer,\n // but nested track() calls (e.g., computed recompute) still work normally.\n observerStack.push(undefined as unknown as Observer);\n try {\n return fn();\n } finally {\n observerStack.pop();\n }\n};\n\nexport const scheduleObserver = (observer: Observer): void => {\n if (batchDepth > 0) {\n pendingObservers.add(observer);\n return;\n }\n observer();\n};\n\nconst flushObservers = (): void => {\n for (const observer of Array.from(pendingObservers)) {\n pendingObservers.delete(observer);\n try {\n observer();\n } catch (error) {\n console.error('bQuery reactive: Error in observer during batch flush', error);\n }\n }\n};\n\nexport const beginBatch = (): void => {\n batchDepth += 1;\n};\n\nexport const endBatch = (): void => {\n if (batchDepth <= 0) return;\n batchDepth -= 1;\n if (batchDepth === 0) {\n flushObservers();\n }\n};\n\n/**\n * Registers a dependency between an observer and a reactive source.\n * @internal\n */\nexport const registerDependency = (observer: Observer, source: ReactiveSource): void => {\n let deps = observerDependencies.get(observer);\n if (!deps) {\n deps = new Set();\n observerDependencies.set(observer, deps);\n }\n deps.add(source);\n};\n\n/**\n * Removes a specific source from an observer's dependency set.\n * Used when a source (e.g. Signal) is disposed to prevent stale references.\n * @internal\n */\nexport const removeDependency = (observer: Observer, source: ReactiveSource): void => {\n const deps = observerDependencies.get(observer);\n if (deps) {\n deps.delete(source);\n }\n};\n\n/**\n * Clears all dependencies for an observer, unsubscribing from all sources.\n * @internal\n */\nexport const clearDependencies = (observer: Observer): void => {\n const deps = observerDependencies.get(observer);\n if (deps) {\n for (const source of deps) {\n source.unsubscribe(observer);\n }\n deps.clear();\n }\n};\n","/**\n * Batched reactive updates.\n */\n\nimport { beginBatch, endBatch } from './internals';\n\n/**\n * Batches multiple signal updates into a single notification cycle.\n *\n * Updates made inside the batch function are deferred until the batch\n * completes, preventing intermediate re-renders and improving performance.\n *\n * @param fn - Function containing multiple signal updates\n */\nexport const batch = (fn: () => void): void => {\n beginBatch();\n try {\n fn();\n } finally {\n endBatch();\n }\n};\n","/**\n * Global bQuery configuration helpers.\n *\n * @module bquery/platform\n */\n\nimport { isPlainObject, merge } from '../core/utils/object';\n\n/** Supported response parsing strategies for fetch composables. */\nexport type BqueryFetchParseAs = 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData' | 'response';\n\n/** Global fetch defaults used by useFetch(). */\nexport interface BqueryFetchConfig {\n /** Optional base URL prepended to relative request URLs. */\n baseUrl?: string;\n /** Default request headers. */\n headers?: HeadersInit;\n /** Default response parser. */\n parseAs?: BqueryFetchParseAs;\n}\n\n/** Global cookie defaults used by useCookie(). */\nexport interface BqueryCookieConfig {\n /** Default cookie path. */\n path?: string;\n /** Default SameSite mode. */\n sameSite?: 'Strict' | 'Lax' | 'None';\n /** Whether cookies should be marked secure by default. */\n secure?: boolean;\n}\n\n/** Global announcer defaults used by useAnnouncer(). */\nexport interface BqueryAnnouncerConfig {\n /** Default politeness level. */\n politeness?: 'polite' | 'assertive';\n /** Whether announcements should be treated atomically. */\n atomic?: boolean;\n /** Delay before writing the message into the live region. */\n delay?: number;\n /** Delay after which the live region is cleared automatically. */\n clearDelay?: number;\n}\n\n/** Global page meta defaults used by definePageMeta(). */\nexport interface BqueryPageMetaConfig {\n /** Optional title template function. */\n titleTemplate?: (title: string) => string;\n}\n\n/** Global motion defaults used by transition(). */\nexport interface BqueryTransitionConfig {\n /** Skip transitions when reduced motion is preferred. */\n skipOnReducedMotion?: boolean;\n /** Classes applied to the root element during transitions. */\n classes?: string[];\n /** Transition type identifiers added when supported by the browser. */\n types?: string[];\n}\n\n/** Global default component library configuration. */\nexport interface BqueryComponentLibraryConfig {\n /** Prefix used by registerDefaultComponents(). */\n prefix?: string;\n}\n\n/** Complete global bQuery configuration object. */\nexport interface BqueryConfig {\n /** Fetch composable defaults. */\n fetch?: BqueryFetchConfig;\n /** Cookie composable defaults. */\n cookies?: BqueryCookieConfig;\n /** Announcer composable defaults. */\n announcer?: BqueryAnnouncerConfig;\n /** Page metadata defaults. */\n pageMeta?: BqueryPageMetaConfig;\n /** View transition defaults. */\n transitions?: BqueryTransitionConfig;\n /** Default component library options. */\n components?: BqueryComponentLibraryConfig;\n}\n\nconst defaultConfig: BqueryConfig = {\n fetch: {\n headers: {},\n parseAs: 'json',\n },\n cookies: {\n path: '/',\n sameSite: 'Lax',\n secure: false,\n },\n announcer: {\n politeness: 'polite',\n atomic: true,\n delay: 16,\n clearDelay: 1000,\n },\n pageMeta: {},\n transitions: {\n skipOnReducedMotion: false,\n classes: [],\n types: [],\n },\n components: {\n prefix: 'bq',\n },\n};\n\nconst cloneConfigValue = <T>(value: T): T => {\n if (typeof Headers !== 'undefined' && value instanceof Headers) {\n return new Headers(value) as T;\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => cloneConfigValue(entry)) as T;\n }\n\n if (isPlainObject(value)) {\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n result[key] = cloneConfigValue(entry);\n }\n return result as T;\n }\n\n return value;\n};\n\nlet currentConfig: BqueryConfig = cloneConfigValue(defaultConfig);\n\n/**\n * Define or extend the global bQuery configuration.\n *\n * @param config - Partial configuration values to merge into the current config\n * @returns The resolved configuration after merging\n *\n * @example\n * ```ts\n * defineBqueryConfig({\n * fetch: { baseUrl: 'https://api.example.com' },\n * components: { prefix: 'ui' },\n * });\n * ```\n */\nexport const defineBqueryConfig = (config: BqueryConfig): BqueryConfig => {\n currentConfig = cloneConfigValue(\n merge(\n defaultConfig as Record<string, unknown>,\n currentConfig as Record<string, unknown>,\n config as Record<string, unknown>\n ) as BqueryConfig\n );\n return getBqueryConfig();\n};\n\n/**\n * Get the currently resolved bQuery configuration.\n *\n * @returns A cloned snapshot of the active configuration\n */\nexport const getBqueryConfig = (): BqueryConfig => {\n return cloneConfigValue(currentConfig);\n};\n","/**\n * Reactive effect scopes for grouped disposal.\n *\n * An `EffectScope` collects all effects, computed values, and watches created\n * inside its `run()` callback so they can be disposed together with a single\n * `stop()` call. Scopes nest — an inner scope is collected by its parent.\n *\n * @module bquery/reactive\n */\n\nimport type { CleanupFn } from './internals';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A scope that collects reactive resources for grouped disposal.\n *\n * @example\n * ```ts\n * import { effectScope, signal, effect, computed } from '@bquery/bquery/reactive';\n *\n * const scope = effectScope();\n *\n * scope.run(() => {\n * const count = signal(0);\n * effect(() => console.log(count.value));\n * const doubled = computed(() => count.value * 2);\n * });\n *\n * scope.stop(); // All effects and computed values disposed\n * ```\n */\nexport interface EffectScope {\n /** Whether the scope has not yet been stopped. */\n readonly active: boolean;\n\n /**\n * Executes `fn` inside this scope, collecting any reactive resources\n * (effects, computed values, watches, nested scopes) created during the call.\n *\n * `run()` is synchronous-only. Do not pass an async function or a function\n * that returns a Promise — resources created after an `await` cannot be\n * collected reliably.\n *\n * @template T - Return type of the provided function\n * @param fn - Function to run inside the scope\n * @returns The return value of `fn`\n * @throws {Error} If the scope has already been stopped\n */\n run<T>(fn: () => T): T;\n\n /**\n * Disposes all collected resources and marks the scope as inactive.\n * Calling `stop()` on an already-stopped scope is a safe no-op.\n */\n stop(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Internal scope stack\n// ---------------------------------------------------------------------------\n\n/** @internal */\ninterface ScopeInternal extends EffectScope {\n /** @internal – Register a cleanup callback to run when the scope stops. */\n _addDisposer(fn: CleanupFn): void;\n}\n\nconst scopeStack: ScopeInternal[] = [];\n\n/** @internal */\nexport const hasScopeDisposer = (\n scope: EffectScope | undefined\n): scope is EffectScope & { _addDisposer(fn: CleanupFn): void } =>\n typeof scope === 'object' && scope !== null && '_addDisposer' in scope;\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n (typeof value === 'object' || typeof value === 'function') &&\n value !== null &&\n typeof (value as { then?: unknown }).then === 'function';\n\n/**\n * Best-effort detection for native async functions so `run()` can reject them\n * before invocation. Transpiled async functions may not preserve this shape, so\n * promise-like return values are still checked after execution as a fallback.\n * @internal\n */\nconst isAsyncFunction = (value: unknown): value is (...args: never[]) => Promise<unknown> => {\n const constructorName =\n typeof (value as { constructor?: unknown }).constructor === 'function'\n ? (value as { constructor: { name?: unknown } }).constructor.name\n : undefined;\n\n return (\n typeof value === 'function' &&\n ((Symbol.toStringTag in value &&\n (value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag] === 'AsyncFunction') ||\n constructorName === 'AsyncFunction')\n );\n};\n\n/**\n * Returns the currently active scope, or `undefined` if none.\n * @internal\n */\nexport const getActiveScope = (): EffectScope | undefined => {\n for (let i = scopeStack.length - 1; i >= 0; i--) {\n if (scopeStack[i].active) {\n return scopeStack[i];\n }\n }\n\n return undefined;\n};\n\n// ---------------------------------------------------------------------------\n// EffectScope implementation\n// ---------------------------------------------------------------------------\n\nclass EffectScopeImpl implements ScopeInternal {\n private disposers: CleanupFn[] = [];\n private _active = true;\n\n get active(): boolean {\n return this._active;\n }\n\n /** @internal */\n _addDisposer(fn: CleanupFn): void {\n if (this._active) {\n this.disposers.push(fn);\n }\n }\n\n run<T>(fn: () => T): T {\n if (!this._active) {\n throw new Error('bQuery reactive: Cannot run in a stopped effectScope');\n }\n if (isAsyncFunction(fn)) {\n throw new Error('bQuery reactive: effectScope.run() only supports synchronous callbacks');\n }\n\n scopeStack.push(this);\n try {\n const result = fn();\n if (isPromiseLike(result)) {\n this.stop();\n throw new Error('bQuery reactive: effectScope.run() only supports synchronous callbacks');\n }\n return result;\n } finally {\n scopeStack.pop();\n }\n }\n\n stop(): void {\n if (!this._active) return;\n this._active = false;\n\n // Dispose in reverse order (LIFO) to mirror creation order\n for (let i = this.disposers.length - 1; i >= 0; i--) {\n try {\n this.disposers[i]();\n } catch (error) {\n console.error('bQuery reactive: Error in scope cleanup', error);\n }\n }\n this.disposers.length = 0;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a new effect scope for grouped disposal of reactive resources.\n *\n * All `effect()`, `computed()`, `watch()`, and nested `effectScope()` calls\n * made inside `scope.run(fn)` are automatically collected. Calling\n * `scope.stop()` disposes them all at once.\n *\n * `run()` is synchronous-only. Create the scope outside async flows when\n * needed, but keep the callback itself synchronous so cleanup registration\n * stays deterministic.\n *\n * @returns A new {@link EffectScope}\n *\n * @example\n * ```ts\n * import { effectScope, signal, effect, onScopeDispose } from '@bquery/bquery/reactive';\n *\n * const scope = effectScope();\n *\n * scope.run(() => {\n * const count = signal(0);\n *\n * effect(() => console.log(count.value));\n *\n * onScopeDispose(() => {\n * console.log('Custom cleanup');\n * });\n * });\n *\n * scope.stop(); // logs \"Custom cleanup\", all effects stopped\n * ```\n */\nexport const effectScope = (): EffectScope => {\n const scope = new EffectScopeImpl();\n\n // If created inside another scope, auto-collect as a nested scope\n const parent = getActiveScope();\n if (hasScopeDisposer(parent)) {\n parent._addDisposer(() => scope.stop());\n }\n\n return scope;\n};\n\n/**\n * Returns the currently active {@link EffectScope}, or `undefined` if\n * code is not running inside any scope's `run()` callback.\n *\n * @returns The active scope, or `undefined`\n *\n * @example\n * ```ts\n * import { effectScope, getCurrentScope } from '@bquery/bquery/reactive';\n *\n * const scope = effectScope();\n * scope.run(() => {\n * console.log(getCurrentScope() !== undefined); // true\n * });\n *\n * console.log(getCurrentScope()); // undefined\n * ```\n */\nexport const getCurrentScope = (): EffectScope | undefined => getActiveScope();\n\n/**\n * Registers a cleanup callback on the currently active scope.\n *\n * The callback runs when the scope is stopped. This is useful for\n * registering arbitrary cleanup (e.g. event listeners, timers)\n * alongside effects and computed values.\n *\n * @param fn - Cleanup function to run when the scope stops\n * @throws {Error} If called outside an active scope\n *\n * @example\n * ```ts\n * import { effectScope, onScopeDispose } from '@bquery/bquery/reactive';\n *\n * const scope = effectScope();\n *\n * scope.run(() => {\n * const controller = new AbortController();\n * fetch('/api/data', { signal: controller.signal });\n *\n * onScopeDispose(() => controller.abort());\n * });\n *\n * scope.stop(); // abort() is called\n * ```\n */\nexport const onScopeDispose = (fn: CleanupFn): void => {\n const scope = getActiveScope();\n if (!scope || !scope.active || !hasScopeDisposer(scope)) {\n throw new Error(\n 'bQuery reactive: onScopeDispose() must be called inside an active effectScope'\n );\n }\n scope._addDisposer(fn);\n};\n","/**\n * Computed reactive values.\n */\n\nimport {\n clearDependencies,\n getCurrentObserver,\n registerDependency,\n scheduleObserver,\n track,\n withoutCurrentObserver,\n type ReactiveSource,\n} from './internals';\nimport { getActiveScope, hasScopeDisposer } from './scope';\n\n/**\n * A computed value that derives from other reactive sources.\n *\n * Computed values are lazily evaluated and cached. They only\n * recompute when their dependencies change.\n *\n * @template T - The type of the computed value\n */\nexport class Computed<T> implements ReactiveSource {\n private cachedValue!: T;\n private hasCachedValue = false;\n private dirty = true;\n private disposed = false;\n private subscribers = new Set<() => void>();\n private readonly markDirty = () => {\n if (this.disposed) {\n return;\n }\n this.dirty = true;\n // Create snapshot to avoid issues with subscribers modifying the set during iteration\n const subscribersSnapshot = Array.from(this.subscribers);\n for (const subscriber of subscribersSnapshot) {\n scheduleObserver(subscriber);\n }\n };\n\n /**\n * Creates a new computed value.\n * @param compute - Function that computes the value\n */\n constructor(private readonly compute: () => T) {}\n\n /**\n * Gets the computed value, recomputing if dependencies changed.\n * During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.\n */\n get value(): T {\n if (this.disposed) {\n if (!this.hasCachedValue) {\n this.cachedValue = withoutCurrentObserver(() => this.compute());\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n const current = getCurrentObserver();\n if (current) {\n this.subscribers.add(current);\n registerDependency(current, this);\n }\n if (this.dirty) {\n this.dirty = false;\n // Clear old dependencies before recomputing\n clearDependencies(this.markDirty);\n this.cachedValue = track(this.markDirty, this.compute);\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n /**\n * Reads the current computed value without tracking.\n * Useful when you need the value but don't want to create a dependency.\n *\n * @returns The current cached value (recomputes if dirty)\n */\n peek(): T {\n if (this.disposed) {\n if (!this.hasCachedValue) {\n this.cachedValue = withoutCurrentObserver(() => this.compute());\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n if (this.dirty) {\n this.dirty = false;\n // Clear old dependencies before recomputing\n clearDependencies(this.markDirty);\n this.cachedValue = track(this.markDirty, this.compute);\n this.hasCachedValue = true;\n }\n return this.cachedValue;\n }\n\n /**\n * Removes an observer from this computed's subscriber set.\n * @internal\n */\n unsubscribe(observer: () => void): void {\n this.subscribers.delete(observer);\n }\n\n /**\n * Disposes the computed value by unsubscribing its internal observer\n * from all upstream dependencies and clearing subscribers.\n */\n dispose(): void {\n this.disposed = true;\n if (this.dirty) {\n this.hasCachedValue = false;\n }\n this.dirty = false;\n clearDependencies(this.markDirty);\n this.subscribers.clear();\n }\n}\n\n/**\n * Creates a new computed value.\n *\n * If created inside an {@link effectScope}, the computed value is automatically\n * collected and will be disposed when the scope stops.\n *\n * @template T - The type of the computed value\n * @param fn - Function that computes the value from reactive sources\n * @returns A new Computed instance\n */\nexport const computed = <T>(fn: () => T): Computed<T> => {\n const c = new Computed(fn);\n\n // Auto-register with the current scope so scope.stop() disposes this computed\n const scope = getActiveScope();\n if (hasScopeDisposer(scope)) {\n scope._addDisposer(() => c.dispose());\n }\n\n return c;\n};\n","/**\n * Reactive effects.\n */\n\nimport { CleanupFn, Observer, track, clearDependencies } from './internals';\nimport { getActiveScope, hasScopeDisposer } from './scope';\n\n/**\n * Creates a side effect that automatically re-runs when dependencies change.\n *\n * The effect runs immediately upon creation and then re-runs whenever\n * any signal or computed value read inside it changes.\n *\n * If created inside an {@link effectScope}, the effect is automatically\n * collected and will be disposed when the scope stops.\n *\n * @param fn - The effect function to run\n * @returns A cleanup function to stop the effect\n */\nexport const effect = (fn: () => void | CleanupFn): CleanupFn => {\n let cleanupFn: CleanupFn | void;\n let isDisposed = false;\n const scope = getActiveScope();\n\n const runCleanup = (): void => {\n if (cleanupFn) {\n try {\n cleanupFn();\n } catch (error) {\n console.error('bQuery reactive: Error in effect cleanup', error);\n }\n cleanupFn = undefined;\n }\n };\n\n const clearEffectState = (): void => {\n runCleanup();\n // Clean up all dependencies when effect is disposed\n clearDependencies(observer);\n };\n\n const dispose: CleanupFn = () => {\n if (isDisposed) {\n return;\n }\n\n isDisposed = true;\n clearEffectState();\n };\n\n if (hasScopeDisposer(scope)) {\n scope._addDisposer(dispose);\n }\n\n const observer: Observer = () => {\n if (isDisposed) return;\n\n runCleanup();\n\n // Clear old dependencies before running to avoid stale subscriptions\n clearDependencies(observer);\n\n try {\n cleanupFn = track(observer, fn);\n } catch (error) {\n console.error('bQuery reactive: Error in effect', error);\n }\n\n if (isDisposed) {\n clearEffectState();\n }\n };\n\n observer();\n\n return dispose;\n};\n","/**\n * Core reactive signals.\n */\n\nimport {\n getCurrentObserver,\n registerDependency,\n removeDependency,\n scheduleObserver,\n type ReactiveSource,\n} from './internals';\n\n/**\n * A reactive value container that notifies subscribers on change.\n *\n * Signals are the foundational primitive of the reactive system.\n * Reading a signal's value inside an effect or computed automatically\n * establishes a reactive dependency.\n *\n * @template T - The type of the stored value\n */\nexport class Signal<T> implements ReactiveSource {\n private subscribers = new Set<() => void>();\n\n /**\n * Creates a new signal with an initial value.\n * @param _value - The initial value\n */\n constructor(private _value: T) {}\n\n /**\n * Gets the current value and tracks the read if inside an observer.\n * During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.\n */\n get value(): T {\n const current = getCurrentObserver();\n if (current) {\n this.subscribers.add(current);\n registerDependency(current, this);\n }\n return this._value;\n }\n\n /**\n * Sets a new value and notifies all subscribers if the value changed.\n * Uses Object.is for equality comparison.\n */\n set value(next: T) {\n if (Object.is(this._value, next)) return;\n this._value = next;\n // Create snapshot to avoid issues with subscribers modifying the set during iteration\n const subscribersSnapshot = Array.from(this.subscribers);\n for (const subscriber of subscribersSnapshot) {\n scheduleObserver(subscriber);\n }\n }\n\n /**\n * Reads the current value without tracking.\n * Useful when you need the value but don't want to create a dependency.\n *\n * @returns The current value\n */\n peek(): T {\n return this._value;\n }\n\n /**\n * Updates the value using a function.\n * Useful for updates based on the current value.\n *\n * @param updater - Function that receives current value and returns new value\n */\n update(updater: (current: T) => T): void {\n this.value = updater(this._value);\n }\n\n /**\n * Removes all subscribers from this signal.\n * Use this when a signal is no longer needed to prevent memory leaks.\n *\n * @example\n * ```ts\n * const count = signal(0);\n * effect(() => console.log(count.value));\n * count.dispose(); // All subscribers removed\n * ```\n */\n dispose(): void {\n // Remove this signal from each subscriber's dependency set\n // so the observer no longer holds a strong reference to it\n for (const subscriber of this.subscribers) {\n removeDependency(subscriber, this);\n }\n this.subscribers.clear();\n }\n\n /**\n * Removes an observer from this signal's subscriber set.\n * @internal\n */\n unsubscribe(observer: () => void): void {\n this.subscribers.delete(observer);\n }\n}\n\n/**\n * Creates a new reactive signal.\n *\n * @template T - The type of the signal value\n * @param value - The initial value\n * @returns A new Signal instance\n */\nexport const signal = <T>(value: T): Signal<T> => new Signal(value);\n","/**\n * Dependency tracking control helpers.\n */\n\nimport { withoutCurrentObserver } from './internals';\n\n/**\n * Executes a function without tracking any signal dependencies.\n * Useful when reading a signal value without creating a reactive dependency.\n *\n * This implementation temporarily hides the current observer rather than\n * disabling tracking globally. This ensures that nested reactive internals\n * (e.g., computed recomputation triggered during untrack) can still properly\n * track their own dependencies.\n *\n * @template T - The return type of the function\n * @param fn - The function to execute without tracking\n * @returns The result of the function\n *\n * @example\n * ```ts\n * const count = signal(0);\n * effect(() => {\n * // This read creates a dependency\n * console.log(count.value);\n * // This read does not create a dependency\n * const snapshot = untrack(() => count.value);\n * });\n * ```\n */\nexport const untrack = <T>(fn: () => T): T => withoutCurrentObserver(fn);\n","/**\n * Async data and fetch composables built on bQuery signals.\n *\n * @module bquery/reactive\n */\n\nimport { merge } from '../core/utils/object';\nimport { getBqueryConfig, type BqueryFetchParseAs } from '../platform/config';\nimport { computed } from './computed';\nimport { effect } from './effect';\nimport { Signal, signal } from './core';\nimport { untrack } from './untrack';\n\n/** Allowed status values for async composables. */\nexport type AsyncDataStatus = 'idle' | 'pending' | 'success' | 'error';\n\n/** Reactive source types that can trigger refreshes. */\nexport type AsyncWatchSource = (() => unknown) | { value: unknown };\n\n/** Options shared by async composables. */\nexport interface UseAsyncDataOptions<TResult, TData = TResult> {\n /** Run the handler immediately (default: true). */\n immediate?: boolean;\n /** Default data value before the first successful execution. */\n defaultValue?: TData;\n /** Optional reactive sources that trigger refreshes when they change. */\n watch?: AsyncWatchSource[];\n /** Transform the resolved value before storing it. */\n transform?: (value: TResult) => TData;\n /** Called after a successful execution. */\n onSuccess?: (value: TData) => void;\n /** Called after a failed execution. */\n onError?: (error: Error) => void;\n}\n\n/** Return value of useAsyncData() and useFetch(). */\nexport interface AsyncDataState<TData> {\n /** Reactive data signal. */\n data: Signal<TData | undefined>;\n /** Last error encountered by the composable. */\n error: Signal<Error | null>;\n /** Current lifecycle status. */\n status: Signal<AsyncDataStatus>;\n /** Computed boolean that mirrors `status === 'pending'`. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Execute the handler manually. Returns the cached data value when called after dispose(). */\n execute: () => Promise<TData | undefined>;\n /** Alias for execute(). */\n refresh: () => Promise<TData | undefined>;\n /** Abort the current in-flight request (useFetch only; no-op for useAsyncData). */\n abort: () => void;\n /** Clear data, error, and status back to the initial state. */\n clear: () => void;\n /** Dispose reactive watchers and prevent future executions. */\n dispose: () => void;\n}\n\n/** Configuration for automatic request retries in useFetch(). */\nexport interface UseFetchRetryConfig {\n /** Maximum number of retry attempts (default: 3). */\n count: number;\n /** Delay in ms between retries, or a function receiving the attempt index. */\n delay?: number | ((attempt: number) => number);\n /** Predicate deciding whether to retry. Defaults to network / 5xx errors. */\n retryOn?: (error: Error, attempt: number) => boolean;\n}\n\n/** Options for useFetch(). */\nexport interface UseFetchOptions<TResponse = unknown, TData = TResponse>\n extends UseAsyncDataOptions<TResponse, TData>, Omit<RequestInit, 'body' | 'headers' | 'signal'> {\n /** Base URL prepended to relative URLs. */\n baseUrl?: string;\n /** Query parameters appended to the request URL. */\n query?: Record<string, unknown>;\n /** Request headers. */\n headers?: HeadersInit;\n /** Request body, including plain objects for JSON requests. */\n body?: BodyInit | Record<string, unknown> | unknown[] | null;\n /** Override the parser used for the response body. */\n parseAs?: BqueryFetchParseAs;\n /** Custom fetch implementation for testing or adapters. */\n fetcher?: typeof fetch;\n /** Request timeout in milliseconds. 0 means no timeout. */\n timeout?: number;\n /** External AbortSignal for request cancellation. */\n signal?: AbortSignal;\n /** Retry configuration. Pass a number for simple retry count, or a config object. */\n retry?: number | UseFetchRetryConfig;\n /** Custom status validation. Returns `true` for acceptable statuses. */\n validateStatus?: (status: number) => boolean;\n}\n\n/** Input accepted by useFetch(). */\nexport type FetchInput = string | URL | Request | (() => string | URL | Request);\n\nconst normalizeError = (error: unknown): Error => {\n if (error instanceof Error) return error;\n if (typeof error === 'string') {\n return new Error(error);\n }\n\n try {\n return new Error(JSON.stringify(error));\n } catch {\n return new Error(String(error));\n }\n};\n\nconst readWatchSource = (source: AsyncWatchSource): unknown => {\n if (typeof source === 'function') {\n return source();\n }\n return source.value;\n};\n\nconst toHeaders = (...sources: Array<HeadersInit | undefined>): Headers => {\n const headers = new Headers();\n for (const source of sources) {\n if (!source) continue;\n new Headers(source).forEach((value, key) => {\n headers.set(key, value);\n });\n }\n return headers;\n};\n\nconst isBodyLike = (value: unknown): value is BodyInit => {\n if (typeof value === 'string') return true;\n if (value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams) {\n return true;\n }\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) return true;\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) return true;\n return typeof value === 'object' && value !== null && ArrayBuffer.isView(value);\n};\n\nconst serializeBody = (\n body: UseFetchOptions['body'],\n headers: Headers\n): BodyInit | null | undefined => {\n if (body == null) return body;\n if (isBodyLike(body)) return body;\n\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n return JSON.stringify(body);\n};\n\nconst resolveInput = (input: FetchInput): string | URL | Request => {\n return typeof input === 'function' ? input() : input;\n};\n\nconst appendQuery = (url: URL, query: Record<string, unknown>): void => {\n for (const [key, value] of Object.entries(query)) {\n if (value == null) continue;\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item != null) {\n url.searchParams.append(key, String(item));\n }\n }\n continue;\n }\n\n url.searchParams.set(key, String(value));\n }\n};\n\nconst toUrl = (input: string | URL, baseUrl?: string): URL => {\n const runtimeBase =\n typeof window !== 'undefined' && /^https?:/i.test(window.location.href)\n ? window.location.href\n : 'http://localhost';\n const base = baseUrl ? new URL(baseUrl, runtimeBase).toString() : runtimeBase;\n return input instanceof URL ? new URL(input.toString(), base) : new URL(input, base);\n};\n\nconst parseResponse = async <TResponse>(\n response: Response,\n parseAs: BqueryFetchParseAs\n): Promise<TResponse> => {\n if (parseAs === 'response') return response as TResponse;\n if (parseAs === 'text') return (await response.text()) as TResponse;\n if (parseAs === 'blob') return (await response.blob()) as TResponse;\n if (parseAs === 'arrayBuffer') return (await response.arrayBuffer()) as TResponse;\n if (parseAs === 'formData') return (await response.formData()) as TResponse;\n\n const text = await response.text();\n if (!text) {\n return undefined as TResponse;\n }\n\n try {\n return JSON.parse(text) as TResponse;\n } catch (error) {\n const detail = response.url ? ` for ${response.url}` : '';\n throw new Error(\n `Failed to parse JSON response${detail} (status ${response.status}): ${error instanceof Error ? error.message : String(error)}`\n );\n }\n};\n\nconst normalizeMethod = (method?: string): string | undefined => {\n const normalized = method?.trim();\n return normalized ? normalized.toUpperCase() : undefined;\n};\n\nconst resolveMethod = (\n explicitMethod: string | undefined,\n requestInput: string | URL | Request,\n bodyProvided: boolean\n): string | undefined => {\n const requestMethod =\n requestInput instanceof Request ? normalizeMethod(requestInput.method) : undefined;\n return explicitMethod ?? requestMethod ?? (bodyProvided ? 'POST' : undefined);\n};\n\nconst resolveRequestInitMethod = (\n explicitMethod: string | undefined,\n requestInput: string | URL | Request,\n method: string | undefined\n): string | undefined => {\n if (explicitMethod) return explicitMethod;\n return requestInput instanceof Request ? undefined : method;\n};\n\nconst toRequestInit = (request: Request): RequestInit => {\n const requestMethod = normalizeMethod(request.method);\n let body: BodyInit | undefined;\n if (requestMethod !== 'GET' && requestMethod !== 'HEAD' && !request.bodyUsed) {\n try {\n body = request.clone().body ?? undefined;\n } catch {\n body = undefined;\n }\n }\n\n return {\n method: requestMethod,\n headers: request.headers,\n body,\n cache: request.cache,\n credentials: request.credentials,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: request.signal,\n };\n};\n\n/**\n * Create a reactive wrapper around an async resolver.\n *\n * @template TResult - Raw result type returned by the handler\n * @template TData - Stored data type after optional transformation\n * @param handler - Async function to execute\n * @param options - Execution, transform, and refresh options\n * @returns Reactive data state with execute(), refresh(), and clear()\n *\n * @example\n * ```ts\n * const user = useAsyncData(() => fetch('/api/user').then((res) => res.json()));\n * ```\n */\nexport const useAsyncData = <TResult, TData = TResult>(\n handler: () => Promise<TResult>,\n options: UseAsyncDataOptions<TResult, TData> = {}\n): AsyncDataState<TData> => {\n const immediate = options.immediate ?? true;\n const data = signal<TData | undefined>(options.defaultValue);\n const error = signal<Error | null>(null);\n const status = signal<AsyncDataStatus>('idle');\n const pending = computed(() => status.value === 'pending');\n let executionId = 0;\n let disposed = false;\n let stopWatching = (): void => {};\n\n const clear = (): void => {\n executionId += 1;\n data.value = options.defaultValue;\n error.value = null;\n status.value = 'idle';\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n executionId += 1;\n stopWatching();\n };\n\n const execute = async (): Promise<TData | undefined> => {\n if (disposed) {\n return data.peek();\n }\n\n const currentExecution = ++executionId;\n status.value = 'pending';\n error.value = null;\n\n try {\n const resolved = await handler();\n const transformed = options.transform\n ? options.transform(resolved)\n : (resolved as unknown as TData);\n\n if (disposed || currentExecution !== executionId) {\n return data.peek();\n }\n\n data.value = transformed;\n status.value = 'success';\n options.onSuccess?.(transformed);\n return transformed;\n } catch (caught) {\n const normalizedError = normalizeError(caught);\n\n if (disposed || currentExecution !== executionId) {\n return data.peek();\n }\n\n error.value = normalizedError;\n status.value = 'error';\n options.onError?.(normalizedError);\n return data.peek();\n }\n };\n\n if (options.watch?.length) {\n let initialized = false;\n stopWatching = effect(() => {\n for (const source of options.watch ?? []) {\n readWatchSource(source);\n }\n\n if (!initialized) {\n initialized = true;\n if (immediate) {\n void untrack(() => execute());\n }\n return;\n }\n\n void untrack(() => execute());\n });\n } else if (immediate) {\n void execute();\n }\n\n return {\n data,\n error,\n status,\n pending,\n execute,\n refresh: execute,\n abort: () => {},\n clear,\n dispose,\n };\n};\n\n/** @internal */\nconst DEFAULT_VALIDATE_STATUS = (status: number): boolean => status >= 200 && status < 300;\n\n/** @internal */\nconst isDomExceptionNamed = (error: unknown, name: string): error is DOMException =>\n error instanceof DOMException && error.name === name;\n\n/** @internal */\nconst isTimeoutDomException = (error: unknown): error is DOMException =>\n isDomExceptionNamed(error, 'TimeoutError');\n\n/** @internal */\nconst isAbortDomException = (error: unknown): error is DOMException =>\n isDomExceptionNamed(error, 'AbortError');\n\n/** @internal */\nconst DEFAULT_RETRY_ON = (error: Error): boolean => {\n if (\n isAbortDomException(error) ||\n isTimeoutDomException(error) ||\n (error as Error & { code?: string }).code === 'ABORT' ||\n (error as Error & { code?: string }).code === 'TIMEOUT'\n ) {\n return false;\n }\n const status = (error as Error & { status?: number }).status;\n return status === undefined || status >= 500;\n};\n\n/** @internal */\nconst normalizeRetryConfig = (retry: UseFetchOptions['retry']): UseFetchRetryConfig | undefined => {\n if (retry == null) return undefined;\n if (typeof retry === 'number') return { count: retry };\n return retry;\n};\n\n/** @internal */\nconst resolveRetryDelay = (delay: UseFetchRetryConfig['delay'], attempt: number): number => {\n if (delay == null) return Math.min(1000 * 2 ** attempt, 30_000);\n if (typeof delay === 'number') return delay;\n return delay(attempt);\n};\n\n/** @internal */\nconst sleepWithSignal = (ms: number, abortSignal?: AbortSignal): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n if (abortSignal?.aborted) {\n reject(abortSignal.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n return;\n }\n let cleanedUp = false;\n let timer: ReturnType<typeof setTimeout>;\n\n const onAbort = (): void => {\n if (cleanedUp) return;\n cleanedUp = true;\n clearTimeout(timer);\n abortSignal?.removeEventListener('abort', onAbort);\n reject(abortSignal?.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n };\n\n timer = setTimeout(() => {\n if (cleanedUp) return;\n cleanedUp = true;\n abortSignal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n\n abortSignal?.addEventListener('abort', onAbort, { once: true });\n });\n\n/**\n * Reactive fetch composable using the browser Fetch API.\n *\n * Supports timeout, abort, retry, and custom status validation in addition\n * to the core useFetch features (query params, JSON body, baseUrl, watch).\n *\n * @template TResponse - Raw parsed response type\n * @template TData - Stored response type after optional transformation\n * @param input - Request URL, Request object, or lazy input factory\n * @param options - Request and reactive state options\n * @returns Reactive fetch state with execute(), refresh(), abort(), clear(), and dispose()\n *\n * @example\n * ```ts\n * const users = useFetch<{ id: number; name: string }[]>('/api/users', {\n * timeout: 5000,\n * retry: 3,\n * });\n * ```\n */\nexport const useFetch = <TResponse = unknown, TData = TResponse>(\n input: FetchInput,\n options: UseFetchOptions<TResponse, TData> = {}\n): AsyncDataState<TData> => {\n const fetchConfig = getBqueryConfig().fetch;\n const parseAs = options.parseAs ?? fetchConfig?.parseAs ?? 'json';\n const fetcher = options.fetcher ?? fetch;\n const validateStatus = options.validateStatus ?? DEFAULT_VALIDATE_STATUS;\n\n let currentAbortController: AbortController | null = null;\n const normalizeAbortLikeError = (reason: unknown, didTimeout: boolean): Error => {\n const isTimeout =\n didTimeout ||\n isTimeoutDomException(reason) ||\n isTimeoutDomException(currentAbortController?.signal.reason);\n\n return Object.assign(\n new Error(isTimeout ? `Request timeout of ${options.timeout}ms exceeded` : 'Request aborted'),\n { code: isTimeout ? 'TIMEOUT' : 'ABORT' }\n );\n };\n\n const state = useAsyncData<TResponse, TData>(async () => {\n const requestInput = resolveInput(input);\n const requestUrl =\n typeof requestInput === 'string' || requestInput instanceof URL\n ? toUrl(requestInput, options.baseUrl ?? fetchConfig?.baseUrl)\n : requestInput instanceof Request && options.query\n ? new URL(requestInput.url)\n : null;\n\n if (requestUrl && options.query) {\n appendQuery(requestUrl, options.query);\n }\n\n const baseHeaders = toHeaders(\n fetchConfig?.headers,\n requestInput instanceof Request ? requestInput.headers : undefined,\n options.headers\n );\n const bodyProvided = options.body != null;\n const explicitMethod = normalizeMethod(options.method);\n const method = resolveMethod(explicitMethod, requestInput, bodyProvided);\n const bodylessMethod = method === 'GET' || method === 'HEAD' ? method : null;\n if (bodyProvided && bodylessMethod) {\n throw new Error(`Cannot send a request body with ${bodylessMethod} requests`);\n }\n const requestInitMethod = resolveRequestInitMethod(explicitMethod, requestInput, method);\n const retryConfig = normalizeRetryConfig(options.retry);\n const maxAttempts = (retryConfig?.count ?? 0) + 1;\n\n // Abort controller: compose timeout + external signal + manual abort\n const abortController = new AbortController();\n currentAbortController = abortController;\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let didTimeout = false;\n let externalAbortHandler: (() => void) | undefined;\n\n if (options.signal) {\n if (options.signal.aborted) {\n abortController.abort(options.signal.reason);\n } else {\n externalAbortHandler = () => abortController.abort(options.signal?.reason);\n options.signal.addEventListener('abort', externalAbortHandler, { once: true });\n }\n }\n\n if (options.timeout && options.timeout > 0) {\n timeoutId = setTimeout(() => {\n didTimeout = true;\n abortController.abort(new DOMException('Request timeout', 'TimeoutError'));\n }, options.timeout);\n }\n\n const baseRequestInit: Omit<RequestInit, 'body' | 'signal'> = {\n ...options,\n method: requestInitMethod,\n headers: baseHeaders,\n };\n\n delete (baseRequestInit as Partial<UseFetchOptions>).baseUrl;\n delete (baseRequestInit as Partial<UseFetchOptions>).query;\n delete (baseRequestInit as Partial<UseFetchOptions>).parseAs;\n delete (baseRequestInit as Partial<UseFetchOptions>).fetcher;\n delete (baseRequestInit as Partial<UseFetchOptions>).defaultValue;\n delete (baseRequestInit as Partial<UseFetchOptions>).immediate;\n delete (baseRequestInit as Partial<UseFetchOptions>).watch;\n delete (baseRequestInit as Partial<UseFetchOptions>).transform;\n delete (baseRequestInit as Partial<UseFetchOptions>).onSuccess;\n delete (baseRequestInit as Partial<UseFetchOptions>).onError;\n delete (baseRequestInit as Partial<UseFetchOptions>).timeout;\n delete (baseRequestInit as Partial<UseFetchOptions>).retry;\n delete (baseRequestInit as Partial<UseFetchOptions>).validateStatus;\n\n let requestTarget: Request | string | URL = requestUrl ?? requestInput;\n if (\n requestInput instanceof Request &&\n requestUrl &&\n requestUrl.toString() !== requestInput.url\n ) {\n requestTarget = new Request(requestUrl.toString(), toRequestInit(requestInput));\n }\n\n const createAttemptRequestInit = (): RequestInit => {\n const headers = new Headers(baseHeaders);\n return {\n ...baseRequestInit,\n headers,\n body: serializeBody(options.body, headers),\n signal: abortController.signal,\n };\n };\n\n if (\n maxAttempts > 1 &&\n typeof ReadableStream !== 'undefined' &&\n options.body instanceof ReadableStream\n ) {\n throw new Error('Cannot retry requests with ReadableStream bodies');\n }\n\n if (\n maxAttempts > 1 &&\n typeof Request !== 'undefined' &&\n requestTarget instanceof Request &&\n requestTarget.body !== null\n ) {\n throw new Error('Cannot retry requests with non-replayable Request bodies');\n }\n let lastError: Error | undefined;\n\n try {\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n const response = await fetcher(requestTarget, createAttemptRequestInit());\n\n if (!validateStatus(response.status)) {\n throw Object.assign(new Error(`Request failed with status ${response.status}`), {\n response,\n status: response.status,\n statusText: response.statusText,\n });\n }\n\n return await parseResponse<TResponse>(response, parseAs);\n } catch (error) {\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n\n // Abort errors should not be retried\n if (\n abortController.signal.aborted ||\n isAbortDomException(normalizedError) ||\n isTimeoutDomException(normalizedError)\n ) {\n throw normalizeAbortLikeError(\n abortController.signal.aborted ? abortController.signal.reason : normalizedError,\n didTimeout\n );\n }\n\n lastError = normalizedError;\n\n const shouldRetry = retryConfig\n ? (retryConfig.retryOn ?? DEFAULT_RETRY_ON)(normalizedError, attempt)\n : false;\n\n if (!shouldRetry || attempt >= maxAttempts - 1) {\n throw normalizedError;\n }\n\n await sleepWithSignal(\n resolveRetryDelay(retryConfig!.delay, attempt),\n abortController.signal\n );\n }\n }\n\n throw lastError!;\n } finally {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n if (options.signal && externalAbortHandler) {\n options.signal.removeEventListener('abort', externalAbortHandler);\n }\n if (currentAbortController === abortController) {\n currentAbortController = null;\n }\n }\n }, options);\n\n // Override abort with real abort logic\n state.abort = (): void => {\n if (currentAbortController) {\n currentAbortController.abort(new DOMException('Request aborted', 'AbortError'));\n }\n };\n\n return state;\n};\n\n/**\n * Create a preconfigured useFetch() helper.\n *\n * @param defaults - Default request options merged into every useFetch() call\n * @returns A useFetch-compatible function with merged defaults\n *\n * @example\n * ```ts\n * const useApiFetch = createUseFetch({ baseUrl: 'https://api.example.com' });\n * const profile = useApiFetch('/profile');\n * ```\n */\n/** Overload for factories without a configured transform, preserving per-call `TResponse -> TData` inference. */\nexport function createUseFetch<TDefaultResponse = unknown>(\n defaults?: UseFetchOptions<TDefaultResponse, TDefaultResponse>\n): <TResponse = TDefaultResponse, TData = TResponse>(\n input: FetchInput,\n options?: UseFetchOptions<TResponse, TData>\n) => AsyncDataState<TData>;\n\n/** Overload for factories with a configured transform, preserving the transformed factory data type by default. */\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData>\n): <TResponse = TDefaultResponse, TData = TDefaultData>(\n input: FetchInput,\n options?: UseFetchOptions<TResponse, TData>\n) => AsyncDataState<TData>;\n\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData> = {}\n) {\n return <TResponse = TDefaultResponse, TData = TDefaultData>(\n input: FetchInput,\n options: UseFetchOptions<TResponse, TData> = {}\n ): AsyncDataState<TData> => {\n const resolvedDefaults = defaults as unknown as UseFetchOptions<TResponse, TData>;\n const mergedQuery = merge({}, resolvedDefaults.query ?? {}, options.query ?? {}) as Record<\n string,\n unknown\n >;\n\n return useFetch<TResponse, TData>(input, {\n ...resolvedDefaults,\n ...options,\n headers: toHeaders(resolvedDefaults.headers, options.headers),\n query: Object.keys(mergedQuery).length > 0 ? mergedQuery : undefined,\n });\n };\n}\n","/**\n * Imperative HTTP client with Axios-like API, interceptors, retry, timeout,\n * cancellation, and progress tracking — built on the native Fetch API.\n *\n * @module bquery/reactive\n */\n\nimport { merge, isPlainObject } from '../core/utils/object';\nimport { getBqueryConfig, type BqueryFetchParseAs } from '../platform/config';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Configuration for automatic request retries. */\nexport interface RetryConfig {\n /** Maximum number of retry attempts (default: 3). */\n count: number;\n /** Delay in ms between retries, or a function receiving the attempt index. */\n delay?: number | ((attempt: number) => number);\n /** Predicate deciding whether to retry a given error. Defaults to network / 5xx errors. */\n retryOn?: (error: HttpError, attempt: number) => boolean;\n /** Called before each retry attempt with the error and 1-indexed attempt number. */\n onRetry?: (error: HttpError, attempt: number) => void;\n}\n\n/** Progress information emitted during upload or download. */\nexport interface HttpProgressEvent {\n /** Bytes transferred so far. */\n loaded: number;\n /** Total bytes if known, otherwise 0. */\n total: number;\n /** Percentage between 0 and 100, or `undefined` when total is unknown. */\n percent: number | undefined;\n}\n\n/** Full request configuration accepted by the HTTP client. */\nexport interface HttpRequestConfig extends Omit<RequestInit, 'body' | 'headers' | 'signal'> {\n /** Request URL (resolved against `baseUrl`). */\n url?: string;\n /** Base URL prepended to relative request URLs. */\n baseUrl?: string;\n /** Request headers. */\n headers?: HeadersInit;\n /** Query parameters appended to the URL. */\n query?: Record<string, unknown>;\n /** Request body — plain objects/arrays are JSON-serialised automatically. */\n body?: BodyInit | Record<string, unknown> | unknown[] | null;\n /** Request timeout in milliseconds. 0 means no timeout (default). */\n timeout?: number;\n /** Response parsing strategy. */\n parseAs?: BqueryFetchParseAs;\n /** Custom status validation. Returns `true` for acceptable statuses. Default: `status >= 200 && status < 300`. */\n validateStatus?: (status: number) => boolean;\n /** Custom fetch implementation for testing or adapters. */\n fetcher?: typeof fetch;\n /** External `AbortSignal` for request cancellation. */\n signal?: AbortSignal;\n /** Retry configuration. Pass a number for simple retry count, or a `RetryConfig` object. */\n retry?: number | RetryConfig;\n /** Called repeatedly as response body chunks arrive. */\n onDownloadProgress?: (event: HttpProgressEvent) => void;\n}\n\n/** Structured HTTP response returned by every client method. */\nexport interface HttpResponse<T = unknown> {\n /** Parsed response data. */\n data: T;\n /** HTTP status code. */\n status: number;\n /** HTTP status text. */\n statusText: string;\n /** Response headers. */\n headers: Headers;\n /** Resolved request configuration used for this call. */\n config: HttpRequestConfig;\n}\n\n/** Error subclass thrown on failed HTTP requests with rich metadata. */\nexport class HttpError extends Error {\n /** HTTP response (available when the server replied). */\n response?: HttpResponse;\n /** Resolved request configuration. */\n config: HttpRequestConfig;\n /** Original error code string (e.g. `'TIMEOUT'`, `'ABORT'`, `'NETWORK'`). */\n code: string;\n\n constructor(message: string, config: HttpRequestConfig, code: string, response?: HttpResponse) {\n super(message);\n this.name = 'HttpError';\n this.config = config;\n this.code = code;\n this.response = response;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Interceptors\n// ---------------------------------------------------------------------------\n\n/** Single interceptor handler pair. */\nexport interface Interceptor<T> {\n fulfilled?: (value: T) => T | Promise<T>;\n rejected?: (error: unknown) => unknown;\n}\n\n/** Manager for adding and removing interceptors. */\nexport interface InterceptorManager<T> {\n /** Register an interceptor. Returns a numeric id for later removal via `eject()`. */\n use(fulfilled?: (value: T) => T | Promise<T>, rejected?: (error: unknown) => unknown): number;\n /** Remove a previously registered interceptor by id. */\n eject(id: number): void;\n /** Remove all interceptors. */\n clear(): void;\n}\n\n/** @internal */\ninterface InterceptorEntry<T> {\n id: number;\n fulfilled?: (value: T) => T | Promise<T>;\n rejected?: (error: unknown) => unknown;\n}\n\n/** @internal */\nfunction createInterceptorManager<T>(): InterceptorManager<T> & {\n /** @internal */ forEach(fn: (entry: InterceptorEntry<T>) => void): void;\n} {\n const entries: Array<InterceptorEntry<T> | null> = [];\n let nextId = 0;\n\n return {\n use(fulfilled, rejected) {\n const id = nextId++;\n entries.push({ id, fulfilled, rejected });\n return id;\n },\n eject(id) {\n const index = entries.findIndex((e) => e?.id === id);\n if (index !== -1) entries[index] = null;\n },\n clear() {\n entries.length = 0;\n },\n forEach(fn) {\n for (const entry of entries) {\n if (entry) fn(entry);\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// HttpClient interface\n// ---------------------------------------------------------------------------\n\n/** Imperative HTTP client with interceptors and convenience method shortcuts. */\nexport interface HttpClient {\n /** Send a request using the provided configuration. */\n request<T = unknown>(config: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send a GET request. */\n get<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send a POST request. */\n post<T = unknown>(\n url: string,\n body?: HttpRequestConfig['body'],\n config?: HttpRequestConfig\n ): Promise<HttpResponse<T>>;\n /** Send a PUT request. */\n put<T = unknown>(\n url: string,\n body?: HttpRequestConfig['body'],\n config?: HttpRequestConfig\n ): Promise<HttpResponse<T>>;\n /** Send a PATCH request. */\n patch<T = unknown>(\n url: string,\n body?: HttpRequestConfig['body'],\n config?: HttpRequestConfig\n ): Promise<HttpResponse<T>>;\n /** Send a DELETE request. */\n delete<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send a HEAD request. */\n head<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Send an OPTIONS request. */\n options<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;\n /** Request and response interceptors. */\n interceptors: {\n request: InterceptorManager<HttpRequestConfig>;\n response: InterceptorManager<HttpResponse>;\n };\n /** The merged default configuration used by this client. */\n defaults: HttpRequestConfig;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_VALIDATE_STATUS = (status: number): boolean => status >= 200 && status < 300;\n\nconst DEFAULT_RETRY_ON = (error: HttpError): boolean => {\n if (error.code === 'PARSE') return false;\n if (error.code === 'TIMEOUT' || error.code === 'NETWORK') return true;\n const status = error.response?.status;\n return status !== undefined && status >= 500;\n};\n\n/** @internal */\nconst normalizeRetry = (retry: HttpRequestConfig['retry']): RetryConfig | undefined => {\n if (retry == null) return undefined;\n if (typeof retry === 'number') return { count: retry };\n return retry;\n};\n\n/** @internal */\nconst resolveRetryDelay = (delay: RetryConfig['delay'], attempt: number): number => {\n if (delay == null) return Math.min(1000 * 2 ** attempt, 30_000);\n if (typeof delay === 'number') return delay;\n return delay(attempt);\n};\n\n/** @internal */\nconst sleep = (ms: number, signal?: AbortSignal): Promise<void> =>\n new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n return;\n }\n let timer: ReturnType<typeof setTimeout>;\n const onAbort = (): void => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n reject(signal?.reason ?? new DOMException('The operation was aborted.', 'AbortError'));\n };\n timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n if (signal) {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n\n/** @internal */\nconst toHeaders = (...sources: Array<HeadersInit | undefined>): Headers => {\n const headers = new Headers();\n for (const source of sources) {\n if (!source) continue;\n new Headers(source).forEach((value, key) => {\n headers.set(key, value);\n });\n }\n return headers;\n};\n\n/** @internal */\nconst isBodyLike = (value: unknown): value is BodyInit => {\n if (typeof value === 'string') return true;\n if (value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams) {\n return true;\n }\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) return true;\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) return true;\n return typeof value === 'object' && value !== null && ArrayBuffer.isView(value);\n};\n\n/** @internal */\nconst serializeBody = (\n body: HttpRequestConfig['body'],\n headers: Headers\n): BodyInit | null | undefined => {\n if (body == null) return body;\n if (isBodyLike(body)) return body;\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n return JSON.stringify(body);\n};\n\n/** @internal */\nconst appendQuery = (url: URL, query: Record<string, unknown>): void => {\n for (const [key, value] of Object.entries(query)) {\n if (value == null) continue;\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item != null) url.searchParams.append(key, String(item));\n }\n continue;\n }\n url.searchParams.set(key, String(value));\n }\n};\n\n/** @internal */\nconst buildUrl = (url: string, baseUrl?: string): URL => {\n const runtimeBase =\n typeof window !== 'undefined' && /^https?:/i.test(window.location.href)\n ? window.location.href\n : 'http://localhost';\n const base = baseUrl ? new URL(baseUrl, runtimeBase).toString() : runtimeBase;\n return new URL(url, base);\n};\n\n/** @internal */\nconst parseResponseBody = async <T>(\n response: Response,\n parseAs: BqueryFetchParseAs,\n config: HttpRequestConfig\n): Promise<T> => {\n if (parseAs === 'response') return response as T;\n if (parseAs === 'text') return (await response.text()) as T;\n if (parseAs === 'blob') return (await response.blob()) as T;\n if (parseAs === 'arrayBuffer') return (await response.arrayBuffer()) as T;\n if (parseAs === 'formData') return (await response.formData()) as T;\n\n const text = await response.text();\n if (!text) return undefined as T;\n\n try {\n return JSON.parse(text) as T;\n } catch (parseError) {\n const detail = response.url ? ` for ${response.url}` : '';\n throw new HttpError(\n `Failed to parse JSON response${detail} (status ${response.status}): ${parseError instanceof Error ? parseError.message : String(parseError)}`,\n config,\n 'PARSE',\n {\n data: text,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n config,\n }\n );\n }\n};\n\n/** @internal – wrap a response body stream to report download progress. */\nconst wrapDownloadStream = (\n response: Response,\n onProgress: (event: HttpProgressEvent) => void\n): Response => {\n const body = response.body;\n if (!body) return response;\n\n const total = parseInt(response.headers.get('content-length') ?? '0', 10) || 0;\n let loaded = 0;\n\n const reader = body.getReader();\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n loaded += value.byteLength;\n onProgress({\n loaded,\n total,\n percent: total > 0 ? Math.round((loaded / total) * 100) : undefined,\n });\n controller.enqueue(value);\n },\n cancel(reason) {\n reader.cancel(reason);\n },\n });\n\n return new Response(stream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n};\n\n// ---------------------------------------------------------------------------\n// Core request execution\n// ---------------------------------------------------------------------------\n\n/** @internal Execute a single HTTP request (no retry/interceptor logic). */\nconst executeRequest = async <T>(config: HttpRequestConfig): Promise<HttpResponse<T>> => {\n const fetchConfig = getBqueryConfig().fetch;\n const parseAs = config.parseAs ?? fetchConfig?.parseAs ?? 'json';\n const fetcher = config.fetcher ?? fetch;\n const validateStatus = config.validateStatus ?? DEFAULT_VALIDATE_STATUS;\n\n const urlString = config.url ?? '/';\n const url = buildUrl(urlString, config.baseUrl ?? fetchConfig?.baseUrl);\n\n if (config.query) {\n appendQuery(url, config.query);\n }\n\n const headers = toHeaders(fetchConfig?.headers, config.headers);\n const serializedBody = serializeBody(config.body, headers);\n\n // Build RequestInit, omitting non-standard keys\n const requestInit: RequestInit = {};\n if (config.method) requestInit.method = config.method.toUpperCase();\n requestInit.headers = headers;\n if (serializedBody != null) requestInit.body = serializedBody;\n if (config.cache) requestInit.cache = config.cache;\n if (config.credentials) requestInit.credentials = config.credentials;\n if (config.integrity) requestInit.integrity = config.integrity;\n if (config.keepalive !== undefined) requestInit.keepalive = config.keepalive;\n if (config.mode) requestInit.mode = config.mode;\n if (config.redirect) requestInit.redirect = config.redirect;\n if (config.referrer) requestInit.referrer = config.referrer;\n if (config.referrerPolicy) requestInit.referrerPolicy = config.referrerPolicy;\n\n // Abort / timeout\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let mergedSignal: AbortSignal | undefined = config.signal;\n let externalAbortHandler: (() => void) | undefined;\n\n if (config.timeout && config.timeout > 0) {\n const controller = new AbortController();\n\n if (config.signal) {\n // Compose: abort when *either* the external signal or the timeout fires\n externalAbortHandler = () => controller.abort(config.signal?.reason);\n config.signal.addEventListener('abort', externalAbortHandler, { once: true });\n }\n\n timeoutId = setTimeout(() => {\n controller.abort(new DOMException('Request timeout', 'TimeoutError'));\n }, config.timeout);\n\n mergedSignal = controller.signal;\n }\n\n if (mergedSignal) requestInit.signal = mergedSignal;\n\n try {\n let response = await fetcher(url.toString(), requestInit);\n\n if (config.onDownloadProgress) {\n response = wrapDownloadStream(response, config.onDownloadProgress);\n }\n\n if (!validateStatus(response.status)) {\n throw new HttpError(\n `Request failed with status ${response.status}`,\n config,\n 'ERR_BAD_RESPONSE',\n {\n data: undefined,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n config,\n }\n );\n }\n\n const data = await parseResponseBody<T>(response, parseAs, config);\n\n const httpResponse: HttpResponse<T> = {\n data,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n config,\n };\n\n return httpResponse;\n } catch (error) {\n if (error instanceof HttpError) throw error;\n\n if (error instanceof DOMException) {\n if (error.name === 'AbortError' || error.name === 'TimeoutError') {\n const isTimeout = error.name === 'TimeoutError' || error.message === 'Request timeout';\n throw new HttpError(\n isTimeout ? `Request timeout of ${config.timeout}ms exceeded` : 'Request aborted',\n config,\n isTimeout ? 'TIMEOUT' : 'ABORT'\n );\n }\n }\n\n throw new HttpError(error instanceof Error ? error.message : String(error), config, 'NETWORK');\n } finally {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n if (config.signal && externalAbortHandler) {\n config.signal.removeEventListener('abort', externalAbortHandler);\n }\n }\n};\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a preconfigured HTTP client instance with interceptors.\n *\n * @param defaults - Default request configuration merged into every request\n * @returns An `HttpClient` with `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()`, `.options()`\n *\n * @example\n * ```ts\n * import { createHttp } from '@bquery/bquery/reactive';\n *\n * const api = createHttp({\n * baseUrl: 'https://api.example.com',\n * headers: { authorization: 'Bearer token' },\n * timeout: 10_000,\n * });\n *\n * api.interceptors.request.use((config) => {\n * config.headers = { ...Object.fromEntries(new Headers(config.headers)), 'x-req-id': crypto.randomUUID() };\n * return config;\n * });\n *\n * const { data } = await api.get<User[]>('/users');\n * ```\n */\nexport function createHttp(defaults: HttpRequestConfig = {}): HttpClient {\n const requestInterceptors = createInterceptorManager<HttpRequestConfig>();\n const responseInterceptors = createInterceptorManager<HttpResponse>();\n\n const mergeConfig = (perCall: HttpRequestConfig): HttpRequestConfig => {\n const mergedQuery = merge({}, defaults.query ?? {}, perCall.query ?? {}) as Record<\n string,\n unknown\n >;\n\n return {\n ...defaults,\n ...perCall,\n headers: toHeaders(defaults.headers, perCall.headers),\n query: Object.keys(mergedQuery).length > 0 ? mergedQuery : undefined,\n };\n };\n\n const dispatchRequest = async <T>(config: HttpRequestConfig): Promise<HttpResponse<T>> => {\n // Run request interceptors\n let resolvedConfig = config;\n const requestChain: Array<InterceptorEntry<HttpRequestConfig>> = [];\n requestInterceptors.forEach((entry) => requestChain.push(entry));\n\n for (const { fulfilled, rejected } of requestChain) {\n try {\n if (fulfilled) {\n resolvedConfig = await fulfilled(resolvedConfig);\n }\n } catch (err) {\n if (rejected) {\n const result = await rejected(err);\n if (isPlainObject(result)) {\n resolvedConfig = result as unknown as HttpRequestConfig;\n } else {\n throw err;\n }\n } else {\n throw err;\n }\n }\n }\n\n // Execute with retry\n const retryConfig = normalizeRetry(resolvedConfig.retry);\n let lastError: HttpError | undefined;\n\n const maxAttempts = (retryConfig?.count ?? 0) + 1;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n let response = await executeRequest<T>(resolvedConfig);\n\n // Run response interceptors\n const responseChain: Array<InterceptorEntry<HttpResponse>> = [];\n responseInterceptors.forEach((entry) => responseChain.push(entry));\n\n for (const { fulfilled, rejected } of responseChain) {\n try {\n if (fulfilled) {\n response = (await fulfilled(response as HttpResponse)) as HttpResponse<T>;\n }\n } catch (err) {\n if (rejected) {\n const result = await rejected(err);\n if (result && typeof result === 'object' && 'data' in result) {\n response = result as HttpResponse<T>;\n } else {\n throw err;\n }\n } else {\n throw err;\n }\n }\n }\n\n return response;\n } catch (error) {\n const httpError =\n error instanceof HttpError\n ? error\n : new HttpError(\n error instanceof Error ? error.message : String(error),\n resolvedConfig,\n 'NETWORK'\n );\n\n lastError = httpError;\n\n const shouldRetry = retryConfig\n ? (retryConfig.retryOn ?? DEFAULT_RETRY_ON)(httpError, attempt)\n : false;\n\n if (!shouldRetry || attempt >= maxAttempts - 1) {\n // Run response error interceptors before throwing\n const responseChain: Array<InterceptorEntry<HttpResponse>> = [];\n responseInterceptors.forEach((entry) => responseChain.push(entry));\n\n let finalError: unknown = httpError;\n for (const { rejected } of responseChain) {\n if (rejected) {\n try {\n const result = await rejected(finalError);\n if (result && typeof result === 'object' && 'data' in result) {\n return result as HttpResponse<T>;\n }\n if (result != null) {\n finalError = result;\n }\n } catch (innerErr) {\n if (innerErr != null) {\n finalError = innerErr;\n }\n }\n }\n }\n\n if (!(finalError instanceof Error)) {\n finalError = httpError;\n }\n\n throw finalError;\n }\n\n const retryDelay = retryConfig ? resolveRetryDelay(retryConfig.delay, attempt) : 0;\n retryConfig?.onRetry?.(httpError, attempt + 1);\n await sleep(retryDelay, resolvedConfig.signal);\n }\n }\n\n throw lastError!;\n };\n\n const request = <T>(config: HttpRequestConfig): Promise<HttpResponse<T>> =>\n dispatchRequest<T>(mergeConfig(config));\n\n const client: HttpClient = {\n request,\n get: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'GET' }),\n post: <T>(url: string, body?: HttpRequestConfig['body'], config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'POST', body }),\n put: <T>(url: string, body?: HttpRequestConfig['body'], config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'PUT', body }),\n patch: <T>(url: string, body?: HttpRequestConfig['body'], config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'PATCH', body }),\n delete: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'DELETE' }),\n head: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'HEAD' }),\n options: <T>(url: string, config: HttpRequestConfig = {}) =>\n request<T>({ ...config, url, method: 'OPTIONS' }),\n interceptors: {\n request: requestInterceptors,\n response: responseInterceptors,\n },\n defaults,\n };\n\n return client;\n}\n\n/**\n * Default HTTP client instance using global bQuery fetch config.\n *\n * @example\n * ```ts\n * import { http } from '@bquery/bquery/reactive';\n *\n * const { data } = await http.get<User[]>('/api/users');\n * const { data: created } = await http.post('/api/users', { name: 'Ada' });\n * ```\n */\nexport const http: HttpClient = createHttp();\n\n// ---------------------------------------------------------------------------\n// Request Queue\n// ---------------------------------------------------------------------------\n\n/** Options for `createRequestQueue()`. */\nexport interface RequestQueueOptions {\n /** Maximum number of concurrent in-flight requests (default: 6). */\n concurrency?: number;\n}\n\n/** A queued request entry. */\ninterface QueueEntry<T = unknown> {\n execute: () => Promise<HttpResponse<T>>;\n resolve: (value: HttpResponse<T>) => void;\n reject: (reason: unknown) => void;\n}\n\n/** Return value of `createRequestQueue()`. */\nexport interface RequestQueue {\n /** Enqueue a request. Returns a promise that resolves when the request completes. */\n add: <T = unknown>(execute: () => Promise<HttpResponse<T>>) => Promise<HttpResponse<T>>;\n /** Number of requests currently being processed. */\n readonly pending: number;\n /** Number of requests waiting in the queue. */\n readonly size: number;\n /** Remove all pending (not yet started) requests from the queue. Their promises will reject. */\n clear: () => void;\n}\n\n/**\n * Create a request queue with a concurrency limit.\n *\n * Useful for rate-limiting parallel HTTP requests (e.g. browser connection limits,\n * API throttling) while maintaining a simple promise-based interface.\n *\n * @param options - Queue configuration\n * @returns A `RequestQueue` with `.add()`, `.clear()`, `.pending`, and `.size`\n *\n * @example\n * ```ts\n * import { createRequestQueue, createHttp } from '@bquery/bquery/reactive';\n *\n * const api = createHttp({ baseUrl: 'https://api.example.com' });\n * const queue = createRequestQueue({ concurrency: 3 });\n *\n * // These will run at most 3 at a time\n * const results = await Promise.all(\n * ids.map(id => queue.add(() => api.get(`/items/${id}`)))\n * );\n * ```\n */\nexport function createRequestQueue(options: RequestQueueOptions = {}): RequestQueue {\n const { concurrency = 6 } = options;\n if (!Number.isInteger(concurrency) || concurrency < 1) {\n throw new Error('Request queue concurrency must be a positive integer');\n }\n const queue: Array<QueueEntry> = [];\n let running = 0;\n\n const drain = (): void => {\n while (running < concurrency && queue.length > 0) {\n const entry = queue.shift()!;\n running++;\n Promise.resolve()\n .then(entry.execute)\n .then(entry.resolve, entry.reject)\n .finally(() => {\n running--;\n drain();\n });\n }\n };\n\n return {\n add<T = unknown>(execute: () => Promise<HttpResponse<T>>): Promise<HttpResponse<T>> {\n return new Promise<HttpResponse<T>>((resolve, reject) => {\n queue.push({\n execute: execute as () => Promise<HttpResponse>,\n resolve: resolve as (value: HttpResponse) => void,\n reject,\n });\n drain();\n });\n },\n get pending() {\n return running;\n },\n get size() {\n return queue.length;\n },\n clear() {\n const cleared = queue.splice(0);\n for (const entry of cleared) {\n entry.reject(new Error('Request queue cleared'));\n }\n },\n };\n}\n","/**\n * Linked (writable) computed helpers.\n */\n\nimport { computed, Computed } from './computed';\n\n/**\n * A writable computed-like signal.\n */\nexport interface LinkedSignal<T> {\n /** Gets or sets the current value with dependency tracking. */\n value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Creates a writable computed signal by linking a getter and setter.\n *\n * @template T - The derived value type\n * @param getValue - Getter that derives the current value\n * @param setValue - Setter that writes back to underlying signals\n * @returns A writable computed-like signal\n *\n * @example\n * ```ts\n * const first = signal('Ada');\n * const last = signal('Lovelace');\n * const fullName = linkedSignal(\n * () => `${first.value} ${last.value}`,\n * (next) => {\n * const [a, b] = next.split(' ');\n * first.value = a ?? '';\n * last.value = b ?? '';\n * }\n * );\n * ```\n */\nexport const linkedSignal = <T>(\n getValue: () => T,\n setValue: (value: T) => void\n): LinkedSignal<T> => {\n const derived: Computed<T> = computed(getValue);\n\n return {\n get value(): T {\n return derived.value;\n },\n set value(next: T) {\n setValue(next);\n },\n peek(): T {\n return derived.peek();\n },\n };\n};\n","/**\n * Pagination and infinite-scroll composables for reactive data fetching.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { Signal, signal } from './core';\nimport {\n useFetch,\n type AsyncDataState,\n type AsyncDataStatus,\n type UseFetchOptions,\n} from './async-data';\n\n// ---------------------------------------------------------------------------\n// usePaginatedFetch\n// ---------------------------------------------------------------------------\n\n/** Options for usePaginatedFetch(). */\nexport interface UsePaginatedFetchOptions<\n TResponse = unknown,\n TData = TResponse,\n> extends UseFetchOptions<TResponse, TData> {\n /** Initial page number (default: 1). */\n initialPage?: number;\n}\n\n/** Return value of usePaginatedFetch(). */\nexport interface PaginatedState<TData> extends AsyncDataState<TData> {\n /** Current page number signal (writable). */\n page: Signal<number>;\n /** Go to the next page. */\n next: () => Promise<TData | undefined>;\n /** Go to the previous page (minimum 1). */\n prev: () => Promise<TData | undefined>;\n /** Jump to a specific page. */\n goTo: (page: number) => Promise<TData | undefined>;\n}\n\n/**\n * Reactive paginated fetch composable.\n *\n * Takes a URL factory receiving the current page number, and exposes\n * `page`, `next()`, `prev()`, and `goTo()` helpers alongside the\n * standard `AsyncDataState`.\n *\n * @template TResponse - Raw parsed response type\n * @template TData - Stored response type after optional transformation\n * @param inputFactory - Function that receives the page number and returns a URL string, URL, or Request\n * @param options - Fetch and pagination options\n * @returns Paginated data state\n *\n * @example\n * ```ts\n * import { usePaginatedFetch } from '@bquery/bquery/reactive';\n *\n * const users = usePaginatedFetch<User[]>(\n * (page) => `/api/users?page=${page}`,\n * { baseUrl: 'https://api.example.com' }\n * );\n *\n * // Navigate pages\n * await users.next();\n * await users.prev();\n * await users.goTo(5);\n * console.log(users.page.value); // 5\n * ```\n */\nexport const usePaginatedFetch = <TResponse = unknown, TData = TResponse>(\n inputFactory: (page: number) => string | URL | Request,\n options: UsePaginatedFetchOptions<TResponse, TData> = {}\n): PaginatedState<TData> => {\n const { initialPage = 1, ...fetchOptions } = options;\n const page = signal(initialPage);\n\n const state = useFetch<TResponse, TData>(() => inputFactory(page.value), {\n ...fetchOptions,\n watch: fetchOptions.watch,\n });\n\n const next = async (): Promise<TData | undefined> => {\n page.value = page.peek() + 1;\n return state.execute();\n };\n\n const prev = async (): Promise<TData | undefined> => {\n const current = page.peek();\n if (current > 1) {\n page.value = current - 1;\n }\n return state.execute();\n };\n\n const goTo = async (target: number): Promise<TData | undefined> => {\n page.value = Math.max(1, target);\n return state.execute();\n };\n\n return {\n ...state,\n page,\n next,\n prev,\n goTo,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useInfiniteFetch\n// ---------------------------------------------------------------------------\n\n/** Options for useInfiniteFetch(). */\nexport interface UseInfiniteFetchOptions<\n TResponse = unknown,\n TData = TResponse,\n TCursor = number,\n> extends Omit<UseFetchOptions<TResponse, TData>, 'transform'> {\n /** Extract the cursor for the next page from a response. */\n getNextCursor: (lastResponse: TResponse, allPages: TResponse[]) => TCursor | undefined;\n /** Transform all accumulated pages into the final data shape. */\n transform?: (pages: TResponse[]) => TData;\n /** Initial cursor value (default: undefined, meaning first page). */\n initialCursor?: TCursor;\n}\n\n/** Return value of useInfiniteFetch(). */\nexport interface InfiniteState<TData, TResponse = unknown> {\n /** All accumulated page data, transformed. */\n data: Signal<TData | undefined>;\n /** Raw accumulated pages. */\n pages: Signal<TResponse[]>;\n /** Last error encountered. */\n error: Signal<Error | null>;\n /** Current lifecycle status. */\n status: Signal<AsyncDataStatus>;\n /** Computed boolean that mirrors `status === 'pending'`. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Whether there are more pages to load. */\n hasMore: { readonly value: boolean; peek(): boolean };\n /** Fetch the next page and append it to the accumulated data. */\n fetchNextPage: () => Promise<TData | undefined>;\n /** Reset all pages and re-fetch from the initial cursor. */\n refresh: () => Promise<TData | undefined>;\n /** Clear all accumulated data. */\n clear: () => void;\n /** Dispose reactive watchers and prevent future executions. */\n dispose: () => void;\n}\n\n/**\n * Reactive infinite-scroll / load-more composable.\n *\n * Accumulates pages of data and exposes `fetchNextPage()` to load\n * additional results. Uses a cursor-based approach with `getNextCursor()`\n * to determine pagination.\n *\n * @template TResponse - Raw parsed response type for a single page\n * @template TData - Transformed accumulated data type\n * @template TCursor - Cursor type used for pagination\n * @param inputFactory - Function receiving the cursor and returning a FetchInput\n * @param options - Fetch and infinite-scroll options\n * @returns Infinite data state with fetchNextPage(), hasMore, and accumulated pages\n *\n * @example\n * ```ts\n * import { useInfiniteFetch } from '@bquery/bquery/reactive';\n *\n * const feed = useInfiniteFetch<Post[], Post[]>(\n * (cursor) => `/api/posts?cursor=${cursor ?? ''}`,\n * {\n * getNextCursor: (page) => page.length > 0 ? page[page.length - 1].id : undefined,\n * transform: (pages) => pages.flat(),\n * baseUrl: 'https://api.example.com',\n * }\n * );\n *\n * // Load more pages\n * await feed.fetchNextPage();\n * console.log(feed.data.value); // All accumulated posts\n * console.log(feed.hasMore.value); // true if more pages available\n * ```\n */\nexport const useInfiniteFetch = <TResponse = unknown, TData = TResponse[], TCursor = number>(\n inputFactory: (cursor: TCursor | undefined) => string | URL | Request,\n options: UseInfiniteFetchOptions<TResponse, TData, TCursor>\n): InfiniteState<TData, TResponse> => {\n const {\n getNextCursor,\n transform: transformPages,\n initialCursor,\n immediate = true,\n // Keep these callbacks on the infinite-fetch layer instead of forwarding\n // them into the inner per-page useFetch() instance.\n onSuccess: infiniteOnSuccess,\n onError: infiniteOnError,\n ...fetchOptions\n } = options;\n\n const pages = signal<TResponse[]>([]);\n const data = signal<TData | undefined>(options.defaultValue);\n const error = signal<Error | null>(null);\n const status = signal<AsyncDataStatus>('idle');\n const pending = computed(() => status.value === 'pending');\n const nextCursor = signal<TCursor | undefined>(initialCursor);\n const hasMore = computed(() => pages.value.length === 0 || nextCursor.value !== undefined);\n\n let disposed = false;\n let executionId = 0;\n\n const applyTransform = (allPages: TResponse[]): TData => {\n if (transformPages) {\n return transformPages(allPages);\n }\n return allPages as unknown as TData;\n };\n\n const fetchNextPage = async (): Promise<TData | undefined> => {\n if (disposed) return data.peek();\n\n const currentExecution = ++executionId;\n status.value = 'pending';\n error.value = null;\n\n try {\n const cursor = nextCursor.peek();\n const input = inputFactory(cursor);\n const pageState = useFetch<TResponse>(input, {\n ...(fetchOptions as UseFetchOptions<TResponse>),\n immediate: false,\n watch: undefined,\n });\n\n const pageData = await pageState.execute();\n const pageError = pageState.error.peek();\n pageState.dispose();\n\n if (disposed || currentExecution !== executionId) return data.peek();\n\n // Check if the inner fetch encountered an error\n if (pageError) {\n error.value = pageError;\n status.value = 'error';\n infiniteOnError?.(pageError);\n return data.peek();\n }\n\n if (pageData !== undefined) {\n const typedPageData = pageData as TResponse;\n const newPages: TResponse[] = [...pages.peek(), typedPageData];\n pages.value = newPages;\n\n const newCursor = getNextCursor(typedPageData, newPages);\n nextCursor.value = newCursor;\n\n const transformed = applyTransform(newPages);\n data.value = transformed;\n status.value = 'success';\n infiniteOnSuccess?.(transformed);\n return transformed;\n }\n\n status.value = 'success';\n return data.peek();\n } catch (caught) {\n if (disposed || currentExecution !== executionId) return data.peek();\n\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n error.value = normalizedError;\n status.value = 'error';\n infiniteOnError?.(normalizedError);\n return data.peek();\n }\n };\n\n const refresh = async (): Promise<TData | undefined> => {\n pages.value = [];\n nextCursor.value = initialCursor;\n data.value = options.defaultValue;\n error.value = null;\n status.value = 'idle';\n executionId += 1;\n return fetchNextPage();\n };\n\n const clear = (): void => {\n executionId += 1;\n pages.value = [];\n nextCursor.value = initialCursor;\n data.value = options.defaultValue;\n error.value = null;\n status.value = 'idle';\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n executionId += 1;\n };\n\n if (immediate) {\n void fetchNextPage();\n }\n\n return {\n data,\n pages,\n error,\n status,\n pending,\n hasMore,\n fetchNextPage,\n refresh,\n clear,\n dispose,\n };\n};\n","/**\n * LocalStorage-backed signals.\n */\n\nimport { signal, Signal } from './core';\nimport { effect } from './effect';\n\n/**\n * Creates a signal that persists to localStorage.\n *\n * @template T - The type of the signal value\n * @param key - The localStorage key\n * @param initialValue - The initial value if not found in storage\n * @returns A Signal that syncs with localStorage (falls back to in-memory if unavailable)\n */\nexport const persistedSignal = <T>(key: string, initialValue: T): Signal<T> => {\n // Check if localStorage is available and accessible\n let hasLocalStorage = false;\n let storage: Storage | null = null;\n\n try {\n // In Safari private mode, accessing localStorage can throw SecurityError\n storage = globalThis.localStorage;\n if (storage) {\n // Test actual access to ensure it's not just present but usable\n // Use a randomized test key to avoid overwriting real user data\n const testKey = `__bquery_test_${Math.random().toString(36).slice(2, 9)}__`;\n const testValue = '__test__';\n try {\n storage.setItem(testKey, testValue);\n storage.getItem(testKey);\n hasLocalStorage = true;\n } finally {\n // Ensure we don't leave any test data behind\n try {\n storage.removeItem(testKey);\n } catch {\n // Ignore cleanup errors (e.g., storage becoming unavailable)\n }\n }\n }\n } catch {\n // localStorage unavailable or access denied (Safari private mode, sandboxed iframes, etc.)\n hasLocalStorage = false;\n }\n\n let stored: T = initialValue;\n\n if (hasLocalStorage && storage) {\n try {\n const raw = storage.getItem(key);\n if (raw !== null) {\n stored = JSON.parse(raw) as T;\n }\n } catch {\n // Use initial value on parse error or access denial\n }\n }\n\n const sig = signal(stored);\n\n // Only set up persistence effect if localStorage is available\n if (hasLocalStorage && storage) {\n effect(() => {\n try {\n storage!.setItem(key, JSON.stringify(sig.value));\n } catch {\n // Ignore storage errors (quota exceeded, sandboxed iframes, etc.)\n }\n });\n }\n\n return sig;\n};\n","/**\n * Reactive polling composable for periodic data fetching.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { effect } from './effect';\nimport { signal } from './core';\nimport { untrack } from './untrack';\nimport { useFetch, type AsyncDataState, type FetchInput, type UseFetchOptions } from './async-data';\n\n/** Options for usePolling(). */\nexport interface UsePollingOptions<TResponse = unknown, TData = TResponse> extends UseFetchOptions<\n TResponse,\n TData\n> {\n /** Polling interval in milliseconds. */\n interval: number;\n /** Whether polling is initially enabled (default: true). Can be a reactive getter. */\n enabled?: boolean | (() => boolean);\n /** Pause polling when the document is hidden (default: true). */\n pauseOnHidden?: boolean;\n /** Pause polling when the browser is offline (default: true). */\n pauseOnOffline?: boolean;\n}\n\n/** Extended return value from usePolling(). */\nexport interface PollingState<TData> extends AsyncDataState<TData> {\n /** Pause polling. */\n pause: () => void;\n /** Resume polling. */\n resume: () => void;\n /** Reactive boolean indicating whether polling is currently active. */\n isActive: { readonly value: boolean; peek(): boolean };\n}\n\n/**\n * Reactive polling composable that periodically fetches data.\n *\n * @template TResponse - Raw parsed response type\n * @template TData - Stored response type after optional transformation\n * @param input - Request URL, Request object, or lazy input factory\n * @param options - Polling and fetch options\n * @returns Extended fetch state with pause(), resume(), and isActive\n *\n * @example\n * ```ts\n * import { usePolling } from '@bquery/bquery/reactive';\n *\n * const notifications = usePolling<Notification[]>('/api/notifications', {\n * interval: 30_000,\n * pauseOnHidden: true,\n * pauseOnOffline: true,\n * });\n *\n * // Manually pause/resume\n * notifications.pause();\n * notifications.resume();\n * ```\n */\nexport const usePolling = <TResponse = unknown, TData = TResponse>(\n input: FetchInput,\n options: UsePollingOptions<TResponse, TData>\n): PollingState<TData> => {\n const {\n interval,\n enabled: enabledOption = true,\n pauseOnHidden = true,\n pauseOnOffline = true,\n immediate = true,\n ...fetchOptions\n } = options;\n\n if (!Number.isFinite(interval) || interval < 1) {\n throw new Error('Polling interval must be a finite number of at least 1');\n }\n\n const manuallyPaused = signal(false);\n const documentHidden = signal(false);\n const browserOffline = signal(false);\n\n const enabledGetter = typeof enabledOption === 'function' ? enabledOption : () => enabledOption;\n\n const isActive = computed(\n () =>\n enabledGetter() &&\n !manuallyPaused.value &&\n !(pauseOnHidden && documentHidden.value) &&\n !(pauseOnOffline && browserOffline.value)\n );\n\n // Create the underlying useFetch with immediate control\n const fetchState = useFetch<TResponse, TData>(input, {\n ...fetchOptions,\n immediate: immediate && enabledGetter(),\n });\n\n let intervalId: ReturnType<typeof setInterval> | undefined;\n let cleanups: Array<() => void> = [];\n\n const startPolling = (): void => {\n stopPolling();\n intervalId = setInterval(() => {\n void fetchState.execute();\n }, interval);\n };\n\n const stopPolling = (): void => {\n if (intervalId !== undefined) {\n clearInterval(intervalId);\n intervalId = undefined;\n }\n };\n\n // Watch isActive and start/stop polling accordingly\n const stopWatcher = effect(() => {\n const active = isActive.value;\n untrack(() => {\n if (active) {\n startPolling();\n } else {\n stopPolling();\n }\n });\n });\n\n // Listen for visibility changes\n if (pauseOnHidden && typeof document !== 'undefined') {\n documentHidden.value = document.hidden;\n const onVisibilityChange = (): void => {\n documentHidden.value = document.hidden;\n };\n document.addEventListener('visibilitychange', onVisibilityChange);\n cleanups.push(() => document.removeEventListener('visibilitychange', onVisibilityChange));\n }\n\n // Listen for online/offline changes\n if (pauseOnOffline && typeof window !== 'undefined') {\n const onOnline = (): void => {\n browserOffline.value = false;\n };\n const onOffline = (): void => {\n browserOffline.value = true;\n };\n window.addEventListener('online', onOnline);\n window.addEventListener('offline', onOffline);\n cleanups.push(() => {\n window.removeEventListener('online', onOnline);\n window.removeEventListener('offline', onOffline);\n });\n browserOffline.value =\n typeof navigator !== 'undefined' && navigator.onLine !== undefined\n ? !navigator.onLine\n : false;\n }\n\n const originalDispose = fetchState.dispose;\n\n const dispose = (): void => {\n stopPolling();\n stopWatcher();\n for (const cleanup of cleanups) cleanup();\n cleanups = [];\n originalDispose();\n };\n\n return {\n ...fetchState,\n pause: () => {\n manuallyPaused.value = true;\n },\n resume: () => {\n manuallyPaused.value = false;\n },\n isActive,\n dispose,\n };\n};\n","/**\n * Read-only signal wrappers.\n */\n\nimport type { Signal } from './core';\n\nconst READONLY_SIGNAL_BRAND: unique symbol = Symbol('bquery.readonlySignal');\n\n/** @internal */\ntype ReadonlySignalWrapper<T> = ReadonlySignal<T> & {\n readonly [READONLY_SIGNAL_BRAND]: true;\n};\n\n/**\n * A readonly wrapper around a signal that prevents writes.\n * Provides read-only access to a signal's value while maintaining reactivity.\n *\n * @template T - The type of the wrapped value\n */\nexport interface ReadonlySignal<T> {\n /** Gets the current value with dependency tracking. */\n readonly value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Determines whether a value is a bQuery readonly signal wrapper.\n *\n * @internal\n */\nexport const isReadonlySignal = <T>(value: unknown): value is ReturnType<typeof readonly<T>> => {\n return (\n typeof value === 'object' &&\n value !== null &&\n Object.prototype.hasOwnProperty.call(value, READONLY_SIGNAL_BRAND)\n );\n};\n\n/**\n * Creates a read-only view of a signal.\n * Useful for exposing reactive state without allowing modifications.\n *\n * @template T - The type of the signal value\n * @param sig - The signal to wrap\n * @returns A readonly signal wrapper\n */\nexport const readonly = <T>(sig: Signal<T>): ReadonlySignalWrapper<T> =>\n Object.defineProperties(\n {},\n {\n value: {\n get(): T {\n return sig.value;\n },\n enumerable: true,\n },\n peek: {\n value(): T {\n return sig.peek();\n },\n enumerable: true,\n },\n [READONLY_SIGNAL_BRAND]: {\n value: true,\n enumerable: false,\n configurable: false,\n writable: false,\n },\n }\n ) as ReadonlySignalWrapper<T>;\n\n/**\n * Branded readonly wrapper type produced by {@link readonly}.\n *\n * Useful for APIs that compose additional behavior on top of a readonly signal\n * without widening to arbitrary structural `{ value, peek }` objects.\n */\nexport type ReadonlySignalHandle<T> = ReturnType<typeof readonly<T>>;\n","/**\n * REST resource composable for CRUD operations with optimistic updates,\n * form submission, and reactive caching built on the bQuery fetch layer.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { Signal, signal } from './core';\nimport { useFetch, type AsyncDataStatus, type UseFetchOptions } from './async-data';\nimport { createHttp, type HttpClient, type HttpRequestConfig, type HttpResponse } from './http';\n\n// ---------------------------------------------------------------------------\n// useResource — full CRUD composable\n// ---------------------------------------------------------------------------\n\n/** HTTP method shortcuts available on a resource. */\nexport interface ResourceActions<T> {\n /** Fetch the resource (GET). */\n fetch: () => Promise<T | undefined>;\n /** Create a new item (POST). */\n create: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Replace the resource (PUT). */\n update: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Partially update the resource (PATCH). */\n patch: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Delete the resource (DELETE). */\n remove: () => Promise<void>;\n}\n\n/** Options for `useResource()`. */\nexport interface UseResourceOptions<T = unknown> extends Omit<\n UseFetchOptions<T>,\n 'method' | 'body'\n> {\n /** Enable optimistic updates for mutating operations (default: false). */\n optimistic?: boolean;\n /** Called after any successful mutation (create / update / patch / remove). */\n onMutationSuccess?: (data: T | undefined, action: string) => void;\n /** Called after a failed mutation, receives the error and action name. */\n onMutationError?: (error: Error, action: string) => void;\n}\n\n/** Return value of `useResource()`. */\nexport interface UseResourceReturn<T> {\n /** Reactive resource data. */\n data: Signal<T | undefined>;\n /** Last error. */\n error: Signal<Error | null>;\n /** Lifecycle status for the initial fetch. */\n status: Signal<AsyncDataStatus>;\n /** Whether the initial fetch is pending. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Whether any mutation is in progress. */\n isMutating: { readonly value: boolean; peek(): boolean };\n /** CRUD actions. */\n actions: ResourceActions<T>;\n /** Refresh the resource (re-GET). */\n refresh: () => Promise<T | undefined>;\n /** Clear data, error, and status. */\n clear: () => void;\n /** Dispose all reactive state and prevent future operations. */\n dispose: () => void;\n}\n\n/**\n * Reactive REST resource composable providing CRUD operations.\n *\n * Binds a base URL to a resource and exposes `fetch`, `create`, `update`,\n * `patch`, and `remove` helpers with optional optimistic updates.\n *\n * @template T - Resource data type\n * @param url - Resource endpoint URL or getter\n * @param options - Fetch and resource options\n * @returns Reactive resource state with CRUD actions\n *\n * @example\n * ```ts\n * import { useResource } from '@bquery/bquery/reactive';\n *\n * const user = useResource<User>('/api/users/1', {\n * baseUrl: 'https://api.example.com',\n * optimistic: true,\n * });\n *\n * // Read\n * await user.actions.fetch();\n *\n * // Update\n * await user.actions.patch({ name: 'Ada' });\n *\n * // Delete\n * await user.actions.remove();\n * ```\n */\nexport const useResource = <T = unknown>(\n url: string | URL | (() => string | URL),\n options: UseResourceOptions<T> = {}\n): UseResourceReturn<T> => {\n const { optimistic = false, onMutationSuccess, onMutationError, ...fetchOptions } = options;\n\n // Internal fetch state for the GET\n const fetchState = useFetch<T>(url, {\n ...fetchOptions,\n });\n\n const mutating = signal(false);\n const isMutating = computed(() => mutating.value);\n\n let disposed = false;\n\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const stripGetLifecycleOptions = <TResult>(): Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n > => {\n const {\n defaultValue: _defaultValue,\n transform: _transform,\n onSuccess: _onSuccess,\n onError: _onError,\n ...remainingOpts\n } = fetchOptions;\n return remainingOpts as Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n >;\n };\n\n const executeMutation = async (\n action: string,\n method: string,\n body?: Partial<T> | Record<string, unknown>,\n optimisticData?: T | undefined\n ): Promise<T | undefined> => {\n if (disposed) return fetchState.data.peek();\n\n const previousData = fetchState.data.peek();\n\n // Optimistic update\n if (optimistic && optimisticData !== undefined) {\n fetchState.data.value = optimisticData;\n }\n\n mutating.value = true;\n fetchState.error.value = null;\n\n try {\n const mutationState = useFetch<T>(resolveUrl(), {\n ...stripGetLifecycleOptions<T>(),\n method,\n body: body ?? undefined,\n immediate: false,\n watch: undefined,\n });\n\n const result = await mutationState.execute();\n const mutationError = mutationState.error.peek();\n mutationState.dispose();\n\n if (disposed) return fetchState.data.peek();\n\n // Check if the inner fetch encountered an error\n if (mutationError) {\n // Rollback on optimistic failure\n if (optimistic && optimisticData !== undefined) {\n fetchState.data.value = previousData;\n }\n\n fetchState.error.value = mutationError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(mutationError, action);\n return fetchState.data.peek();\n }\n\n // For non-DELETE mutations, update data with server response\n if (method !== 'DELETE' && result !== undefined) {\n fetchState.data.value = result;\n }\n\n mutating.value = false;\n fetchState.status.value = 'success';\n onMutationSuccess?.(result, action);\n return result;\n } catch (caught) {\n if (disposed) return fetchState.data.peek();\n\n // Rollback on optimistic failure\n if (optimistic && optimisticData !== undefined) {\n fetchState.data.value = previousData;\n }\n\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n fetchState.error.value = normalizedError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(normalizedError, action);\n return fetchState.data.peek();\n }\n };\n\n const actions: ResourceActions<T> = {\n fetch: () => fetchState.execute(),\n create: (body) => executeMutation('create', 'POST', body),\n update: (body) => {\n const base = fetchState.data.peek();\n return executeMutation(\n 'update',\n 'PUT',\n body,\n optimistic && base !== undefined ? ({ ...base, ...body } as T) : undefined\n );\n },\n patch: (body) => {\n const base = fetchState.data.peek();\n return executeMutation(\n 'patch',\n 'PATCH',\n body,\n optimistic && base !== undefined ? ({ ...base, ...body } as T) : undefined\n );\n },\n remove: async () => {\n await executeMutation('remove', 'DELETE');\n if (!disposed && fetchState.error.peek() == null) {\n fetchState.data.value = undefined;\n }\n },\n };\n\n const originalDispose = fetchState.dispose;\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n originalDispose();\n };\n\n return {\n data: fetchState.data,\n error: fetchState.error,\n status: fetchState.status,\n pending: fetchState.pending,\n isMutating,\n actions,\n refresh: fetchState.execute,\n clear: fetchState.clear,\n dispose,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useSubmit — form submission composable\n// ---------------------------------------------------------------------------\n\n/** Options for `useSubmit()`. */\nexport interface UseSubmitOptions<TResponse = unknown> extends Omit<\n UseFetchOptions<TResponse>,\n 'body' | 'immediate'\n> {\n /** HTTP method (default: `'POST'`). */\n method?: string;\n}\n\n/** Return value of `useSubmit()`. */\nexport interface UseSubmitReturn<TResponse = unknown> {\n /** Last response data. */\n data: Signal<TResponse | undefined>;\n /** Last error. */\n error: Signal<Error | null>;\n /** Current status. */\n status: Signal<AsyncDataStatus>;\n /** Whether the submission is pending. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Submit data to the endpoint. */\n submit: (body: Record<string, unknown> | FormData | BodyInit) => Promise<TResponse | undefined>;\n /** Reset state. */\n clear: () => void;\n}\n\n/**\n * Reactive form submission composable.\n *\n * Provides a `submit()` function that sends data to an endpoint with\n * reactive status, data, and error signals.\n *\n * @template TResponse - Response data type\n * @param url - Submission endpoint URL\n * @param options - Fetch options (method defaults to POST)\n * @returns Reactive submission state with `submit()` and `clear()`\n *\n * @example\n * ```ts\n * import { useSubmit } from '@bquery/bquery/reactive';\n *\n * const form = useSubmit<{ id: number }>('/api/users', {\n * baseUrl: 'https://api.example.com',\n * headers: { 'x-csrf': token },\n * });\n *\n * const result = await form.submit({ name: 'Ada', email: 'ada@example.com' });\n * console.log(form.status.value); // 'success'\n * ```\n */\nexport const useSubmit = <TResponse = unknown>(\n url: string | URL,\n options: UseSubmitOptions<TResponse> = {}\n): UseSubmitReturn<TResponse> => {\n const { method = 'POST', ...fetchOptions } = options;\n\n const data = signal<TResponse | undefined>(undefined);\n const error = signal<Error | null>(null);\n const status = signal<AsyncDataStatus>('idle');\n const pending = computed(() => status.value === 'pending');\n\n const submit = async (\n body: Record<string, unknown> | FormData | BodyInit\n ): Promise<TResponse | undefined> => {\n status.value = 'pending';\n error.value = null;\n\n try {\n const state = useFetch<TResponse>(url, {\n ...fetchOptions,\n method,\n body: body as UseFetchOptions['body'],\n immediate: false,\n watch: undefined,\n });\n\n const result = await state.execute();\n const fetchError = state.error.peek();\n state.dispose();\n\n if (fetchError) {\n error.value = fetchError;\n status.value = 'error';\n return undefined;\n }\n\n data.value = result;\n status.value = 'success';\n return result;\n } catch (caught) {\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n error.value = normalizedError;\n status.value = 'error';\n return undefined;\n }\n };\n\n const clear = (): void => {\n data.value = undefined;\n error.value = null;\n status.value = 'idle';\n };\n\n return {\n data,\n error,\n status,\n pending,\n submit,\n clear,\n };\n};\n\n// ---------------------------------------------------------------------------\n// createRestClient — imperative REST client\n// ---------------------------------------------------------------------------\n\n/** Typed CRUD methods for a REST endpoint. */\nexport interface RestClient<T = unknown> {\n /** GET all items. */\n list: (config?: HttpRequestConfig) => Promise<HttpResponse<T[]>>;\n /** GET a single item by ID. */\n get: (id: string | number, config?: HttpRequestConfig) => Promise<HttpResponse<T>>;\n /** POST a new item. */\n create: (\n body: Partial<T> | Record<string, unknown>,\n config?: HttpRequestConfig\n ) => Promise<HttpResponse<T>>;\n /** PUT (full replace) an item by ID. */\n update: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>,\n config?: HttpRequestConfig\n ) => Promise<HttpResponse<T>>;\n /** PATCH (partial update) an item by ID. */\n patch: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>,\n config?: HttpRequestConfig\n ) => Promise<HttpResponse<T>>;\n /** DELETE an item by ID. */\n remove: (id: string | number, config?: HttpRequestConfig) => Promise<HttpResponse<void>>;\n /** The underlying HttpClient instance. */\n http: HttpClient;\n}\n\n/**\n * Create a typed REST client for a specific API resource.\n *\n * Wraps `createHttp()` and maps standard CRUD operations to their\n * conventional REST endpoints (`GET /`, `GET /:id`, `POST /`, `PUT /:id`,\n * `PATCH /:id`, `DELETE /:id`).\n *\n * @template T - Resource item type\n * @param baseUrl - Base URL of the resource (e.g. `https://api.example.com/users`)\n * @param defaults - Default request configuration merged into every call\n * @returns Typed REST client with `list`, `get`, `create`, `update`, `patch`, `remove`\n *\n * @example\n * ```ts\n * import { createRestClient } from '@bquery/bquery/reactive';\n *\n * interface User { id: number; name: string; email: string }\n *\n * const users = createRestClient<User>('https://api.example.com/users', {\n * headers: { authorization: '******' },\n * timeout: 10_000,\n * });\n *\n * const { data: allUsers } = await users.list();\n * const { data: user } = await users.get(1);\n * const { data: created } = await users.create({ name: 'Ada' });\n * await users.update(1, { name: 'Ada', email: 'ada@example.com' });\n * await users.patch(1, { email: 'new@example.com' });\n * await users.remove(1);\n * ```\n */\nexport const createRestClient = <T = unknown>(\n baseUrl: string,\n defaults: HttpRequestConfig = {}\n): RestClient<T> => {\n const httpClient = createHttp({ ...defaults });\n\n // Ensure the base URL ends without a trailing slash for consistent joining\n let base = baseUrl;\n while (base.endsWith('/')) base = base.slice(0, -1);\n\n return {\n list: (config) => httpClient.get<T[]>(base, config),\n get: (id, config) => httpClient.get<T>(`${base}/${encodeURIComponent(String(id))}`, config),\n create: (body, config) => httpClient.post<T>(base, body as HttpRequestConfig['body'], config),\n update: (id, body, config) =>\n httpClient.put<T>(\n `${base}/${encodeURIComponent(String(id))}`,\n body as HttpRequestConfig['body'],\n config\n ),\n patch: (id, body, config) =>\n httpClient.patch<T>(\n `${base}/${encodeURIComponent(String(id))}`,\n body as HttpRequestConfig['body'],\n config\n ),\n remove: (id, config) =>\n httpClient.delete<void>(`${base}/${encodeURIComponent(String(id))}`, config),\n http: httpClient,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useResourceList — reactive collection CRUD\n// ---------------------------------------------------------------------------\n\n/** Extract a unique identifier from an item. */\nexport type IdExtractor<T> = (item: T) => string | number;\n\n/** Options for `useResourceList()`. */\nexport interface UseResourceListOptions<T = unknown> extends Omit<\n UseFetchOptions<T[]>,\n 'method' | 'body'\n> {\n /** Extract the unique ID from each item (default: `item.id`). */\n getId?: IdExtractor<T>;\n /** Enable optimistic list mutations (default: false). */\n optimistic?: boolean;\n /** Called after a successful list mutation. */\n onMutationSuccess?: (action: string) => void;\n /** Called after a failed list mutation. */\n onMutationError?: (error: Error, action: string) => void;\n}\n\n/** CRUD actions for a list resource. */\nexport interface ResourceListActions<T> {\n /** Refresh the list (GET). */\n fetch: () => Promise<T[] | undefined>;\n /** Add a new item to the list (POST). */\n add: (body: Partial<T> | Record<string, unknown>) => Promise<T | undefined>;\n /** Update an existing item (PUT) by ID. */\n update: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>\n ) => Promise<T | undefined>;\n /** Partially update an existing item (PATCH) by ID. */\n patch: (\n id: string | number,\n body: Partial<T> | Record<string, unknown>\n ) => Promise<T | undefined>;\n /** Remove an item from the list (DELETE) by ID. */\n remove: (id: string | number) => Promise<void>;\n}\n\n/** Return value of `useResourceList()`. */\nexport interface UseResourceListReturn<T> {\n /** Reactive list data. */\n data: Signal<T[] | undefined>;\n /** Last error. */\n error: Signal<Error | null>;\n /** Lifecycle status. */\n status: Signal<AsyncDataStatus>;\n /** Whether the list fetch is pending. */\n pending: { readonly value: boolean; peek(): boolean };\n /** Whether any mutation is in progress. */\n isMutating: { readonly value: boolean; peek(): boolean };\n /** CRUD actions. */\n actions: ResourceListActions<T>;\n /** Refresh the list. */\n refresh: () => Promise<T[] | undefined>;\n /** Clear data, error, and status. */\n clear: () => void;\n /** Dispose all reactive state. */\n dispose: () => void;\n}\n\n/**\n * Reactive list/collection CRUD composable with optimistic add, remove, and update.\n *\n * Fetches a list of items and provides typed CRUD helpers that update the\n * reactive array optimistically or after server confirmation.\n *\n * @template T - Item type\n * @param url - List endpoint URL or getter\n * @param options - Fetch and list options\n * @returns Reactive list state with CRUD actions\n *\n * @example\n * ```ts\n * import { useResourceList } from '@bquery/bquery/reactive';\n *\n * interface Todo { id: number; title: string; done: boolean }\n *\n * const todos = useResourceList<Todo>('/api/todos', {\n * baseUrl: 'https://api.example.com',\n * optimistic: true,\n * getId: (t) => t.id,\n * });\n *\n * await todos.actions.add({ title: 'Buy milk', done: false });\n * await todos.actions.patch(1, { done: true });\n * await todos.actions.remove(1);\n * ```\n */\nexport const useResourceList = <T = unknown>(\n url: string | URL | (() => string | URL),\n options: UseResourceListOptions<T> = {}\n): UseResourceListReturn<T> => {\n const {\n getId = (item: T) => (item as Record<string, unknown>).id as string | number,\n optimistic = false,\n onMutationSuccess,\n onMutationError,\n ...fetchOptions\n } = options;\n\n const fetchState = useFetch<T[]>(url, { ...fetchOptions });\n\n const mutating = signal(false);\n const isMutating = computed(() => mutating.value);\n\n let disposed = false;\n\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const baseUrl = (): string => {\n let base = resolveUrl();\n while (base.endsWith('/')) base = base.slice(0, -1);\n return base;\n };\n\n const toMutationFetchOptions = <TResult>(): Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n > => {\n // Strip list-level async-data defaults/callbacks; mutations operate on item payloads instead.\n const {\n defaultValue: _defaultValue,\n transform: _transform,\n onSuccess: _onSuccess,\n onError: _onError,\n ...transportOpts\n } = fetchOptions;\n return transportOpts as Omit<\n UseFetchOptions<TResult>,\n 'method' | 'body' | 'defaultValue' | 'transform' | 'onSuccess' | 'onError'\n >;\n };\n\n const runMutation = async <TResult>(\n action: string,\n method: string,\n urlSuffix: string,\n body: Record<string, unknown> | Partial<T> | undefined,\n applyOptimistic: (() => void) | undefined,\n rollback: (() => void) | undefined\n ): Promise<TResult | undefined> => {\n if (disposed) return undefined;\n\n if (optimistic && applyOptimistic) applyOptimistic();\n\n mutating.value = true;\n fetchState.error.value = null;\n\n try {\n const mutationUrl = `${baseUrl()}${urlSuffix}`;\n const mutationState = useFetch<TResult>(mutationUrl, {\n ...toMutationFetchOptions<TResult>(),\n method,\n body: body ?? undefined,\n immediate: false,\n watch: undefined,\n });\n\n const result = await mutationState.execute();\n const mutationError = mutationState.error.peek();\n mutationState.dispose();\n\n if (disposed) return undefined;\n\n if (mutationError) {\n if (optimistic && rollback) rollback();\n fetchState.error.value = mutationError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(mutationError, action);\n return undefined;\n }\n\n mutating.value = false;\n fetchState.status.value = 'success';\n onMutationSuccess?.(action);\n return result as TResult | undefined;\n } catch (caught) {\n if (disposed) return undefined;\n if (optimistic && rollback) rollback();\n const normalizedError = caught instanceof Error ? caught : new Error(String(caught));\n fetchState.error.value = normalizedError;\n fetchState.status.value = 'error';\n mutating.value = false;\n onMutationError?.(normalizedError, action);\n return undefined;\n }\n };\n\n const actions: ResourceListActions<T> = {\n fetch: () => fetchState.execute(),\n\n add: async (body) => {\n const previousList = fetchState.data.peek();\n const optimisticItem = body as T;\n const optimisticInsertionIndex = previousList?.length ?? 0;\n\n const result = await runMutation<T>(\n 'add',\n 'POST',\n '',\n body as Record<string, unknown>,\n optimistic\n ? () => {\n fetchState.data.value = [...(previousList ?? []), optimisticItem];\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n if (result !== undefined && !disposed) {\n const current = fetchState.data.peek() ?? [];\n if (optimistic) {\n const next = [...current];\n // Replace the optimistic placeholder when it is still present; otherwise append.\n if (\n optimisticInsertionIndex < next.length &&\n next[optimisticInsertionIndex] === optimisticItem\n ) {\n next[optimisticInsertionIndex] = result;\n } else {\n next.push(result);\n }\n fetchState.data.value = next;\n } else {\n fetchState.data.value = [...current, result];\n }\n }\n\n return result;\n },\n\n update: async (id, body) => {\n const previousList = fetchState.data.peek();\n\n const result = await runMutation<T>(\n 'update',\n 'PUT',\n `/${encodeURIComponent(String(id))}`,\n body as Record<string, unknown>,\n optimistic && previousList\n ? () => {\n fetchState.data.value = previousList.map((item) =>\n getId(item) === id ? ({ ...item, ...body } as T) : item\n );\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n if (result !== undefined && !disposed) {\n const current = fetchState.data.peek() ?? [];\n fetchState.data.value = current.map((item) => (getId(item) === id ? result : item));\n }\n\n return result;\n },\n\n patch: async (id, body) => {\n const previousList = fetchState.data.peek();\n\n const result = await runMutation<T>(\n 'patch',\n 'PATCH',\n `/${encodeURIComponent(String(id))}`,\n body as Record<string, unknown>,\n optimistic && previousList\n ? () => {\n fetchState.data.value = previousList.map((item) =>\n getId(item) === id ? ({ ...item, ...body } as T) : item\n );\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n if (result !== undefined && !disposed) {\n const current = fetchState.data.peek() ?? [];\n fetchState.data.value = current.map((item) => (getId(item) === id ? result : item));\n }\n\n return result;\n },\n\n remove: async (id) => {\n const previousList = fetchState.data.peek();\n\n await runMutation<void>(\n 'remove',\n 'DELETE',\n `/${encodeURIComponent(String(id))}`,\n undefined,\n optimistic && previousList\n ? () => {\n fetchState.data.value = previousList.filter((item) => getId(item) !== id);\n }\n : undefined,\n optimistic\n ? () => {\n fetchState.data.value = previousList;\n }\n : undefined\n );\n\n // If not optimistic, remove from the list after server confirms\n if (!optimistic && !disposed && fetchState.error.peek() == null) {\n const current = fetchState.data.peek() ?? [];\n fetchState.data.value = current.filter((item) => getId(item) !== id);\n }\n },\n };\n\n const originalDispose = fetchState.dispose;\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n originalDispose();\n };\n\n return {\n data: fetchState.data as Signal<T[] | undefined>,\n error: fetchState.error,\n status: fetchState.status,\n pending: fetchState.pending,\n isMutating,\n actions,\n refresh: fetchState.execute,\n clear: fetchState.clear,\n dispose,\n };\n};\n\n// ---------------------------------------------------------------------------\n// Request deduplication\n// ---------------------------------------------------------------------------\n\n/** @internal In-flight request/operation cache for deduplication. */\nconst inflightRequests = new Map<string, Promise<unknown>>();\n\n/**\n * Deduplicate identical in-flight requests or operations keyed by `key`.\n *\n * If an operation with the same key is already in flight, reuse its promise\n * instead of starting a new one. Once the operation completes, the entry is removed.\n *\n * @param key - Cache key for the in-flight operation (for HTTP, typically URL + serialized query)\n * @param execute - The operation function to run if no duplicate is in flight\n * @returns The shared result promise for callers using the same key concurrently\n *\n * @example\n * ```ts\n * import { deduplicateRequest, createHttp } from '@bquery/bquery/reactive';\n *\n * const api = createHttp({ baseUrl: 'https://api.example.com' });\n *\n * // Both calls share the same in-flight operation\n * const [a, b] = await Promise.all([\n * deduplicateRequest('/users', () => api.get('/users')),\n * deduplicateRequest('/users', () => api.get('/users')),\n * ]);\n * ```\n */\nexport function deduplicateRequest<T>(key: string, execute: () => Promise<T>): Promise<T> {\n const existing = inflightRequests.get(key);\n if (existing) return existing as Promise<T>;\n\n const promise = execute().finally(() => {\n inflightRequests.delete(key);\n });\n\n inflightRequests.set(key, promise);\n return promise;\n}\n","/**\n * Type guards for reactive primitives.\n */\n\nimport { Computed } from './computed';\nimport { Signal } from './core';\n\n/**\n * Type guard to check if a value is a Signal instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Signal\n */\nexport const isSignal = (value: unknown): value is Signal<unknown> => value instanceof Signal;\n\n/**\n * Type guard to check if a value is a Computed instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Computed\n */\nexport const isComputed = (value: unknown): value is Computed<unknown> => value instanceof Computed;\n","/**\n * Utility to unwrap reactive or plain values.\n */\n\nimport { Computed } from './computed';\nimport { Signal } from './core';\nimport { readonly, isReadonlySignal } from './readonly';\n\n/**\n * A value that may be a raw value, a Signal, a `readonly()` wrapper, or a Computed.\n *\n * Useful for APIs that accept both reactive and plain inputs.\n *\n * Readonly wrappers are limited to the values returned by {@link readonly}. This keeps\n * the type aligned with runtime behavior, where arbitrary structural `{ value, peek }`\n * objects are intentionally returned unchanged.\n *\n * @template T - The underlying value type\n *\n * @example\n * ```ts\n * function useTitle(title: MaybeSignal<string>) {\n * document.title = toValue(title);\n * }\n *\n * useTitle('Hello'); // plain string\n * useTitle(signal('Hello')); // reactive signal\n * useTitle(computed(() => 'Hi')); // computed value\n * ```\n */\nexport type MaybeSignal<T> = T | Signal<T> | ReturnType<typeof readonly<T>> | Computed<T>;\n\n/**\n * Extracts the current value from a Signal, a bQuery `readonly()` wrapper, a\n * Computed, or returns the raw value as-is. This eliminates repetitive\n * `isSignal(x) ? x.value : x` patterns throughout user code.\n *\n * Reading a Signal or Computed via `toValue()` uses `.value`, so the\n * read **does** participate in reactive tracking when called inside\n * an effect or computed.\n *\n * @template T - The underlying value type\n * @param source - A plain value, Signal, bQuery readonly wrapper, or Computed\n * @returns The unwrapped value\n *\n * @example\n * ```ts\n * import { signal, computed, toValue } from '@bquery/bquery/reactive';\n *\n * const count = signal(5);\n * const doubled = computed(() => count.value * 2);\n *\n * toValue(42); // 42\n * toValue(count); // 5\n * toValue(doubled); // 10\n * toValue(null); // null\n * ```\n */\nexport const toValue = <T>(source: MaybeSignal<T>): T => {\n if (source instanceof Signal || source instanceof Computed) {\n return source.value;\n }\n\n if (isReadonlySignal<T>(source)) {\n return source.value;\n }\n\n // Remaining values are plain `T` inputs. Structural readonly-like objects that are not\n // branded bQuery wrappers intentionally fall through and are returned unchanged.\n return source as T;\n};\n","/**\n * Value watching helpers.\n */\n\nimport type { Computed } from './computed';\nimport type { Signal } from './core';\nimport type { CleanupFn } from './internals';\n\nimport { effect } from './effect';\n\n/**\n * Options for the watch function.\n */\nexport interface WatchOptions<T> {\n /** If true, the callback is invoked immediately with the current value. */\n immediate?: boolean;\n /** Custom equality function. Defaults to Object.is. */\n equals?: (a: T, b: T | undefined) => boolean;\n}\n\n/**\n * Watches a signal or computed value and calls a callback with old and new values.\n * Unlike effect, watch provides access to the previous value.\n * The callback is only invoked when the value actually changes (compared via Object.is or custom equals).\n *\n * @template T - The type of the watched value\n * @param source - The signal or computed to watch\n * @param callback - Function called with (newValue, oldValue) on changes\n * @param options - Watch options\n * @returns A cleanup function to stop watching\n *\n * @example\n * ```ts\n * const count = signal(0);\n * watch(count, (newVal, oldVal) => {\n * console.log(`Changed from ${oldVal} to ${newVal}`);\n * });\n *\n * // With custom equality for objects\n * const user = signal({ id: 1, name: 'Alice' });\n * watch(user, (newVal, oldVal) => { ... }, {\n * equals: (a, b) => a?.id === b?.id\n * });\n * ```\n */\nexport const watch = <T>(\n source: Signal<T> | Computed<T>,\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions<T> = {}\n): CleanupFn => {\n const { immediate = false, equals = Object.is } = options;\n let oldValue: T | undefined;\n let isFirst = true;\n\n return effect(() => {\n const newValue = source.value;\n\n if (isFirst) {\n isFirst = false;\n oldValue = newValue;\n if (immediate) {\n callback(newValue, undefined);\n }\n return;\n }\n\n // Only call callback if value actually changed\n if (!equals(newValue, oldValue)) {\n callback(newValue, oldValue);\n oldValue = newValue;\n }\n });\n};\n","/**\n * Reactive WebSocket composable with auto-reconnect, heartbeat,\n * message history, and signal-based connection state.\n *\n * @module bquery/reactive\n */\n\nimport { computed } from './computed';\nimport { Signal, signal } from './core';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Connection status for a WebSocket. */\nexport type WebSocketStatus = 'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED';\n/** Connection status for an EventSource. */\nexport type EventSourceStatus = 'CONNECTING' | 'OPEN' | 'CLOSED';\n\n/** Configuration for automatic reconnection. */\nexport interface WebSocketReconnectConfig {\n /** Maximum number of reconnection attempts. Use `0` to disable reconnection (default: Infinity / unlimited). */\n maxAttempts?: number;\n /** Base delay in ms between reconnects (default: 1000). */\n delay?: number;\n /** Maximum delay in ms between reconnects (default: 30000). */\n maxDelay?: number;\n /** Multiply factor for exponential backoff (default: 2). */\n factor?: number;\n /** Custom predicate — return `false` to prevent a reconnect attempt. */\n shouldReconnect?: (event: CloseEvent, attempts: number) => boolean;\n}\n\n/** Reconnect configuration supported by `useEventSource()`. */\nexport type EventSourceReconnectConfig = Pick<\n WebSocketReconnectConfig,\n 'maxAttempts' | 'delay' | 'maxDelay' | 'factor'\n>;\n\n/** Configuration for keep-alive heartbeats. */\nexport interface WebSocketHeartbeatConfig {\n /** Outgoing ping message (default: `'ping'`). */\n message?: string | ArrayBufferLike | Blob | ArrayBufferView;\n /** Interval in ms between heartbeat pings (default: 30 000). */\n interval?: number;\n /** Time in ms to wait for a pong before assuming the connection is dead (default: 10 000). */\n pongTimeout?: number;\n /** Expected response message. If set, only messages matching this value reset the pong timer. */\n responseMessage?: string;\n}\n\n/** Serializer/deserializer for typed messaging. */\nexport interface WebSocketSerializer<TSend = unknown, TReceive = unknown> {\n /** Serialize a value before sending over the wire. Default: `JSON.stringify`. */\n serialize?: (data: TSend) => string | ArrayBufferLike | Blob | ArrayBufferView;\n /** Deserialize an incoming message. Default: `JSON.parse`. */\n deserialize?: (event: MessageEvent) => TReceive;\n}\n\n/** Full configuration accepted by `useWebSocket()`. */\nexport interface UseWebSocketOptions<\n TSend = unknown,\n TReceive = unknown,\n> extends WebSocketSerializer<TSend, TReceive> {\n /** Sub-protocols to request during the WebSocket handshake. */\n protocols?: string | string[];\n /** Open the connection immediately (default: true). */\n immediate?: boolean;\n /** Automatically reconnect on unexpected close (default: true). Pass `false` or config. */\n autoReconnect?: boolean | WebSocketReconnectConfig;\n /** Keep-alive heartbeat configuration. Pass `true` for defaults or a config object. */\n heartbeat?: boolean | WebSocketHeartbeatConfig;\n /** Maximum number of messages to keep in `history` (default: 0 = disabled). */\n historySize?: number;\n /** Called when the connection opens. */\n onOpen?: (event: Event) => void;\n /** Called when a message is received (after deserialization). */\n onMessage?: (data: TReceive, event: MessageEvent) => void;\n /** Called when the connection closes. */\n onClose?: (event: CloseEvent) => void;\n /** Called when a connection error occurs. */\n onError?: (event: Event) => void;\n /** Called after a successful reconnection. Receives the reconnection attempt count. */\n onReconnect?: (attempts: number) => void;\n}\n\n/** Return value of `useWebSocket()`. */\nexport interface UseWebSocketReturn<TSend = unknown, TReceive = unknown> {\n /** Reactive connection status. */\n status: { readonly value: WebSocketStatus; peek(): WebSocketStatus };\n /** Reactive last received message (deserialized). */\n data: Signal<TReceive | undefined>;\n /** Last error event. */\n error: Signal<Event | null>;\n /** Rolling message history (newest last). */\n history: Signal<TReceive[]>;\n /** Computed boolean — `true` when the socket is `OPEN`. */\n isConnected: { readonly value: boolean; peek(): boolean };\n /** Number of reconnection attempts since last successful open. */\n reconnectAttempts: Signal<number>;\n /** Round-trip latency in ms measured via heartbeat pings (requires `heartbeat` option). */\n latency: Signal<number>;\n /** Timestamp of the last unexpected disconnection, or 0 if never disconnected. */\n lastDisconnectedAt: Signal<number>;\n /**\n * Send a message.\n *\n * If the socket is not `OPEN`, the message is queued and sent once a\n * connection is (re)established, subject to the configured options.\n */\n send: (data: TSend) => void;\n /**\n * Send raw data without serialization.\n *\n * Uses the same queuing behavior as {@link send}: data is queued when the\n * socket is not `OPEN` and flushed once a connection is (re)established.\n */\n sendRaw: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;\n /** Manually open / reconnect the WebSocket. */\n open: () => void;\n /** Gracefully close the connection. */\n close: (code?: number, reason?: string) => void;\n /** Tear down all resources (close + remove listeners + stop reconnect/heartbeat). */\n dispose: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** @internal */\nfunction resolveReconnect(\n opt: UseWebSocketOptions['autoReconnect']\n): WebSocketReconnectConfig | false;\n/** @internal */\nfunction resolveReconnect(\n opt: UseEventSourceOptions['autoReconnect']\n): EventSourceReconnectConfig | false;\n/** @internal */\nfunction resolveReconnect(\n opt: boolean | WebSocketReconnectConfig | EventSourceReconnectConfig | undefined\n): WebSocketReconnectConfig | EventSourceReconnectConfig | false {\n if (opt === false) return false;\n if (opt === true || opt === undefined) return {};\n return opt;\n}\n\n/** @internal */\nconst resolveHeartbeat = (\n opt: UseWebSocketOptions['heartbeat']\n): WebSocketHeartbeatConfig | false => {\n if (!opt) return false;\n if (opt === true) return {};\n return opt;\n};\n\n/** @internal */\nconst computeDelay = (attempt: number, config: WebSocketReconnectConfig): number => {\n const base = config.delay ?? 1000;\n const factor = config.factor ?? 2;\n const max = config.maxDelay ?? 30_000;\n return Math.min(base * factor ** attempt, max);\n};\n\n// ---------------------------------------------------------------------------\n// useWebSocket\n// ---------------------------------------------------------------------------\n\n/**\n * Reactive WebSocket composable with auto-reconnect, heartbeat,\n * typed messaging, and signal-based connection state.\n *\n * @template TSend - Type of outgoing messages (serialized via `serialize`)\n * @template TReceive - Type of incoming messages (deserialized via `deserialize`)\n * @param url - WebSocket URL (`ws://` or `wss://`) or a getter returning one\n * @param options - Connection, reconnect, heartbeat, and serialization options\n * @returns Reactive WebSocket state with `send()`, `open()`, `close()`, and `dispose()`\n *\n * @example\n * ```ts\n * import { useWebSocket } from '@bquery/bquery/reactive';\n *\n * const ws = useWebSocket<{ type: string; payload: unknown }>('wss://api.example.com/ws', {\n * autoReconnect: { maxAttempts: 5, delay: 2000 },\n * heartbeat: true,\n * historySize: 50,\n * onMessage: (data) => console.log('Received:', data),\n * });\n *\n * ws.send({ type: 'subscribe', payload: { channel: 'updates' } });\n *\n * // Reactive state\n * effect(() => {\n * console.log('Connected:', ws.isConnected.value);\n * console.log('Last message:', ws.data.value);\n * });\n *\n * // Cleanup\n * ws.dispose();\n * ```\n */\nexport const useWebSocket = <TSend = string, TReceive = string>(\n url: string | URL | (() => string | URL),\n options: UseWebSocketOptions<TSend, TReceive> = {}\n): UseWebSocketReturn<TSend, TReceive> => {\n const {\n protocols,\n immediate = true,\n historySize = 0,\n onOpen,\n onMessage,\n onClose,\n onError,\n onReconnect,\n } = options;\n\n const serialize = options.serialize ?? ((d: TSend) => JSON.stringify(d));\n const deserialize =\n options.deserialize ??\n ((event: MessageEvent) => {\n const raw = event.data;\n if (typeof raw === 'string') {\n try {\n return JSON.parse(raw) as TReceive;\n } catch {\n return raw as unknown as TReceive;\n }\n }\n return raw as TReceive;\n });\n\n // --- Reactive state ---\n const status = signal<WebSocketStatus>('CLOSED');\n const data = signal<TReceive | undefined>(undefined);\n const error = signal<Event | null>(null);\n const history = signal<TReceive[]>([]);\n const reconnectAttempts = signal(0);\n const latency = signal(0);\n const lastDisconnectedAt = signal(0);\n const isConnected = computed(() => status.value === 'OPEN');\n\n // --- Internal state ---\n let ws: WebSocket | null = null;\n let disposed = false;\n let explicitClose = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n let pongTimer: ReturnType<typeof setTimeout> | undefined;\n let internalReconnectCount = 0;\n let isAutoReconnecting = false;\n let pingSentAt = 0;\n const sendQueue: Array<string | ArrayBufferLike | Blob | ArrayBufferView> = [];\n\n const reconnectConfig = resolveReconnect(options.autoReconnect);\n const heartbeatConfig = resolveHeartbeat(options.heartbeat);\n\n // --- Heartbeat ---\n const startHeartbeat = (): void => {\n if (!heartbeatConfig) return;\n stopHeartbeat();\n const interval = heartbeatConfig.interval ?? 30_000;\n const timeout = heartbeatConfig.pongTimeout ?? 10_000;\n const pingMsg = heartbeatConfig.message ?? 'ping';\n\n heartbeatTimer = setInterval(() => {\n if (ws?.readyState === WebSocket.OPEN) {\n pingSentAt = Date.now();\n ws.send(pingMsg);\n if (pongTimer !== undefined) {\n clearTimeout(pongTimer);\n }\n pongTimer = setTimeout(() => {\n // No pong received — force close to trigger reconnect\n ws?.close(4000, 'Heartbeat timeout');\n }, timeout);\n }\n }, interval);\n };\n\n const stopHeartbeat = (): void => {\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n if (pongTimer !== undefined) {\n clearTimeout(pongTimer);\n pongTimer = undefined;\n }\n };\n\n const resetPongTimer = (): void => {\n if (pongTimer !== undefined) {\n clearTimeout(pongTimer);\n pongTimer = undefined;\n }\n if (pingSentAt > 0) {\n latency.value = Date.now() - pingSentAt;\n pingSentAt = 0;\n }\n };\n\n // --- Reconnect ---\n const scheduleReconnect = (event: CloseEvent): void => {\n if (disposed || explicitClose || !reconnectConfig) return;\n\n const maxAttempts = reconnectConfig.maxAttempts ?? Infinity;\n\n if (internalReconnectCount >= maxAttempts) return;\n\n if (\n reconnectConfig.shouldReconnect &&\n !reconnectConfig.shouldReconnect(event, internalReconnectCount)\n ) {\n return;\n }\n\n const delay = computeDelay(internalReconnectCount, reconnectConfig);\n reconnectTimer = setTimeout(() => {\n internalReconnectCount++;\n reconnectAttempts.value = internalReconnectCount;\n isAutoReconnecting = true;\n open();\n }, delay);\n };\n\n const cancelReconnect = (): void => {\n if (reconnectTimer !== undefined) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n };\n\n // --- Queue ---\n const flushQueue = (): void => {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n let index = 0;\n for (; index < sendQueue.length; index++) {\n if (ws.readyState !== WebSocket.OPEN) {\n break;\n }\n ws.send(sendQueue[index]);\n }\n\n if (index > 0) {\n sendQueue.splice(0, index);\n }\n };\n\n // --- Core ---\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const open = (): void => {\n if (disposed) return;\n cancelReconnect();\n\n // Clean up any existing connection\n if (ws) {\n stopHeartbeat();\n pingSentAt = 0;\n ws.onopen = null;\n ws.onmessage = null;\n ws.onclose = null;\n ws.onerror = null;\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n ws.close();\n }\n ws = null;\n }\n\n explicitClose = false;\n status.value = 'CONNECTING';\n error.value = null;\n\n try {\n ws = new WebSocket(resolveUrl(), protocols);\n } catch {\n status.value = 'CLOSED';\n return;\n }\n\n ws.onopen = (event: Event): void => {\n status.value = 'OPEN';\n const wasReconnecting = isAutoReconnecting;\n const reconnectCount = internalReconnectCount;\n internalReconnectCount = 0;\n reconnectAttempts.value = 0;\n isAutoReconnecting = false;\n flushQueue();\n startHeartbeat();\n onOpen?.(event);\n if (wasReconnecting) {\n onReconnect?.(reconnectCount);\n }\n };\n\n ws.onmessage = (event: MessageEvent): void => {\n // Heartbeat pong detection\n if (heartbeatConfig) {\n const responseMsg = heartbeatConfig.responseMessage;\n if (responseMsg === undefined || event.data === responseMsg) {\n resetPongTimer();\n }\n }\n\n const deserialized = deserialize(event);\n data.value = deserialized;\n\n if (historySize > 0) {\n const current = history.peek();\n const updated = [...current, deserialized];\n history.value = updated.length > historySize ? updated.slice(-historySize) : updated;\n }\n\n onMessage?.(deserialized, event);\n };\n\n ws.onclose = (event: CloseEvent): void => {\n status.value = 'CLOSED';\n stopHeartbeat();\n\n if (!explicitClose) {\n lastDisconnectedAt.value = Date.now();\n }\n\n onClose?.(event);\n\n if (!explicitClose && !disposed) {\n scheduleReconnect(event);\n }\n };\n\n ws.onerror = (event: Event): void => {\n error.value = event;\n onError?.(event);\n };\n };\n\n const close = (code?: number, reason?: string): void => {\n explicitClose = true;\n cancelReconnect();\n stopHeartbeat();\n\n if (ws) {\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n status.value = 'CLOSING';\n ws.close(code, reason);\n }\n }\n };\n\n const send = (msg: TSend): void => {\n if (disposed) return;\n const serialized = serialize(msg);\n sendRaw(serialized);\n };\n\n const sendRaw = (raw: string | ArrayBufferLike | Blob | ArrayBufferView): void => {\n if (disposed) return;\n if (ws?.readyState === WebSocket.OPEN) {\n ws.send(raw);\n } else {\n sendQueue.push(raw);\n }\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n close();\n sendQueue.length = 0;\n ws = null;\n };\n\n // --- Start ---\n if (immediate) {\n open();\n }\n\n return {\n status,\n data,\n error,\n history,\n isConnected,\n reconnectAttempts,\n latency,\n lastDisconnectedAt,\n send,\n sendRaw,\n open,\n close,\n dispose,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useWebSocketChannel — topic-based multiplexer\n// ---------------------------------------------------------------------------\n\n/** Default channel message format used by `useWebSocketChannel()`. */\nexport interface ChannelMessage<T = unknown> {\n /** Channel / topic name. */\n channel: string;\n /** Message payload. */\n data: T;\n}\n\n/** Configuration for `useWebSocketChannel()`. */\nexport interface UseWebSocketChannelOptions<TSend = unknown, TReceive = unknown> {\n /**\n * Extract the channel name from an incoming deserialized message.\n * Default: reads `(msg as ChannelMessage).channel`.\n */\n getChannel?: (msg: TReceive) => string | undefined;\n /**\n * Wrap a payload + channel into the wire format before sending.\n * Default: `{ channel, data }`.\n */\n wrap?: (channel: string, data: TSend) => TReceive;\n}\n\n/** A single channel subscription returned by `subscribe()`. */\nexport interface ChannelSubscription<TReceive = unknown> {\n /** Reactive last message received on this channel. */\n data: Signal<TReceive | undefined>;\n /** Unsubscribe from this channel. */\n unsubscribe: () => void;\n}\n\n/** Return value of `useWebSocketChannel()`. */\nexport interface UseWebSocketChannelReturn<TSend = unknown, TReceive = unknown> {\n /** Subscribe to a topic. Multiple subscriptions to the same channel share a signal. */\n subscribe: (channel: string) => ChannelSubscription<TReceive>;\n /** Publish a message to a channel. */\n publish: (channel: string, data: TSend) => void;\n /** The underlying `useWebSocket` return for direct access. */\n ws: UseWebSocketReturn<TReceive, TReceive>;\n}\n\n/**\n * Topic-based channel multiplexer over a single WebSocket connection.\n *\n * Builds on `useWebSocket()` and routes incoming messages to per-channel\n * reactive signals based on a configurable channel extractor.\n *\n * @template TSend - Type of outgoing message payloads\n * @template TReceive - Type of incoming deserialized messages\n * @param url - WebSocket URL\n * @param wsOptions - All `useWebSocket` options\n * @param channelOptions - Channel routing configuration\n * @returns Channel multiplexer with `subscribe()`, `publish()`, and the underlying `ws`\n *\n * @example\n * ```ts\n * import { useWebSocketChannel } from '@bquery/bquery/reactive';\n *\n * const chat = useWebSocketChannel('wss://chat.example.com/ws');\n *\n * const general = chat.subscribe('general');\n * const updates = chat.subscribe('updates');\n *\n * effect(() => console.log('General:', general.data.value));\n *\n * chat.publish('general', { text: 'Hello!' });\n * ```\n */\nexport const useWebSocketChannel = <TSend = unknown, TReceive = unknown>(\n url: string | URL | (() => string | URL),\n wsOptions: UseWebSocketOptions<TReceive, TReceive> = {},\n channelOptions: UseWebSocketChannelOptions<TSend, TReceive> = {}\n): UseWebSocketChannelReturn<TSend, TReceive> => {\n const getChannel =\n channelOptions.getChannel ?? ((msg: TReceive) => (msg as ChannelMessage).channel);\n\n const wrap =\n channelOptions.wrap ??\n ((ch: string, data: TSend) => ({ channel: ch, data }) as unknown as TReceive);\n\n const channels = new Map<string, Signal<TReceive | undefined>>();\n const channelSubscriptions = new Map<string, number>();\n\n const ws = useWebSocket<TReceive, TReceive>(url, {\n ...wsOptions,\n onMessage: (msg, event) => {\n const ch = getChannel(msg);\n if (ch !== undefined) {\n const sig = channels.get(ch);\n if (sig) {\n sig.value = msg;\n }\n }\n wsOptions.onMessage?.(msg, event);\n },\n });\n\n const subscribe = (channel: string): ChannelSubscription<TReceive> => {\n let sig = channels.get(channel);\n if (!sig) {\n sig = signal<TReceive | undefined>(undefined);\n channels.set(channel, sig);\n }\n channelSubscriptions.set(channel, (channelSubscriptions.get(channel) ?? 0) + 1);\n let unsubscribed = false;\n\n return {\n data: sig,\n unsubscribe: () => {\n if (unsubscribed) return;\n unsubscribed = true;\n const remaining = (channelSubscriptions.get(channel) ?? 1) - 1;\n if (remaining <= 0) {\n channelSubscriptions.delete(channel);\n channels.delete(channel);\n } else {\n channelSubscriptions.set(channel, remaining);\n }\n },\n };\n };\n\n const publish = (channel: string, data: TSend): void => {\n ws.send(wrap(channel, data));\n };\n\n return { subscribe, publish, ws };\n};\n\n// ---------------------------------------------------------------------------\n// useEventSource\n// ---------------------------------------------------------------------------\n\n/** Configuration for `useEventSource()`. */\nexport interface UseEventSourceOptions<TData = unknown> {\n /** Whether to open the connection immediately (default: true). */\n immediate?: boolean;\n /** Automatically reconnect on error (default: true). Pass a reconnect config to customize delay and attempt limits. */\n autoReconnect?: boolean | EventSourceReconnectConfig;\n /** Event names to listen for besides the default `message` event. */\n events?: string[];\n /** Deserializer for incoming event data. Default: `JSON.parse` with string fallback. */\n deserialize?: (data: string) => TData;\n /** EventSource init options (e.g. `withCredentials`). */\n eventSourceInit?: EventSourceInit;\n /** Called when the connection opens. */\n onOpen?: (event: Event) => void;\n /** Called when a message is received. */\n onMessage?: (data: TData, event: MessageEvent) => void;\n /** Called when an error occurs. */\n onError?: (event: Event) => void;\n}\n\n/** Return value of `useEventSource()`. */\nexport interface UseEventSourceReturn<TData = unknown> {\n /** Current connection status (`CONNECTING`, `OPEN`, `CLOSED`). */\n status: { readonly value: EventSourceStatus; peek(): EventSourceStatus };\n /** Last received data (deserialized). */\n data: Signal<TData | undefined>;\n /** Last event name that delivered data. */\n eventName: Signal<string | undefined>;\n /** Last error event. */\n error: Signal<Event | null>;\n /** Computed boolean — `true` when the EventSource is open. */\n isConnected: { readonly value: boolean; peek(): boolean };\n /** Manually open / reconnect the EventSource. */\n open: () => void;\n /** Close the connection. */\n close: () => void;\n /** Tear down all resources. */\n dispose: () => void;\n}\n\n/**\n * Reactive Server-Sent Events (SSE) composable.\n *\n * Wraps the native `EventSource` API with reactive signals, auto-reconnect,\n * and typed deserialization.\n *\n * @template TData - Type of deserialized event data\n * @param url - SSE endpoint URL or a getter returning one\n * @param options - EventSource options\n * @returns Reactive EventSource state with `open()`, `close()`, and `dispose()`\n *\n * @example\n * ```ts\n * import { useEventSource } from '@bquery/bquery/reactive';\n *\n * const sse = useEventSource<{ type: string; message: string }>('/api/events', {\n * events: ['notification', 'update'],\n * onMessage: (data) => console.log('Event:', data),\n * });\n *\n * effect(() => {\n * if (sse.data.value) {\n * console.log(`[${sse.eventName.value}]`, sse.data.value);\n * }\n * });\n *\n * sse.dispose();\n * ```\n */\nexport const useEventSource = <TData = unknown>(\n url: string | URL | (() => string | URL),\n options: UseEventSourceOptions<TData> = {}\n): UseEventSourceReturn<TData> => {\n const { immediate = true, events = [], eventSourceInit, onOpen, onMessage, onError } = options;\n\n const deserialize =\n options.deserialize ??\n ((raw: string) => {\n try {\n return JSON.parse(raw) as TData;\n } catch {\n return raw as unknown as TData;\n }\n });\n\n const status = signal<EventSourceStatus>('CLOSED');\n const data = signal<TData | undefined>(undefined);\n const eventName = signal<string | undefined>(undefined);\n const error = signal<Event | null>(null);\n const isConnected = computed(() => status.value === 'OPEN');\n\n const reconnectConfig = resolveReconnect(options.autoReconnect);\n\n let es: EventSource | null = null;\n let disposed = false;\n let explicitClose = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined;\n let reconnectAttemptCount = 0;\n\n const resolveUrl = (): string => {\n const resolved = typeof url === 'function' ? url() : url;\n return resolved instanceof URL ? resolved.toString() : resolved;\n };\n\n const handleMessage =\n (name: string) =>\n (event: MessageEvent): void => {\n const deserialized = deserialize(event.data);\n data.value = deserialized;\n eventName.value = name;\n onMessage?.(deserialized, event);\n };\n\n const cancelReconnect = (): void => {\n if (reconnectTimer !== undefined) {\n clearTimeout(reconnectTimer);\n reconnectTimer = undefined;\n }\n };\n\n const scheduleReconnect = (): void => {\n if (disposed || explicitClose || !reconnectConfig) return;\n\n const maxAttempts = reconnectConfig.maxAttempts ?? Infinity;\n if (reconnectAttemptCount >= maxAttempts) return;\n\n const delay = computeDelay(reconnectAttemptCount, reconnectConfig);\n reconnectTimer = setTimeout(() => {\n reconnectAttemptCount++;\n open();\n }, delay);\n };\n\n const open = (): void => {\n if (disposed) return;\n cancelReconnect();\n\n if (es) {\n es.close();\n es = null;\n }\n\n explicitClose = false;\n status.value = 'CONNECTING';\n error.value = null;\n\n try {\n es = new EventSource(resolveUrl(), eventSourceInit);\n } catch {\n status.value = 'CLOSED';\n return;\n }\n\n es.onopen = (event: Event): void => {\n status.value = 'OPEN';\n reconnectAttemptCount = 0;\n onOpen?.(event);\n };\n\n es.onerror = (event: Event): void => {\n error.value = event;\n onError?.(event);\n\n // EventSource closes on error when readyState is CLOSED\n if (es?.readyState === EventSource.CLOSED) {\n status.value = 'CLOSED';\n if (!explicitClose && !disposed) {\n scheduleReconnect();\n }\n }\n };\n\n // Default \"message\" event\n es.addEventListener('message', handleMessage('message'));\n\n // Named events\n for (const name of events) {\n es.addEventListener(name, handleMessage(name) as EventListener);\n }\n };\n\n const close = (): void => {\n explicitClose = true;\n cancelReconnect();\n if (es) {\n es.close();\n es = null;\n }\n status.value = 'CLOSED';\n };\n\n const dispose = (): void => {\n if (disposed) return;\n disposed = true;\n close();\n };\n\n if (immediate) {\n open();\n }\n\n return {\n status,\n data,\n eventName,\n error,\n isConnected,\n open,\n close,\n dispose,\n };\n};\n","/**\n * Prop coercion utilities.\n *\n * @module bquery/component\n */\n\nimport type { PropDefinition } from './types';\n\n/**\n * Coerces a string attribute value into a typed prop value.\n * Supports String, Number, Boolean, Object, Array, and custom converters.\n *\n * @internal\n * @template T - The target type\n * @param rawValue - The raw string value from the attribute\n * @param config - The prop definition with type information\n * @returns The coerced value of type T\n */\nexport const coercePropValue = <T>(rawValue: string, config: PropDefinition<T>): T => {\n const { type } = config;\n\n if (type === String) return rawValue as T;\n\n if (type === Number) {\n return Number(rawValue) as T;\n }\n\n if (type === Boolean) {\n const normalized = rawValue.trim().toLowerCase();\n if (normalized === '' || normalized === 'true' || normalized === '1') {\n return true as T;\n }\n if (normalized === 'false' || normalized === '0') {\n return false as T;\n }\n return Boolean(rawValue) as T;\n }\n\n if (type === Object || type === Array) {\n try {\n return JSON.parse(rawValue) as T;\n } catch {\n return rawValue as T;\n }\n }\n\n if (typeof type === 'function') {\n const callable = type as (value: unknown) => T;\n const constructable = type as new (value: unknown) => T;\n\n // Explicit construct mode takes precedence\n if (config.construct === true) {\n return Reflect.construct(constructable, [rawValue]) as T;\n }\n if (config.construct === false) {\n return callable(rawValue);\n }\n\n // Auto-detect: Check if type is constructable\n // A function is considered constructable if:\n // 1. It has a prototype with properties beyond just constructor, OR\n // 2. Its prototype.constructor is not itself (inherited), OR\n // 3. It's a class (toString starts with \"class\")\n const hasPrototype = type.prototype !== undefined && type.prototype !== null;\n const prototypeProps = hasPrototype ? Object.getOwnPropertyNames(type.prototype) : [];\n const hasPrototypeMethods = prototypeProps.length > 1;\n const hasInheritedConstructor = hasPrototype && type.prototype.constructor !== type;\n const isClassSyntax = /^class\\s/.test(Function.prototype.toString.call(type));\n\n const isConstructable = hasPrototypeMethods || hasInheritedConstructor || isClassSyntax;\n\n // For constructable types (e.g. Date, custom classes), prefer `new` to avoid\n // silent wrong-type returns (Date() returns string, new Date() returns Date)\n if (isConstructable) {\n try {\n return Reflect.construct(constructable, [rawValue]) as T;\n } catch {\n // Fall back to calling as function if construction fails\n return callable(rawValue);\n }\n }\n\n // For non-constructable types (arrow functions, plain functions), call directly\n // but fall back to constructor if result is undefined (common for function constructors)\n try {\n const result = callable(rawValue);\n\n // If calling without `new` returned undefined and the function has a prototype,\n // it's likely a function constructor that should be called with `new`\n if (result === undefined && hasPrototype) {\n try {\n return Reflect.construct(constructable, [rawValue]) as T;\n } catch {\n // Construction also failed, return the undefined\n return result as T;\n }\n }\n\n return result as T;\n } catch (error) {\n // Fall back to constructor if error indicates 'new' is required\n const isNewRequired =\n error instanceof TypeError &&\n /cannot be invoked without 'new'|is not a function/i.test(error.message);\n\n if (isNewRequired) {\n return Reflect.construct(constructable, [rawValue]) as T;\n }\n\n // Rethrow original error for non-constructable converters\n throw error;\n }\n }\n\n return rawValue as T;\n};\n","/**\n * Shared environment detection helpers.\n *\n * @internal\n */\n\ntype BQueryEnvGlobal = typeof globalThis & {\n __BQUERY_DEV__?: boolean;\n process?: {\n env?: {\n NODE_ENV?: string;\n };\n release?: {\n name?: string;\n };\n versions?: {\n node?: string;\n };\n };\n};\n\n/**\n * Returns whether development-only diagnostics should be enabled.\n *\n * Priority:\n * 1. Explicit global override via `globalThis.__BQUERY_DEV__`\n * 2. `process.env.NODE_ENV`\n * 3. Actual Node-like runtimes without `NODE_ENV` default to development\n * 4. Production-safe fallback (`false`)\n *\n * @internal\n */\nexport const detectDevEnvironment = (): boolean => {\n try {\n const globalObject = globalThis as BQueryEnvGlobal;\n\n if (typeof globalObject.__BQUERY_DEV__ === 'boolean') {\n return globalObject.__BQUERY_DEV__;\n }\n\n const nodeEnv = globalObject.process?.env?.NODE_ENV;\n if (typeof nodeEnv === 'string') {\n return nodeEnv !== 'production';\n }\n\n const nodeVersion = globalObject.process?.versions?.node;\n if (typeof nodeVersion === 'string' && nodeVersion.length > 0) {\n return true;\n }\n\n const releaseName = globalObject.process?.release?.name;\n if (releaseName === 'node' || releaseName === 'io.js') {\n return true;\n }\n\n return false;\n } catch {\n return false;\n }\n};\n","/**\n * Component-scoped reactive primitives.\n *\n * Provides `useSignal`, `useComputed`, and `useEffect` that automatically\n * dispose when their owning component disconnects from the DOM.\n *\n * @module bquery/component\n */\n\nimport type { Computed } from '../reactive/computed';\nimport { computed } from '../reactive/computed';\nimport { detectDevEnvironment } from '../core/env';\nimport type { Signal } from '../reactive/core';\nimport { signal } from '../reactive/core';\nimport { effect } from '../reactive/effect';\nimport type { CleanupFn } from '../reactive/index';\n\n/**\n * Holds disposable resources created inside a component scope.\n * All registered disposers run when the component disconnects.\n * @internal\n */\nexport interface ComponentScope {\n /** Register a cleanup function to run on dispose */\n addDisposer(fn: CleanupFn): void;\n /** Dispose all registered resources */\n dispose(): void;\n}\n\n/** Currently active component scope. @internal */\nlet currentScope: ComponentScope | undefined;\n\n/**\n * Sets the active component scope.\n * @internal\n */\nexport function setCurrentScope(scope: ComponentScope | undefined): ComponentScope | undefined {\n const previousScope = currentScope;\n currentScope = scope;\n return previousScope;\n}\n\n/**\n * Returns the active component scope, or undefined if none.\n * @internal\n */\nexport function getCurrentScope(): ComponentScope | undefined {\n return currentScope;\n}\n\n/**\n * Creates a new component scope that tracks disposable resources.\n * @internal\n */\nexport function createComponentScope(): ComponentScope {\n const disposers: CleanupFn[] = [];\n\n return {\n addDisposer(fn: CleanupFn): void {\n disposers.push(fn);\n },\n dispose(): void {\n for (const fn of disposers) {\n try {\n fn();\n } catch (error) {\n if (\n detectDevEnvironment() &&\n typeof console !== 'undefined' &&\n typeof console.error === 'function'\n ) {\n console.error('bQuery component: Error disposing scoped resource', error);\n }\n }\n }\n disposers.length = 0;\n },\n };\n}\n\n/**\n * Creates a reactive signal scoped to the current component.\n *\n * The signal is automatically disposed when the component disconnects\n * from the DOM, removing all subscribers and preventing memory leaks.\n *\n * Must be called during a component lifecycle hook such as `connected`,\n * `beforeMount`, `onAdopted`, or `onAttributeChanged`.\n *\n * Do not create scoped primitives from `render()`. Repeated renders can\n * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.\n *\n * @template T - The type of the signal value\n * @param initialValue - The initial value of the signal\n * @returns A new Signal instance that auto-disposes with the component\n * @throws {Error} If called outside a component scope\n *\n * @example\n * ```ts\n * import { component, html, useSignal } from '@bquery/bquery/component';\n *\n * component('my-counter', {\n * connected() {\n * const count = useSignal(0);\n * // count.dispose() is called automatically on disconnect\n * },\n * render({ state }) {\n * return html`<span>${state.count}</span>`;\n * },\n * });\n * ```\n */\nexport function useSignal<T>(initialValue: T): Signal<T> {\n const scope = currentScope;\n if (!scope) {\n throw new Error(\n 'bQuery component: useSignal() must be called inside a component lifecycle hook. Avoid calling it directly from render()'\n );\n }\n const s = signal(initialValue);\n scope.addDisposer(() => s.dispose());\n return s;\n}\n\n/**\n * Creates a computed value scoped to the current component.\n *\n * The computed value's internal effect is automatically cleaned up\n * when the component disconnects from the DOM.\n *\n * Must be called during a component lifecycle hook such as `connected`,\n * `beforeMount`, `onAdopted`, or `onAttributeChanged`.\n *\n * Do not create scoped primitives from `render()`. Repeated renders can\n * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.\n *\n * @template T - The type of the computed value\n * @param fn - Derivation function that reads reactive sources\n * @returns A new Computed instance that auto-cleans-up with the component\n * @throws {Error} If called outside a component scope\n *\n * @example\n * ```ts\n * import { component, html, useSignal, useComputed } from '@bquery/bquery/component';\n *\n * component('my-doubler', {\n * connected() {\n * const count = useSignal(1);\n * const doubled = useComputed(() => count.value * 2);\n * },\n * render({ state }) {\n * return html`<span>${state.doubled}</span>`;\n * },\n * });\n * ```\n */\nexport function useComputed<T>(fn: () => T): Computed<T> {\n const scope = currentScope;\n if (!scope) {\n throw new Error(\n 'bQuery component: useComputed() must be called inside a component lifecycle hook. Avoid calling it directly from render()'\n );\n }\n const c = computed(fn);\n scope.addDisposer(() => c.dispose());\n return c;\n}\n\n/**\n * Creates a side effect scoped to the current component.\n *\n * The effect runs immediately and re-runs when its reactive dependencies\n * change. It is automatically disposed when the component disconnects\n * from the DOM.\n *\n * Must be called during a component lifecycle hook such as `connected`,\n * `beforeMount`, `onAdopted`, or `onAttributeChanged`.\n *\n * Do not create scoped primitives from `render()`. Repeated renders can\n * accumulate render-scoped resources until disconnect; prefer lifecycle hooks.\n *\n * @param fn - The effect function; may return a cleanup function\n * @returns A cleanup function to manually stop the effect early\n * @throws {Error} If called outside a component scope\n *\n * @example\n * ```ts\n * import { component, useSignal, useEffect } from '@bquery/bquery/component';\n *\n * component('my-logger', {\n * connected() {\n * const count = useSignal(0);\n * useEffect(() => {\n * console.log('Count changed:', count.value);\n * return () => console.log('Cleanup');\n * });\n * },\n * render() { return '<p>Logger</p>'; },\n * });\n * ```\n */\nexport function useEffect(fn: () => void | CleanupFn): CleanupFn {\n const scope = currentScope;\n if (!scope) {\n throw new Error(\n 'bQuery component: useEffect() must be called inside a component lifecycle hook. Avoid calling it directly from render()'\n );\n }\n const cleanup = effect(fn);\n scope.addDisposer(cleanup);\n return cleanup;\n}\n","/**\n * Web Component factory and registry.\n *\n * @module bquery/component\n */\n\nimport type { CleanupFn } from '../reactive/signal';\nimport { effect, untrack } from '../reactive/signal';\nimport { sanitizeHtml } from '../security/sanitize';\nimport { coercePropValue } from './props';\nimport { createComponentScope, setCurrentScope, type ComponentScope } from './scope';\nimport type {\n AttributeChange,\n ComponentClass,\n ComponentDefinition,\n ComponentSignalLike,\n ComponentSignals,\n ComponentStateShape,\n PropDefinition,\n ShadowMode,\n} from './types';\n\n/**\n * Base extra tags preserved for component shadow DOM renders in addition to the\n * global sanitizer defaults. `slot` must remain allowed here because shadow DOM\n * content projection depends on authored `<slot>` elements in component render\n * output.\n */\nconst COMPONENT_ALLOWED_TAGS = ['slot'];\n\n/**\n * Base extra attributes preserved for component shadow DOM renders in addition\n * to the global sanitizer defaults.\n */\nconst COMPONENT_ALLOWED_ATTRIBUTES = [\n 'part',\n // Standard form attributes required by interactive shadow DOM content\n 'disabled',\n 'checked',\n 'placeholder',\n 'value',\n 'rows',\n 'cols',\n 'readonly',\n 'required',\n 'maxlength',\n 'minlength',\n 'max',\n 'min',\n 'step',\n 'pattern',\n 'autocomplete',\n 'autofocus',\n 'for',\n 'multiple',\n 'selected',\n 'wrap',\n];\n\n/**\n * Creates a custom element class for a component definition.\n *\n * This is useful when you want to extend or register the class manually\n * (e.g. with different tag names in tests or custom registries).\n *\n * @template TProps - Type of the component's props\n * @param tagName - The custom element tag name (used for diagnostics)\n * @param definition - The component configuration\n */\nconst createComponentClass = <\n TProps extends Record<string, unknown>,\n TState extends Record<string, unknown> | undefined = undefined,\n TSignals extends ComponentSignals = Record<string, never>,\n>(\n tagName: string,\n definition: ComponentDefinition<TProps, TState, TSignals>\n): ComponentClass<TState> => {\n const componentAllowedTags = [\n ...COMPONENT_ALLOWED_TAGS,\n ...(definition.sanitize?.allowTags ?? []),\n ];\n const componentAllowedAttributes = [\n ...COMPONENT_ALLOWED_ATTRIBUTES,\n ...(definition.sanitize?.allowAttributes ?? []),\n ];\n const signalSources = Object.values(definition.signals ?? {}) as ComponentSignalLike<unknown>[];\n\n /** Resolve the Shadow DOM mode from the `shadow` option. */\n const resolveShadowMode = (option: ShadowMode | undefined): 'open' | 'closed' | false => {\n if (option === false) return false;\n if (option === 'closed') return 'closed';\n // true, 'open', or undefined all resolve to 'open'\n return 'open';\n };\n const shadowMode = resolveShadowMode(definition.shadow);\n\n /**\n * Merges prop-derived observed attributes with any extra attributes from\n * `observeAttributes`, deduplicating to avoid redundant callbacks.\n */\n const observedAttrs = Array.from(\n new Set([...Object.keys(definition.props ?? {}), ...(definition.observeAttributes ?? [])])\n );\n\n class BQueryComponent extends HTMLElement {\n /** Internal state object for the component */\n private readonly state: ComponentStateShape<TState> = {\n ...(definition.state ?? {}),\n } as ComponentStateShape<TState>;\n /** Typed props object populated from attributes */\n private props = {} as TProps;\n /** Tracks missing required props for validation during connectedCallback */\n private missingRequiredProps = new Set<string>();\n /** Tracks whether the component has completed its initial mount */\n private hasMounted = false;\n /** Cleanup for external signal subscriptions */\n private signalEffectCleanup?: CleanupFn;\n /** Component-scoped reactive resource tracker */\n private scope?: ComponentScope;\n /** Render target for open/closed shadow roots or the host element when shadow DOM is disabled */\n private readonly renderRootNode: HTMLElement | ShadowRoot;\n\n constructor() {\n super();\n if (shadowMode !== false) {\n this.renderRootNode = this.attachShadow({ mode: shadowMode });\n } else {\n this.renderRootNode = this;\n }\n this.syncProps();\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n */\n static get observedAttributes(): string[] {\n return observedAttrs;\n }\n\n /**\n * Called when the element is added to the DOM.\n */\n connectedCallback(): void {\n try {\n // Defer only the initial mount until all required props are present.\n // Already-mounted components must still reconnect their signal\n // subscriptions so reactive updates can resume after reattachment.\n if (!this.hasMounted && this.missingRequiredProps.size > 0) {\n // Component will mount once all required props are satisfied\n // via attributeChangedCallback\n return;\n }\n if (this.hasMounted) {\n // Recreate scope for reconnected component\n this.scope = createComponentScope();\n const previousScope = setCurrentScope(this.scope);\n try {\n definition.connected?.call(this);\n } catch (error) {\n this.handleError(error as Error);\n } finally {\n setCurrentScope(previousScope);\n }\n this.setupSignalSubscriptions(true);\n return;\n }\n this.mount();\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * Performs the initial mount of the component.\n * Called when the element is connected and all required props are present.\n * @internal\n */\n private mount(): void {\n if (this.hasMounted) return;\n const previousScope = setCurrentScope(this.ensureScope());\n let hookError = false;\n try {\n definition.beforeMount?.call(this);\n definition.connected?.call(this);\n } catch (error) {\n hookError = true;\n this.handleError(error as Error);\n } finally {\n setCurrentScope(previousScope);\n }\n if (hookError) {\n this.scope?.dispose();\n this.scope = undefined;\n return;\n }\n this.render();\n this.setupSignalSubscriptions();\n this.hasMounted = true;\n }\n\n /**\n * Called when the element is removed from the DOM.\n */\n disconnectedCallback(): void {\n try {\n this.signalEffectCleanup?.();\n this.signalEffectCleanup = undefined;\n // Dispose all scoped reactive resources (useSignal, useComputed, useEffect)\n this.scope?.dispose();\n this.scope = undefined;\n definition.disconnected?.call(this);\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * Called when an observed attribute changes.\n */\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n try {\n const previousProps = this.cloneProps();\n this.syncProps();\n\n // Fire the user-facing onAttributeChanged hook for every observed attribute change\n if (definition.onAttributeChanged) {\n const previousScope = setCurrentScope(this.ensureScope());\n try {\n definition.onAttributeChanged.call(this, name, oldValue, newValue);\n } finally {\n setCurrentScope(previousScope);\n }\n }\n\n if (this.hasMounted) {\n // Component already mounted - trigger update render\n this.render(true, previousProps, { name, oldValue, newValue });\n } else if (this.isConnected && this.missingRequiredProps.size === 0) {\n // All required props are now satisfied and element is connected\n // Trigger the deferred initial mount\n this.mount();\n }\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * Called when the element is moved to a new document (e.g. via `document.adoptNode`).\n */\n adoptedCallback(): void {\n if (!definition.onAdopted) {\n return;\n }\n\n const previousScope = setCurrentScope(this.ensureScope());\n try {\n definition.onAdopted.call(this);\n } catch (error) {\n this.handleError(error as Error);\n } finally {\n setCurrentScope(previousScope);\n }\n }\n\n /**\n * Handles errors during component lifecycle.\n * @internal\n */\n private handleError(error: Error): void {\n if (definition.onError) {\n definition.onError.call(this, error);\n } else {\n console.error(`bQuery component error in <${tagName}>:`, error);\n }\n }\n\n /**\n * Ensures the component has an active scope for scoped reactive primitives.\n * @internal\n */\n private ensureScope(): ComponentScope {\n return (this.scope ??= createComponentScope());\n }\n\n /**\n * Updates a state property and triggers a re-render.\n *\n * @param key - The state property key\n * @param value - The new value\n */\n setState<TKey extends keyof ComponentStateShape<TState>>(\n key: TKey,\n value: ComponentStateShape<TState>[TKey]\n ): void {\n this.state[key] = value;\n this.render(true, this.cloneProps(), undefined, false);\n }\n\n /**\n * Gets a state property value.\n *\n * @param key - The state property key\n * @returns The current value\n */\n getState<TKey extends keyof ComponentStateShape<TState>>(\n key: TKey\n ): ComponentStateShape<TState>[TKey];\n getState<TResult = unknown>(key: string): TResult;\n getState(key: string): unknown {\n return (this.state as Record<string, unknown>)[key];\n }\n\n /**\n * Subscribes to declared reactive sources and re-renders on change.\n *\n * @param renderOnInitialRun - When true, immediately re-renders after\n * re-subscribing so detached components resync with any signal changes\n * that happened while they were disconnected.\n * @internal\n */\n private setupSignalSubscriptions(renderOnInitialRun = false): void {\n if (this.signalEffectCleanup || signalSources.length === 0) return;\n\n let isInitialRun = true;\n this.signalEffectCleanup = effect(() => {\n try {\n for (const source of signalSources) {\n // Intentionally read each source to register this effect as a subscriber.\n void source.value;\n }\n\n if (isInitialRun) {\n isInitialRun = false;\n if (renderOnInitialRun && this.hasMounted && this.isConnected) {\n // Signal-driven reconnect renders do not change props, so the\n // previous-props snapshot is the current prop set at reconnect time.\n const previousProps = this.cloneProps();\n untrack(() => {\n this.render(true, previousProps, undefined, false);\n });\n }\n return;\n }\n\n if (!this.hasMounted || !this.isConnected) return;\n\n // Signal updates leave props unchanged, so cloning the current props\n // provides the previous-props snapshot expected by beforeUpdate().\n const previousProps = this.cloneProps();\n untrack(() => {\n this.render(true, previousProps, undefined, false);\n });\n } catch (error) {\n this.handleError(error as Error);\n }\n });\n }\n\n /**\n * Synchronizes props from attributes.\n * @internal\n */\n private syncProps(): void {\n const props = definition.props ?? {};\n for (const [key, config] of Object.entries(props) as [string, PropDefinition][]) {\n const attrValue = this.getAttribute(key);\n let value: unknown;\n\n if (attrValue == null) {\n if (config.required && config.default === undefined) {\n // Mark as missing instead of throwing - validate during connectedCallback\n this.missingRequiredProps.add(key);\n value = undefined;\n } else {\n value = config.default ?? undefined;\n }\n } else {\n // Attribute is present, remove from missing set if it was there\n if (this.missingRequiredProps.has(key)) {\n this.missingRequiredProps.delete(key);\n }\n value = coercePropValue(attrValue, config);\n }\n\n if (config.validator && value !== undefined) {\n const isValid = config.validator(value);\n if (!isValid) {\n throw new Error(\n `bQuery component: validation failed for prop \"${key}\" with value ${JSON.stringify(value)}`\n );\n }\n }\n\n (this.props as Record<string, unknown>)[key] = value;\n }\n }\n\n /**\n * Creates a shallow snapshot of the current props for lifecycle diffing.\n * A shallow copy is sufficient because component props are re-derived from\n * reflected attributes on each update, so nested object mutation is not\n * tracked as part of this lifecycle diff.\n * @internal\n */\n private cloneProps(): TProps {\n return { ...(this.props as Record<string, unknown>) } as TProps;\n }\n\n /**\n * Renders the component to its shadow root or host element.\n * @internal\n */\n private render(): void;\n private render(triggerUpdated: true, oldProps: TProps, change?: AttributeChange): void;\n private render(\n triggerUpdated: true,\n oldProps: TProps,\n change: AttributeChange | undefined,\n runBeforeUpdate: boolean\n ): void;\n private render(\n triggerUpdated = false,\n oldProps?: TProps,\n change?: AttributeChange,\n runBeforeUpdate = true\n ): void {\n try {\n if (triggerUpdated && runBeforeUpdate && definition.beforeUpdate) {\n if (!oldProps) {\n throw new Error('bQuery component: previous props are required for update renders');\n }\n const shouldUpdate = definition.beforeUpdate.call(this, this.props, oldProps);\n if (shouldUpdate === false) return;\n }\n\n const emit = (event: string, detail?: unknown): void => {\n this.dispatchEvent(new CustomEvent(event, { detail, bubbles: true, composed: true }));\n };\n\n const renderRoot = this.renderRootNode;\n\n const markup = definition.render({\n props: this.props,\n state: this.state,\n signals: (definition.signals ?? {}) as TSignals,\n emit,\n });\n\n // Component render output is authored by the component definition itself,\n // so we can explicitly preserve shadow-DOM-specific markup such as <slot>,\n // the stylistic `part` attribute, and standard form/input attributes without\n // relaxing the global DOM sanitization rules.\n const sanitizedMarkup = sanitizeHtml(markup, {\n allowTags: componentAllowedTags,\n allowAttributes: componentAllowedAttributes,\n });\n let existingStyleElement: HTMLStyleElement | null = null;\n if (definition.styles) {\n existingStyleElement = renderRoot.querySelector<HTMLStyleElement>(\n 'style[data-bquery-component-style]'\n );\n }\n\n renderRoot.innerHTML = sanitizedMarkup;\n\n if (definition.styles) {\n const styleElement = existingStyleElement ?? document.createElement('style');\n if (!existingStyleElement) {\n styleElement.setAttribute('data-bquery-component-style', '');\n }\n styleElement.textContent = definition.styles;\n renderRoot.prepend(styleElement);\n }\n\n if (triggerUpdated) {\n definition.updated?.call(this, change);\n }\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n }\n\n return BQueryComponent as ComponentClass<TState>;\n};\n\n/**\n * Creates a custom element class for a component definition.\n *\n * This is useful when you want to extend or register the class manually\n * (e.g. with different tag names in tests or custom registries).\n *\n * @template TProps - Type of the component's props\n * @template TState - Type of the component's internal state. When provided,\n * `definition.state` is required, `render({ state })` is strongly typed, and\n * returned instances expose typed `getState()` / `setState()` helpers.\n * @param tagName - The custom element tag name (used for diagnostics)\n * @param definition - The component configuration\n */\nexport function defineComponent<\n TProps extends Record<string, unknown>,\n TSignals extends ComponentSignals = Record<string, never>,\n>(\n tagName: string,\n definition: ComponentDefinition<TProps, undefined, TSignals>\n): ComponentClass<undefined>;\nexport function defineComponent<\n TProps extends Record<string, unknown>,\n TState extends Record<string, unknown>,\n TSignals extends ComponentSignals = Record<string, never>,\n>(\n tagName: string,\n definition: ComponentDefinition<TProps, TState, TSignals>\n): ComponentClass<TState>;\nexport function defineComponent<\n TProps extends Record<string, unknown>,\n TState extends Record<string, unknown> | undefined = undefined,\n TSignals extends ComponentSignals = Record<string, never>,\n>(\n tagName: string,\n definition: ComponentDefinition<TProps, TState, TSignals>\n): ComponentClass<TState> {\n return createComponentClass(tagName, definition);\n}\n\n/**\n * Defines and registers a custom Web Component.\n *\n * This function creates a new custom element with the given tag name\n * and configuration. The component uses Shadow DOM for encapsulation\n * and automatically re-renders when observed attributes change.\n *\n * @template TProps - Type of the component's props\n * @template TState - Type of the component's internal state. When provided,\n * `definition.state` is required and lifecycle hooks receive typed state\n * helpers via `this.getState()` / `this.setState()`.\n * @param tagName - The custom element tag name (must contain a hyphen)\n * @param definition - The component configuration\n *\n * @example\n * ```ts\n * component<{ start: number }, { count: number }>('counter-button', {\n * props: {\n * start: { type: Number, default: 0 },\n * },\n * state: { count: 0 },\n * styles: `\n * button { padding: 0.5rem 1rem; }\n * `,\n * connected() {\n * // Use event delegation on shadow root so handler survives re-renders\n * const handleClick = (event: Event) => {\n * const target = event.target as HTMLElement | null;\n * if (target?.matches('button')) {\n * this.setState('count', this.getState('count') + 1);\n * }\n * };\n * this.shadowRoot?.addEventListener('click', handleClick);\n * // Store handler for cleanup\n * (this as any)._handleClick = handleClick;\n * },\n * disconnected() {\n * // Clean up event listener to prevent memory leaks\n * const handleClick = (this as any)._handleClick;\n * if (handleClick) {\n * this.shadowRoot?.removeEventListener('click', handleClick);\n * }\n * },\n * render({ props, state }) {\n * return html`\n * <button>\n * Count: ${state.count}\n * </button>\n * `;\n * },\n * });\n * ```\n */\nexport function component<\n TProps extends Record<string, unknown>,\n TSignals extends ComponentSignals = Record<string, never>,\n>(tagName: string, definition: ComponentDefinition<TProps, undefined, TSignals>): void;\nexport function component<\n TProps extends Record<string, unknown>,\n TState extends Record<string, unknown>,\n TSignals extends ComponentSignals = Record<string, never>,\n>(tagName: string, definition: ComponentDefinition<TProps, TState, TSignals>): void;\nexport function component<\n TProps extends Record<string, unknown>,\n TState extends Record<string, unknown> | undefined = undefined,\n TSignals extends ComponentSignals = Record<string, never>,\n>(tagName: string, definition: ComponentDefinition<TProps, TState, TSignals>): void {\n const elementClass = createComponentClass(tagName, definition);\n\n if (!customElements.get(tagName)) {\n customElements.define(tagName, elementClass);\n }\n}\n","import {\n isTrustedHtml,\n type SanitizedHtml,\n toSanitizedHtml,\n unwrapTrustedHtml,\n} from '../security/trusted-html';\nconst BOOLEAN_ATTRIBUTE_MARKER: unique symbol = Symbol('bquery.booleanAttribute');\nconst BOOLEAN_ATTRIBUTE_NAME = /^[^\\0-\\x20\"'/>=]+$/;\n\n/**\n * Public shape of a boolean HTML attribute created by {@link bool}.\n *\n * This type is returned from {@link bool} and can be interpolated into\n * {@link html} / {@link safeHtml} templates to conditionally include or omit\n * an attribute by name. The internal marker property used for runtime checks\n * remains private and is not part of the public API.\n *\n * @example\n * ```ts\n * const disabled = bool('disabled', isDisabled);\n * const button = html`<button ${disabled}>Click</button>`;\n * ```\n */\nexport interface BooleanAttribute {\n readonly enabled: boolean;\n readonly name: string;\n}\n\ninterface BooleanAttributeValue extends BooleanAttribute {\n readonly [BOOLEAN_ATTRIBUTE_MARKER]: true;\n}\n\nconst isBooleanAttributeValue = (value: unknown): value is BooleanAttributeValue => {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as Partial<BooleanAttributeValue>;\n return (\n candidate[BOOLEAN_ATTRIBUTE_MARKER] === true &&\n typeof candidate.enabled === 'boolean' &&\n typeof candidate.name === 'string'\n );\n};\n\nconst stringifyTemplateValue = (value: unknown): string => {\n if (isBooleanAttributeValue(value)) {\n return value.enabled ? value.name : '';\n }\n\n return String(value ?? '');\n};\n\nconst escapeMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n '`': '&#x60;',\n};\n\nconst escapeTemplateValue = (value: unknown): string => {\n if (isBooleanAttributeValue(value)) {\n return value.enabled ? value.name : '';\n }\n\n return stringifyTemplateValue(value).replace(/[&<>\"'`]/g, (char) => escapeMap[char]);\n};\n\n/**\n * Creates a boolean-attribute marker for the {@link html} and {@link safeHtml} template tags.\n *\n * When the condition is truthy, the attribute name is rendered without a value.\n * When the condition is falsy, an empty string is rendered and any surrounding\n * template-literal whitespace is preserved.\n *\n * @param name - HTML attribute name to emit\n * @param enabled - Whether the boolean attribute should be present\n * @returns Internal marker consumed by template tags\n *\n * @example\n * ```ts\n * html`<button ${bool('disabled', isDisabled)}>Save</button>`;\n * // Result when isDisabled = true: '<button disabled>Save</button>'\n * ```\n */\nexport const bool = (name: string, enabled: unknown): BooleanAttribute => {\n if (!BOOLEAN_ATTRIBUTE_NAME.test(name)) {\n throw new TypeError(`Invalid boolean attribute name: ${name}`);\n }\n\n const attribute: BooleanAttributeValue = {\n [BOOLEAN_ATTRIBUTE_MARKER]: true,\n enabled: Boolean(enabled),\n name,\n };\n\n return Object.freeze(attribute);\n};\n\n/**\n * Tagged template literal for creating HTML strings.\n *\n * This function handles interpolation of values into HTML templates,\n * converting null/undefined to empty strings.\n *\n * @param strings - Template literal string parts\n * @param values - Interpolated values\n * @returns Combined HTML string\n *\n * @example\n * ```ts\n * const name = 'World';\n * const greeting = html`<h1>Hello, ${name}!</h1>`;\n * // Result: '<h1>Hello, World!</h1>'\n * ```\n */\nexport const html = (strings: TemplateStringsArray, ...values: unknown[]): string => {\n return strings.reduce(\n (acc, part, index) => `${acc}${part}${stringifyTemplateValue(values[index])}`,\n ''\n );\n};\n\n/**\n * Escapes HTML entities in interpolated values for XSS prevention.\n * Use this when you need to safely embed user content in templates.\n *\n * @param strings - Template literal string parts\n * @param values - Interpolated values to escape\n * @returns Branded escaped HTML string safe for bQuery template composition\n *\n * @example\n * ```ts\n * const userInput = '<script>alert(\"xss\")</script>';\n * const safe = safeHtml`<div>${userInput}</div>`;\n * // Result: '<div>&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;</div>'\n * ```\n */\nexport const safeHtml = (strings: TemplateStringsArray, ...values: unknown[]): SanitizedHtml => {\n const escape = (value: unknown): string => {\n if (isTrustedHtml(value)) return unwrapTrustedHtml(value);\n return escapeTemplateValue(value);\n };\n\n return toSanitizedHtml(\n strings.reduce(\n (acc, part, index) => `${acc}${part}${index < values.length ? escape(values[index]) : ''}`,\n ''\n )\n );\n};\n","/**\n * Default component library based on native Web Components.\n *\n * @module bquery/component\n */\n\nimport { getBqueryConfig } from '../platform/config';\nimport { escapeHtml } from '../security';\nimport { component } from './component';\nimport { html } from './html';\n\n/** Options for registering the default component library. */\nexport interface DefaultComponentLibraryOptions {\n /** Prefix used for all registered component tags. Defaults to `bq`. */\n prefix?: string;\n}\n\n/** Tag names returned by registerDefaultComponents(). */\nexport interface RegisteredDefaultComponents {\n /** Button component tag name. */\n button: string;\n /** Card component tag name. */\n card: string;\n /** Input component tag name. */\n input: string;\n /** Textarea component tag name. */\n textarea: string;\n /** Checkbox component tag name. */\n checkbox: string;\n}\n\nconst baseStyles = `\n :host {\n color: inherit;\n font: inherit;\n }\n`;\n\nconst controlStyles = `\n ${baseStyles}\n .field {\n display: inline-flex;\n flex-direction: column;\n gap: 0.375rem;\n width: 100%;\n }\n .label {\n color: #334155;\n font-size: 0.875rem;\n font-weight: 600;\n }\n .control {\n border: 1px solid #cbd5e1;\n border-radius: 0.75rem;\n box-sizing: border-box;\n font: inherit;\n min-height: 2.75rem;\n outline: none;\n padding: 0.75rem 0.875rem;\n width: 100%;\n background: #fff;\n color: #0f172a;\n transition: border-color 160ms ease, box-shadow 160ms ease;\n }\n .control:focus {\n border-color: #2563eb;\n box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);\n }\n .control:disabled {\n background: #f8fafc;\n color: #94a3b8;\n cursor: not-allowed;\n }\n`;\n\nconst escapeProp = (value: string): string => escapeHtml(value);\n\nconst handlerStore = new WeakMap<HTMLElement, Record<string, EventListener>>();\n\nconst readHandler = (element: HTMLElement, key: string): EventListener | undefined => {\n return handlerStore.get(element)?.[key];\n};\n\nconst storeHandler = (element: HTMLElement, key: string, value: EventListener): void => {\n const handlers = handlerStore.get(element) ?? {};\n handlers[key] = value;\n handlerStore.set(element, handlers);\n};\n\n/**\n * Detect a value-only input update, patch the live control in place, and\n * return whether the component can skip a full shadow DOM re-render.\n *\n * @param element - The host custom element whose shadow DOM is being updated\n * @param newProps - The next reflected input props for the pending update\n * @param oldProps - The previous reflected input props from the last render\n */\nconst canSkipInputRender = (\n element: HTMLElement,\n newProps: {\n label: string;\n type: string;\n value: string;\n placeholder: string;\n name: string;\n disabled: boolean;\n },\n oldProps: {\n label: string;\n type: string;\n value: string;\n placeholder: string;\n name: string;\n disabled: boolean;\n }\n): boolean => {\n if (oldProps.label !== newProps.label) return false;\n if (oldProps.type !== newProps.type) return false;\n if (oldProps.placeholder !== newProps.placeholder) return false;\n if (oldProps.name !== newProps.name) return false;\n if (oldProps.disabled !== newProps.disabled) return false;\n\n // Verify shadow DOM still matches expected non-value props before skipping re-render\n const shadowRoot = element.shadowRoot;\n if (!shadowRoot) return false;\n\n const labelEl = shadowRoot.querySelector('.label');\n if ((labelEl?.textContent ?? '') !== newProps.label) return false;\n\n const control = shadowRoot.querySelector('input.control') as HTMLInputElement | null;\n if (!control) return false;\n\n if (control.type !== newProps.type) return false;\n if (control.placeholder !== newProps.placeholder) return false;\n if (control.name !== newProps.name) return false;\n if (control.disabled !== newProps.disabled) return false;\n\n if (control.value !== newProps.value) {\n control.value = newProps.value;\n }\n\n return true;\n};\n\n/**\n * Detect a value-only textarea update, patch the live control in place, and\n * return whether the component can skip a full shadow DOM re-render.\n *\n * @param element - The host custom element whose shadow DOM is being updated\n * @param newProps - The next reflected textarea props for the pending update\n * @param oldProps - The previous reflected textarea props from the last render\n */\nconst canSkipTextareaRender = (\n element: HTMLElement,\n newProps: {\n label: string;\n value: string;\n placeholder: string;\n name: string;\n rows: number;\n disabled: boolean;\n },\n oldProps: {\n label: string;\n value: string;\n placeholder: string;\n name: string;\n rows: number;\n disabled: boolean;\n }\n): boolean => {\n if (oldProps.label !== newProps.label) return false;\n if (oldProps.placeholder !== newProps.placeholder) return false;\n if (oldProps.name !== newProps.name) return false;\n if (oldProps.rows !== newProps.rows) return false;\n if (oldProps.disabled !== newProps.disabled) return false;\n\n // Verify shadow DOM still matches expected non-value props before skipping re-render\n const shadowRoot = element.shadowRoot;\n if (!shadowRoot) return false;\n\n const labelEl = shadowRoot.querySelector('.label');\n if ((labelEl?.textContent ?? '') !== newProps.label) return false;\n\n const control = shadowRoot.querySelector('textarea.control') as HTMLTextAreaElement | null;\n if (!control) return false;\n\n if (control.placeholder !== newProps.placeholder) return false;\n if (control.name !== newProps.name) return false;\n if (Number(control.rows) !== newProps.rows) return false;\n if (control.disabled !== newProps.disabled) return false;\n\n if (control.value !== newProps.value) {\n control.value = newProps.value;\n }\n return true;\n};\n\nconst renderTextareaControl = (props: {\n value: string;\n placeholder: string;\n name: string;\n rows: number;\n disabled: boolean;\n}): string => {\n return [\n '<textarea',\n ' part=\"control\"',\n ' class=\"control\"',\n ` placeholder=\"${escapeProp(props.placeholder)}\"`,\n ` name=\"${escapeProp(props.name)}\"`,\n ` rows=\"${props.rows}\"`,\n props.disabled ? ' disabled' : '',\n `>${escapeProp(props.value)}</textarea>`,\n ].join('');\n};\n\n/**\n * Register a default set of foundational UI components.\n *\n * The library is intentionally small and dependency-free, providing common\n * primitives that can be themed via shadow parts and CSS custom properties.\n *\n * @param options - Optional registration settings such as a custom tag prefix\n * @returns The registered tag names for each component\n */\nexport const registerDefaultComponents = (\n options: DefaultComponentLibraryOptions = {}\n): RegisteredDefaultComponents => {\n const prefix = options.prefix ?? getBqueryConfig().components?.prefix ?? 'bq';\n const tags: RegisteredDefaultComponents = {\n button: `${prefix}-button`,\n card: `${prefix}-card`,\n input: `${prefix}-input`,\n textarea: `${prefix}-textarea`,\n checkbox: `${prefix}-checkbox`,\n };\n\n component<{\n label: string;\n variant: string;\n size: string;\n type: string;\n disabled: boolean;\n }>(tags.button, {\n props: {\n label: { type: String, default: '' },\n variant: { type: String, default: 'primary' },\n size: { type: String, default: 'md' },\n type: { type: String, default: 'button' },\n disabled: { type: Boolean, default: false },\n },\n styles: `\n ${baseStyles}\n button {\n appearance: none;\n border: 0;\n border-radius: 999px;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font: inherit;\n font-weight: 600;\n gap: 0.5rem;\n min-height: 2.5rem;\n padding: 0.65rem 1rem;\n transition: transform 160ms ease, opacity 160ms ease, background 160ms ease;\n background: #2563eb;\n color: #fff;\n }\n button[data-variant='secondary'] {\n background: #e2e8f0;\n color: #0f172a;\n }\n button[data-size='sm'] {\n min-height: 2.125rem;\n padding: 0.5rem 0.875rem;\n }\n button[data-size='lg'] {\n min-height: 3rem;\n padding: 0.875rem 1.25rem;\n }\n button:hover:not(:disabled) {\n transform: translateY(-1px);\n }\n button:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n `,\n render: ({ props }) => html`\n <button\n part=\"button\"\n type=\"${escapeProp(props.type)}\"\n data-variant=\"${escapeProp(props.variant)}\"\n data-size=\"${escapeProp(props.size)}\"\n ${props.disabled ? 'disabled' : ''}\n >\n <slot>${escapeProp(props.label)}</slot>\n </button>\n `,\n });\n\n component<{ title: string; footer: string; elevated: boolean }>(tags.card, {\n props: {\n title: { type: String, default: '' },\n footer: { type: String, default: '' },\n elevated: { type: Boolean, default: true },\n },\n styles: `\n ${baseStyles}\n article {\n background: #fff;\n border: 1px solid #e2e8f0;\n border-radius: 1rem;\n box-shadow: 0 10px 25px rgba(15, 23, 42, 0.08);\n color: #0f172a;\n display: block;\n padding: 1rem;\n }\n article[data-elevated='false'] {\n box-shadow: none;\n }\n header, footer {\n color: #475569;\n font-size: 0.95rem;\n font-weight: 600;\n }\n header {\n margin-bottom: 0.75rem;\n }\n footer {\n margin-top: 0.75rem;\n }\n `,\n render: ({ props }) => html`\n <article part=\"card\" data-elevated=\"${String(props.elevated)}\">\n ${props.title ? `<header part=\"header\">${escapeProp(props.title)}</header>` : ''}\n <section part=\"body\"><slot></slot></section>\n ${props.footer ? `<footer part=\"footer\">${escapeProp(props.footer)}</footer>` : ''}\n </article>\n `,\n });\n\n component<{\n label: string;\n type: string;\n value: string;\n placeholder: string;\n name: string;\n disabled: boolean;\n }>(tags.input, {\n props: {\n label: { type: String, default: '' },\n type: { type: String, default: 'text' },\n value: { type: String, default: '' },\n placeholder: { type: String, default: '' },\n name: { type: String, default: '' },\n disabled: { type: Boolean, default: false },\n },\n styles: controlStyles,\n /**\n * Skip the full shadow DOM re-render when only the reflected input value\n * changed, because the live control has already been patched in place.\n */\n beforeUpdate(newProps, oldProps) {\n if (canSkipInputRender(this, newProps, oldProps)) {\n return false;\n }\n return true;\n },\n connected() {\n const handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement | null;\n if (!target?.matches('input')) return;\n event.stopPropagation();\n this.setAttribute('value', target.value);\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: { value: target.value },\n bubbles: true,\n composed: true,\n })\n );\n };\n storeHandler(this, '__bqueryInputHandler', handleInput);\n this.shadowRoot?.addEventListener('input', handleInput);\n },\n disconnected() {\n const handleInput = readHandler(this, '__bqueryInputHandler');\n if (handleInput) {\n this.shadowRoot?.removeEventListener('input', handleInput);\n }\n },\n render: ({ props }) => html`\n <label part=\"field\" class=\"field\">\n ${props.label ? `<span part=\"label\" class=\"label\">${escapeProp(props.label)}</span>` : ''}\n <input\n part=\"control\"\n class=\"control\"\n type=\"${escapeProp(props.type)}\"\n value=\"${escapeProp(props.value)}\"\n placeholder=\"${escapeProp(props.placeholder)}\"\n name=\"${escapeProp(props.name)}\"\n ${props.disabled ? 'disabled' : ''}\n />\n </label>\n `,\n });\n\n component<{\n label: string;\n value: string;\n placeholder: string;\n name: string;\n rows: number;\n disabled: boolean;\n }>(tags.textarea, {\n props: {\n label: { type: String, default: '' },\n value: { type: String, default: '' },\n placeholder: { type: String, default: '' },\n name: { type: String, default: '' },\n rows: { type: Number, default: 4 },\n disabled: { type: Boolean, default: false },\n },\n styles: `${controlStyles}\n textarea.control {\n min-height: 6rem;\n resize: vertical;\n }\n `,\n /**\n * Skip the full shadow DOM re-render when only the reflected textarea value\n * changed, because the live control has already been patched in place.\n */\n beforeUpdate(newProps, oldProps) {\n if (canSkipTextareaRender(this, newProps, oldProps)) {\n return false;\n }\n return true;\n },\n connected() {\n const handleInput = (event: Event) => {\n const target = event.target as HTMLTextAreaElement | null;\n if (!target?.matches('textarea')) return;\n event.stopPropagation();\n this.setAttribute('value', target.value);\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: { value: target.value },\n bubbles: true,\n composed: true,\n })\n );\n };\n storeHandler(this, '__bqueryTextareaHandler', handleInput);\n this.shadowRoot?.addEventListener('input', handleInput);\n },\n disconnected() {\n const handleInput = readHandler(this, '__bqueryTextareaHandler');\n if (handleInput) {\n this.shadowRoot?.removeEventListener('input', handleInput);\n }\n },\n render: ({ props }) => html`\n <label part=\"field\" class=\"field\">\n ${props.label ? `<span part=\"label\" class=\"label\">${escapeProp(props.label)}</span>` : ''}\n ${renderTextareaControl(props)}\n </label>\n `,\n });\n\n component<{ label: string; checked: boolean; disabled: boolean }>(tags.checkbox, {\n props: {\n label: { type: String, default: '' },\n checked: { type: Boolean, default: false },\n disabled: { type: Boolean, default: false },\n },\n styles: `\n ${baseStyles}\n label {\n align-items: center;\n color: #0f172a;\n cursor: pointer;\n display: inline-flex;\n gap: 0.625rem;\n }\n input {\n accent-color: #2563eb;\n block-size: 1rem;\n inline-size: 1rem;\n }\n input:disabled {\n cursor: not-allowed;\n }\n `,\n connected() {\n const handleChange = (event: Event) => {\n const target = event.target as HTMLInputElement | null;\n if (!target?.matches('input[type=\"checkbox\"]')) return;\n event.stopPropagation();\n if (target.checked) {\n this.setAttribute('checked', 'true');\n } else {\n this.removeAttribute('checked');\n }\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: { checked: target.checked },\n bubbles: true,\n composed: true,\n })\n );\n };\n storeHandler(this, '__bqueryCheckboxHandler', handleChange);\n this.shadowRoot?.addEventListener('change', handleChange);\n },\n disconnected() {\n const handleChange = readHandler(this, '__bqueryCheckboxHandler');\n if (handleChange) {\n this.shadowRoot?.removeEventListener('change', handleChange);\n }\n },\n render: ({ props }) => html`\n <label part=\"label\">\n <input\n part=\"control\"\n type=\"checkbox\"\n ${props.checked ? 'checked' : ''}\n ${props.disabled ? 'disabled' : ''}\n />\n <span part=\"text\"><slot>${escapeProp(props.label)}</slot></span>\n </label>\n `,\n });\n\n return tags;\n};\n","/**\n * Reduced motion detection and global toggle helpers.\n *\n * @module bquery/motion\n */\n\n/**\n * Global override for reduced motion preference.\n * When `null`, the system preference is used.\n * When `true`, reduced motion is forced on.\n * When `false`, reduced motion is forced off.\n *\n * @internal\n */\nlet reducedMotionOverride: boolean | null = null;\n\n/**\n * Check whether reduced motion should be applied.\n *\n * Returns the global override if set via {@link setReducedMotion},\n * otherwise checks the user's system preference.\n *\n * @returns `true` if reduced motion should be applied\n *\n * @example\n * ```ts\n * if (prefersReducedMotion()) {\n * // skip animation\n * }\n * ```\n */\nexport const prefersReducedMotion = (): boolean => {\n if (reducedMotionOverride !== null) {\n return reducedMotionOverride;\n }\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return false;\n }\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n};\n\n/**\n * Programmatically override the reduced motion preference globally.\n *\n * When set to `true`, all motion functions that respect reduced motion\n * will skip animations. When set to `false`, animations run regardless\n * of system settings. Pass `null` to restore system-preference detection.\n *\n * @param override - `true` to force reduced motion, `false` to force\n * full motion, or `null` to use system preference\n *\n * @example\n * ```ts\n * // Force all animations to be instant\n * setReducedMotion(true);\n *\n * // Re-enable animations regardless of system\n * setReducedMotion(false);\n *\n * // Restore system preference\n * setReducedMotion(null);\n * ```\n */\nexport const setReducedMotion = (override: boolean | null): void => {\n reducedMotionOverride = override;\n};\n","/**\n * Web Animations helpers.\n *\n * @module bquery/motion\n */\n\nimport { prefersReducedMotion } from './reduced-motion';\nimport type { AnimateOptions } from './types';\n\n/** @internal */\nconst isStyleValue = (value: unknown): value is string | number =>\n typeof value === 'string' || typeof value === 'number';\n\n/**\n * Convert camelCase property names to kebab-case for CSS.\n * @internal\n */\nconst toKebabCase = (str: string): string => {\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n};\n\n/** @internal */\nexport const applyFinalKeyframeStyles = (\n element: Element,\n keyframes: Keyframe[] | PropertyIndexedKeyframes\n): void => {\n const htmlElement = element as HTMLElement;\n const style = htmlElement.style;\n\n if (Array.isArray(keyframes)) {\n const last = keyframes[keyframes.length - 1];\n if (!last) return;\n for (const [prop, value] of Object.entries(last)) {\n if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;\n if (isStyleValue(value)) {\n // Convert camelCase to kebab-case for CSS properties\n const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);\n style.setProperty(cssProp, String(value));\n }\n }\n return;\n }\n\n for (const [prop, value] of Object.entries(keyframes)) {\n if (prop === 'offset' || prop === 'easing' || prop === 'composite') continue;\n const finalValue = Array.isArray(value) ? value[value.length - 1] : value;\n if (isStyleValue(finalValue)) {\n // Convert camelCase to kebab-case for CSS properties\n const cssProp = prop.startsWith('--') ? prop : toKebabCase(prop);\n style.setProperty(cssProp, String(finalValue));\n }\n }\n};\n\n/**\n * Animate an element using the Web Animations API with reduced-motion fallback.\n *\n * @param element - Element to animate\n * @param config - Animation configuration\n * @returns Promise that resolves when animation completes\n *\n * @example\n * ```ts\n * await animate(element, {\n * keyframes: [{ opacity: 0 }, { opacity: 1 }],\n * options: { duration: 200, easing: 'ease-out' },\n * });\n * ```\n */\nexport const animate = (element: Element, config: AnimateOptions): Promise<void> => {\n const { keyframes, options, commitStyles = true, respectReducedMotion = true, onFinish } = config;\n\n if (respectReducedMotion && prefersReducedMotion()) {\n if (commitStyles) {\n applyFinalKeyframeStyles(element, keyframes);\n }\n onFinish?.();\n return Promise.resolve();\n }\n\n const htmlElement = element as HTMLElement;\n if (typeof htmlElement.animate !== 'function') {\n if (commitStyles) {\n applyFinalKeyframeStyles(element, keyframes);\n }\n onFinish?.();\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n const animation = htmlElement.animate(keyframes, options);\n let finalized = false;\n const finalize = () => {\n if (finalized) return;\n finalized = true;\n if (commitStyles) {\n if (typeof animation.commitStyles === 'function') {\n animation.commitStyles();\n } else {\n applyFinalKeyframeStyles(element, keyframes);\n }\n }\n animation.cancel();\n onFinish?.();\n resolve();\n };\n\n animation.onfinish = finalize;\n if (animation.finished) {\n animation.finished.then(finalize).catch(finalize);\n }\n });\n};\n","/**\n * Easing helpers.\n *\n * @module bquery/motion\n */\n\nimport type { EasingFunction } from './types';\n\nconst clamp = (value: number) => Math.min(1, Math.max(0, value));\n\nexport const linear: EasingFunction = (t) => clamp(t);\nexport const easeInQuad: EasingFunction = (t) => clamp(t * t);\nexport const easeOutQuad: EasingFunction = (t) => clamp(1 - (1 - t) * (1 - t));\nexport const easeInOutQuad: EasingFunction = (t) =>\n clamp(t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2);\nexport const easeInCubic: EasingFunction = (t) => clamp(t * t * t);\nexport const easeOutCubic: EasingFunction = (t) => clamp(1 - Math.pow(1 - t, 3));\nexport const easeInOutCubic: EasingFunction = (t) =>\n clamp(t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2);\nexport const easeOutBack: EasingFunction = (t) => {\n const c1 = 1.70158;\n const c3 = c1 + 1;\n return clamp(1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2));\n};\nexport const easeOutExpo: EasingFunction = (t) => clamp(t === 1 ? 1 : 1 - Math.pow(2, -10 * t));\n\n/**\n * Named easing presets.\n */\nexport const easingPresets = {\n linear,\n easeInQuad,\n easeOutQuad,\n easeInOutQuad,\n easeInCubic,\n easeOutCubic,\n easeInOutCubic,\n easeOutBack,\n easeOutExpo,\n};\n","/**\n * FLIP animation helpers.\n *\n * @module bquery/motion\n */\n\nimport type { ElementBounds, FlipGroupOptions, FlipOptions } from './types';\n\n/**\n * Capture the current bounds of an element for FLIP animation.\n *\n * @param element - The DOM element to measure\n * @returns The element's current position and size\n */\nexport const capturePosition = (element: Element): ElementBounds => {\n const rect = element.getBoundingClientRect();\n return {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Perform a FLIP (First, Last, Invert, Play) animation.\n * Animates an element from its captured position to its current position.\n *\n * @param element - The element to animate\n * @param firstBounds - The previously captured bounds\n * @param options - Animation configuration\n * @returns Promise that resolves when animation completes\n *\n * @example\n * ```ts\n * const first = capturePosition(element);\n * // ... DOM changes that move the element ...\n * await flip(element, first, { duration: 300 });\n * ```\n */\nexport const flip = (\n element: Element,\n firstBounds: ElementBounds,\n options: FlipOptions = {}\n): Promise<void> => {\n const { duration = 300, easing = 'ease-out', onComplete } = options;\n\n // Last: Get current position\n const lastBounds = capturePosition(element);\n\n // Skip animation if element has zero dimensions (avoid division by zero)\n if (lastBounds.width === 0 || lastBounds.height === 0) {\n onComplete?.();\n return Promise.resolve();\n }\n\n // Invert: Calculate the delta\n const deltaX = firstBounds.left - lastBounds.left;\n const deltaY = firstBounds.top - lastBounds.top;\n const deltaW = firstBounds.width / lastBounds.width;\n const deltaH = firstBounds.height / lastBounds.height;\n\n // Skip animation if no change\n if (deltaX === 0 && deltaY === 0 && deltaW === 1 && deltaH === 1) {\n onComplete?.();\n return Promise.resolve();\n }\n\n const htmlElement = element as HTMLElement;\n\n // Feature check: fallback if Web Animations API is unavailable\n if (typeof htmlElement.animate !== 'function') {\n onComplete?.();\n return Promise.resolve();\n }\n\n // Apply inverted transform\n htmlElement.style.transform = `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`;\n htmlElement.style.transformOrigin = 'top left';\n\n // Force reflow\n void htmlElement.offsetHeight;\n\n // Play: Animate back to current position\n return new Promise((resolve) => {\n const animation = htmlElement.animate(\n [\n {\n transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`,\n },\n { transform: 'translate(0, 0) scale(1, 1)' },\n ],\n { duration, easing, fill: 'forwards' }\n );\n\n let finalized = false;\n const finalize = () => {\n if (finalized) return;\n finalized = true;\n htmlElement.style.transform = '';\n htmlElement.style.transformOrigin = '';\n onComplete?.();\n resolve();\n };\n\n animation.onfinish = finalize;\n // Handle cancel/rejection via the finished promise\n if (animation.finished) {\n animation.finished.then(finalize).catch(finalize);\n }\n });\n};\n\n/**\n * FLIP helper for animating a list of elements.\n * Useful for reordering lists with smooth animations.\n *\n * @param elements - Array of elements to animate\n * @param performUpdate - Function that performs the DOM update\n * @param options - Animation configuration\n *\n * @example\n * ```ts\n * await flipList(listItems, () => {\n * container.appendChild(container.firstChild); // Move first to last\n * });\n * ```\n */\nexport const flipList = async (\n elements: Element[],\n performUpdate: () => void,\n options: FlipOptions = {}\n): Promise<void> => {\n await flipElements(elements, performUpdate, options);\n};\n\n/**\n * FLIP helper with optional stagger support.\n *\n * @param elements - Array of elements to animate\n * @param performUpdate - Function that performs the DOM update\n * @param options - Animation configuration\n */\nexport const flipElements = async (\n elements: Element[],\n performUpdate: () => void,\n options: FlipGroupOptions = {}\n): Promise<void> => {\n const { stagger, ...flipOptions } = options;\n\n // First: Capture all positions\n const positions = new Map<Element, ElementBounds>();\n for (const el of elements) {\n positions.set(el, capturePosition(el));\n }\n\n // Perform DOM update\n performUpdate();\n\n const total = elements.length;\n\n // Animate each element\n const animations = elements.map((el, index) => {\n const first = positions.get(el);\n if (!first) return Promise.resolve();\n const delay = stagger ? stagger(index, total) : 0;\n if (delay > 0) {\n return new Promise((resolve) => setTimeout(resolve, delay)).then(() =>\n flip(el, first, flipOptions)\n );\n }\n return flip(el, first, flipOptions);\n });\n\n await Promise.all(animations);\n};\n","/**\n * Keyframe presets.\n *\n * @module bquery/motion\n */\n\n/**\n * Common keyframe presets for quick animations.\n */\nexport const keyframePresets = {\n fadeIn: (from = 0, to = 1): Keyframe[] => [{ opacity: from }, { opacity: to }],\n fadeOut: (from = 1, to = 0): Keyframe[] => [{ opacity: from }, { opacity: to }],\n slideInUp: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateY(${distance}px)` },\n { opacity: 1, transform: 'translateY(0)' },\n ],\n slideInDown: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateY(-${distance}px)` },\n { opacity: 1, transform: 'translateY(0)' },\n ],\n slideInLeft: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateX(${distance}px)` },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n slideInRight: (distance = 16): Keyframe[] => [\n { opacity: 0, transform: `translateX(-${distance}px)` },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n scaleIn: (from = 0.95, to = 1): Keyframe[] => [\n { opacity: 0, transform: `scale(${from})` },\n { opacity: 1, transform: `scale(${to})` },\n ],\n scaleOut: (from = 1, to = 0.95): Keyframe[] => [\n { opacity: 1, transform: `scale(${from})` },\n { opacity: 0, transform: `scale(${to})` },\n ],\n pop: (from = 0.9, mid = 1.02, to = 1): Keyframe[] => [\n { opacity: 0, transform: `scale(${from})` },\n { opacity: 1, transform: `scale(${mid})`, offset: 0.6 },\n { opacity: 1, transform: `scale(${to})` },\n ],\n rotateIn: (degrees = 6): Keyframe[] => [\n { opacity: 0, transform: `rotate(${degrees}deg) scale(0.98)` },\n { opacity: 1, transform: 'rotate(0deg) scale(1)' },\n ],\n};\n","/**\n * FLIP-based morph animation between two element states.\n *\n * @module bquery/motion\n */\n\nimport { prefersReducedMotion } from './reduced-motion';\nimport type { MorphOptions } from './types';\n\n/**\n * Perform a FLIP-based morph animation between two elements.\n *\n * Captures the bounding rect of the `from` element, hides it, shows the\n * `to` element, then animates the `to` element from the `from` position\n * using CSS transforms and opacity.\n *\n * @param from - The source element (will be hidden at the end)\n * @param to - The destination element (will be shown and animated into place)\n * @param options - Morph animation options\n * @returns Promise that resolves when the morph completes\n *\n * @example\n * ```ts\n * const card = document.querySelector('.card');\n * const detail = document.querySelector('.detail');\n * await morphElement(card, detail, { duration: 400, easing: 'ease-out' });\n * ```\n */\nexport const morphElement = (\n from: Element,\n to: Element,\n options: MorphOptions = {}\n): Promise<void> => {\n const { duration = 300, easing = 'ease', respectReducedMotion = true, onComplete } = options;\n\n const fromEl = from as HTMLElement;\n const toEl = to as HTMLElement;\n\n if (\n typeof window === 'undefined' ||\n typeof document === 'undefined' ||\n typeof fromEl.getBoundingClientRect !== 'function' ||\n typeof toEl.getBoundingClientRect !== 'function' ||\n typeof fromEl.style === 'undefined' ||\n typeof toEl.style === 'undefined'\n ) {\n onComplete?.();\n return Promise.resolve();\n }\n\n // Capture FIRST position of source element\n const firstRect = from.getBoundingClientRect();\n\n // Ensure destination is visible so we can measure it\n const previousDisplay = toEl.style.display;\n const previousVisibility = toEl.style.visibility;\n const previousTransform = toEl.style.transform;\n const previousOpacity = toEl.style.opacity;\n const computedDisplay =\n typeof getComputedStyle === 'function'\n ? getComputedStyle(toEl).display\n : previousDisplay || 'block';\n // Prefer an explicit inline display, otherwise fall back to the current computed\n // display, and finally to `block` so hidden destinations remain measurable.\n const forcedDisplay =\n computedDisplay === 'none' ? 'block' : previousDisplay || computedDisplay || 'block';\n const restoreAnimatedInlineStyles = () => {\n toEl.style.transform = previousTransform;\n toEl.style.opacity = previousOpacity;\n };\n\n toEl.style.visibility = 'hidden';\n toEl.style.display = forcedDisplay;\n\n // Capture LAST position of destination element\n const lastRect = to.getBoundingClientRect();\n\n // Restore visibility (it will be animated in)\n toEl.style.visibility = previousVisibility;\n\n // Hide source, show destination\n fromEl.style.display = 'none';\n if (computedDisplay === 'none') {\n toEl.style.display = forcedDisplay;\n } else if (previousDisplay === 'none') {\n toEl.style.display = '';\n } else {\n toEl.style.display = previousDisplay;\n }\n\n // If reduced motion is preferred, skip the animation\n if (respectReducedMotion && prefersReducedMotion()) {\n restoreAnimatedInlineStyles();\n onComplete?.();\n return Promise.resolve();\n }\n\n // Calculate the transform inversion (FLIP: Invert)\n const dx = firstRect.left - lastRect.left;\n const dy = firstRect.top - lastRect.top;\n const sx = firstRect.width / (lastRect.width || 1);\n const sy = firstRect.height / (lastRect.height || 1);\n\n // If no visual change, skip animation\n if (dx === 0 && dy === 0 && sx === 1 && sy === 1) {\n restoreAnimatedInlineStyles();\n onComplete?.();\n return Promise.resolve();\n }\n\n const keyframes: Keyframe[] = [\n {\n transform: `translate(${dx}px, ${dy}px) scale(${sx}, ${sy})`,\n opacity: '0.5',\n },\n {\n transform: 'translate(0, 0) scale(1, 1)',\n opacity: '1',\n },\n ];\n\n // Check if animate API is available\n if (typeof toEl.animate !== 'function') {\n restoreAnimatedInlineStyles();\n onComplete?.();\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve) => {\n const animation = toEl.animate(keyframes, {\n duration,\n easing,\n fill: 'forwards',\n });\n\n let finalized = false;\n const finalize = () => {\n if (finalized) return;\n finalized = true;\n restoreAnimatedInlineStyles();\n animation.cancel();\n onComplete?.();\n resolve();\n };\n\n animation.onfinish = finalize;\n if (animation.finished) {\n animation.finished.then(finalize).catch(finalize);\n }\n });\n};\n","/**\n * Scroll-linked parallax effect.\n *\n * @module bquery/motion\n */\n\nimport { prefersReducedMotion } from './reduced-motion';\nimport type { ParallaxCleanup, ParallaxOptions } from './types';\n\n/**\n * Apply a scroll-linked parallax effect to an element.\n *\n * The element's position is translated based on the scroll position\n * multiplied by the speed factor. A speed of `0.5` means the element\n * moves at half the scroll speed (classic background parallax).\n *\n * @param element - The element to apply the parallax effect to\n * @param options - Parallax configuration\n * @returns A cleanup function that removes the scroll listener\n *\n * @example\n * ```ts\n * const cleanup = parallax(document.querySelector('.hero-bg')!, {\n * speed: 0.3,\n * direction: 'vertical',\n * });\n *\n * // Later, remove the effect:\n * cleanup();\n * ```\n */\nexport const parallax = (element: Element, options: ParallaxOptions = {}): ParallaxCleanup => {\n if (\n typeof window === 'undefined' ||\n typeof window.addEventListener !== 'function' ||\n typeof window.removeEventListener !== 'function' ||\n typeof requestAnimationFrame !== 'function' ||\n typeof cancelAnimationFrame !== 'function'\n ) {\n return () => {};\n }\n\n const { speed = 0.5, direction = 'vertical', respectReducedMotion = true } = options;\n\n const el = element as HTMLElement;\n const previousTransform = el.style.transform;\n\n // If reduced motion is preferred, don't apply parallax\n if (respectReducedMotion && prefersReducedMotion()) {\n return () => {};\n }\n\n let ticking = false;\n let destroyed = false;\n let frameId: number | null = null;\n\n const cleanup = (): void => {\n if (destroyed) return;\n destroyed = true;\n window.removeEventListener('scroll', onScroll);\n if (frameId !== null) {\n cancelAnimationFrame(frameId);\n frameId = null;\n }\n ticking = false;\n el.style.transform = previousTransform;\n };\n\n const updatePosition = () => {\n if (destroyed) return;\n\n // Re-check reduced motion on each frame (in case toggle changed)\n if (respectReducedMotion && prefersReducedMotion()) {\n cleanup();\n return;\n }\n\n const scrollY = window.scrollY;\n const scrollX = window.scrollX;\n\n let tx = 0;\n let ty = 0;\n\n if (direction === 'vertical' || direction === 'both') {\n ty = scrollY * speed;\n }\n if (direction === 'horizontal' || direction === 'both') {\n tx = scrollX * speed;\n }\n\n const parallaxTransform = `translate3d(${tx}px, ${ty}px, 0)`;\n el.style.transform = previousTransform\n ? `${previousTransform} ${parallaxTransform}`\n : parallaxTransform;\n };\n\n const onScroll = () => {\n if (destroyed) return;\n if (respectReducedMotion && prefersReducedMotion()) {\n cleanup();\n return;\n }\n if (!ticking) {\n ticking = true;\n frameId = requestAnimationFrame(() => {\n frameId = null;\n updatePosition();\n ticking = false;\n });\n }\n };\n\n // Apply initial position\n updatePosition();\n\n // Listen to scroll events\n window.addEventListener('scroll', onScroll, { passive: true });\n\n return cleanup;\n};\n","/**\n * Scroll-triggered animation helpers.\n *\n * @module bquery/motion\n */\n\nimport { animate } from './animate';\nimport type { ScrollAnimateCleanup, ScrollAnimateOptions } from './types';\n\nconst resolveElements = (elements: Element | Iterable<Element> | ArrayLike<Element>): Element[] => {\n if (typeof Element !== 'undefined' && elements instanceof Element) return [elements];\n return Array.from(elements as Iterable<Element>);\n};\n\n/**\n * Animate elements when they enter the viewport.\n *\n * @param elements - Target element(s)\n * @param options - Scroll animation configuration\n * @returns Cleanup function to disconnect observers\n */\nexport const scrollAnimate = (\n elements: Element | Iterable<Element> | ArrayLike<Element>,\n options: ScrollAnimateOptions\n): ScrollAnimateCleanup => {\n const targets = resolveElements(elements);\n if (!targets.length) return () => undefined;\n\n const { root = null, rootMargin, threshold, once = true, onEnter, ...animationConfig } = options;\n\n if (typeof IntersectionObserver === 'undefined') {\n targets.forEach((element) => {\n onEnter?.(element);\n void animate(element, animationConfig);\n });\n return () => undefined;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (!entry.isIntersecting) return;\n const element = entry.target as Element;\n onEnter?.(element);\n void animate(element, animationConfig);\n if (once) {\n observer.unobserve(element);\n }\n });\n },\n { root, rootMargin, threshold }\n );\n\n targets.forEach((element) => observer.observe(element));\n\n return () => observer.disconnect();\n};\n","/**\n * Spring physics helpers.\n *\n * @module bquery/motion\n */\n\nimport type { Spring, SpringConfig } from './types';\n\n/**\n * Default spring configuration values.\n */\nconst DEFAULT_SPRING_CONFIG: Required<SpringConfig> = {\n stiffness: 100,\n damping: 10,\n mass: 1,\n precision: 0.01,\n};\n\n/**\n * Create a spring-based animation for smooth, physics-based motion.\n *\n * Uses variable frame rate timing based on `requestAnimationFrame` timestamps\n * to ensure consistent animation speed across different devices and frame rates.\n * Large time deltas (e.g., from tab backgrounding) are clamped to maintain\n * simulation stability.\n *\n * @param initialValue - Starting value for the spring\n * @param config - Spring physics configuration\n * @returns Spring instance for controlling the animation\n *\n * @example\n * ```ts\n * const x = spring(0, { stiffness: 120, damping: 14 });\n * x.onChange((value) => {\n * element.style.transform = `translateX(${value}px)`;\n * });\n * await x.to(100);\n * ```\n */\nexport const spring = (initialValue: number, config: SpringConfig = {}): Spring => {\n const { stiffness, damping, mass, precision } = {\n ...DEFAULT_SPRING_CONFIG,\n ...config,\n };\n\n let current = initialValue;\n let velocity = 0;\n let target = initialValue;\n let animationFrame: number | null = null;\n let resolvePromise: (() => void) | null = null;\n let lastTime: number | null = null;\n const listeners = new Set<(value: number) => void>();\n\n const notifyListeners = () => {\n for (const listener of listeners) {\n listener(current);\n }\n };\n\n const step = (timestamp: number) => {\n // Calculate time delta (in seconds) from last frame\n // If this is the first frame, use a sensible default (1/60s)\n // This ensures the animation speed is independent of frame rate\n const deltaTime = lastTime !== null ? (timestamp - lastTime) / 1000 : 1 / 60;\n // Clamp large deltas to prevent instability (e.g. tab backgrounding)\n // Maximum delta of 1/30s (~33ms) keeps simulation stable\n const clampedDelta = Math.min(deltaTime, 1 / 30);\n lastTime = timestamp;\n\n // Spring physics calculation\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n velocity += acceleration * clampedDelta;\n current += velocity * clampedDelta;\n\n notifyListeners();\n\n // Check if spring has settled\n if (Math.abs(velocity) < precision && Math.abs(displacement) < precision) {\n current = target;\n velocity = 0;\n animationFrame = null;\n notifyListeners();\n resolvePromise?.();\n resolvePromise = null;\n return;\n }\n\n animationFrame = requestAnimationFrame(step);\n };\n\n return {\n to(newTarget: number): Promise<void> {\n target = newTarget;\n\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n }\n\n // Resolve any pending promise from a previous to() call\n // This ensures all returned promises eventually settle\n resolvePromise?.();\n\n // Reset lastTime to ensure clean start for new animation\n lastTime = null;\n\n return new Promise((resolve) => {\n resolvePromise = resolve;\n animationFrame = requestAnimationFrame(step);\n });\n },\n\n current(): number {\n return current;\n },\n\n stop(): void {\n if (animationFrame !== null) {\n cancelAnimationFrame(animationFrame);\n animationFrame = null;\n }\n velocity = 0;\n lastTime = null;\n resolvePromise?.();\n resolvePromise = null;\n },\n\n onChange(callback: (value: number) => void): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n};\n\n/**\n * Preset spring configurations for common use cases.\n */\nexport const springPresets = {\n /** Gentle, slow-settling spring */\n gentle: { stiffness: 80, damping: 15 } as SpringConfig,\n /** Responsive, snappy spring */\n snappy: { stiffness: 200, damping: 20 } as SpringConfig,\n /** Bouncy, playful spring */\n bouncy: { stiffness: 300, damping: 8 } as SpringConfig,\n /** Stiff, quick spring with minimal overshoot */\n stiff: { stiffness: 400, damping: 30 } as SpringConfig,\n};\n","/**\n * Stagger helpers.\n *\n * @module bquery/motion\n */\n\nimport type { StaggerFunction, StaggerOptions } from './types';\n\n/**\n * Create a staggered delay function for list animations.\n *\n * @param step - Delay between items in milliseconds\n * @param options - Stagger configuration\n * @returns Function that returns delay for a given index\n *\n * @example\n * ```ts\n * const delay = stagger(50, { from: 'center' });\n * delay(0, 3); // 50\n * delay(1, 3); // 0\n * ```\n */\nexport const stagger = (step: number, options: StaggerOptions = {}): StaggerFunction => {\n const { start = 0, from = 'start', easing } = options;\n\n return (index: number, total = 0): number => {\n const origin =\n typeof from === 'number'\n ? from\n : from === 'center'\n ? (total - 1) / 2\n : from === 'end'\n ? total - 1\n : 0;\n\n const distance = Math.abs(index - origin);\n const maxDistance = total > 1 ? Math.max(origin, total - 1 - origin) : 1;\n const normalized = maxDistance === 0 ? 0 : distance / maxDistance;\n const eased = easing ? easing(normalized) * maxDistance : distance;\n\n return start + eased * step;\n };\n};\n","/**\n * Timeline and sequence helpers.\n *\n * @module bquery/motion\n */\n\nimport { animate, applyFinalKeyframeStyles } from './animate';\nimport { prefersReducedMotion } from './reduced-motion';\nimport type {\n SequenceOptions,\n SequenceStep,\n TimelineConfig,\n TimelineControls,\n TimelineStep,\n} from './types';\n\nconst resolveTimeValue = (value?: number | string): number => {\n if (typeof value === 'number') return value;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed.endsWith('ms')) {\n const parsed = Number.parseFloat(trimmed.slice(0, -2));\n return Number.isFinite(parsed) ? parsed : 0;\n }\n if (trimmed.endsWith('s')) {\n const parsed = Number.parseFloat(trimmed.slice(0, -1));\n return Number.isFinite(parsed) ? parsed * 1000 : 0;\n }\n const parsed = Number.parseFloat(trimmed);\n return Number.isFinite(parsed) ? parsed : 0;\n }\n return 0;\n};\n\nconst resolveAt = (at: TimelineStep['at'], previousEnd: number): number => {\n if (typeof at === 'number') return at;\n if (typeof at === 'string') {\n const match = /^([+-])=(\\d+(?:\\.\\d+)?)$/.exec(at);\n if (match) {\n const delta = Number.parseFloat(match[2]);\n if (!Number.isFinite(delta)) return previousEnd;\n return match[1] === '+' ? previousEnd + delta : previousEnd - delta;\n }\n }\n return previousEnd;\n};\n\nconst normalizeDuration = (options?: KeyframeAnimationOptions): number => {\n const baseDuration = resolveTimeValue(options?.duration as number | string | undefined);\n const endDelay = resolveTimeValue(options?.endDelay as number | string | undefined);\n const rawIterations = options?.iterations ?? 1;\n\n // Handle infinite iterations - treat as a special case with a very large duration\n // In practice, infinite iterations shouldn't be used in timelines as they never end\n if (rawIterations === Infinity) {\n // Return a large sentinel value - timeline calculations will be incorrect,\n // but this at least prevents NaN/Infinity from breaking scheduling\n return Number.MAX_SAFE_INTEGER;\n }\n\n // Per Web Animations spec, iterations must be a non-negative number\n // Treat negative as 0 (only endDelay duration)\n const iterations = Math.max(0, rawIterations);\n\n // Total duration = (baseDuration * iterations) + endDelay\n // Note: endDelay is applied once at the end, after all iterations\n return baseDuration * iterations + endDelay;\n};\n\nconst scheduleSteps = (steps: TimelineStep[]) => {\n let previousEnd = 0;\n return steps.map((step) => {\n const baseStart = resolveAt(step.at, previousEnd);\n const stepDelay = resolveTimeValue(step.options?.delay as number | string | undefined);\n const start = Math.max(0, baseStart + stepDelay);\n const duration = normalizeDuration(step.options);\n const end = start + duration;\n previousEnd = Math.max(previousEnd, end);\n return { step, start, end, duration };\n });\n};\n\n/**\n * Run a list of animations sequentially.\n *\n * @param steps - Steps to run in order\n * @param options - Sequence configuration\n */\nexport const sequence = async (\n steps: SequenceStep[],\n options: SequenceOptions = {}\n): Promise<void> => {\n const { stagger, onFinish } = options;\n const total = steps.length;\n\n for (let index = 0; index < steps.length; index += 1) {\n const step = steps[index];\n const delay = stagger ? stagger(index, total) : 0;\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n await animate(step.target, step);\n }\n\n onFinish?.();\n};\n\n/**\n * Create a timeline controller for multiple animations.\n *\n * @param initialSteps - Steps for the timeline\n * @param config - Timeline configuration\n */\nexport const timeline = (\n initialSteps: TimelineStep[] = [],\n config: TimelineConfig = {}\n): TimelineControls => {\n const steps = [...initialSteps];\n const listeners = new Set<() => void>();\n let animations: Array<{ animation: Animation; step: TimelineStep; start: number }> = [];\n let totalDuration = 0;\n let reducedMotionApplied = false;\n let finalized = false;\n\n const { commitStyles = true, respectReducedMotion = true, onFinish } = config;\n\n const finalize = () => {\n if (finalized) return;\n finalized = true;\n\n if (commitStyles) {\n for (const item of animations) {\n const { animation, step } = item;\n if (typeof animation.commitStyles === 'function') {\n animation.commitStyles();\n } else {\n applyFinalKeyframeStyles(step.target, step.keyframes);\n }\n animation.cancel();\n }\n }\n\n listeners.forEach((listener) => listener());\n onFinish?.();\n };\n\n const buildAnimations = () => {\n animations.forEach(({ animation }) => animation.cancel());\n animations = [];\n finalized = false;\n\n const schedule = scheduleSteps(steps);\n totalDuration = schedule.length ? Math.max(...schedule.map((item) => item.end)) : 0;\n\n if (respectReducedMotion && prefersReducedMotion()) {\n if (commitStyles) {\n schedule.forEach(({ step }) => applyFinalKeyframeStyles(step.target, step.keyframes));\n }\n reducedMotionApplied = true;\n return;\n }\n\n // Check if Web Animations API is available on all targets\n const animateUnavailable = schedule.some(\n ({ step }) => typeof (step.target as HTMLElement).animate !== 'function'\n );\n if (animateUnavailable) {\n if (commitStyles) {\n schedule.forEach(({ step }) => applyFinalKeyframeStyles(step.target, step.keyframes));\n }\n reducedMotionApplied = true;\n return;\n }\n\n reducedMotionApplied = false;\n animations = schedule.map(({ step, start }) => {\n const { delay: _delay, ...options } = step.options ?? {};\n const animation = step.target.animate(step.keyframes, {\n ...options,\n delay: start,\n fill: options.fill ?? 'both',\n });\n return { animation, step, start };\n });\n };\n\n return {\n add(step: TimelineStep): void {\n steps.push(step);\n },\n\n duration(): number {\n if (!steps.length) return 0;\n if (!animations.length) {\n const schedule = scheduleSteps(steps);\n return Math.max(...schedule.map((item) => item.end));\n }\n return totalDuration;\n },\n\n async play(): Promise<void> {\n buildAnimations();\n\n if (reducedMotionApplied || animations.length === 0) {\n finalize();\n return;\n }\n\n const finishPromises = animations.map((item) =>\n item.animation.finished.catch(() => undefined)\n );\n await Promise.all(finishPromises);\n finalize();\n },\n\n pause(): void {\n if (reducedMotionApplied) return;\n animations.forEach(({ animation }) => animation.pause());\n },\n\n resume(): void {\n if (reducedMotionApplied) return;\n animations.forEach(({ animation }) => animation.play());\n },\n\n stop(): void {\n animations.forEach(({ animation }) => animation.cancel());\n animations = [];\n reducedMotionApplied = false;\n },\n\n seek(time: number): void {\n if (reducedMotionApplied) return;\n animations.forEach(({ animation }) => {\n // currentTime is measured from the beginning of the animation including delay,\n // so we set it directly to the requested timeline time\n animation.currentTime = time;\n });\n },\n\n onFinish(callback: () => void): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n },\n };\n};\n","/**\n * View transition helpers.\n *\n * @module bquery/motion\n */\n\nimport type { TransitionOptions } from './types';\nimport { prefersReducedMotion } from './reduced-motion';\nimport { getBqueryConfig } from '../platform/config';\n\n/** Extended document type with View Transitions API */\ntype DocumentWithTransition = Document & {\n startViewTransition?: (callback: () => void | Promise<void>) => {\n finished: Promise<void>;\n ready: Promise<void>;\n updateCallbackDone: Promise<void>;\n skipTransition?: () => void;\n types?: {\n add: (type: string) => void;\n };\n };\n};\n\nconst sanitizeTokens = (tokens?: string[]): string[] =>\n (tokens ?? []).map((token) => token.trim()).filter((token) => token.length > 0);\n\n/**\n * Execute a DOM update with view transition animation.\n * Falls back to immediate update when View Transitions API is unavailable.\n *\n * @param updateOrOptions - Update function or options object\n * @returns Promise that resolves when transition completes\n *\n * @example\n * ```ts\n * await transition(() => {\n * $('#content').text('Updated');\n * });\n * ```\n */\nexport const transition = async (\n updateOrOptions: (() => void | Promise<void>) | TransitionOptions\n): Promise<void> => {\n const config = getBqueryConfig().transitions;\n const options: TransitionOptions =\n typeof updateOrOptions === 'function'\n ? {\n update: updateOrOptions,\n classes: config?.classes,\n types: config?.types,\n skipOnReducedMotion: config?.skipOnReducedMotion,\n }\n : {\n ...updateOrOptions,\n classes: updateOrOptions.classes ?? config?.classes,\n types: updateOrOptions.types ?? config?.types,\n skipOnReducedMotion: updateOrOptions.skipOnReducedMotion ?? config?.skipOnReducedMotion,\n };\n const update = options.update;\n\n // SSR/non-DOM environment fallback\n if (typeof document === 'undefined') {\n await update();\n return;\n }\n\n const doc = document as DocumentWithTransition;\n const root = document.documentElement;\n const classes = sanitizeTokens(options.classes);\n const types = sanitizeTokens(options.types);\n\n if (!doc.startViewTransition || (options.skipOnReducedMotion && prefersReducedMotion())) {\n await update();\n options.onFinish?.();\n return;\n }\n\n classes.forEach((className: string) => root.classList.add(className));\n\n try {\n const viewTransition = doc.startViewTransition(() => update());\n const transitionTypes = viewTransition.types;\n\n if (transitionTypes) {\n for (const type of types) {\n transitionTypes.add(type);\n }\n }\n\n await viewTransition.ready;\n options.onReady?.();\n await viewTransition.finished;\n options.onFinish?.();\n } finally {\n classes.forEach((className: string) => root.classList.remove(className));\n }\n};\n","/**\n * Character-by-character typewriter text animation.\n *\n * @module bquery/motion\n */\n\nimport { prefersReducedMotion } from './reduced-motion';\nimport type { TypewriterControls, TypewriterOptions } from './types';\n\n/**\n * Animate text appearing character by character in an element.\n *\n * @param element - The element to type text into\n * @param text - The text to display\n * @param options - Typewriter configuration\n * @returns Controls with `.stop()` to cancel and `.done` promise\n *\n * @example\n * ```ts\n * const tw = typewriter(\n * document.querySelector('#output')!,\n * 'Hello, world!',\n * { speed: 80, cursor: true },\n * );\n *\n * // Wait for it to finish:\n * await tw.done;\n *\n * // Or cancel early:\n * tw.stop();\n * ```\n */\nexport const typewriter = (\n element: HTMLElement,\n text: string,\n options: TypewriterOptions = {}\n): TypewriterControls => {\n const {\n speed = 50,\n delay = 0,\n cursor = false,\n cursorChar = '|',\n loop = false,\n loopDelay = 1000,\n respectReducedMotion = true,\n onComplete,\n } = options;\n\n if (typeof document === 'undefined') {\n return {\n stop: () => {},\n done: Promise.resolve(),\n };\n }\n\n const el = element;\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let cursorEl: HTMLSpanElement | null = null;\n let cursorTimer: ReturnType<typeof setInterval> | null = null;\n let resolvePromise: (() => void) | null = null;\n\n // Add cursor element if enabled\n const setupCursor = () => {\n if (!cursor) return;\n cursorEl = document.createElement('span');\n cursorEl.setAttribute('aria-hidden', 'true');\n cursorEl.textContent = cursorChar;\n el.appendChild(cursorEl);\n\n // Blink the cursor\n let visible = true;\n cursorTimer = setInterval(() => {\n if (cursorEl) {\n visible = !visible;\n cursorEl.style.opacity = visible ? '1' : '0';\n }\n }, 530);\n };\n\n const removeCursor = () => {\n if (cursorTimer !== null) {\n clearInterval(cursorTimer);\n cursorTimer = null;\n }\n if (cursorEl && cursorEl.parentNode) {\n cursorEl.parentNode.removeChild(cursorEl);\n cursorEl = null;\n }\n };\n\n const stop = () => {\n if (stopped) return;\n stopped = true;\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n removeCursor();\n // Resolve the done promise so callers awaiting it are unblocked\n resolvePromise?.();\n resolvePromise = null;\n };\n\n // If reduced motion, show text instantly\n if (respectReducedMotion && prefersReducedMotion()) {\n el.textContent = text;\n onComplete?.();\n return {\n stop: () => {},\n done: Promise.resolve(),\n };\n }\n\n const done = new Promise<void>((resolve) => {\n resolvePromise = resolve;\n\n const typeLoop = () => {\n let charIndex = 0;\n el.textContent = '';\n setupCursor();\n const textNode = document.createTextNode('');\n\n if (cursorEl) {\n el.insertBefore(textNode, cursorEl);\n } else {\n el.appendChild(textNode);\n }\n\n const typeNextChar = () => {\n if (stopped) {\n return;\n }\n if (charIndex < text.length) {\n textNode.data = text.slice(0, charIndex + 1);\n charIndex++;\n timer = setTimeout(typeNextChar, speed);\n } else {\n // Typing complete for this iteration\n onComplete?.();\n\n if (loop && !stopped) {\n timer = setTimeout(() => {\n if (!stopped) {\n removeCursor();\n typeLoop();\n }\n }, loopDelay);\n } else {\n removeCursor();\n resolve();\n resolvePromise = null;\n }\n }\n };\n\n timer = setTimeout(typeNextChar, delay);\n };\n\n typeLoop();\n });\n\n return { stop, done };\n};\n","/**\n * Storage Buckets API wrapper.\n * Provides a simplified interface for storing blobs and binary data.\n * Falls back to IndexedDB when Storage Buckets API is not available.\n */\n\n/**\n * Bucket interface for blob storage operations.\n */\nexport interface Bucket {\n /**\n * Store a blob in the bucket.\n * @param key - Unique identifier for the blob\n * @param data - Blob data to store\n */\n put(key: string, data: Blob): Promise<void>;\n\n /**\n * Retrieve a blob from the bucket.\n * @param key - Blob identifier\n * @returns The stored blob or null if not found\n */\n get(key: string): Promise<Blob | null>;\n\n /**\n * Remove a blob from the bucket.\n * @param key - Blob identifier\n */\n remove(key: string): Promise<void>;\n\n /**\n * List all keys in the bucket.\n * @returns Array of blob keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * IndexedDB-based bucket implementation.\n * Used as fallback when Storage Buckets API is unavailable.\n */\nclass IndexedDBBucket implements Bucket {\n private dbPromise: Promise<IDBDatabase> | null = null;\n private readonly storeName = 'blobs';\n\n constructor(private readonly bucketName: string) {}\n\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n const dbName = `bquery-bucket-${this.bucketName}`;\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(dbName, 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.storeName)) {\n db.createObjectStore(this.storeName);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.storeName, mode);\n const store = tx.objectStore(this.storeName);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async put(key: string, data: Blob): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(data, key));\n }\n\n async get(key: string): Promise<Blob | null> {\n const result = await this.withStore<Blob | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Bucket manager for creating and accessing storage buckets.\n */\nexport const buckets = {\n /**\n * Open or create a storage bucket.\n * @param name - Bucket name\n * @returns Bucket instance for blob operations\n */\n async open(name: string): Promise<Bucket> {\n // Storage Buckets API is experimental; use IndexedDB fallback\n return new IndexedDBBucket(name);\n },\n};\n","/**\n * Cache Storage API wrapper.\n * Provides a simplified interface for caching responses and assets.\n */\n\n/**\n * Cache handle interface for managing cached resources.\n */\nexport interface CacheHandle {\n /**\n * Add a resource to the cache by URL.\n * Fetches the resource and stores the response.\n * @param url - URL to fetch and cache\n */\n add(url: string): Promise<void>;\n\n /**\n * Add multiple resources to the cache.\n * @param urls - Array of URLs to fetch and cache\n */\n addAll(urls: string[]): Promise<void>;\n\n /**\n * Store a custom response in the cache.\n * @param url - URL key for the cached response\n * @param response - Response object to cache\n */\n put(url: string, response: Response): Promise<void>;\n\n /**\n * Retrieve a cached response.\n * @param url - URL to look up\n * @returns Cached Response or undefined if not found\n */\n match(url: string): Promise<Response | undefined>;\n\n /**\n * Remove a cached response.\n * @param url - URL to remove from cache\n * @returns True if the entry was deleted\n */\n remove(url: string): Promise<boolean>;\n\n /**\n * Get all cached request URLs.\n * @returns Array of cached URLs\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Internal cache handle implementation.\n */\nclass CacheHandleImpl implements CacheHandle {\n constructor(private readonly cache: Cache) {}\n\n async add(url: string): Promise<void> {\n await this.cache.add(url);\n }\n\n async addAll(urls: string[]): Promise<void> {\n await this.cache.addAll(urls);\n }\n\n async put(url: string, response: Response): Promise<void> {\n await this.cache.put(url, response);\n }\n\n async match(url: string): Promise<Response | undefined> {\n return this.cache.match(url);\n }\n\n async remove(url: string): Promise<boolean> {\n return this.cache.delete(url);\n }\n\n async keys(): Promise<string[]> {\n const requests = await this.cache.keys();\n return requests.map((req) => req.url);\n }\n}\n\n/**\n * Cache manager for accessing the Cache Storage API.\n */\nexport const cache = {\n /**\n * Check if Cache Storage API is supported.\n * @returns True if caches API is available\n */\n isSupported(): boolean {\n return 'caches' in window;\n },\n\n /**\n * Open or create a named cache.\n * @param name - Cache name\n * @returns CacheHandle for cache operations\n */\n async open(name: string): Promise<CacheHandle> {\n if (!this.isSupported()) {\n throw new Error('bQuery: Cache Storage API not supported');\n }\n const c = await caches.open(name);\n return new CacheHandleImpl(c);\n },\n\n /**\n * Delete a named cache.\n * @param name - Cache name to delete\n * @returns True if the cache was deleted\n */\n async delete(name: string): Promise<boolean> {\n if (!this.isSupported()) {\n return false;\n }\n return caches.delete(name);\n },\n\n /**\n * List all cache names.\n * @returns Array of cache names\n */\n async keys(): Promise<string[]> {\n if (!this.isSupported()) {\n return [];\n }\n return caches.keys();\n },\n};\n","/**\n * Reactive cookie helpers.\n *\n * @module bquery/platform\n */\n\nimport { effect, signal, type Signal } from '../reactive/signal';\nimport { getBqueryConfig } from './config';\n\n/** Options for useCookie(). */\nexport interface UseCookieOptions<T> {\n /** Default value when the cookie is not present. */\n defaultValue?: T;\n /** Cookie path. Defaults to the global config or `/`. */\n path?: string;\n /** Optional cookie domain. */\n domain?: string;\n /** Cookie SameSite attribute. */\n sameSite?: 'Strict' | 'Lax' | 'None';\n /** Whether the cookie should be marked secure. */\n secure?: boolean;\n /** Cookie expiry date. */\n expires?: Date;\n /** Cookie max-age in seconds. */\n maxAge?: number;\n /** Automatically persist signal updates back to document.cookie. */\n watch?: boolean;\n /** Serialize a value before writing it into the cookie. */\n serialize?: (value: T) => string;\n /** Deserialize a cookie string into a typed value. */\n deserialize?: (value: string) => T;\n}\n\nconst readCookie = (name: string): string | null => {\n if (typeof document === 'undefined') return null;\n\n const prefix = `${encodeURIComponent(name)}=`;\n const segments = document.cookie ? document.cookie.split(';') : [];\n\n for (const segment of segments) {\n const normalizedSegment = segment.trim();\n if (normalizedSegment.startsWith(prefix)) {\n const rawValue = normalizedSegment.slice(prefix.length);\n try {\n return decodeURIComponent(rawValue);\n } catch {\n return rawValue;\n }\n }\n }\n\n return null;\n};\n\nconst requiresJsonParsing = (value: string): boolean => {\n const normalized = value.trim();\n return normalized.startsWith('{') || normalized.startsWith('[') || normalized.startsWith('\"');\n};\n\nconst removeCookie = (\n name: string,\n options: Pick<UseCookieOptions<unknown>, 'path' | 'domain' | 'sameSite' | 'secure'>\n): void => {\n if (typeof document === 'undefined') return;\n\n const segments = [`${encodeURIComponent(name)}=`, 'Expires=Thu, 01 Jan 1970 00:00:00 GMT'];\n\n if (options.path) segments.push(`Path=${options.path}`);\n if (options.domain) segments.push(`Domain=${options.domain}`);\n if (options.sameSite) segments.push(`SameSite=${options.sameSite}`);\n if (options.secure) segments.push('Secure');\n\n document.cookie = segments.join('; ');\n};\n\nconst writeCookie = <T>(name: string, value: T, options: UseCookieOptions<T>): void => {\n if (typeof document === 'undefined') return;\n\n const serialized = options.serialize\n ? options.serialize(value)\n : typeof value === 'string'\n ? value\n : JSON.stringify(value);\n\n const segments = [`${encodeURIComponent(name)}=${encodeURIComponent(serialized)}`];\n\n if (options.path) segments.push(`Path=${options.path}`);\n if (options.domain) segments.push(`Domain=${options.domain}`);\n if (typeof options.maxAge === 'number') segments.push(`Max-Age=${options.maxAge}`);\n if (options.expires) segments.push(`Expires=${options.expires.toUTCString()}`);\n if (options.sameSite) segments.push(`SameSite=${options.sameSite}`);\n if (options.secure) segments.push('Secure');\n\n document.cookie = segments.join('; ');\n};\n\n/**\n * Create a reactive cookie signal.\n *\n * @template T - Cookie value type\n * @param name - Cookie name\n * @param options - Read/write configuration for the cookie\n * @returns Reactive signal representing the cookie value\n *\n * @example\n * ```ts\n * const theme = useCookie('theme', { defaultValue: 'light' });\n * theme.value = 'dark';\n * ```\n */\nexport const useCookie = <T>(name: string, options: UseCookieOptions<T> = {}): Signal<T | null> => {\n const cookieConfig = getBqueryConfig().cookies;\n const resolvedOptions: UseCookieOptions<T> = {\n path: cookieConfig?.path ?? '/',\n sameSite: cookieConfig?.sameSite ?? 'Lax',\n secure: cookieConfig?.secure ?? false,\n watch: true,\n ...options,\n };\n\n if (resolvedOptions.sameSite === 'None') {\n resolvedOptions.secure = true;\n }\n\n const raw = readCookie(name);\n let initialValue = (resolvedOptions.defaultValue ?? null) as T | null;\n\n if (raw !== null) {\n try {\n initialValue = resolvedOptions.deserialize\n ? resolvedOptions.deserialize(raw)\n : requiresJsonParsing(raw)\n ? (JSON.parse(raw) as T)\n : ((raw as T) ?? initialValue);\n } catch (error) {\n console.warn(`bQuery: Failed to deserialize cookie \"${name}\", using raw string value`, error);\n initialValue = (raw as T) ?? initialValue;\n }\n }\n\n const cookie = signal<T | null>(initialValue);\n\n if (typeof document === 'undefined' || resolvedOptions.watch === false) {\n return cookie;\n }\n\n let initialized = false;\n effect(() => {\n const nextValue = cookie.value;\n\n if (!initialized) {\n initialized = true;\n return;\n }\n\n if (nextValue == null) {\n removeCookie(name, resolvedOptions);\n return;\n }\n\n writeCookie(name, nextValue, resolvedOptions);\n });\n\n return cookie;\n};\n","/**\n * Web Notifications API wrapper.\n * Provides a simplified interface for browser notifications.\n */\n\n/**\n * Notification options matching the standard NotificationOptions interface.\n */\nexport interface NotificationOptions {\n /** Body text of the notification */\n body?: string;\n /** Icon URL for the notification */\n icon?: string;\n /** Badge icon for mobile devices */\n badge?: string;\n /** Tag for grouping notifications */\n tag?: string;\n /** Whether to require user interaction */\n requireInteraction?: boolean;\n /** Vibration pattern for mobile devices */\n vibrate?: number[];\n /** Additional data attached to the notification */\n data?: unknown;\n}\n\n/**\n * Notifications manager providing a clean interface for web notifications.\n */\nexport const notifications = {\n /**\n * Check if notifications are supported.\n * @returns True if Notification API is available\n */\n isSupported(): boolean {\n return 'Notification' in window;\n },\n\n /**\n * Get current permission status.\n * @returns Current permission state\n */\n getPermission(): NotificationPermission {\n if (!this.isSupported()) return 'denied';\n return Notification.permission;\n },\n\n /**\n * Request notification permission from the user.\n * @returns Promise resolving to the permission result\n */\n async requestPermission(): Promise<NotificationPermission> {\n if (!this.isSupported()) {\n return 'denied';\n }\n\n if (Notification.permission === 'granted') {\n return 'granted';\n }\n\n if (Notification.permission === 'denied') {\n return 'denied';\n }\n\n return Notification.requestPermission();\n },\n\n /**\n * Send a notification.\n * Requires 'granted' permission.\n * @param title - Notification title\n * @param options - Optional notification settings\n * @returns The Notification instance or null if not permitted\n */\n send(title: string, options?: NotificationOptions): Notification | null {\n if (!this.isSupported()) {\n console.warn('bQuery: Notifications not supported in this browser');\n return null;\n }\n\n if (Notification.permission !== 'granted') {\n console.warn('bQuery: Notification permission not granted');\n return null;\n }\n\n return new Notification(title, options);\n },\n};\n","/**\n * Accessibility live-region announcer helpers.\n *\n * @module bquery/platform\n */\n\nimport { effect, signal, type Signal } from '../reactive/signal';\nimport { getBqueryConfig } from './config';\n\n/** Options for creating an announcer. */\nexport interface UseAnnouncerOptions {\n /** Live region politeness. */\n politeness?: 'polite' | 'assertive';\n /** Whether the live region should be atomic. */\n atomic?: boolean;\n /** Delay before applying the message. */\n delay?: number;\n /** Delay after which the message is cleared automatically. */\n clearDelay?: number;\n /** Optional element id for the live region. */\n id?: string;\n /** Optional CSS class name. */\n className?: string;\n /** Optional container used to append the live region. */\n container?: HTMLElement;\n}\n\n/** Runtime options for a single announcement. */\nexport interface AnnounceOptions {\n /** Override politeness for this specific announcement. */\n politeness?: 'polite' | 'assertive';\n /** Override the message delay for this specific announcement. */\n delay?: number;\n /** Override the auto-clear delay for this specific announcement. */\n clearDelay?: number;\n}\n\n/** Returned announcer API. */\nexport interface AnnouncerHandle {\n /** The live region element or null outside the DOM. */\n element: HTMLElement | null;\n /** Reactive message signal. */\n message: Signal<string>;\n /** Announce a message to assistive technologies. */\n announce: (value: string, options?: AnnounceOptions) => void;\n /** Clear the current announcement. */\n clear: () => void;\n /** Remove the live region if it was created by this announcer. */\n destroy: () => void;\n}\n\nconst visuallyHiddenStyle = [\n 'position:absolute',\n 'width:1px',\n 'height:1px',\n 'padding:0',\n 'margin:-1px',\n 'overflow:hidden',\n 'clip:rect(0, 0, 0, 0)',\n 'white-space:nowrap',\n 'border:0',\n].join(';');\n\n/**\n * Create or reuse an accessible live region.\n *\n * @param options - Live region configuration\n * @returns An announcer handle with announce(), clear(), and destroy()\n *\n * @example\n * ```ts\n * const announcer = useAnnouncer();\n * announcer.announce('Saved successfully');\n * ```\n */\nexport const useAnnouncer = (options: UseAnnouncerOptions = {}): AnnouncerHandle => {\n const defaults = getBqueryConfig().announcer;\n const resolvedOptions: Required<\n Pick<UseAnnouncerOptions, 'politeness' | 'atomic' | 'delay' | 'clearDelay'>\n > &\n UseAnnouncerOptions = {\n politeness: defaults?.politeness ?? 'polite',\n atomic: defaults?.atomic ?? true,\n delay: defaults?.delay ?? 16,\n clearDelay: defaults?.clearDelay ?? 1000,\n ...options,\n };\n\n const message = signal('');\n\n if (typeof document === 'undefined') {\n return {\n element: null,\n message,\n announce(value: string) {\n message.value = value;\n },\n clear() {\n message.value = '';\n },\n destroy() {\n message.value = '';\n },\n };\n }\n\n const existing = resolvedOptions.id ? document.getElementById(resolvedOptions.id) : null;\n const element = (existing ?? document.createElement('div')) as HTMLElement;\n const created = !existing;\n\n if (resolvedOptions.id) {\n element.id = resolvedOptions.id;\n }\n\n if (resolvedOptions.className) {\n element.className = resolvedOptions.className;\n }\n\n element.setAttribute('aria-live', resolvedOptions.politeness);\n element.setAttribute('aria-atomic', String(resolvedOptions.atomic));\n element.setAttribute('role', resolvedOptions.politeness === 'assertive' ? 'alert' : 'status');\n element.setAttribute('data-bquery-announcer', 'true');\n if (!element.getAttribute('style')) {\n element.setAttribute('style', visuallyHiddenStyle);\n }\n\n if (created) {\n const parent = resolvedOptions.container ?? document.body ?? document.documentElement;\n if (!parent) {\n return {\n element: null,\n message,\n announce(value: string) {\n message.value = value;\n },\n clear() {\n message.value = '';\n },\n destroy() {\n message.value = '';\n },\n };\n }\n parent.appendChild(element);\n }\n\n const disposeMessageEffect = effect(() => {\n element.textContent = message.value;\n });\n\n let messageTimer: ReturnType<typeof setTimeout> | undefined;\n let clearTimer: ReturnType<typeof setTimeout> | undefined;\n let destroyed = false;\n\n const clearTimers = (): void => {\n if (messageTimer) {\n clearTimeout(messageTimer);\n messageTimer = undefined;\n }\n if (clearTimer) {\n clearTimeout(clearTimer);\n clearTimer = undefined;\n }\n };\n\n const clear = (): void => {\n if (destroyed) return;\n clearTimers();\n message.value = '';\n };\n\n const announce = (value: string, announceOptions: AnnounceOptions = {}): void => {\n if (destroyed) return;\n const politeness = announceOptions.politeness ?? resolvedOptions.politeness;\n const delay = announceOptions.delay ?? resolvedOptions.delay;\n const clearDelay = announceOptions.clearDelay ?? resolvedOptions.clearDelay;\n\n clearTimers();\n\n element.setAttribute('aria-live', politeness);\n element.setAttribute('role', politeness === 'assertive' ? 'alert' : 'status');\n message.value = '';\n\n messageTimer = setTimeout(() => {\n if (destroyed) return;\n message.value = value;\n if (clearDelay > 0) {\n clearTimer = setTimeout(() => {\n if (destroyed) return;\n message.value = '';\n }, clearDelay);\n }\n }, delay);\n };\n\n const destroy = (): void => {\n if (destroyed) return;\n destroyed = true;\n clearTimers();\n message.value = '';\n disposeMessageEffect();\n if (created) {\n element.remove();\n }\n };\n\n return { element, message, announce, clear, destroy };\n};\n","/**\n * Document title and meta helpers.\n *\n * @module bquery/platform\n */\n\nimport { getBqueryConfig } from './config';\n\n/** Meta tag definition. */\nexport interface PageMetaTag {\n /** Standard meta name attribute. */\n name?: string;\n /** Open Graph / custom property attribute. */\n property?: string;\n /** http-equiv attribute. */\n httpEquiv?: string;\n /** Meta tag content. */\n content: string;\n}\n\n/** Link tag definition. */\nexport interface PageLinkTag {\n /** Link relation. */\n rel: string;\n /** Link URL. */\n href: string;\n /** Optional type attribute. */\n type?: string;\n /** Optional media query. */\n media?: string;\n /** Optional crossOrigin attribute. */\n crossOrigin?: 'anonymous' | 'use-credentials';\n}\n\n/** Page metadata definition. */\nexport interface PageMetaDefinition {\n /** Document title. */\n title?: string;\n /** Convenience shortcut for the description meta tag. */\n description?: string;\n /** Additional meta tags. */\n meta?: PageMetaTag[];\n /** Additional link tags. */\n link?: PageLinkTag[];\n /** Attributes applied to the html element. */\n htmlAttributes?: Record<string, string>;\n /** Attributes applied to the body element. */\n bodyAttributes?: Record<string, string>;\n}\n\n/** Cleanup function returned by definePageMeta(). */\nexport type PageMetaCleanup = () => void;\n\nconst setAttributes = (target: HTMLElement, attributes: Record<string, string>): (() => void) => {\n const previousValues = new Map<string, string | null>();\n\n for (const [name, value] of Object.entries(attributes)) {\n previousValues.set(name, target.getAttribute(name));\n target.setAttribute(name, value);\n }\n\n return () => {\n for (const [name, value] of previousValues.entries()) {\n if (value == null) {\n target.removeAttribute(name);\n } else {\n target.setAttribute(name, value);\n }\n }\n };\n};\n\nconst createElement = <T extends 'meta' | 'link'>(\n tagName: T,\n attributes: Record<string, string | undefined>\n): HTMLElementTagNameMap[T] => {\n const element = document.createElement(tagName);\n element.setAttribute('data-bquery-page-meta', 'true');\n\n for (const [name, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n element.setAttribute(name, value);\n }\n }\n\n return element;\n};\n\n/**\n * Apply document metadata for the current page.\n *\n * @param definition - Title, meta tags, link tags, and document attributes\n * @returns Cleanup function that restores the previous document state\n *\n * @example\n * ```ts\n * const cleanup = definePageMeta({\n * title: 'Dashboard',\n * description: 'Overview of your account',\n * });\n * ```\n */\nexport const definePageMeta = (definition: PageMetaDefinition): PageMetaCleanup => {\n if (typeof document === 'undefined') {\n return () => {};\n }\n\n const config = getBqueryConfig().pageMeta;\n const title = definition.title\n ? config?.titleTemplate\n ? config.titleTemplate(definition.title)\n : definition.title\n : undefined;\n\n const inserted: HTMLElement[] = [];\n const restoreFns: Array<() => void> = [];\n const previousTitle = document.title;\n\n if (title !== undefined) {\n document.title = title;\n }\n\n const metaEntries = [...(definition.meta ?? [])];\n if (definition.description) {\n metaEntries.unshift({ name: 'description', content: definition.description });\n }\n\n for (const entry of metaEntries) {\n const meta = createElement('meta', {\n name: entry.name,\n property: entry.property,\n 'http-equiv': entry.httpEquiv,\n content: entry.content,\n });\n document.head.appendChild(meta);\n inserted.push(meta);\n }\n\n for (const entry of definition.link ?? []) {\n const link = createElement('link', {\n rel: entry.rel,\n href: entry.href,\n type: entry.type,\n media: entry.media,\n crossorigin: entry.crossOrigin,\n });\n document.head.appendChild(link);\n inserted.push(link);\n }\n\n if (definition.htmlAttributes) {\n restoreFns.push(setAttributes(document.documentElement, definition.htmlAttributes));\n }\n\n if (definition.bodyAttributes && document.body) {\n restoreFns.push(setAttributes(document.body, definition.bodyAttributes));\n }\n\n return () => {\n document.title = previousTitle;\n for (const restore of restoreFns.reverse()) {\n restore();\n }\n for (const element of inserted) {\n element.remove();\n }\n };\n};\n","/**\n * Unified storage adapters for web platform storage APIs.\n * Provides a consistent, promise-based interface with predictable errors.\n */\n\n/**\n * Common interface for all storage adapters.\n * All methods return promises for a unified async API.\n */\nexport interface StorageAdapter {\n /**\n * Retrieve a value by key.\n * @param key - The storage key\n * @returns The stored value or null if not found\n */\n get<T>(key: string): Promise<T | null>;\n\n /**\n * Store a value by key.\n * @param key - The storage key\n * @param value - The value to store\n */\n set<T>(key: string, value: T): Promise<void>;\n\n /**\n * Remove a value by key.\n * @param key - The storage key\n */\n remove(key: string): Promise<void>;\n\n /**\n * Clear all stored values.\n */\n clear(): Promise<void>;\n\n /**\n * Get all storage keys.\n * @returns Array of all keys\n */\n keys(): Promise<string[]>;\n}\n\n/**\n * Abstract base class for web storage adapters (localStorage/sessionStorage).\n * Implements DRY principle by sharing common logic.\n */\nabstract class WebStorageAdapter implements StorageAdapter {\n constructor(protected readonly storage: Storage) {}\n\n async get<T>(key: string): Promise<T | null> {\n const raw = this.storage.getItem(key);\n if (raw === null) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return raw as unknown as T;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n const serialized = typeof value === 'string' ? value : JSON.stringify(value);\n this.storage.setItem(key, serialized);\n }\n\n async remove(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n\n async keys(): Promise<string[]> {\n const result: string[] = [];\n for (let i = 0; i < this.storage.length; i++) {\n const key = this.storage.key(i);\n if (key !== null) {\n result.push(key);\n }\n }\n return result;\n }\n}\n\n/**\n * localStorage adapter with async interface.\n */\nclass LocalStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(localStorage);\n }\n}\n\n/**\n * sessionStorage adapter with async interface.\n */\nclass SessionStorageAdapter extends WebStorageAdapter {\n constructor() {\n super(sessionStorage);\n }\n}\n\n/**\n * IndexedDB configuration options.\n */\nexport interface IndexedDBOptions {\n /** Database name */\n name: string;\n /** Object store name */\n store: string;\n /** Database version (optional) */\n version?: number;\n}\n\n/**\n * IndexedDB key-value adapter.\n * Wraps IndexedDB with a simple key-value interface.\n */\nclass IndexedDBAdapter implements StorageAdapter {\n private dbPromise: Promise<IDBDatabase> | null = null;\n\n constructor(private readonly options: IndexedDBOptions) {}\n\n /**\n * Opens or creates the IndexedDB database.\n */\n private openDB(): Promise<IDBDatabase> {\n if (this.dbPromise) return this.dbPromise;\n\n this.dbPromise = new Promise((resolve, reject) => {\n const request = indexedDB.open(this.options.name, this.options.version ?? 1);\n\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains(this.options.store)) {\n db.createObjectStore(this.options.store);\n }\n };\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n\n return this.dbPromise;\n }\n\n /**\n * Executes a transaction on the object store.\n */\n private async withStore<T>(\n mode: IDBTransactionMode,\n operation: (store: IDBObjectStore) => IDBRequest<T>\n ): Promise<T> {\n const db = await this.openDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.options.store, mode);\n const store = tx.objectStore(this.options.store);\n const request = operation(store);\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n }\n\n async get<T>(key: string): Promise<T | null> {\n const result = await this.withStore<T | undefined>('readonly', (store) => store.get(key));\n return result ?? null;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n await this.withStore('readwrite', (store) => store.put(value, key));\n }\n\n async remove(key: string): Promise<void> {\n await this.withStore('readwrite', (store) => store.delete(key));\n }\n\n async clear(): Promise<void> {\n await this.withStore('readwrite', (store) => store.clear());\n }\n\n async keys(): Promise<string[]> {\n const result = await this.withStore<IDBValidKey[]>('readonly', (store) => store.getAllKeys());\n return result.map((key) => String(key));\n }\n}\n\n/**\n * Storage factory providing access to different storage adapters.\n */\nexport const storage = {\n /**\n * Create a localStorage adapter.\n * @returns StorageAdapter wrapping localStorage\n */\n local(): StorageAdapter {\n return new LocalStorageAdapter();\n },\n\n /**\n * Create a sessionStorage adapter.\n * @returns StorageAdapter wrapping sessionStorage\n */\n session(): StorageAdapter {\n return new SessionStorageAdapter();\n },\n\n /**\n * Create an IndexedDB adapter with key-value interface.\n * @param options - Database and store configuration\n * @returns StorageAdapter wrapping IndexedDB\n */\n indexedDB(options: IndexedDBOptions): StorageAdapter {\n return new IndexedDBAdapter(options);\n },\n};\n","/**\n * Internal router state (active router and current route signal).\n * @module bquery/router\n */\n\nimport { computed, readonly, signal, type ReadonlySignal, type Signal } from '../reactive/index';\nimport type { Route, Router } from './types';\n\n// ============================================================================\n// Internal State\n// ============================================================================\n\n/** @internal */\nlet activeRouter: Router | null = null;\n\n/** @internal */\nexport const routeSignal: Signal<Route> = signal<Route>({\n path: '',\n params: {},\n query: {},\n matched: null,\n hash: '',\n});\n\n/**\n * Reactive signal containing the current route.\n *\n * @example\n * ```ts\n * import { currentRoute } from '@bquery/bquery/router';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * effect(() => {\n * document.title = `Page: ${currentRoute.value.path}`;\n * });\n * ```\n */\nexport const currentRoute: ReadonlySignal<Route> = computed(() => routeSignal.value);\n\n/** @internal */\nconst navigationCountSignal: Signal<number> = signal(0);\n\n/** @internal */\nconst isNavigatingSignal: Signal<boolean> = signal(false);\n\n/**\n * Reactive signal indicating whether a navigation is currently in progress.\n *\n * This becomes `true` while async guards or redirect resolution are running,\n * then flips back to `false` once navigation finishes or is canceled.\n *\n * @example\n * ```ts\n * import { isNavigating } from '@bquery/bquery/router';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * effect(() => {\n * document.body.toggleAttribute('data-loading-route', isNavigating.value);\n * });\n * ```\n */\nexport const isNavigating: ReadonlySignal<boolean> = readonly(isNavigatingSignal);\n\n/** @internal */\nexport const beginNavigation = (): void => {\n if (navigationCountSignal.value === 0) {\n isNavigatingSignal.value = true;\n }\n navigationCountSignal.value += 1;\n};\n\n/** @internal */\nexport const endNavigation = (): void => {\n const nextCount = Math.max(0, navigationCountSignal.value - 1);\n navigationCountSignal.value = nextCount;\n\n if (nextCount === 0) {\n isNavigatingSignal.value = false;\n }\n};\n\n/** @internal */\nexport const resetNavigationState = (): void => {\n navigationCountSignal.value = 0;\n isNavigatingSignal.value = false;\n};\n\n/** @internal */\nexport const getActiveRouter = (): Router | null => activeRouter;\n\n/** @internal */\nexport const setActiveRouter = (router: Router | null): void => {\n activeRouter = router;\n};\n","/**\n * Navigation helpers and global router access.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\n\n/**\n * Navigates to a new path.\n *\n * @param path - The path to navigate to\n * @param options - Navigation options\n *\n * @example\n * ```ts\n * import { navigate } from 'bquery/router';\n *\n * // Push to history\n * await navigate('/dashboard');\n *\n * // Replace current entry\n * await navigate('/login', { replace: true });\n * ```\n */\nexport const navigate = async (\n path: string,\n options: { replace?: boolean } = {}\n): Promise<void> => {\n const activeRouter = getActiveRouter();\n if (!activeRouter) {\n throw new Error('bQuery router: No router initialized. Call createRouter() first.');\n }\n\n await activeRouter[options.replace ? 'replace' : 'push'](path);\n};\n\n/**\n * Programmatically go back in history.\n *\n * @example\n * ```ts\n * import { back } from 'bquery/router';\n * back();\n * ```\n */\nexport const back = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.back();\n } else {\n history.back();\n }\n};\n\n/**\n * Programmatically go forward in history.\n *\n * @example\n * ```ts\n * import { forward } from 'bquery/router';\n * forward();\n * ```\n */\nexport const forward = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.forward();\n } else {\n history.forward();\n }\n};\n","/**\n * `<bq-link>` custom element for declarative SPA navigation.\n *\n * Exposes an accessible custom element that behaves like a link for\n * client-side routing. Automatically toggles an active class when the\n * target path matches the current route.\n *\n * @module bquery/router\n *\n * @example\n * ```html\n * <bq-link to=\"/\">Home</bq-link>\n * <bq-link to=\"/about\" active-class=\"selected\">About</bq-link>\n * <bq-link to=\"/settings\" replace exact>Settings</bq-link>\n * ```\n */\n\nimport { effect, type CleanupFn } from '../reactive/index';\nimport { navigate } from './navigation';\nimport { getActiveRouter, routeSignal } from './state';\n\n/**\n * Default CSS class applied when the link's target path is active.\n * @internal\n */\nconst DEFAULT_ACTIVE_CLASS = 'active';\n\n/** @internal */\nconst tokenizeClassNames = (value: string): string[] => {\n return value\n .split(/\\s+/)\n .map((token) => token.trim())\n .filter((token) => token.length > 0);\n};\n\n/** @internal SSR-safe base class for environments without HTMLElement. */\nconst BQ_LINK_BASE =\n typeof HTMLElement !== 'undefined' ? HTMLElement : (class {} as unknown as typeof HTMLElement);\n\n/**\n * `<bq-link>` — A navigation custom element for bQuery routers.\n *\n * Attributes:\n * - `to` — Target path (required). Example: `to=\"/dashboard\"`.\n * - `replace` — If present, replaces the current history entry instead of pushing.\n * - `exact` — If present, the active class is only applied on an exact path match.\n * - `active-class` — CSS class added when the route is active (default: `'active'`).\n *\n * The custom element itself acts as the interactive link target using\n * `role=\"link\"` and keyboard handling. It does not render a native `<a>`,\n * so browser-native link affordances like context-menu \"open in new tab\"\n * are not provided automatically.\n *\n * @example\n * ```ts\n * import { registerBqLink } from '@bquery/bquery/router';\n *\n * // Register the <bq-link> element (idempotent)\n * registerBqLink();\n *\n * // Then use in HTML:\n * // <bq-link to=\"/about\">About</bq-link>\n * ```\n */\nexport class BqLinkElement extends BQ_LINK_BASE {\n /** @internal */\n private _cleanup: CleanupFn | null = null;\n\n /** @internal */\n private _trackedActiveClasses = new Map<string, boolean>();\n\n static get observedAttributes(): string[] {\n return ['to', 'replace', 'exact', 'active-class'];\n }\n\n /** The target path for navigation. */\n get to(): string {\n const to = this.getAttribute('to');\n return to == null || to.trim() === '' ? '/' : to;\n }\n\n set to(value: string) {\n this.setAttribute('to', value);\n }\n\n /** Whether to replace the current history entry. */\n get replace(): boolean {\n return this.hasAttribute('replace');\n }\n\n set replace(value: boolean) {\n if (value) {\n this.setAttribute('replace', '');\n } else {\n this.removeAttribute('replace');\n }\n }\n\n /** Whether to match the path exactly for active class. */\n get exact(): boolean {\n return this.hasAttribute('exact');\n }\n\n set exact(value: boolean) {\n if (value) {\n this.setAttribute('exact', '');\n } else {\n this.removeAttribute('exact');\n }\n }\n\n /** CSS class applied when the route is active. */\n get activeClass(): string {\n return this.getAttribute('active-class') ?? DEFAULT_ACTIVE_CLASS;\n }\n\n set activeClass(value: string) {\n this.setAttribute('active-class', value);\n }\n\n /** @internal */\n connectedCallback(): void {\n // Set role for accessibility if not an <a> already\n if (!this.getAttribute('role')) {\n this.setAttribute('role', 'link');\n }\n\n // Make focusable if not already\n if (!this.hasAttribute('tabindex')) {\n this.setAttribute('tabindex', '0');\n }\n\n // Attach click handler\n this.addEventListener('click', this._handleClick);\n this.addEventListener('keydown', this._handleKeydown);\n\n // Set up reactive active-class tracking\n this._setupActiveTracking();\n }\n\n /** @internal */\n disconnectedCallback(): void {\n this.removeEventListener('click', this._handleClick);\n this.removeEventListener('keydown', this._handleKeydown);\n\n if (this._cleanup) {\n this._cleanup();\n this._cleanup = null;\n }\n\n this._clearTrackedActiveClasses();\n }\n\n /** @internal */\n attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void {\n // Re-setup active tracking when relevant attributes change\n if (name === 'to' || name === 'exact' || name === 'active-class') {\n if (this.isConnected) {\n this._setupActiveTracking();\n }\n }\n }\n\n /**\n * Sets up the reactive effect that toggles the active CSS class\n * based on the current route.\n * @internal\n */\n private _setupActiveTracking(): void {\n // Clean up previous effect\n if (this._cleanup) {\n this._cleanup();\n this._cleanup = null;\n }\n\n this._clearTrackedActiveClasses();\n\n const targetPath = this.to;\n const exactMatch = this.exact;\n const cssClasses = tokenizeClassNames(this.activeClass);\n this._trackedActiveClasses = new Map(\n cssClasses.map((cssClass) => [cssClass, this.classList.contains(cssClass)])\n );\n\n this._cleanup = effect(() => {\n const current = routeSignal.value.path;\n const isMatch = exactMatch\n ? current === targetPath\n : targetPath === '/'\n ? current === '/'\n : current === targetPath ||\n current.startsWith(targetPath.endsWith('/') ? targetPath : targetPath + '/');\n\n for (const cssClass of cssClasses) {\n const wasPresentInitially = this._trackedActiveClasses.get(cssClass) ?? false;\n this.classList.toggle(cssClass, isMatch || wasPresentInitially);\n }\n\n // Update aria-current for accessibility\n if (isMatch) {\n this.setAttribute('aria-current', 'page');\n } else {\n this.removeAttribute('aria-current');\n }\n });\n }\n\n /** @internal */\n private _clearTrackedActiveClasses(): void {\n for (const [cssClass, wasPresentInitially] of this._trackedActiveClasses) {\n this.classList.toggle(cssClass, wasPresentInitially);\n }\n this._trackedActiveClasses.clear();\n }\n\n /**\n * Handles click events for SPA navigation.\n * @internal\n */\n private _handleClick = (e: Event): void => {\n if (!(e instanceof MouseEvent)) return;\n if (e.defaultPrevented) return;\n if (e.button !== 0) return; // Only left clicks\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;\n\n e.preventDefault();\n this._navigate();\n };\n\n /**\n * Handles keyboard activation (Enter).\n * @internal\n */\n private _handleKeydown = (e: Event): void => {\n if (e instanceof KeyboardEvent && e.key === 'Enter') {\n e.preventDefault();\n this._navigate();\n }\n };\n\n /**\n * Performs the actual navigation.\n * @internal\n */\n private _navigate(): void {\n const targetPath = this.to;\n if (!targetPath) return;\n if (!getActiveRouter()) return;\n\n void navigate(targetPath, { replace: this.replace }).catch((err) => {\n console.error('bq-link: Navigation failed:', err);\n });\n }\n}\n\n/**\n * Registers the `<bq-link>` custom element.\n *\n * This function is idempotent — calling it multiple times is safe.\n * The element is registered under the tag name `bq-link`.\n *\n * @example\n * ```ts\n * import { registerBqLink } from '@bquery/bquery/router';\n *\n * registerBqLink();\n *\n * // Now use <bq-link to=\"/about\">About</bq-link> in HTML\n * ```\n */\nexport const registerBqLink = (): void => {\n if (\n typeof HTMLElement !== 'undefined' &&\n typeof customElements !== 'undefined' &&\n !customElements.get('bq-link')\n ) {\n customElements.define('bq-link', BqLinkElement);\n }\n};\n","/**\n * Link helpers for client-side navigation.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\nimport { navigate } from './navigation';\n\n// ============================================================================\n// Router Link Helper\n// ============================================================================\n\n/**\n * Creates click handler for router links.\n * Attach to anchor elements to enable client-side navigation.\n *\n * @param path - Target path\n * @param options - Navigation options\n * @returns Click event handler\n *\n * @example\n * ```ts\n * import { link } from 'bquery/router';\n * import { $ } from 'bquery/core';\n *\n * $('#nav-home').on('click', link('/'));\n * $('#nav-about').on('click', link('/about'));\n * ```\n */\nexport const link = (path: string, options: { replace?: boolean } = {}): ((e: Event) => void) => {\n return (e: Event) => {\n e.preventDefault();\n void navigate(path, options).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n};\n\n/**\n * Intercepts all link clicks within a container for client-side routing.\n * Only intercepts links with matching origins and no target attribute.\n *\n * @param container - The container element to intercept links in\n * @returns Cleanup function to remove the listener\n *\n * @example\n * ```ts\n * import { interceptLinks } from 'bquery/router';\n *\n * // Intercept all links in the app\n * const cleanup = interceptLinks(document.body);\n *\n * // Later, remove the interceptor\n * cleanup();\n * ```\n */\nexport const interceptLinks = (container?: Element): (() => void) => {\n // Provide safe default in DOM environments only\n const targetContainer = container ?? (typeof document !== 'undefined' ? document.body : null);\n if (!targetContainer) {\n // No container available (SSR or invalid input)\n return () => undefined;\n }\n\n const handler = (e: Event) => {\n // Only intercept standard left-clicks without modifier keys\n if (!(e instanceof MouseEvent)) return;\n if (e.defaultPrevented) return; // Already handled\n if (e.button !== 0) return; // Not left-click (middle-click opens new tab, right-click shows context menu)\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; // Modifier keys (Ctrl/Cmd-click = new tab)\n\n // Guard against non-Element targets and non-DOM environments\n if (typeof Element === 'undefined' || !(e.target instanceof Element)) return;\n const target = e.target as HTMLElement;\n const anchor = target.closest('a');\n\n if (!anchor) return;\n\n // Cross-realm compatible anchor check: use owner document's constructor if available\n const anchorWindow = anchor.ownerDocument.defaultView;\n const AnchorConstructor = anchorWindow?.HTMLAnchorElement ?? HTMLAnchorElement;\n if (!(anchor instanceof AnchorConstructor)) return;\n\n if (anchor.target) return; // Has target attribute\n if (anchor.hasAttribute('download')) return;\n if (typeof window === 'undefined') return; // Non-window environment\n if (anchor.origin !== window.location.origin) return; // External link\n\n // Get active router config to handle base paths correctly.\n // If no router is active, proceed with no base/hash; navigate() will throw a\n // \"No router initialized\" error, which is caught and logged below.\n const router = getActiveRouter();\n if (!router) {\n // No active router - trigger navigate(), allowing its error to be logged here\n e.preventDefault();\n void navigate(anchor.pathname + anchor.search + anchor.hash).catch((err) => {\n console.error('Navigation failed:', err);\n });\n return;\n }\n\n const base = router.base;\n const useHash = router.hash;\n\n // Detect hash-routing mode: links written as href=\"#/page\"\n // In this case, anchor.hash contains the route path\n let path: string;\n if (useHash && anchor.hash && anchor.hash.startsWith('#/')) {\n // Hash-routing mode: extract path from the hash\n // e.g., href=\"#/page?foo=bar\" → path = \"/page?foo=bar\"\n path = anchor.hash.slice(1); // Remove leading #\n } else {\n // History mode: use pathname + search + hash\n // Strip base from pathname to avoid duplication (router.push() re-adds it)\n let pathname = anchor.pathname;\n if (base && base !== '/' && pathname.startsWith(base)) {\n pathname = pathname.slice(base.length) || '/';\n }\n path = pathname + anchor.search + anchor.hash;\n }\n\n e.preventDefault();\n void navigate(path).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n\n targetContainer.addEventListener('click', handler);\n return () => targetContainer.removeEventListener('click', handler);\n};\n","/**\n * Query string helpers.\n * @module bquery/router\n */\n\nimport { isPrototypePollutionKey } from '../core/utils/object';\n\n/**\n * Parses query string into an object.\n * Single values are stored as strings, duplicate keys become arrays.\n * @internal\n *\n * @example\n * parseQuery('?foo=1') // { foo: '1' }\n * parseQuery('?tag=a&tag=b') // { tag: ['a', 'b'] }\n * parseQuery('?x=1&y=2&x=3') // { x: ['1', '3'], y: '2' }\n */\nexport const parseQuery = (search: string): Record<string, string | string[]> => {\n const query: Record<string, string | string[]> = {};\n const params = new URLSearchParams(search);\n\n params.forEach((value, key) => {\n if (isPrototypePollutionKey(key)) return;\n const existing = query[key];\n if (existing === undefined) {\n // First occurrence: store as string\n query[key] = value;\n } else if (Array.isArray(existing)) {\n // Already an array: append\n existing.push(value);\n } else {\n // Second occurrence: convert to array\n query[key] = [existing, value];\n }\n });\n\n return query;\n};\n","/**\n * Shared helpers for validating and normalizing route param constraints.\n * @internal\n */\n\nconst MAX_ROUTE_CONSTRAINT_CACHE_SIZE = 128;\nconst normalizedConstraintCache = new Map<string, string>();\nconst compiledConstraintRegexCache = new Map<string, RegExp>();\n\nconst setBoundedCacheEntry = <T>(cache: Map<string, T>, key: string, value: T): void => {\n if (cache.has(key)) {\n cache.delete(key);\n }\n\n cache.set(key, value);\n\n if (cache.size <= MAX_ROUTE_CONSTRAINT_CACHE_SIZE) {\n return;\n }\n\n const oldestKey = cache.keys().next().value;\n if (oldestKey !== undefined) {\n cache.delete(oldestKey);\n }\n};\n\n/**\n * Detects potentially super-linear (ReDoS) patterns caused by quantified\n * groups that already contain inner quantifiers, such as `(a+)+` or `(a*)*`.\n * @internal\n */\nconst hasNestedQuantifier = (pattern: string): boolean => {\n const groupQuantifierStack: boolean[] = [];\n let inCharClass = false;\n\n for (let i = 0; i < pattern.length; i++) {\n const ch = pattern[i];\n\n if (ch === '\\\\' && i + 1 < pattern.length) {\n i++;\n continue;\n }\n\n if (ch === '[' && !inCharClass) {\n inCharClass = true;\n continue;\n }\n if (ch === ']' && inCharClass) {\n inCharClass = false;\n continue;\n }\n if (inCharClass) continue;\n\n if (ch === '(') {\n groupQuantifierStack.push(false);\n continue;\n }\n\n if (ch === ')') {\n const groupHasInnerQuantifier = groupQuantifierStack.pop() ?? false;\n // Check if the closing paren is followed by a quantifier\n const next = pattern[i + 1];\n if (\n groupHasInnerQuantifier &&\n (next === '+' || next === '*' || next === '?' || next === '{')\n ) {\n return true;\n }\n if (groupHasInnerQuantifier && groupQuantifierStack.length > 0) {\n groupQuantifierStack[groupQuantifierStack.length - 1] = true;\n }\n continue;\n }\n\n if (groupQuantifierStack.length > 0) {\n if (ch === '?' && i > 0 && pattern[i - 1] === '(') {\n continue;\n }\n\n if (ch === '+' || ch === '*' || ch === '?' || ch === '{') {\n groupQuantifierStack[groupQuantifierStack.length - 1] = true;\n }\n }\n }\n\n return false;\n};\n\nconst normalizeConstraintCaptures = (constraint: string): string => {\n let normalized = '';\n let inCharacterClass = false;\n\n for (let i = 0; i < constraint.length; i++) {\n const char = constraint[i];\n\n if (char === '\\\\' && i + 1 < constraint.length) {\n if (!inCharacterClass && constraint[i + 1] >= '1' && constraint[i + 1] <= '9') {\n throw new Error(\n `bQuery router: Route constraints cannot use backreferences: \"${constraint}\".`\n );\n }\n\n if (!inCharacterClass && constraint[i + 1] === 'k' && constraint[i + 2] === '<') {\n throw new Error(\n `bQuery router: Route constraints cannot use backreferences: \"${constraint}\".`\n );\n }\n\n normalized += char + constraint[i + 1];\n i++;\n continue;\n }\n\n if (char === '[' && !inCharacterClass) {\n inCharacterClass = true;\n normalized += char;\n continue;\n }\n\n if (char === ']' && inCharacterClass) {\n inCharacterClass = false;\n normalized += char;\n continue;\n }\n\n if (!inCharacterClass && char === '(') {\n if (i + 1 < constraint.length && constraint[i + 1] === '?') {\n if (constraint[i + 2] === '<') {\n if (constraint[i + 3] === '=' || constraint[i + 3] === '!') {\n normalized += '(';\n continue;\n }\n\n const namedCaptureEnd = constraint.indexOf('>', i + 3);\n if (namedCaptureEnd === -1) {\n throw new Error(\n `bQuery router: Invalid route constraint named capture group: \"${constraint}\".`\n );\n }\n normalized += '(?:';\n i = namedCaptureEnd;\n continue;\n }\n\n normalized += '(';\n continue;\n }\n\n normalized += '(?:';\n continue;\n }\n\n normalized += char;\n }\n\n return normalized;\n};\n\nexport const getNormalizedRouteConstraint = (constraint: string): string => {\n const cached = normalizedConstraintCache.get(constraint);\n if (cached !== undefined) {\n return cached;\n }\n\n const normalized = normalizeConstraintCaptures(constraint);\n setBoundedCacheEntry(normalizedConstraintCache, constraint, normalized);\n return normalized;\n};\n\nexport const getRouteConstraintRegex = (constraint: string): RegExp => {\n const normalizedConstraint = getNormalizedRouteConstraint(constraint);\n const cached = compiledConstraintRegexCache.get(normalizedConstraint);\n if (cached) {\n return cached;\n }\n\n if (hasNestedQuantifier(normalizedConstraint)) {\n throw new Error(\n `bQuery router: Route constraint contains a potentially catastrophic (ReDoS) pattern. Nested quantifiers are not allowed: \"${constraint}\".`\n );\n }\n\n try {\n const compiled = new RegExp(`^(?:${normalizedConstraint})$`);\n setBoundedCacheEntry(compiledConstraintRegexCache, normalizedConstraint, compiled);\n return compiled;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(\n `bQuery router: Invalid route constraint regex \"${constraint}\": ${error.message}`\n );\n }\n throw error;\n }\n};\n\nexport const routeConstraintMatches = (constraint: string, value: string): boolean => {\n return getRouteConstraintRegex(constraint).test(value);\n};\n\nexport const clearRouteConstraintCache = (): void => {\n normalizedConstraintCache.clear();\n compiledConstraintRegexCache.clear();\n};\n","/**\n * Shared helpers for parsing route path params and constraints.\n * @internal\n */\n\n/** Validates whether a character can start a route param name. @internal */\nexport const isParamStart = (char: string | undefined): boolean =>\n char !== undefined &&\n ((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char === '_');\n\n/** Validates whether a character can appear after the start of a route param name. @internal */\nexport const isParamChar = (char: string | undefined): boolean =>\n isParamStart(char) || (char !== undefined && char >= '0' && char <= '9');\n\n/** Reads a route param constraint while preserving escaped chars and nested groups. @internal */\nexport const readConstraint = (\n path: string,\n startIndex: number\n): { constraint: string; endIndex: number } | null => {\n let depth = 1;\n let constraint = '';\n let i = startIndex + 1;\n let inCharacterClass = false;\n\n while (i < path.length) {\n const char = path[i];\n\n if (char === '\\\\' && i + 1 < path.length) {\n constraint += char + path[i + 1];\n i += 2;\n continue;\n }\n\n if (char === '[' && !inCharacterClass) {\n inCharacterClass = true;\n } else if (char === ']' && inCharacterClass) {\n inCharacterClass = false;\n } else if (!inCharacterClass && char === '(') {\n depth++;\n } else if (!inCharacterClass && char === ')') {\n depth--;\n if (depth === 0) {\n return { constraint, endIndex: i + 1 };\n }\n }\n\n constraint += char;\n i++;\n }\n\n return null;\n};\n","/**\n * Route matching helpers.\n * @module bquery/router\n */\n\nimport { parseQuery } from './query';\nimport { getNormalizedRouteConstraint, getRouteConstraintRegex } from './constraints';\nimport { isParamChar, isParamStart, readConstraint } from './path-pattern';\nimport type { Route, RouteDefinition } from './types';\n\nconst readConstraintOrThrow = (\n path: string,\n startIndex: number\n): { constraint: string; endIndex: number } => {\n const parsedConstraint = readConstraint(path, startIndex);\n if (!parsedConstraint) {\n throw new Error(\n `bQuery router: Invalid route param constraint syntax in path \"${path}\" at index ${startIndex}.`\n );\n }\n return parsedConstraint;\n};\n\ntype RouteParamDescriptor = {\n name: string;\n constraint?: string;\n nextIndex: number;\n};\n\nconst validatedRoutePathCache = new Set<string>();\n\nconst readParamDescriptor = (path: string, index: number): RouteParamDescriptor | null => {\n if (path[index] !== ':' || !isParamStart(path[index + 1])) {\n return null;\n }\n\n let nameEnd = index + 2;\n while (nameEnd < path.length && isParamChar(path[nameEnd])) {\n nameEnd++;\n }\n\n let nextIndex = nameEnd;\n let constraint: string | undefined;\n\n if (path[nameEnd] === '(') {\n const parsedConstraint = readConstraintOrThrow(path, nameEnd);\n constraint = parsedConstraint.constraint;\n nextIndex = parsedConstraint.endIndex;\n }\n\n return {\n name: path.slice(index + 1, nameEnd),\n constraint,\n nextIndex,\n };\n};\n\nconst validateRoutePathPattern = (path: string): void => {\n if (validatedRoutePathCache.has(path)) {\n return;\n }\n\n for (let i = 0; i < path.length; ) {\n const char = path[i];\n\n if (char === ':' && isParamStart(path[i + 1])) {\n const param = readParamDescriptor(path, i);\n if (param?.constraint) {\n getNormalizedRouteConstraint(param.constraint);\n }\n i = param?.nextIndex ?? i + 1;\n continue;\n }\n\n i++;\n }\n\n validatedRoutePathCache.add(path);\n};\n\nconst findSegmentBoundary = (value: string, startIndex: number): number => {\n const slashIndex = value.indexOf('/', startIndex);\n return slashIndex === -1 ? value.length : slashIndex;\n};\n\nconst readNextStaticChunk = (path: string, startIndex: number): string => {\n let chunkEnd = startIndex;\n\n while (chunkEnd < path.length) {\n if (path[chunkEnd] === '*') {\n break;\n }\n\n if (path[chunkEnd] === ':' && isParamStart(path[chunkEnd + 1])) {\n break;\n }\n\n chunkEnd++;\n }\n\n return path.slice(startIndex, chunkEnd);\n};\n\nconst findAnchoredCandidateEnds = (\n actualPath: string,\n startIndex: number,\n limit: number,\n nextStaticChunk: string\n): number[] => {\n const candidates: number[] = [];\n let searchIndex = startIndex;\n\n while (searchIndex <= limit) {\n const candidateEnd = actualPath.indexOf(nextStaticChunk, searchIndex);\n if (candidateEnd === -1 || candidateEnd > limit) {\n break;\n }\n\n candidates.push(candidateEnd);\n searchIndex = candidateEnd + 1;\n }\n\n return candidates.reverse();\n};\n\nconst matchPathPattern = (routePath: string, actualPath: string): Record<string, string> | null => {\n // Memoization keeps wildcard/param backtracking linear for repeated subproblems\n // within a single route/path match attempt.\n const memo = new Map<string, Record<string, string> | null>();\n\n const matchFrom = (routeIndex: number, pathIndex: number): Record<string, string> | null => {\n const memoKey = `${routeIndex}:${pathIndex}`;\n if (memo.has(memoKey)) {\n return memo.get(memoKey) ?? null;\n }\n\n if (routeIndex === routePath.length) {\n const result = pathIndex === actualPath.length ? {} : null;\n memo.set(memoKey, result);\n return result;\n }\n\n const routeChar = routePath[routeIndex];\n\n if (routeChar === '*') {\n if (routeIndex === routePath.length - 1) {\n const result = {};\n memo.set(memoKey, result);\n return result;\n }\n\n const nextStaticChunk = readNextStaticChunk(routePath, routeIndex + 1);\n const anchoredCandidateEnds =\n nextStaticChunk.length > 0\n ? findAnchoredCandidateEnds(actualPath, pathIndex, actualPath.length, nextStaticChunk)\n : null;\n\n const iterateCandidateEnds = anchoredCandidateEnds\n ? (callback: (candidateEnd: number) => Record<string, string> | null) => {\n for (const candidateEnd of anchoredCandidateEnds) {\n const result = callback(candidateEnd);\n if (result) {\n return result;\n }\n }\n return null;\n }\n : (callback: (candidateEnd: number) => Record<string, string> | null) => {\n for (let candidateEnd = actualPath.length; candidateEnd >= pathIndex; candidateEnd--) {\n const result = callback(candidateEnd);\n if (result) {\n return result;\n }\n }\n return null;\n };\n\n const wildcardMatch = iterateCandidateEnds((candidateEnd) => {\n const suffixMatch = matchFrom(routeIndex + 1, candidateEnd);\n if (suffixMatch) {\n memo.set(memoKey, suffixMatch);\n return suffixMatch;\n }\n return null;\n });\n\n if (wildcardMatch) {\n return wildcardMatch;\n }\n\n memo.set(memoKey, null);\n return null;\n }\n\n const param = readParamDescriptor(routePath, routeIndex);\n if (param) {\n const constraintRegex = param.constraint\n ? getRouteConstraintRegex(param.constraint)\n : undefined;\n const candidateLimit = param.constraint\n ? actualPath.length\n : findSegmentBoundary(actualPath, pathIndex);\n const nextStaticChunk = readNextStaticChunk(routePath, param.nextIndex);\n const anchoredCandidateEnds =\n nextStaticChunk.length > 0\n ? findAnchoredCandidateEnds(actualPath, pathIndex, candidateLimit, nextStaticChunk)\n : null;\n\n const iterateCandidateEnds = anchoredCandidateEnds\n ? (callback: (candidateEnd: number) => Record<string, string> | null) => {\n for (const candidateEnd of anchoredCandidateEnds) {\n if (candidateEnd <= pathIndex) {\n continue;\n }\n const result = callback(candidateEnd);\n if (result) {\n return result;\n }\n }\n return null;\n }\n : (callback: (candidateEnd: number) => Record<string, string> | null) => {\n for (let candidateEnd = candidateLimit; candidateEnd > pathIndex; candidateEnd--) {\n const result = callback(candidateEnd);\n if (result) {\n return result;\n }\n }\n return null;\n };\n\n const paramMatch = iterateCandidateEnds((candidateEnd) => {\n const candidateValue = actualPath.slice(pathIndex, candidateEnd);\n\n if (constraintRegex) {\n if (!constraintRegex.test(candidateValue)) {\n return null;\n }\n }\n\n const suffixMatch = matchFrom(param.nextIndex, candidateEnd);\n if (suffixMatch) {\n const result = {\n [param.name]: candidateValue,\n ...suffixMatch,\n };\n memo.set(memoKey, result);\n return result;\n }\n return null;\n });\n\n if (paramMatch) {\n return paramMatch;\n }\n\n memo.set(memoKey, null);\n return null;\n }\n\n if (pathIndex >= actualPath.length || routeChar !== actualPath[pathIndex]) {\n memo.set(memoKey, null);\n return null;\n }\n\n const result = matchFrom(routeIndex + 1, pathIndex + 1);\n memo.set(memoKey, result);\n return result;\n };\n\n return matchFrom(0, 0);\n};\n\n/**\n * Matches a path against route definitions and extracts params.\n * @internal\n */\nexport const matchRoute = (\n path: string,\n routes: RouteDefinition[]\n): { matched: RouteDefinition; params: Record<string, string> } | null => {\n for (const route of routes) {\n validateRoutePathPattern(route.path);\n const params = matchPathPattern(route.path, path);\n if (params) {\n return { matched: route, params };\n }\n }\n\n return null;\n};\n\n/**\n * Creates a Route object from the current URL.\n * @internal\n */\nexport const createRoute = (\n pathname: string,\n search: string,\n hash: string,\n routes: RouteDefinition[]\n): Route => {\n const result = matchRoute(pathname, routes);\n\n return {\n path: pathname,\n params: result?.params ?? {},\n query: parseQuery(search),\n matched: result?.matched ?? null,\n hash: hash.replace(/^#/, ''),\n };\n};\n","/**\n * Router utilities.\n * @module bquery/router\n */\n\nimport { computed, type ReadonlySignal } from '../reactive/index';\nimport { getRouteConstraintRegex } from './constraints';\nimport { isParamChar, isParamStart, readConstraint } from './path-pattern';\nimport { getActiveRouter, routeSignal } from './state';\nimport type { RouteDefinition } from './types';\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\n/**\n * Flattens nested routes into a single array with full paths.\n * Does NOT include the router base - base is only for browser history.\n * @internal\n */\nexport const flattenRoutes = (routes: RouteDefinition[], parentPath = ''): RouteDefinition[] => {\n const result: RouteDefinition[] = [];\n\n for (const route of routes) {\n const fullPath = route.path === '*' ? '*' : `${parentPath}${route.path}`.replace(/\\/+/g, '/');\n\n result.push({\n ...route,\n path: fullPath,\n });\n\n if (route.children) {\n result.push(...flattenRoutes(route.children, fullPath));\n }\n }\n\n return result;\n};\n\n/**\n * Resolves a route by name and params.\n *\n * @param name - The route name\n * @param params - Route params to interpolate\n * @returns The resolved path\n * @throws {Error} If no router is initialized, the route name is unknown,\n * a required path param is missing from `params`, a param value does not satisfy\n * its route regex constraint, or a route param constraint has invalid syntax\n *\n * @example\n * ```ts\n * import { resolve } from 'bquery/router';\n *\n * const path = resolve('user', { id: '42' });\n * // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }\n * ```\n */\nexport const resolve = (name: string, params: Record<string, string> = {}): string => {\n const activeRouter = getActiveRouter();\n if (!activeRouter) {\n throw new Error('bQuery router: No router initialized.');\n }\n\n const route = activeRouter.routes.find((r) => r.name === name);\n if (!route) {\n throw new Error(`bQuery router: Route \"${name}\" not found.`);\n }\n\n let path = '';\n for (let i = 0; i < route.path.length; ) {\n if (route.path[i] === ':' && isParamStart(route.path[i + 1])) {\n let nameEnd = i + 2;\n while (nameEnd < route.path.length && isParamChar(route.path[nameEnd])) {\n nameEnd++;\n }\n\n let nextIndex = nameEnd;\n let constraint: string | null = null;\n if (route.path[nameEnd] === '(') {\n const parsedConstraint = readConstraint(route.path, nameEnd);\n if (!parsedConstraint) {\n throw new Error(\n `bQuery router: Invalid constraint syntax in path \"${route.path}\" for route \"${name}\".`\n );\n }\n constraint = parsedConstraint.constraint;\n nextIndex = parsedConstraint.endIndex;\n }\n\n const key = route.path.slice(i + 1, nameEnd);\n const value = params[key];\n if (value === undefined) {\n throw new Error(`bQuery router: Missing required param \"${key}\" for route \"${name}\".`);\n }\n if (constraint && !getRouteConstraintRegex(constraint).test(value)) {\n throw new Error(\n `bQuery router: Param \"${key}\" with value \"${value}\" does not satisfy the route constraint \"${constraint}\" for route \"${name}\".`\n );\n }\n\n path += encodeURIComponent(value);\n i = nextIndex;\n continue;\n }\n\n path += route.path[i];\n i++;\n }\n\n return path;\n};\n\n/**\n * Checks if a path matches the current route.\n *\n * @param path - Path to check\n * @param exact - Whether to match exactly (default: false)\n * @returns True if the path matches\n *\n * @example\n * ```ts\n * import { isActive } from 'bquery/router';\n *\n * if (isActive('/dashboard')) {\n * // Highlight nav item\n * }\n * ```\n */\nexport const isActive = (path: string, exact = false): boolean => {\n const current = routeSignal.value.path;\n return exact ? current === path : current.startsWith(path);\n};\n\n/**\n * Creates a computed signal that checks if a path is active.\n *\n * @param path - Path to check\n * @param exact - Whether to match exactly\n * @returns A reactive signal\n *\n * @example\n * ```ts\n * import { isActiveSignal } from 'bquery/router';\n * import { effect } from 'bquery/reactive';\n *\n * const dashboardActive = isActiveSignal('/dashboard');\n * effect(() => {\n * navItem.classList.toggle('active', dashboardActive.value);\n * });\n * ```\n */\nexport const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {\n return computed(() => {\n const current = routeSignal.value.path;\n return exact ? current === path : current.startsWith(path);\n });\n};\n","/**\n * Router creation and lifecycle management.\n * @module bquery/router\n */\n\nimport { isPrototypePollutionKey } from '../core/utils/object';\nimport { createRoute } from './match';\nimport {\n beginNavigation,\n currentRoute,\n endNavigation,\n getActiveRouter,\n resetNavigationState,\n routeSignal,\n setActiveRouter,\n} from './state';\nimport type { NavigationGuard, Route, Router, RouterOptions } from './types';\nimport { flattenRoutes } from './utils';\n\n// ============================================================================\n// Router Creation\n// ============================================================================\n\nconst MAX_SCROLL_POSITION_ENTRIES = 100;\n\nconst sanitizeHistoryState = (state: Record<string, unknown>): Record<string, unknown> => {\n const sanitized: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(state)) {\n if (isPrototypePollutionKey(key)) continue;\n sanitized[key] = value;\n }\n\n return sanitized;\n};\n\n/**\n * Creates and initializes a router instance.\n *\n * @param options - Router configuration\n * @returns The router instance\n *\n * @example\n * ```ts\n * import { createRouter } from 'bquery/router';\n *\n * const router = createRouter({\n * routes: [\n * { path: '/', component: () => import('./pages/Home') },\n * { path: '/about', component: () => import('./pages/About') },\n * { path: '/user/:id(\\\\d+)', component: () => import('./pages/User') },\n * { path: '/old-page', redirectTo: '/new-page' },\n * { path: '*', component: () => import('./pages/NotFound') },\n * ],\n * base: '/app',\n * scrollRestoration: true,\n * });\n *\n * router.beforeEach((to, from) => {\n * if (to.path === '/admin' && !isAuthenticated()) {\n * return false; // Cancel navigation\n * }\n * });\n * ```\n */\nexport const createRouter = (options: RouterOptions): Router => {\n // Clean up any existing router to prevent guard leakage\n const existingRouter = getActiveRouter();\n if (existingRouter) {\n existingRouter.destroy();\n }\n\n const { routes, base = '', hash: useHash = false, scrollRestoration = false } = options;\n\n // Instance-specific guards and hooks (not shared globally)\n const beforeGuards: NavigationGuard[] = [];\n const afterHooks: Array<(to: Route, from: Route) => void> = [];\n\n // Flatten nested routes (base-relative, not including the base path)\n const flatRoutes = flattenRoutes(routes);\n\n // Scroll position storage keyed by history state id\n const scrollPositions = new Map<string, { x: number; y: number }>();\n let currentScrollKey = '0';\n let scrollKeyCounter = 0;\n let previousScrollRestoration: History['scrollRestoration'] | null = null;\n\n // Enable manual scroll restoration if scrollRestoration is configured\n if (scrollRestoration && typeof history !== 'undefined' && 'scrollRestoration' in history) {\n previousScrollRestoration = history.scrollRestoration;\n if (history.scrollRestoration !== 'manual') {\n history.scrollRestoration = 'manual';\n }\n\n const state =\n history.state && typeof history.state === 'object'\n ? (history.state as Record<string, unknown>)\n : {};\n\n if (typeof state.__bqScrollKey !== 'string') {\n const currentUrl = useHash\n ? window.location.hash || '#/'\n : `${window.location.pathname}${window.location.search}${window.location.hash}`;\n history.replaceState({ ...state, __bqScrollKey: currentScrollKey }, '', currentUrl);\n }\n }\n\n /**\n * Generates a unique key for the current history entry.\n * @internal\n */\n const getScrollKey = (): string => {\n return (history.state && history.state.__bqScrollKey) || currentScrollKey;\n };\n\n /**\n * Generates a unique key for a new history entry.\n * @internal\n */\n const createScrollKey = (): string => `${Date.now()}-${scrollKeyCounter++}`;\n\n /**\n * Saves current scroll position for the current history entry.\n * @internal\n */\n const saveScrollPosition = (key = getScrollKey()): void => {\n if (!scrollRestoration) return;\n if (scrollPositions.has(key)) {\n // Refresh the insertion order so pruning behaves like an LRU cache.\n scrollPositions.delete(key);\n }\n scrollPositions.set(key, { x: window.scrollX, y: window.scrollY });\n while (scrollPositions.size > MAX_SCROLL_POSITION_ENTRIES) {\n const oldestKey = scrollPositions.keys().next().value as string | undefined;\n if (oldestKey === undefined) {\n break;\n }\n scrollPositions.delete(oldestKey);\n }\n };\n\n /**\n * Restores scroll position for the current history entry.\n * @internal\n */\n const restoreScrollPosition = (key = getScrollKey()): void => {\n if (!scrollRestoration) return;\n const pos = scrollPositions.get(key);\n if (pos) {\n window.scrollTo(pos.x, pos.y);\n } else {\n window.scrollTo(0, 0);\n }\n };\n\n /**\n * Builds history state for canceled navigations without dropping\n * the scroll restoration key for the current entry.\n * @internal\n */\n const getRestoreHistoryState = (): Record<string, unknown> => {\n const state =\n history.state && typeof history.state === 'object'\n ? { ...(history.state as Record<string, unknown>) }\n : {};\n\n if (scrollRestoration) {\n state.__bqScrollKey = currentScrollKey;\n }\n\n return state;\n };\n\n /**\n * Gets the current path from the URL.\n */\n const getCurrentPath = (): { pathname: string; search: string; hash: string } => {\n if (useHash) {\n const hashPath = window.location.hash.slice(1) || '/';\n // In hash routing, URL structure is #/path?query#fragment\n // Extract hash fragment first (after the second #)\n const [pathWithQuery, hashPart = ''] = hashPath.split('#');\n // Then extract query from the path\n const [pathname, search = ''] = pathWithQuery.split('?');\n return {\n pathname,\n search: search ? `?${search}` : '',\n hash: hashPart ? `#${hashPart}` : '',\n };\n }\n\n let pathname = window.location.pathname;\n if (base && (pathname === base || pathname.startsWith(base + '/'))) {\n pathname = pathname.slice(base.length) || '/';\n }\n\n return {\n pathname,\n search: window.location.search,\n hash: window.location.hash,\n };\n };\n\n /**\n * Updates the route signal with current URL state.\n */\n const syncRoute = (): void => {\n const { pathname, search, hash } = getCurrentPath();\n const newRoute = createRoute(pathname, search, hash, flatRoutes);\n routeSignal.value = newRoute;\n };\n\n /**\n * Performs navigation with guards.\n */\n const performNavigation = async (\n path: string,\n method: 'pushState' | 'replaceState',\n visitedPaths: Set<string> = new Set()\n ): Promise<void> => {\n beginNavigation();\n try {\n const { pathname, search, hash } = getCurrentPath();\n const from = createRoute(pathname, search, hash, flatRoutes);\n\n // Parse the target path\n const url = new URL(path, window.location.origin);\n const resolvedPath = `${url.pathname}${url.search}${url.hash}`;\n if (visitedPaths.has(resolvedPath)) {\n throw new Error(`bQuery router: redirect loop detected for path \"${resolvedPath}\"`);\n }\n visitedPaths.add(resolvedPath);\n const to = createRoute(url.pathname, url.search, url.hash, flatRoutes);\n\n // Check for redirectTo on the matched route\n if (to.matched?.redirectTo) {\n // Navigate to the redirect target instead\n await performNavigation(to.matched.redirectTo, method, visitedPaths);\n return;\n }\n\n // Run route-level beforeEnter guard\n if (to.matched?.beforeEnter) {\n const result = await to.matched.beforeEnter(to, from);\n if (result === false) {\n return; // Cancel navigation\n }\n }\n\n // Run beforeEach guards\n for (const guard of beforeGuards) {\n const result = await guard(to, from);\n if (result === false) {\n return; // Cancel navigation\n }\n }\n\n // Save scroll position before navigation\n saveScrollPosition();\n\n // Update browser history\n const existingScrollKey = scrollRestoration ? getScrollKey() : undefined;\n const scrollKey =\n method === 'replaceState' && existingScrollKey ? existingScrollKey : createScrollKey();\n const fullPath = useHash ? `#${path}` : `${base}${path}`;\n const baseState =\n scrollRestoration && history.state && typeof history.state === 'object'\n ? sanitizeHistoryState(history.state as Record<string, unknown>)\n : {};\n const state = scrollRestoration ? { ...baseState, __bqScrollKey: scrollKey } : {};\n history[method](state, '', fullPath);\n currentScrollKey = scrollKey;\n\n // Update route signal\n syncRoute();\n\n // Scroll to top on push navigation\n if (scrollRestoration && method === 'pushState') {\n window.scrollTo(0, 0);\n }\n\n // Run afterEach hooks\n for (const hook of afterHooks) {\n hook(routeSignal.value, from);\n }\n } finally {\n endNavigation();\n }\n };\n\n /**\n * Handle popstate events (back/forward).\n */\n const handlePopState = async (event: PopStateEvent): Promise<void> => {\n beginNavigation();\n try {\n const { pathname, search, hash } = getCurrentPath();\n const from = routeSignal.value;\n const to = createRoute(pathname, search, hash, flatRoutes);\n\n // Check for redirectTo on the matched route\n if (to.matched?.redirectTo) {\n await performNavigation(to.matched.redirectTo, 'replaceState');\n return;\n }\n\n // Run route-level beforeEnter guard\n if (to.matched?.beforeEnter) {\n const result = await to.matched.beforeEnter(to, from);\n if (result === false) {\n // Restore previous state with full URL (including query/hash)\n const queryString = new URLSearchParams(\n Object.entries(from.query).flatMap(([key, value]) =>\n Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]\n )\n ).toString();\n const searchStr = queryString ? `?${queryString}` : '';\n const hashStr = from.hash ? `#${from.hash}` : '';\n const restorePath = useHash\n ? `#${from.path}${searchStr}${hashStr}`\n : `${base}${from.path}${searchStr}${hashStr}`;\n history.replaceState(getRestoreHistoryState(), '', restorePath);\n return;\n }\n }\n\n // Run beforeEach guards (supports async guards)\n for (const guard of beforeGuards) {\n const result = await guard(to, from);\n if (result === false) {\n // Restore previous state with full URL (including query/hash)\n const queryString = new URLSearchParams(\n Object.entries(from.query).flatMap(([key, value]) =>\n Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]\n )\n ).toString();\n const search = queryString ? `?${queryString}` : '';\n const hash = from.hash ? `#${from.hash}` : '';\n const restorePath = useHash\n ? `#${from.path}${search}${hash}`\n : `${base}${from.path}${search}${hash}`;\n history.replaceState(getRestoreHistoryState(), '', restorePath);\n return;\n }\n }\n\n // Save scroll position of the page we're leaving\n saveScrollPosition(currentScrollKey);\n\n // Update scroll key from history state\n currentScrollKey =\n (event.state as { __bqScrollKey?: string } | null)?.__bqScrollKey ?? getScrollKey();\n\n syncRoute();\n\n // Restore scroll position for the entry we're navigating to\n restoreScrollPosition(currentScrollKey);\n\n for (const hook of afterHooks) {\n hook(routeSignal.value, from);\n }\n } finally {\n endNavigation();\n }\n };\n\n // Attach popstate listener\n window.addEventListener('popstate', handlePopState);\n\n // Initialize route\n syncRoute();\n\n const router: Router = {\n push: (path: string) => performNavigation(path, 'pushState'),\n replace: (path: string) => performNavigation(path, 'replaceState'),\n back: () => history.back(),\n forward: () => history.forward(),\n go: (delta: number) => history.go(delta),\n\n beforeEach: (guard: NavigationGuard) => {\n beforeGuards.push(guard);\n return () => {\n const index = beforeGuards.indexOf(guard);\n if (index > -1) beforeGuards.splice(index, 1);\n };\n },\n\n afterEach: (hook: (to: Route, from: Route) => void) => {\n afterHooks.push(hook);\n return () => {\n const index = afterHooks.indexOf(hook);\n if (index > -1) afterHooks.splice(index, 1);\n };\n },\n\n currentRoute,\n routes: flatRoutes,\n base,\n hash: useHash,\n\n destroy: () => {\n window.removeEventListener('popstate', handlePopState);\n beforeGuards.length = 0;\n afterHooks.length = 0;\n scrollPositions.clear();\n // Restore the previous scroll restoration mode on destroy\n if (\n previousScrollRestoration !== null &&\n typeof history !== 'undefined' &&\n 'scrollRestoration' in history\n ) {\n history.scrollRestoration = previousScrollRestoration;\n }\n resetNavigationState();\n setActiveRouter(null);\n },\n };\n\n setActiveRouter(router);\n return router;\n};\n","/**\n * Reactive route composable.\n * @module bquery/router\n */\n\nimport { computed, type ReadonlySignal } from '../reactive/index';\nimport { routeSignal } from './state';\nimport type { Route, RouteDefinition } from './types';\n\n// ============================================================================\n// useRoute Composable\n// ============================================================================\n\n/**\n * Return type for {@link useRoute}.\n * Provides reactive access to individual route properties.\n */\nexport type UseRouteReturn = {\n /** Full reactive route object */\n route: ReadonlySignal<Route>;\n /** Reactive current path */\n path: ReadonlySignal<string>;\n /** Reactive route params */\n params: ReadonlySignal<Record<string, string>>;\n /** Reactive query params */\n query: ReadonlySignal<Record<string, string | string[]>>;\n /** Reactive hash fragment (without #) */\n hash: ReadonlySignal<string>;\n /** Reactive matched route definition */\n matched: ReadonlySignal<RouteDefinition | null>;\n};\n\nconst route = computed(() => routeSignal.value);\nconst path = computed(() => route.value.path);\nconst params = computed(() => route.value.params);\nconst query = computed(() => route.value.query);\nconst hash = computed(() => route.value.hash);\nconst matched = computed(() => route.value.matched);\n\nconst routeHandle: UseRouteReturn = { route, path, params, query, hash, matched };\n\n/**\n * Returns reactive access to the current route, params, query, and hash.\n *\n * Each property is a readonly computed signal that updates automatically\n * when the route changes. This is useful for fine-grained reactivity\n * where you only need to subscribe to specific route parts.\n *\n * @returns An object with reactive route properties\n *\n * @example\n * ```ts\n * import { useRoute } from '@bquery/bquery/router';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const { path, params, query, hash } = useRoute();\n *\n * effect(() => {\n * console.log('Path:', path.value);\n * console.log('Params:', params.value);\n * console.log('Query:', query.value);\n * console.log('Hash:', hash.value);\n * });\n * ```\n */\nexport const useRoute = (): UseRouteReturn => {\n return routeHandle;\n};\n","/**\n * Devtools integration for stores.\n * @internal\n */\n\ndeclare global {\n interface Window {\n __BQUERY_DEVTOOLS__?: {\n stores: Map<string, unknown>;\n onStoreCreated?: (id: string, store: unknown) => void;\n onStateChange?: (id: string, state: unknown) => void;\n };\n }\n}\n\nexport type DevtoolsHook = {\n stores: Map<string, unknown>;\n onStoreCreated?: (id: string, store: unknown) => void;\n onStateChange?: (id: string, state: unknown) => void;\n};\n\nconst ensureDevtools = (): DevtoolsHook | undefined => {\n if (typeof window === 'undefined') return undefined;\n if (!window.__BQUERY_DEVTOOLS__) {\n window.__BQUERY_DEVTOOLS__ = { stores: new Map() };\n }\n return window.__BQUERY_DEVTOOLS__;\n};\n\nexport const registerDevtoolsStore = (id: string, store: unknown): void => {\n const devtools = ensureDevtools();\n if (!devtools) return;\n devtools.stores.set(id, store);\n devtools.onStoreCreated?.(id, store);\n};\n\nexport const unregisterDevtoolsStore = (id: string): void => {\n if (typeof window === 'undefined' || !window.__BQUERY_DEVTOOLS__) return;\n window.__BQUERY_DEVTOOLS__.stores.delete(id);\n};\n\nexport const notifyDevtoolsStateChange = (id: string, state: unknown): void => {\n if (typeof window === 'undefined') return;\n window.__BQUERY_DEVTOOLS__?.onStateChange?.(id, state);\n};\n","/**\n * Store plugins API.\n */\n\nimport type { Store, StoreDefinition, StorePlugin } from './types';\n\n/** @internal Registered plugins */\nconst plugins: StorePlugin[] = [];\n\n/**\n * Registers a plugin that extends all stores.\n *\n * @param plugin - The plugin function\n */\nexport const registerPlugin = (plugin: StorePlugin): void => {\n plugins.push(plugin);\n};\n\n/** @internal */\nexport const applyPlugins = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n store: Store<any, any, any>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n options: StoreDefinition<any, any, any>\n): void => {\n for (const plugin of plugins) {\n const extension = plugin({ store, options });\n if (extension) {\n Object.assign(store, extension);\n }\n }\n};\n","/**\n * Store registry utilities.\n */\n\nimport { unregisterDevtoolsStore } from './devtools';\nimport type { Store } from './types';\n\n/** @internal Registry of all stores for devtools */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst storeRegistry = new Map<string, Store<any, any, any>>();\n\n/** @internal */\nexport const hasStore = (id: string): boolean => storeRegistry.has(id);\n\n/** @internal */\nexport const registerStore = (\n id: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n store: Store<any, any, any>\n): void => {\n storeRegistry.set(id, store);\n};\n\n/**\n * Retrieves an existing store by its ID.\n *\n * @param id - The store identifier\n * @returns The store instance or undefined if not found\n */\nexport const getStore = <T = unknown>(id: string): T | undefined => {\n return storeRegistry.get(id) as T | undefined;\n};\n\n/**\n * Lists all registered store IDs.\n *\n * @returns Array of store IDs\n */\nexport const listStores = (): string[] => {\n return Array.from(storeRegistry.keys());\n};\n\n/**\n * Removes a store from the registry.\n *\n * @param id - The store identifier\n */\nexport const destroyStore = (id: string): void => {\n storeRegistry.delete(id);\n unregisterDevtoolsStore(id);\n};\n","/**\n * Internal utilities for the store module.\n * @internal\n */\n\nimport { detectDevEnvironment } from '../core/env';\n\n/**\n * Check if a value is a plain object (not array, null, Date, etc.).\n * @internal\n */\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return (\n value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype\n );\n};\n\n/**\n * Deep clones an object. Used for deep reactivity support.\n * @internal\n */\nexport const deepClone = <T>(obj: T): T => {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(deepClone) as T;\n }\n\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as T;\n }\n\n if (obj instanceof Map) {\n return new Map(Array.from(obj.entries()).map(([k, v]) => [k, deepClone(v)])) as T;\n }\n\n if (obj instanceof Set) {\n return new Set(Array.from(obj).map(deepClone)) as T;\n }\n\n const cloned = {} as T;\n for (const key of Object.keys(obj)) {\n (cloned as Record<string, unknown>)[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return cloned;\n};\n\n/**\n * Compares two values for deep equality.\n * @internal\n */\nexport const deepEqual = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false;\n for (const [key, value] of a.entries()) {\n if (!b.has(key) || !deepEqual(value, b.get(key))) return false;\n }\n return true;\n }\n\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false;\n for (const value of a.values()) {\n let found = false;\n for (const candidate of b.values()) {\n if (deepEqual(value, candidate)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n return true;\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((item, i) => deepEqual(item, b[i]));\n }\n\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n\n const keysA = Object.keys(a as object);\n const keysB = Object.keys(b as object);\n\n if (keysA.length !== keysB.length) return false;\n\n return keysA.every((key) =>\n deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])\n );\n};\n\n/**\n * Detects if nested objects were mutated but the reference stayed the same.\n * Returns the keys where nested mutations were detected.\n * @internal\n */\nexport const detectNestedMutations = <S extends Record<string, unknown>>(\n before: S,\n after: S,\n signalValues: Map<keyof S, unknown>\n): Array<keyof S> => {\n const mutatedKeys: Array<keyof S> = [];\n\n for (const key of Object.keys(after) as Array<keyof S>) {\n const beforeValue = before[key];\n const afterValue = after[key];\n const signalValue = signalValues.get(key);\n\n // Check if it's the same reference but content changed\n if (\n signalValue === afterValue &&\n isPlainObject(beforeValue) &&\n isPlainObject(afterValue) &&\n !deepEqual(beforeValue, afterValue)\n ) {\n mutatedKeys.push(key);\n }\n }\n\n return mutatedKeys;\n};\n\n/** @internal Returns whether development warnings should be enabled */\nexport const isDev = (): boolean => detectDevEnvironment();\n","/**\n * Store creation logic.\n */\n\nimport { isPromise } from '../core/utils/type-guards';\nimport {\n batch,\n computed,\n signal,\n untrack,\n type ReadonlySignal,\n type Signal,\n} from '../reactive/index';\nimport { notifyDevtoolsStateChange, registerDevtoolsStore } from './devtools';\nimport { applyPlugins } from './plugins';\nimport { getStore, hasStore, registerStore } from './registry';\nimport type {\n ActionContext,\n Getters,\n OnActionCallback,\n Store,\n StoreDefinition,\n StoreSubscriber,\n} from './types';\nimport { deepClone, detectNestedMutations, isDev } from './utils';\n\n/**\n * Creates a reactive store with state, getters, and actions.\n *\n * @template S - State type\n * @template G - Getters type\n * @template A - Actions type\n * @param definition - Store definition\n * @returns The reactive store instance\n */\nexport const createStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown> = Record<string, never>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\n>(\n definition: StoreDefinition<S, G, A>\n): Store<S, G, A> => {\n const { id, state: stateFactory, getters = {} as Getters<S, G>, actions = {} as A } = definition;\n\n // Check for duplicate store IDs\n if (hasStore(id)) {\n console.warn(`bQuery store: Store \"${id}\" already exists. Returning existing instance.`);\n return getStore(id) as Store<S, G, A>;\n }\n\n // Create initial state\n const initialState = stateFactory();\n\n // Create signals for each state property\n const stateSignals = new Map<keyof S, Signal<unknown>>();\n for (const key of Object.keys(initialState) as Array<keyof S>) {\n stateSignals.set(key, signal(initialState[key]));\n }\n\n // Subscribers for $subscribe\n const subscribers: Array<StoreSubscriber<S>> = [];\n\n // Action lifecycle hooks for $onAction\n const actionListeners: Array<OnActionCallback<S, G, A>> = [];\n\n const reportOnActionError = (\n phase: 'listener' | 'after' | 'onError',\n actionName: string,\n error: unknown\n ): void => {\n if (!isDev() || typeof console === 'undefined' || typeof console.error !== 'function') return;\n console.error(\n `[bQuery store \"${id}\"] Error in $onAction ${phase} for action \"${actionName}\"`,\n error\n );\n };\n\n const warnedAsyncOnActionListeners = new WeakSet<OnActionCallback<S, G, A>>();\n\n const warnAsyncOnActionListener = (\n listener: OnActionCallback<S, G, A>,\n actionName: string\n ): void => {\n if (!isDev() || typeof console === 'undefined' || typeof console.warn !== 'function') return;\n if (warnedAsyncOnActionListeners.has(listener)) return;\n warnedAsyncOnActionListeners.add(listener);\n console.warn(\n `[bQuery store \"${id}\"] Async $onAction listener detected for action \"${actionName}\". If it awaits, register after()/onError() before the first await; late registrations will not affect the current action.`\n );\n };\n\n /**\n * Executes an action observer callback without allowing observer failures to\n * affect the action result. Handles both synchronous exceptions and async\n * rejections, routing all failures through the standard $onAction logger.\n *\n * @internal\n */\n const runOnActionCallback = (\n phase: 'listener' | 'after' | 'onError',\n actionName: string,\n callback: () => unknown,\n listener?: OnActionCallback<S, G, A>\n ): void => {\n try {\n const result = callback();\n if (isPromise(result)) {\n if (phase === 'listener' && listener) {\n warnAsyncOnActionListener(listener, actionName);\n }\n void result.catch((error) => {\n reportOnActionError(phase, actionName, error);\n });\n }\n } catch (error) {\n reportOnActionError(phase, actionName, error);\n }\n };\n\n /**\n * Gets the current state.\n *\n * For subscriber notifications (where a plain object snapshot is needed),\n * this creates a shallow copy. For internal reads, use stateProxy directly.\n *\n * **Note:** Returns a shallow snapshot. Nested object mutations will NOT\n * trigger reactive updates. This differs from frameworks like Pinia that\n * use deep reactivity. To update nested state, replace the entire object.\n *\n * Uses `untrack()` to prevent accidental dependency tracking when called\n * from within reactive contexts (e.g., `effect()` or `computed()`).\n *\n * @internal\n */\n const getCurrentState = (): S =>\n untrack(() => {\n return { ...stateProxy };\n });\n\n /**\n * Notifies subscribers of state changes.\n * Short-circuits if there are no subscribers and devtools aren't active\n * to avoid unnecessary snapshot overhead.\n * @internal\n */\n const notifySubscribers = (): void => {\n // Early return if no subscribers and no devtools hook\n const hasDevtools =\n typeof window !== 'undefined' &&\n typeof window.__BQUERY_DEVTOOLS__?.onStateChange === 'function';\n if (subscribers.length === 0 && !hasDevtools) {\n return;\n }\n\n const currentState = getCurrentState();\n for (const callback of subscribers) {\n callback(currentState);\n }\n\n notifyDevtoolsStateChange(id, currentState);\n };\n\n /**\n * Cached state proxy that lazily reads signal values.\n * Uses a Proxy to avoid creating new objects on each access.\n *\n * **Note:** This returns a shallow snapshot of the state. Nested object\n * mutations will NOT trigger reactive updates. For nested reactivity,\n * replace the entire object or use signals for nested properties.\n *\n * @internal\n */\n const stateProxy = new Proxy({} as S, {\n get: (_, prop: string | symbol) => {\n const key = prop as keyof S;\n if (stateSignals.has(key)) {\n return stateSignals.get(key)!.value;\n }\n return undefined;\n },\n ownKeys: () => Array.from(stateSignals.keys()) as string[],\n getOwnPropertyDescriptor: (_, prop) => {\n if (stateSignals.has(prop as keyof S)) {\n return { enumerable: true, configurable: true };\n }\n return undefined;\n },\n has: (_, prop) => stateSignals.has(prop as keyof S),\n });\n\n // Create computed getters\n const getterComputed = new Map<keyof G, ReadonlySignal<unknown>>();\n\n // Build the store proxy\n const store = {} as Store<S, G, A>;\n\n // Define state properties with getters/setters\n for (const key of Object.keys(initialState) as Array<keyof S>) {\n Object.defineProperty(store, key, {\n get: () => stateSignals.get(key)!.value,\n set: (value: unknown) => {\n stateSignals.get(key)!.value = value;\n notifySubscribers();\n },\n enumerable: true,\n configurable: false,\n });\n }\n\n // Define getters as computed properties\n for (const key of Object.keys(getters) as Array<keyof G>) {\n const getterFn = getters[key];\n\n // Create computed that reads from state signals via proxy (more efficient)\n const computedGetter = computed(() => {\n const state = stateProxy;\n // For getter dependencies, pass a proxy that reads from computed getters\n const getterProxy = new Proxy({} as G, {\n get: (_, prop: string | symbol) => {\n const propKey = prop as keyof G;\n if (getterComputed.has(propKey)) {\n return getterComputed.get(propKey)!.value;\n }\n return undefined;\n },\n });\n return getterFn(state, getterProxy);\n });\n\n getterComputed.set(key, computedGetter as unknown as ReadonlySignal<unknown>);\n\n Object.defineProperty(store, key, {\n get: () => computedGetter.value,\n enumerable: true,\n configurable: false,\n });\n }\n\n // Bind actions to the store context, with $onAction lifecycle support\n for (const key of Object.keys(actions) as Array<keyof A>) {\n const actionFn = actions[key];\n const actionName = key as keyof A & string;\n\n // Wrap action to enable 'this' binding and $onAction hooks\n (store as Record<string, unknown>)[actionName] = function (...args: unknown[]) {\n // Create a context that allows 'this.property' access\n const context = new Proxy(store, {\n get: (target, prop) => {\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\n return stateSignals.get(prop as keyof S)!.value;\n }\n return (target as Record<string, unknown>)[prop as string];\n },\n set: (target, prop, value) => {\n if (typeof prop === 'string' && stateSignals.has(prop as keyof S)) {\n stateSignals.get(prop as keyof S)!.value = value;\n notifySubscribers();\n return true;\n }\n // Allow non-state property assignments (e.g., temporary variables in actions)\n // by delegating to the target object rather than returning false\n return Reflect.set(target, prop, value);\n },\n });\n\n // Run $onAction hooks if any listeners are registered\n if (actionListeners.length === 0) {\n return actionFn.apply(context, args);\n }\n\n const afterHooks: Array<(result: unknown) => void> = [];\n const errorHooks: Array<(error: unknown) => void> = [];\n const listenerSnapshot = [...actionListeners];\n\n const listenerContext = {\n name: actionName,\n store,\n args: args as Parameters<A[typeof actionName]>,\n after: (callback: (result: Awaited<ReturnType<A[typeof actionName]>>) => void) => {\n afterHooks.push((result) =>\n callback(result as Awaited<ReturnType<A[typeof actionName]>>)\n );\n },\n onError: (callback: (error: unknown) => void) => {\n errorHooks.push(callback);\n },\n } satisfies ActionContext<S, G, A, typeof actionName>;\n\n // Notify all action listeners (before phase)\n for (const listener of listenerSnapshot) {\n runOnActionCallback('listener', actionName, () => listener(listenerContext), listener);\n }\n\n let result: unknown;\n try {\n result = actionFn.apply(context, args);\n } catch (error) {\n for (const hook of errorHooks) {\n runOnActionCallback('onError', actionName, () => hook(error));\n }\n throw error;\n }\n\n // Handle async actions (promises)\n if (isPromise(result)) {\n return result.then(\n (resolved) => {\n for (const hook of afterHooks) {\n runOnActionCallback('after', actionName, () => hook(resolved));\n }\n return resolved;\n },\n (error) => {\n for (const hook of errorHooks) {\n runOnActionCallback('onError', actionName, () => hook(error));\n }\n throw error;\n }\n );\n }\n\n // Sync action — run after hooks immediately\n for (const hook of afterHooks) {\n runOnActionCallback('after', actionName, () => hook(result));\n }\n return result;\n };\n }\n\n // Add store utility methods\n Object.defineProperties(store, {\n $id: {\n value: id,\n writable: false,\n enumerable: false,\n },\n $reset: {\n value: () => {\n const fresh = stateFactory();\n batch(() => {\n for (const [key, sig] of stateSignals) {\n sig.value = fresh[key];\n }\n });\n notifySubscribers();\n },\n writable: false,\n enumerable: false,\n },\n $subscribe: {\n value: (callback: StoreSubscriber<S>) => {\n subscribers.push(callback);\n return () => {\n const index = subscribers.indexOf(callback);\n if (index > -1) subscribers.splice(index, 1);\n };\n },\n writable: false,\n enumerable: false,\n },\n $onAction: {\n value: (callback: OnActionCallback<S, G, A>) => {\n actionListeners.push(callback);\n return () => {\n const index = actionListeners.indexOf(callback);\n if (index > -1) actionListeners.splice(index, 1);\n };\n },\n writable: false,\n enumerable: false,\n },\n $patch: {\n value: (partial: Partial<S> | ((state: S) => void)) => {\n batch(() => {\n if (typeof partial === 'function') {\n // Capture state before mutation for nested mutation detection\n const devMode = isDev();\n const stateBefore = devMode ? deepClone(getCurrentState()) : null;\n const signalValuesBefore = devMode\n ? new Map(Array.from(stateSignals.entries()).map(([k, s]) => [k, s.value]))\n : null;\n\n // Mutation function\n const state = getCurrentState();\n partial(state);\n\n // Detect nested mutations in development mode\n if (devMode && stateBefore && signalValuesBefore) {\n const mutatedKeys = detectNestedMutations(stateBefore, state, signalValuesBefore);\n if (mutatedKeys.length > 0) {\n console.warn(\n `[bQuery store \"${id}\"] Nested mutation detected in $patch() for keys: ${mutatedKeys\n .map(String)\n .join(', ')}.\\n` +\n 'Nested object mutations do not trigger reactive updates because the store uses shallow reactivity.\\n' +\n 'To fix this, either:\\n' +\n ' 1. Replace the entire object: state.user = { ...state.user, name: \"New\" }\\n' +\n ' 2. Use $patchDeep() for automatic deep cloning\\n' +\n 'See: https://bquery.dev/guide/store#deep-reactivity'\n );\n }\n }\n\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = value;\n }\n }\n } else {\n // Partial object\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = value;\n }\n }\n }\n });\n notifySubscribers();\n },\n writable: false,\n enumerable: false,\n },\n $patchDeep: {\n value: (partial: Partial<S> | ((state: S) => void)) => {\n batch(() => {\n if (typeof partial === 'function') {\n // Deep clone state before mutation to ensure new references\n const state = deepClone(getCurrentState());\n partial(state);\n\n for (const [key, value] of Object.entries(state) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = value;\n }\n }\n } else {\n // Deep clone each value in partial to ensure new references\n for (const [key, value] of Object.entries(partial) as Array<[keyof S, unknown]>) {\n if (stateSignals.has(key)) {\n stateSignals.get(key)!.value = deepClone(value);\n }\n }\n }\n });\n notifySubscribers();\n },\n writable: false,\n enumerable: false,\n },\n $state: {\n get: () => getCurrentState(),\n enumerable: false,\n },\n });\n\n // Register store\n registerStore(id, store);\n\n // Apply plugins\n applyPlugins(store, definition);\n\n // Notify devtools\n registerDevtoolsStore(id, store);\n\n return store;\n};\n","/**\n * Store factory helpers.\n */\n\nimport { createStore } from './create-store';\nimport { getStore, hasStore } from './registry';\nimport type { Store, StoreDefinition } from './types';\n\n/**\n * Creates a store factory that returns the store instance.\n *\n * The store is lazily created on first call and cached in the global store\n * registry. Subsequent calls return the same instance. After calling\n * `destroyStore(id)`, the next factory call will create a fresh store.\n *\n * @param id - Store identifier\n * @param definition - Store definition without id\n * @returns A function that returns the store instance\n *\n * @example\n * ```ts\n * const useCounter = defineStore('counter', {\n * state: () => ({ count: 0 }),\n * actions: { increment() { this.count++; } },\n * });\n *\n * const counter = useCounter();\n * counter.increment();\n * ```\n */\nexport const defineStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown> = Record<string, never>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\n>(\n id: string,\n definition: Omit<StoreDefinition<S, G, A>, 'id'>\n): (() => Store<S, G, A>) => {\n // Check registry first to avoid noisy warnings from createStore()\n // when the factory is called multiple times (intended usage pattern).\n // createStore() only called when store doesn't exist or was destroyed.\n return () => {\n if (hasStore(id)) {\n return getStore(id) as Store<S, G, A>;\n }\n return createStore({ id, ...definition });\n };\n};\n","/**\n * Mapping helpers for store state and actions.\n */\n\n/**\n * Maps store state properties to a reactive object for use in components.\n *\n * @param store - The store instance\n * @param keys - State keys to map\n * @returns Object with mapped properties\n */\nexport const mapState = <S extends Record<string, unknown>, K extends keyof S>(\n store: S,\n keys: K[]\n): Pick<S, K> => {\n const mapped = {} as Pick<S, K>;\n\n for (const key of keys) {\n Object.defineProperty(mapped, key, {\n get: () => store[key],\n enumerable: true,\n });\n }\n\n return mapped;\n};\n\n/**\n * Maps store getters to a reactive object for use in components.\n *\n * @param store - The store instance\n * @param keys - Getter keys to map\n * @returns Object with mapped getters\n */\nexport const mapGetters = <G extends Record<string, unknown>, K extends keyof G>(\n store: G,\n keys: K[]\n): Pick<G, K> => {\n const mapped = {} as Pick<G, K>;\n\n for (const key of keys) {\n Object.defineProperty(mapped, key, {\n get: () => store[key],\n enumerable: true,\n });\n }\n\n return mapped;\n};\n\n/**\n * Maps store actions to an object for easier destructuring.\n *\n * @param store - The store instance\n * @param keys - Action keys to map\n * @returns Object with mapped actions\n */\nexport const mapActions = <\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any>,\n K extends keyof A,\n>(\n store: A,\n keys: K[]\n): Pick<A, K> => {\n const mapped = {} as Pick<A, K>;\n\n for (const key of keys) {\n (mapped as Record<string, unknown>)[key as string] = (...args: unknown[]) =>\n (store[key] as (...args: unknown[]) => unknown)(...args);\n }\n\n return mapped;\n};\n","/**\n * Store persistence helpers.\n */\n\nimport { isPrototypePollutionKey } from '../core/utils/object';\nimport { createStore } from './create-store';\nimport { isDev } from './utils';\nimport type { PersistedStoreOptions, StorageBackend, Store, StoreDefinition } from './types';\n\n/** @internal Version key suffix */\nconst VERSION_SUFFIX = '__version';\n\n/** @internal Default JSON serializer */\nconst defaultSerializer = {\n serialize: (state: unknown) => JSON.stringify(state),\n deserialize: (raw: string) => JSON.parse(raw) as unknown,\n};\n\n/** @internal Check whether a value can be merged into store state. */\nconst isPersistedStateObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n};\n\n/**\n * Applies persisted state onto the default state while ignoring dangerous\n * prototype-pollution keys such as `__proto__`, `constructor`, and `prototype`.\n *\n * @internal\n */\nconst mergePersistedState = <S extends Record<string, unknown>>(\n defaultState: S,\n persisted: Record<string, unknown>\n): S => {\n const merged = { ...defaultState };\n for (const [key, value] of Object.entries(persisted)) {\n if (isPrototypePollutionKey(key)) continue;\n if (!Object.prototype.hasOwnProperty.call(defaultState, key)) continue;\n merged[key as keyof S] = value as S[keyof S];\n }\n return merged;\n};\n\n/** @internal Resolve the default storage backend safely. */\nconst getDefaultStorage = (): StorageBackend | undefined => {\n try {\n return globalThis.localStorage;\n } catch {\n return undefined;\n }\n};\n\n/**\n * Creates a store with automatic persistence.\n *\n * Supports configurable storage backends, custom serializers, and schema\n * versioning with migration functions. All options are optional and\n * backward-compatible with the simple `(definition, storageKey?)` signature.\n *\n * @param definition - Store definition\n * @param options - Persistence options or a plain string storage key for backward compatibility\n * @returns The reactive store instance\n *\n * @example Basic usage (localStorage + JSON)\n * ```ts\n * const store = createPersistedStore({\n * id: 'settings',\n * state: () => ({ theme: 'dark' }),\n * });\n * ```\n *\n * @example With sessionStorage and custom key\n * ```ts\n * const store = createPersistedStore(\n * { id: 'session', state: () => ({ token: '' }) },\n * { key: 'my-session', storage: sessionStorage },\n * );\n * ```\n *\n * @example With versioning and migration\n * ```ts\n * const store = createPersistedStore(\n * { id: 'app', state: () => ({ name: '', theme: 'auto' }) },\n * {\n * version: 2,\n * migrate: (old, v) => {\n * if (v < 2) return { ...old, theme: 'auto' };\n * return old;\n * },\n * },\n * );\n * ```\n */\nexport const createPersistedStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown> = Record<string, never>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any> = Record<string, never>,\n>(\n definition: StoreDefinition<S, G, A>,\n options?: PersistedStoreOptions | string\n): Store<S, G, A> => {\n // Normalize options — a plain string is treated as the storage key for backward compatibility\n const opts: PersistedStoreOptions =\n typeof options === 'string' ? { key: options } : (options ?? {});\n\n const key = opts.key ?? `bquery-store-${definition.id}`;\n const storage = opts.storage ?? getDefaultStorage();\n const serializer = opts.serializer ?? defaultSerializer;\n const version = opts.version;\n const migrate = opts.migrate;\n const versionKey = key + VERSION_SUFFIX;\n let shouldPersistInitialVersion = storage !== undefined && version !== undefined;\n let pendingVersionWrite = false;\n let canRetryPendingVersionAfterCreate = false;\n\n const tryPersistVersion = (warningMessage?: string): boolean => {\n if (!storage || version === undefined) return false;\n\n try {\n storage.setItem(versionKey, String(version));\n return true;\n } catch (error) {\n if (\n warningMessage &&\n isDev() &&\n typeof console !== 'undefined' &&\n typeof console.warn === 'function'\n ) {\n console.warn(warningMessage, error);\n }\n return false;\n }\n };\n\n const originalStateFactory = definition.state;\n\n const wrappedDefinition: StoreDefinition<S, G, A> = {\n ...definition,\n state: () => {\n const defaultState = originalStateFactory();\n\n if (!storage) return defaultState;\n\n try {\n const saved = storage.getItem(key);\n if (!saved) return defaultState;\n\n const deserialized = serializer.deserialize(saved);\n if (!isPersistedStateObject(deserialized)) {\n return defaultState;\n }\n\n let persisted = deserialized;\n\n // Handle versioning & migration\n if (version !== undefined && migrate) {\n const rawVersion = storage.getItem(versionKey);\n const parsedVersion = rawVersion !== null ? Number(rawVersion) : 0;\n const oldVersion = Number.isFinite(parsedVersion) ? parsedVersion : 0;\n\n if (oldVersion !== version) {\n shouldPersistInitialVersion = false;\n pendingVersionWrite = true;\n const migrated = migrate(persisted, oldVersion);\n if (!isPersistedStateObject(migrated)) {\n return defaultState;\n }\n persisted = migrated;\n\n let migratedStatePersisted = false;\n // Save the migrated state and version immediately when possible.\n // If the state write fails, never advance the version key.\n try {\n storage.setItem(key, serializer.serialize(persisted));\n migratedStatePersisted = true;\n canRetryPendingVersionAfterCreate = true;\n } catch (e) {\n // Migration will re-run on next load, but state is still usable\n if (isDev() && typeof console !== 'undefined' && typeof console.warn === 'function') {\n console.warn(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated state:`,\n e\n );\n }\n }\n\n if (\n migratedStatePersisted &&\n tryPersistVersion(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version:`\n )\n ) {\n pendingVersionWrite = false;\n }\n } else {\n shouldPersistInitialVersion = false;\n }\n }\n\n return mergePersistedState(defaultState, persisted);\n } catch {\n // Ignore parse errors\n return defaultState;\n }\n },\n };\n\n const store = createStore(wrappedDefinition);\n\n // Persist the version number on first creation\n if (shouldPersistInitialVersion && storage) {\n tryPersistVersion();\n } else if (\n pendingVersionWrite &&\n canRetryPendingVersionAfterCreate &&\n tryPersistVersion(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version after store creation:`\n )\n ) {\n pendingVersionWrite = false;\n }\n\n // Subscribe to save changes\n store.$subscribe((state) => {\n if (!storage) return;\n try {\n storage.setItem(key, serializer.serialize(state));\n if (\n pendingVersionWrite &&\n tryPersistVersion(\n `[bQuery store \"${definition.id}\"] Failed to persist migrated version after a successful state write:`\n )\n ) {\n pendingVersionWrite = false;\n }\n } catch {\n // Ignore quota errors\n }\n });\n\n return store;\n};\n","/**\n * Store watch helpers.\n */\n\nimport type { Store } from './types';\nimport { deepEqual } from './utils';\n\nexport type WatchStoreOptions<T> = {\n /** Call the callback immediately with the current value. */\n immediate?: boolean;\n /** Use deep comparison when determining changes. */\n deep?: boolean;\n /** Custom equality check for selected values. */\n equals?: (a: T, b: T) => boolean;\n};\n\n/**\n * Watch a selected slice of store state.\n *\n * @param store - The store instance\n * @param selector - Function to select the watched value\n * @param callback - Called when the selected value changes\n * @param options - Watch options\n * @returns Unsubscribe function\n */\nexport const watchStore = <\n S extends Record<string, unknown>,\n G extends Record<string, unknown>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- actions may declare specific parameter types\n A extends Record<string, (...args: any[]) => any>,\n T,\n>(\n store: Store<S, G, A>,\n selector: (state: S) => T,\n callback: (value: T, previous: T | undefined) => void,\n options: WatchStoreOptions<T> = {}\n): (() => void) => {\n const equals = options.equals ?? (options.deep ? deepEqual : Object.is);\n let previous = selector(store.$state);\n\n if (options.immediate) {\n callback(previous, undefined);\n }\n\n return store.$subscribe((state) => {\n const current = selector(state);\n if (!equals(current, previous)) {\n const prev = previous;\n previous = current;\n callback(current, prev);\n }\n });\n};\n","import { isPrototypePollutionKey } from '../core/utils/object';\nimport { isComputed, isSignal, type Signal } from '../reactive/index';\nimport type { BindingContext } from './types';\n\n/** Maximum number of cached expression functions before LRU eviction */\nconst MAX_CACHE_SIZE = 500;\n\n/** Compiled function type for expression evaluation */\ntype CompiledFn = (ctx: BindingContext) => unknown;\n\n/**\n * Simple LRU cache for compiled expression functions.\n * Uses Map's insertion order to track recency - accessed items are re-inserted.\n * @internal\n */\nclass LRUCache {\n private cache = new Map<string, CompiledFn>();\n private maxSize: number;\n\n constructor(maxSize: number) {\n this.maxSize = maxSize;\n }\n\n get(key: string): CompiledFn | undefined {\n const value = this.cache.get(key);\n if (value !== undefined) {\n // Move to end (most recently used) by re-inserting\n this.cache.delete(key);\n this.cache.set(key, value);\n }\n return value;\n }\n\n set(key: string, value: CompiledFn): void {\n // Delete first if exists to update insertion order\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxSize) {\n // Evict oldest (first) entry\n const oldest = this.cache.keys().next().value;\n if (oldest !== undefined) {\n this.cache.delete(oldest);\n }\n }\n this.cache.set(key, value);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n get size(): number {\n return this.cache.size;\n }\n}\n\n/** LRU cache for compiled evaluate functions, keyed by expression string */\nconst evaluateCache = new LRUCache(MAX_CACHE_SIZE);\n\n/** LRU cache for compiled evaluateRaw functions, keyed by expression string */\nconst evaluateRawCache = new LRUCache(MAX_CACHE_SIZE);\n\n/**\n * Clears all cached compiled expression functions.\n * Call this when unmounting views or to free memory after heavy template usage.\n *\n * @example\n * ```ts\n * import { clearExpressionCache } from 'bquery/view';\n *\n * // After destroying a view or when cleaning up\n * clearExpressionCache();\n * ```\n */\nexport const clearExpressionCache = (): void => {\n evaluateCache.clear();\n evaluateRawCache.clear();\n};\n\n/**\n * Creates a proxy that lazily unwraps signals/computed only when accessed.\n * This avoids subscribing to signals that aren't referenced in the expression.\n * @internal\n */\nconst createLazyContext = (context: BindingContext): BindingContext =>\n new Proxy(context, {\n get(target, prop: string | symbol) {\n // Only handle string keys for BindingContext indexing\n if (typeof prop !== 'string') {\n return Reflect.get(target, prop);\n }\n const value = target[prop];\n // Auto-unwrap signals/computed only when actually accessed\n if (isSignal(value) || isComputed(value)) {\n return (value as Signal<unknown>).value;\n }\n return value;\n },\n has(target, prop: string | symbol) {\n // Required for `with` statement to resolve identifiers correctly\n if (typeof prop !== 'string') {\n return Reflect.has(target, prop);\n }\n return prop in target;\n },\n });\n\n/**\n * Evaluates an expression in the given context using `new Function()`.\n *\n * Signals and computed values in the context are lazily unwrapped only when\n * accessed by the expression, avoiding unnecessary subscriptions to unused values.\n *\n * @security **WARNING:** This function uses dynamic code execution via `new Function()`.\n * - NEVER pass expressions derived from user input or untrusted sources\n * - Expressions should only come from developer-controlled templates\n * - Malicious expressions can access and exfiltrate context data\n * - Consider this equivalent to `eval()` in terms of security implications\n *\n * @internal\n */\nexport const evaluate = <T = unknown>(expression: string, context: BindingContext): T => {\n try {\n // Create a proxy that lazily unwraps signals/computed on access\n const lazyContext = createLazyContext(context);\n\n // Use cached function or compile and cache a new one\n let fn = evaluateCache.get(expression);\n if (!fn) {\n // Use `with` to enable direct property access from proxy scope.\n // Note: `new Function()` runs in non-strict mode, so `with` is allowed.\n fn = new Function('$ctx', `with($ctx) { return (${expression}); }`) as (\n ctx: BindingContext\n ) => unknown;\n evaluateCache.set(expression, fn);\n }\n return fn(lazyContext) as T;\n } catch (error) {\n console.error(`bQuery view: Error evaluating \"${expression}\"`, error);\n return undefined as T;\n }\n};\n\n/**\n * Evaluates an expression and returns the raw value (for signal access).\n *\n * @security **WARNING:** Uses dynamic code execution. See {@link evaluate} for security notes.\n * @internal\n */\nexport const evaluateRaw = <T = unknown>(expression: string, context: BindingContext): T => {\n try {\n // Use cached function or compile and cache a new one\n let fn = evaluateRawCache.get(expression);\n if (!fn) {\n // Use `with` to enable direct property access from context scope.\n // Unlike `evaluate`, we don't use a lazy proxy - values are accessed directly.\n fn = new Function('$ctx', `with($ctx) { return (${expression}); }`) as (\n ctx: BindingContext\n ) => unknown;\n evaluateRawCache.set(expression, fn);\n }\n return fn(context) as T;\n } catch (error) {\n console.error(`bQuery view: Error evaluating \"${expression}\"`, error);\n return undefined as T;\n }\n};\n\n/**\n * Parses object expression like \"{ active: isActive, disabled: !enabled }\".\n * Handles nested structures like function calls, arrays, and template literals.\n * @internal\n */\nexport const parseObjectExpression = (expression: string): Record<string, string> => {\n const result: Record<string, string> = {};\n\n // Remove outer braces and trim\n const inner = expression\n .trim()\n .replace(/^\\{|\\}$/g, '')\n .trim();\n if (!inner) return result;\n\n // Split by comma at depth 0, respecting strings and nesting\n const parts: string[] = [];\n let current = '';\n let depth = 0;\n let inString: string | null = null;\n\n for (let i = 0; i < inner.length; i++) {\n const char = inner[i];\n\n // Handle string literals: count consecutive backslashes before a quote\n // to correctly distinguish escaped quotes from end-of-string\n if (char === '\"' || char === \"'\" || char === '`') {\n let backslashCount = 0;\n let j = i - 1;\n while (j >= 0 && inner[j] === '\\\\') {\n backslashCount++;\n j--;\n }\n // Quote is escaped only if preceded by an odd number of backslashes\n if (backslashCount % 2 === 0) {\n if (inString === null) {\n inString = char;\n } else if (inString === char) {\n inString = null;\n }\n }\n current += char;\n continue;\n }\n\n // Skip if inside string\n if (inString !== null) {\n current += char;\n continue;\n }\n\n // Track nesting depth for parentheses, brackets, and braces\n if (char === '(' || char === '[' || char === '{') {\n depth++;\n current += char;\n } else if (char === ')' || char === ']' || char === '}') {\n depth--;\n current += char;\n } else if (char === ',' && depth === 0) {\n // Top-level comma - split point\n parts.push(current.trim());\n current = '';\n } else {\n current += char;\n }\n }\n\n // Add the last part\n if (current.trim()) {\n parts.push(current.trim());\n }\n\n // Parse each part to extract key and value\n for (const part of parts) {\n // Find the first colon at depth 0 (to handle ternary operators in values)\n let colonIndex = -1;\n let partDepth = 0;\n let partInString: string | null = null;\n\n for (let i = 0; i < part.length; i++) {\n const char = part[i];\n\n if (char === '\"' || char === \"'\" || char === '`') {\n let backslashCount = 0;\n let j = i - 1;\n while (j >= 0 && part[j] === '\\\\') {\n backslashCount++;\n j--;\n }\n if (backslashCount % 2 === 0) {\n if (partInString === null) {\n partInString = char;\n } else if (partInString === char) {\n partInString = null;\n }\n }\n continue;\n }\n\n if (partInString !== null) continue;\n\n if (char === '(' || char === '[' || char === '{') {\n partDepth++;\n } else if (char === ')' || char === ']' || char === '}') {\n partDepth--;\n } else if (char === ':' && partDepth === 0) {\n colonIndex = i;\n break;\n }\n }\n\n if (colonIndex > -1) {\n const key = part\n .slice(0, colonIndex)\n .trim()\n .replace(/^['\"]|['\"]$/g, '');\n if (isPrototypePollutionKey(key)) continue;\n const value = part.slice(colonIndex + 1).trim();\n result[key] = value;\n }\n }\n\n return result;\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-bind:attr directive - attribute binding.\n * @internal\n */\nexport const handleBind = (attrName: string): DirectiveHandler => {\n return (el, expression, context, cleanups) => {\n const cleanup = effect(() => {\n const value = evaluate(expression, context);\n if (value == null || value === false) {\n el.removeAttribute(attrName);\n } else if (value === true) {\n el.setAttribute(attrName, '');\n } else {\n el.setAttribute(attrName, String(value));\n }\n });\n cleanups.push(cleanup);\n };\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate, parseObjectExpression } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-class directive - dynamic class binding.\n * Tracks previously added classes to ensure proper cleanup when expressions change.\n * @internal\n */\nexport const handleClass: DirectiveHandler = (el, expression, context, cleanups) => {\n // Track classes added by this directive to clean them up on re-evaluation\n let previousClasses: Set<string> = new Set();\n\n const cleanup = effect(() => {\n const newClasses: Set<string> = new Set();\n\n if (expression.trimStart().startsWith('{')) {\n // Object syntax: { active: isActive, disabled: !enabled }\n const classMap = parseObjectExpression(expression);\n for (const [className, conditionExpr] of Object.entries(classMap)) {\n const condition = evaluate<boolean>(conditionExpr, context);\n el.classList.toggle(className, Boolean(condition));\n // Track class regardless of condition - toggle handles add/remove\n newClasses.add(className);\n }\n } else if (/^\\s*\\[/.test(expression)) {\n // Array literal syntax: [class1, class2]\n const classes = evaluate<string[]>(expression, context);\n if (Array.isArray(classes)) {\n for (const cls of classes) {\n if (cls) {\n el.classList.add(cls);\n newClasses.add(cls);\n }\n }\n }\n } else {\n // Single expression returning string or array\n const result = evaluate<string | string[]>(expression, context);\n if (typeof result === 'string') {\n result.split(/\\s+/).forEach((cls) => {\n if (cls) {\n el.classList.add(cls);\n newClasses.add(cls);\n }\n });\n } else if (Array.isArray(result)) {\n result.forEach((cls) => {\n if (cls) {\n el.classList.add(cls);\n newClasses.add(cls);\n }\n });\n }\n }\n\n // Remove classes that were previously added but are no longer in the new set\n // This keeps directive-managed classes in sync across all syntax forms and provides\n // defensive cleanup behavior for edge cases (e.g. external classList changes)\n for (const cls of previousClasses) {\n if (!newClasses.has(cls)) {\n el.classList.remove(cls);\n }\n }\n\n previousClasses = newClasses;\n });\n\n cleanups.push(cleanup);\n};\n","import { effect, signal, type CleanupFn, type Signal } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { BindingContext, DirectiveHandler } from '../types';\n\ntype ProcessElementFn = (\n el: Element,\n context: BindingContext,\n prefix: string,\n cleanups: CleanupFn[]\n) => void;\n\ntype ProcessChildrenFn = (\n el: Element,\n context: BindingContext,\n prefix: string,\n cleanups: CleanupFn[]\n) => void;\n\n/**\n * Represents a rendered item in bq-for with its DOM element and associated cleanup functions.\n * @internal\n */\ntype RenderedItem = {\n key: unknown;\n element: Element;\n cleanups: CleanupFn[];\n item: unknown;\n index: number;\n itemSignal: Signal<unknown>; // Reactive item value for item-dependent bindings\n indexSignal: Signal<number> | null; // Reactive index for index-dependent bindings\n};\n\n/**\n * Extracts a key from an item using the key expression or falls back to index.\n * @internal\n */\nconst getItemKey = (\n item: unknown,\n index: number,\n keyExpression: string | null,\n itemName: string,\n indexName: string | undefined,\n context: BindingContext\n): unknown => {\n if (!keyExpression) {\n return index; // Fallback to index-based keying\n }\n\n const keyContext: BindingContext = {\n ...context,\n [itemName]: item,\n };\n if (indexName) {\n keyContext[indexName] = index;\n }\n\n return evaluate(keyExpression, keyContext);\n};\n\n/**\n * Handles bq-for directive - list rendering with keyed reconciliation.\n *\n * Supports optional `:key` attribute for efficient DOM reuse:\n * ```html\n * <li bq-for=\"item in items\" :key=\"item.id\">...</li>\n * ```\n *\n * Without a key, falls back to index-based tracking (less efficient for reordering).\n *\n * @internal\n */\nexport const createForHandler = (options: {\n prefix: string;\n processElement: ProcessElementFn;\n processChildren: ProcessChildrenFn;\n}): DirectiveHandler => {\n const { prefix, processElement, processChildren } = options;\n\n return (el, expression, context, cleanups) => {\n const parent = el.parentNode;\n if (!parent) return;\n\n // Parse expression: \"item in items\" or \"(item, index) in items\"\n // Use \\S.* instead of .+ to prevent ReDoS by requiring non-whitespace start\n const match = expression.match(/^\\(?(\\w+)(?:\\s*,\\s*(\\w+))?\\)?\\s+in\\s+(\\S.*)$/);\n if (!match) {\n console.error(`bQuery view: Invalid bq-for expression \"${expression}\"`);\n return;\n }\n\n const [, itemName, indexName, listExpression] = match;\n\n // Extract :key attribute if present\n const keyExpression = el.getAttribute(':key') || el.getAttribute(`${prefix}-key`);\n\n const template = el.cloneNode(true) as Element;\n template.removeAttribute(`${prefix}-for`);\n template.removeAttribute(':key');\n template.removeAttribute(`${prefix}-key`);\n\n // Create placeholder comment\n const placeholder = document.createComment(`bq-for: ${expression}`);\n parent.replaceChild(placeholder, el);\n\n // Track rendered items by key for reconciliation\n let renderedItemsMap = new Map<unknown, RenderedItem>();\n let renderedOrder: unknown[] = [];\n\n /**\n * Creates a new DOM element for an item.\n */\n const createItemElement = (item: unknown, index: number, key: unknown): RenderedItem => {\n const clone = template.cloneNode(true) as Element;\n const itemCleanups: CleanupFn[] = [];\n\n // Create reactive signals for item and index\n const itemSig = signal(item);\n const indexSig = indexName ? signal(index) : null;\n\n const childContext: BindingContext = {\n ...context,\n [itemName]: itemSig,\n };\n if (indexName && indexSig) {\n childContext[indexName] = indexSig;\n }\n\n // Process bindings on the clone\n processElement(clone, childContext, prefix, itemCleanups);\n processChildren(clone, childContext, prefix, itemCleanups);\n\n return {\n key,\n element: clone,\n cleanups: itemCleanups,\n item,\n index,\n itemSignal: itemSig,\n indexSignal: indexSig,\n };\n };\n\n /**\n * Removes a rendered item and cleans up its effects.\n */\n const removeItem = (rendered: RenderedItem): void => {\n for (const cleanup of rendered.cleanups) {\n cleanup();\n }\n rendered.element.remove();\n };\n\n /**\n * Updates an existing item's data and index when reused.\n * Updates the reactive signals so bindings re-render.\n */\n const updateItem = (rendered: RenderedItem, newItem: unknown, newIndex: number): void => {\n // Update item if it changed\n if (!Object.is(rendered.item, newItem)) {\n rendered.item = newItem;\n rendered.itemSignal.value = newItem;\n }\n\n // Update index if it changed\n if (rendered.index !== newIndex) {\n rendered.index = newIndex;\n if (rendered.indexSignal) {\n rendered.indexSignal.value = newIndex;\n }\n }\n };\n\n const cleanup = effect(() => {\n const list = evaluate<unknown[]>(listExpression, context);\n\n if (!Array.isArray(list)) {\n // Clear all if list is invalid\n for (const rendered of renderedItemsMap.values()) {\n removeItem(rendered);\n }\n renderedItemsMap.clear();\n renderedOrder = [];\n return;\n }\n\n // Build new key order and detect changes\n const newKeys: unknown[] = [];\n const newItemsByKey = new Map<unknown, { item: unknown; index: number }>();\n const seenKeys = new Set<unknown>();\n\n list.forEach((item, index) => {\n let key = getItemKey(item, index, keyExpression, itemName, indexName, context);\n\n // Detect duplicate keys - warn developer and fall back to unique composite key\n if (seenKeys.has(key)) {\n console.warn(\n `bq-for: Duplicate key \"${String(key)}\" detected at index ${index}. ` +\n `Falling back to index-based key for this item. ` +\n `Ensure :key expressions produce unique values for each item.`\n );\n // Create a unique composite key to avoid corrupting rendered output\n key = { __bqDuplicateKey: key, __bqIndex: index };\n }\n seenKeys.add(key);\n\n newKeys.push(key);\n newItemsByKey.set(key, { item, index });\n });\n\n // Identify items to remove (in old but not in new)\n const keysToRemove: unknown[] = [];\n for (const key of renderedOrder) {\n if (!newItemsByKey.has(key)) {\n keysToRemove.push(key);\n }\n }\n\n // Remove deleted items\n for (const key of keysToRemove) {\n const rendered = renderedItemsMap.get(key);\n if (rendered) {\n removeItem(rendered);\n renderedItemsMap.delete(key);\n }\n }\n\n // Process new list: create new items, update indices, reorder\n const newRenderedMap = new Map<unknown, RenderedItem>();\n let lastInsertedElement: Element | Comment = placeholder;\n\n for (let i = 0; i < newKeys.length; i++) {\n const key = newKeys[i];\n const { item, index } = newItemsByKey.get(key)!;\n let rendered = renderedItemsMap.get(key);\n\n if (rendered) {\n // Reuse existing element\n updateItem(rendered, item, index);\n newRenderedMap.set(key, rendered);\n\n // Check if element needs to be moved\n const currentNext: ChildNode | null = lastInsertedElement.nextSibling;\n if (currentNext !== rendered.element) {\n // Move element to correct position\n lastInsertedElement.after(rendered.element);\n }\n lastInsertedElement = rendered.element;\n } else {\n // Create new element\n rendered = createItemElement(item, index, key);\n newRenderedMap.set(key, rendered);\n\n // Insert at correct position\n lastInsertedElement.after(rendered.element);\n lastInsertedElement = rendered.element;\n }\n }\n\n // Update tracking state\n renderedItemsMap = newRenderedMap;\n renderedOrder = newKeys;\n });\n\n // When the bq-for itself is cleaned up, also cleanup all rendered items\n cleanups.push(() => {\n cleanup();\n for (const rendered of renderedItemsMap.values()) {\n for (const itemCleanup of rendered.cleanups) {\n itemCleanup();\n }\n }\n renderedItemsMap.clear();\n });\n };\n};\n","import { effect } from '../../reactive/index';\nimport { sanitizeHtml } from '../../security/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-html directive - sets innerHTML (sanitized by default).\n * @internal\n */\nexport const handleHtml = (sanitize: boolean): DirectiveHandler => {\n return (el, expression, context, cleanups) => {\n const cleanup = effect(() => {\n const value = evaluate<string>(expression, context);\n const html = String(value ?? '');\n el.innerHTML = sanitize ? sanitizeHtml(html) : html;\n });\n cleanups.push(cleanup);\n };\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-if directive - conditional rendering.\n * @internal\n */\nexport const handleIf: DirectiveHandler = (el, expression, context, cleanups) => {\n const placeholder = document.createComment(`bq-if: ${expression}`);\n\n // Store original element state\n let isInserted = true;\n\n const cleanup = effect(() => {\n const condition = evaluate<boolean>(expression, context);\n\n if (condition && !isInserted) {\n // Insert element using replaceWith to handle moved elements\n placeholder.replaceWith(el);\n isInserted = true;\n } else if (!condition && isInserted) {\n // Remove element using replaceWith to handle moved elements\n el.replaceWith(placeholder);\n isInserted = false;\n }\n });\n\n cleanups.push(cleanup);\n};\n","import { effect, isSignal, type Signal } from '../../reactive/index';\nimport { evaluateRaw } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-model directive - two-way binding.\n * @internal\n */\nexport const handleModel: DirectiveHandler = (el, expression, context, cleanups) => {\n const input = el as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n const rawValue = evaluateRaw<Signal<unknown>>(expression, context);\n\n if (!isSignal(rawValue)) {\n console.warn(`bQuery view: bq-model requires a signal, got \"${expression}\"`);\n return;\n }\n\n const sig = rawValue as Signal<unknown>;\n\n // Initial value sync\n const isCheckbox = input.type === 'checkbox';\n const isRadio = input.type === 'radio';\n\n const updateInput = () => {\n if (isCheckbox) {\n (input as HTMLInputElement).checked = Boolean(sig.value);\n } else if (isRadio) {\n (input as HTMLInputElement).checked = sig.value === input.value;\n } else {\n input.value = String(sig.value ?? '');\n }\n };\n\n // Effect to sync signal -> input\n const cleanup = effect(() => {\n updateInput();\n });\n cleanups.push(cleanup);\n\n // Event listener to sync input -> signal\n const eventType = input.tagName === 'SELECT' ? 'change' : 'input';\n const handler = () => {\n if (isCheckbox) {\n sig.value = (input as HTMLInputElement).checked;\n } else if (isRadio) {\n if ((input as HTMLInputElement).checked) {\n sig.value = input.value;\n }\n } else {\n sig.value = input.value;\n }\n };\n\n input.addEventListener(eventType, handler);\n cleanups.push(() => input.removeEventListener(eventType, handler));\n};\n","import { evaluateRaw } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-on:event directive - event binding.\n * @internal\n */\nexport const handleOn = (eventName: string): DirectiveHandler => {\n return (el, expression, context, cleanups) => {\n const handler = (event: Event) => {\n // Add $event to context for expression evaluation\n const eventContext = { ...context, $event: event, $el: el };\n\n // Check if expression contains a function call (has parentheses)\n // If not, it might be a plain function reference like \"handleClick\"\n // Note: Method references like \"handlers.onClick\" will lose their receiver\n // when auto-invoked. For methods, use explicit calls: \"handlers.onClick($event)\"\n const containsCall = expression.includes('(');\n\n if (!containsCall) {\n // Evaluate the expression - if it returns a function, invoke it with $event\n const result = evaluateRaw<unknown>(expression, eventContext);\n if (typeof result === 'function') {\n // Auto-invoke with event. Note: `this` will be undefined for method references.\n // For proper method binding, use explicit syntax: \"obj.method($event)\"\n result(event);\n return;\n }\n // If not a function, the expression was already evaluated (e.g., \"count.value++\")\n return;\n }\n\n // Otherwise evaluate as expression using evaluateRaw to allow signal mutations\n // (e.g., \"count.value++\" or \"handleClick($event)\")\n evaluateRaw(expression, eventContext);\n };\n\n el.addEventListener(eventName, handler);\n cleanups.push(() => el.removeEventListener(eventName, handler));\n };\n};\n","import { isSignal, type Signal } from '../../reactive/index';\nimport { evaluateRaw } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Checks if an object has a writable `value` property.\n * Returns true if `value` is an own data property or an accessor with a setter.\n * @internal\n */\nfunction hasWritableValue(obj: object): obj is { value: Element | null } {\n const descriptor = Object.getOwnPropertyDescriptor(obj, 'value');\n if (!descriptor) return false;\n // Data property: check writable flag\n if ('value' in descriptor) return descriptor.writable === true;\n // Accessor property: check for setter\n return typeof descriptor.set === 'function';\n}\n\n/**\n * Handles bq-ref directive - element reference.\n * @internal\n */\nexport const handleRef: DirectiveHandler = (el, expression, context, cleanups) => {\n const rawValue = evaluateRaw<Signal<Element | null> | { value: Element | null }>(\n expression,\n context\n );\n\n if (isSignal(rawValue)) {\n rawValue.value = el;\n cleanups.push(() => {\n rawValue.value = null;\n });\n } else if (typeof rawValue === 'object' && rawValue !== null && hasWritableValue(rawValue)) {\n // Object with writable .value property (e.g., { value: null })\n rawValue.value = el;\n cleanups.push(() => {\n rawValue.value = null;\n });\n }\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-show directive - toggle visibility.\n * @internal\n */\nexport const handleShow: DirectiveHandler = (el, expression, context, cleanups) => {\n const htmlEl = el as HTMLElement;\n // Capture the computed display value to properly restore visibility.\n // If inline display is 'none' or empty, we need to use the computed value.\n // Use ownerDocument.defaultView for cross-document/iframe compatibility.\n let originalDisplay = htmlEl.style.display;\n if (!originalDisplay || originalDisplay === 'none') {\n const computed = htmlEl.ownerDocument.defaultView?.getComputedStyle(htmlEl).display ?? '';\n originalDisplay = computed !== 'none' ? computed : '';\n }\n\n const cleanup = effect(() => {\n const condition = evaluate<boolean>(expression, context);\n htmlEl.style.display = condition ? originalDisplay : 'none';\n });\n\n cleanups.push(cleanup);\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate, parseObjectExpression } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-style directive - dynamic style binding.\n * @internal\n */\nexport const handleStyle: DirectiveHandler = (el, expression, context, cleanups) => {\n const htmlEl = el as HTMLElement;\n let appliedStyles: Set<string> = new Set();\n\n const cleanup = effect(() => {\n const newStyles = new Set<string>();\n\n if (expression.trimStart().startsWith('{')) {\n const styleMap = parseObjectExpression(expression);\n for (const [prop, valueExpr] of Object.entries(styleMap)) {\n const value = evaluate<string>(valueExpr, context);\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\n htmlEl.style.setProperty(cssProp, String(value ?? ''));\n newStyles.add(cssProp);\n }\n } else {\n const result = evaluate<Record<string, string>>(expression, context);\n if (result && typeof result === 'object') {\n for (const [prop, value] of Object.entries(result)) {\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\n htmlEl.style.setProperty(cssProp, String(value ?? ''));\n newStyles.add(cssProp);\n }\n }\n }\n\n // Remove styles that were previously applied but are no longer present\n for (const cssProp of appliedStyles) {\n if (!newStyles.has(cssProp)) {\n htmlEl.style.removeProperty(cssProp);\n }\n }\n\n // Update the set of applied styles\n appliedStyles = newStyles;\n });\n\n cleanups.push(cleanup);\n};\n","import { effect } from '../../reactive/index';\nimport { evaluate } from '../evaluate';\nimport type { DirectiveHandler } from '../types';\n\n/**\n * Handles bq-text directive - sets text content.\n * @internal\n */\nexport const handleText: DirectiveHandler = (el, expression, context, cleanups) => {\n const cleanup = effect(() => {\n const value = evaluate(expression, context);\n el.textContent = String(value ?? '');\n });\n cleanups.push(cleanup);\n};\n","import type { DirectiveHandler } from './types';\n\n/**\n * Function signature used to resolve custom directives without coupling the\n * view pipeline directly to the plugin module.\n * @internal\n */\nexport type CustomDirectiveResolver = (name: string) => DirectiveHandler | undefined;\n\nlet customDirectiveResolver: CustomDirectiveResolver | null = null;\n\n/**\n * Registers the resolver used by the view pipeline for custom directives.\n *\n * Pass `null` to unregister the current resolver and reset to the default behavior.\n * @internal\n */\nexport const registerCustomDirectiveResolver = (resolver: CustomDirectiveResolver | null): void => {\n customDirectiveResolver = resolver;\n};\n\n/**\n * Returns a custom directive handler when one is registered.\n * @internal\n */\nexport const getCustomDirective = (name: string): DirectiveHandler | undefined => {\n return customDirectiveResolver ? customDirectiveResolver(name) : undefined;\n};\n","import type { CleanupFn } from '../reactive/index';\nimport { detectDevEnvironment } from '../core/env';\nimport { getCustomDirective } from './custom-directives';\nimport type { BindingContext, DirectiveHandler } from './types';\n\nexport type DirectiveHandlers = {\n text: DirectiveHandler;\n html: DirectiveHandler;\n if: DirectiveHandler;\n show: DirectiveHandler;\n class: DirectiveHandler;\n style: DirectiveHandler;\n model: DirectiveHandler;\n ref: DirectiveHandler;\n for: DirectiveHandler;\n bind: (attrName: string) => DirectiveHandler;\n on: (eventName: string) => DirectiveHandler;\n};\n\n/**\n * Processes a single element for directives.\n * @internal\n */\nexport const processElement = (\n el: Element,\n context: BindingContext,\n prefix: string,\n cleanups: CleanupFn[],\n handlers: DirectiveHandlers\n): void => {\n const attributes = Array.from(el.attributes);\n\n for (const attr of attributes) {\n const { name: attributeName, value } = attr;\n\n if (!attributeName.startsWith(`${prefix}-`)) continue;\n\n const directive = attributeName.slice(prefix.length + 1); // Remove prefix and dash\n\n // Handle bq-for specially (creates new scope)\n if (directive === 'for') {\n handlers.for(el, value, context, cleanups);\n return; // Don't process children, bq-for handles it\n }\n\n // Handle other directives\n if (directive === 'text') {\n handlers.text(el, value, context, cleanups);\n } else if (directive === 'html') {\n handlers.html(el, value, context, cleanups);\n } else if (directive === 'if') {\n handlers.if(el, value, context, cleanups);\n } else if (directive === 'show') {\n handlers.show(el, value, context, cleanups);\n } else if (directive === 'class') {\n handlers.class(el, value, context, cleanups);\n } else if (directive === 'style') {\n handlers.style(el, value, context, cleanups);\n } else if (directive === 'model') {\n handlers.model(el, value, context, cleanups);\n } else if (directive === 'ref') {\n handlers.ref(el, value, context, cleanups);\n } else if (directive.startsWith('bind:')) {\n const attrName = directive.slice(5);\n handlers.bind(attrName)(el, value, context, cleanups);\n } else if (directive.startsWith('on:')) {\n const eventName = directive.slice(3);\n handlers.on(eventName)(el, value, context, cleanups);\n } else {\n // Check for custom directives registered via plugins\n const customHandler = getCustomDirective(directive);\n if (customHandler) {\n customHandler(el, value, context, cleanups);\n } else if (\n detectDevEnvironment() &&\n typeof console !== 'undefined' &&\n typeof console.warn === 'function'\n ) {\n console.warn(\n `[bQuery][view] Unknown directive \"${attributeName}\" (parsed as \"${directive}\") on <${el.tagName.toLowerCase()}>. This may be a typo or a missing custom directive registration.`\n );\n }\n }\n }\n};\n\n/**\n * Recursively processes children of an element.\n * @internal\n */\nexport const processChildren = (\n el: Element,\n context: BindingContext,\n prefix: string,\n cleanups: CleanupFn[],\n handlers: DirectiveHandlers\n): void => {\n const children = Array.from(el.children);\n for (const child of children) {\n // Skip if element has bq-for (handled separately)\n if (!child.hasAttribute(`${prefix}-for`)) {\n processElement(child, context, prefix, cleanups, handlers);\n processChildren(child, context, prefix, cleanups, handlers);\n } else {\n processElement(child, context, prefix, cleanups, handlers);\n }\n }\n};\n","import type { CleanupFn } from '../reactive/index';\nimport {\n createForHandler,\n handleBind,\n handleClass,\n handleHtml,\n handleIf,\n handleModel,\n handleOn,\n handleRef,\n handleShow,\n handleStyle,\n handleText,\n} from './directives/index';\nimport { processChildren, processElement, type DirectiveHandlers } from './process';\nimport type { BindingContext, MountOptions, View } from './types';\n\n/**\n * Mounts a reactive view to an element.\n *\n * @param selector - CSS selector or Element\n * @param context - Binding context with signals, computed, and functions\n * @param options - Mount options\n * @returns The mounted View instance\n *\n * @security **WARNING:** Directive expressions (bq-text, bq-if, bq-on, etc.) are evaluated\n * using `new Function()` at runtime. This means:\n * - Template attributes must come from trusted sources only\n * - NEVER load templates containing bq-* attributes from user input or untrusted APIs\n * - If you must use external templates, validate/sanitize attribute values first\n *\n * @example\n * ```ts\n * import { mount } from 'bquery/view';\n * import { signal, computed } from 'bquery/reactive';\n *\n * const name = signal('World');\n * const greeting = computed(() => `Hello, ${name.value}!`);\n * const items = signal([\n * { id: 1, text: 'Item 1' },\n * { id: 2, text: 'Item 2' },\n * ]);\n *\n * const view = mount('#app', {\n * name,\n * greeting,\n * items,\n * addItem: () => {\n * items.value = [...items.value, { id: Date.now(), text: 'New Item' }];\n * },\n * });\n *\n * // Later, cleanup\n * view.destroy();\n * ```\n */\nexport const mount = (\n selector: string | Element,\n context: BindingContext,\n options: MountOptions = {}\n): View => {\n const { prefix = 'bq', sanitize = true } = options;\n\n const el = typeof selector === 'string' ? document.querySelector(selector) : selector;\n\n if (!el) {\n throw new Error(`bQuery view: Element \"${selector}\" not found.`);\n }\n\n // Reject if root element has bq-for directive\n // bq-for replaces the element with a placeholder comment, which would leave View.el detached\n if (el.hasAttribute(`${prefix}-for`)) {\n throw new Error(\n `bQuery view: Cannot mount on element with ${prefix}-for directive. ` +\n `Wrap the ${prefix}-for element in a container instead.`\n );\n }\n\n const cleanups: CleanupFn[] = [];\n\n const handlers: DirectiveHandlers = {\n text: handleText,\n html: handleHtml(sanitize),\n if: handleIf,\n show: handleShow,\n class: handleClass,\n style: handleStyle,\n model: handleModel,\n ref: handleRef,\n for: createForHandler({\n prefix,\n processElement: (node, nodeContext, nodePrefix, nodeCleanups) =>\n processElement(node, nodeContext, nodePrefix, nodeCleanups, handlers),\n processChildren: (node, nodeContext, nodePrefix, nodeCleanups) =>\n processChildren(node, nodeContext, nodePrefix, nodeCleanups, handlers),\n }),\n bind: handleBind,\n on: handleOn,\n };\n\n const processWithHandlers = (\n node: Element,\n nodeContext: BindingContext,\n nodeCleanups: CleanupFn[]\n ) => {\n // Check if element has bq-for before processing\n // bq-for replaces the element and handles its children internally\n const hasFor = node.hasAttribute(`${prefix}-for`);\n\n processElement(node, nodeContext, prefix, nodeCleanups, handlers);\n\n // Skip processChildren if bq-for was on this element - it handles children itself\n if (!hasFor) {\n processChildren(node, nodeContext, prefix, nodeCleanups, handlers);\n }\n };\n\n // Process the root element and its children\n processWithHandlers(el, context, cleanups);\n\n return {\n el,\n context,\n\n update: (newContext: Partial<BindingContext>) => {\n Object.assign(context, newContext);\n },\n\n destroy: () => {\n for (const cleanup of cleanups) {\n cleanup();\n }\n cleanups.length = 0;\n },\n };\n};\n\n/**\n * Creates a reactive template function.\n *\n * @param template - HTML template string\n * @returns A function that creates a mounted element with the given context\n *\n * @example\n * ```ts\n * import { createTemplate } from 'bquery/view';\n * import { signal } from 'bquery/reactive';\n *\n * const TodoItem = createTemplate(`\n * <li bq-class=\"{ completed: done }\">\n * <input type=\"checkbox\" bq-model=\"done\" />\n * <span bq-text=\"text\"></span>\n * </li>\n * `);\n *\n * const item = TodoItem({\n * done: signal(false),\n * text: 'Buy groceries',\n * });\n *\n * document.querySelector('#list').append(item.el);\n * ```\n */\nexport const createTemplate = (\n template: string,\n options: MountOptions = {}\n): ((context: BindingContext) => View) => {\n return (context: BindingContext) => {\n const container = document.createElement('div');\n container.innerHTML = template.trim();\n\n const el = container.firstElementChild;\n if (!el) {\n throw new Error('bQuery view: Template must contain a single root element.');\n }\n\n // We know at least one element exists (firstElementChild is not null above)\n // Reject if there are multiple root elements\n if (container.childElementCount > 1) {\n throw new Error(\n `bQuery view: Template must contain exactly one root element, found ${container.childElementCount}.`\n );\n }\n\n const { prefix = 'bq' } = options;\n // Reject templates with bq-for or bq-if on the root element\n // These directives replace the element with a placeholder comment, which would leave View.el detached\n // Since processing happens while el is still in the temporary container, the placeholder\n // would remain there while view.el is inserted elsewhere, causing desync on future toggles\n if (el.hasAttribute(`${prefix}-for`) || el.hasAttribute(`${prefix}-if`)) {\n const directive = el.hasAttribute(`${prefix}-for`) ? 'for' : 'if';\n throw new Error(\n `bQuery view: Template root element cannot have ${prefix}-${directive} directive. ` +\n `Wrap the ${prefix}-${directive} element in a container instead.`\n );\n }\n\n return mount(el, context, options);\n };\n};\n","/**\n * Reactive form creation and management.\n *\n * @module bquery/forms\n */\n\nimport { computed, signal } from '../reactive/index';\nimport { isPrototypePollutionKey } from '../core/utils/object';\nimport { isPromise } from '../core/utils/type-guards';\nimport type {\n CrossFieldValidator,\n FieldConfig,\n Form,\n FormConfig,\n FormErrors,\n FormField,\n FormFields,\n ValidationResult,\n Validator,\n} from './types';\n\n/**\n * Determines whether a validator returned a valid result.\n * @internal\n */\nconst isValid = (result: ValidationResult): boolean => result === true || result === undefined;\n\n/**\n * Runs a single validator, normalising sync and async results.\n * @internal\n */\nconst runValidator = async <T>(validator: Validator<T>, value: T): Promise<string | undefined> => {\n const result = validator(value);\n const resolved = isPromise(result) ? await result : result;\n return isValid(resolved) ? undefined : (resolved as string);\n};\n\n/**\n * Creates a reactive form field from its configuration.\n * @internal\n */\nconst createField = <T>(config: FieldConfig<T>): FormField<T> => {\n const initial = config.initialValue;\n const value = signal<T>(initial);\n const error = signal('');\n const isTouched = signal(false);\n\n const isDirty = computed(() => !Object.is(value.value, initial));\n const isPristine = computed(() => !isDirty.value);\n\n return {\n value,\n error,\n isDirty,\n isTouched,\n isPristine,\n touch: () => {\n isTouched.value = true;\n },\n reset: () => {\n value.value = initial;\n error.value = '';\n isTouched.value = false;\n },\n };\n};\n\n/**\n * Validates a single field against its validators.\n * Sets the field's error signal.\n *\n * @returns The first error message, or an empty string if valid.\n * @internal\n */\nconst validateSingleField = async <T>(\n field: FormField<T>,\n validators: Validator<T>[] | undefined\n): Promise<string> => {\n if (!validators || validators.length === 0) {\n field.error.value = '';\n return '';\n }\n\n for (const validator of validators) {\n const errorMsg = await runValidator(validator, field.value.value);\n if (errorMsg) {\n field.error.value = errorMsg;\n return errorMsg;\n }\n }\n\n field.error.value = '';\n return '';\n};\n\n/**\n * Creates a fully reactive form with field-level validation,\n * dirty/touched tracking, cross-field validation, and submission handling.\n *\n * Each field's `value`, `error`, `isDirty`, `isTouched`, and `isPristine`\n * are reactive signals/computed values that can be used in effects, computed\n * values, or directly read/written.\n *\n * @template T - Shape of the form values (e.g. `{ name: string; age: number }`)\n * @param config - Form configuration with field definitions, validators, and submit handler\n * @returns A reactive {@link Form} instance\n *\n * @example\n * ```ts\n * import { createForm, required, email, min } from '@bquery/bquery/forms';\n *\n * const form = createForm({\n * fields: {\n * name: { initialValue: '', validators: [required()] },\n * email: { initialValue: '', validators: [required(), email()] },\n * age: { initialValue: 0, validators: [min(18, 'Must be 18+')] },\n * },\n * onSubmit: async (values) => {\n * await fetch('/api/register', {\n * method: 'POST',\n * body: JSON.stringify(values),\n * });\n * },\n * });\n *\n * // Read reactive state\n * console.log(form.isValid.value); // true (initially, before validation runs)\n * console.log(form.fields.name.value.value); // ''\n *\n * // Update a field\n * form.fields.name.value.value = 'Ada';\n *\n * // Validate and submit\n * await form.handleSubmit();\n * ```\n */\nexport const createForm = <T extends Record<string, unknown>>(config: FormConfig<T>): Form<T> => {\n // Build reactive field objects\n const fieldEntries = Object.entries(config.fields) as [\n keyof T & string,\n FieldConfig<T[keyof T]>,\n ][];\n\n const fields = {} as FormFields<T>;\n const errors = {} as FormErrors<T>;\n\n for (const [name, fieldConfig] of fieldEntries) {\n const field = createField(fieldConfig as FieldConfig<T[typeof name]>);\n (fields as Record<string, FormField>)[name] = field;\n (errors as Record<string, typeof field.error>)[name] = field.error;\n }\n\n const isSubmitting = signal(false);\n\n // Computed: form is valid when all error signals are empty\n const isFormValid = computed(() => {\n for (const name of Object.keys(fields)) {\n if ((fields as Record<string, FormField>)[name].error.value !== '') {\n return false;\n }\n }\n return true;\n });\n\n // Computed: form is dirty when any field is dirty\n const isFormDirty = computed(() => {\n for (const name of Object.keys(fields)) {\n if ((fields as Record<string, FormField>)[name].isDirty.value) {\n return true;\n }\n }\n return false;\n });\n\n /**\n * Validate a single field by name.\n */\n const validateField = async (name: keyof T & string): Promise<void> => {\n const field = (fields as Record<string, FormField>)[name];\n const fieldConfig = (config.fields as Record<string, FieldConfig>)[name];\n if (!field || !fieldConfig) return;\n await validateSingleField(field, fieldConfig.validators);\n };\n\n /**\n * Validate all fields (per-field + cross-field).\n * Returns `true` if the entire form is valid.\n */\n const validate = async (): Promise<boolean> => {\n let hasError = false;\n\n // Per-field validation\n for (const [name, fieldConfig] of fieldEntries) {\n const field = (fields as Record<string, FormField>)[name];\n const error = await validateSingleField(field, (fieldConfig as FieldConfig).validators);\n if (error) hasError = true;\n }\n\n // Cross-field validation\n if (config.crossValidators && config.crossValidators.length > 0) {\n const values = getValues();\n for (const crossValidator of config.crossValidators as CrossFieldValidator<T>[]) {\n const crossErrors = await crossValidator(values);\n if (crossErrors) {\n for (const [fieldName, errorMsg] of Object.entries(crossErrors) as [\n string,\n string | undefined,\n ][]) {\n if (errorMsg) {\n const field = (fields as Record<string, FormField>)[fieldName];\n if (field) {\n // Only set cross-field error if no per-field error exists\n if (field.error.value === '') {\n field.error.value = errorMsg;\n }\n hasError = true;\n }\n }\n }\n }\n }\n }\n\n return !hasError;\n };\n\n /**\n * Validate all fields and, if valid, invoke the onSubmit handler.\n * Prevents concurrent submissions by setting isSubmitting before validation.\n */\n const handleSubmit = async (): Promise<void> => {\n if (isSubmitting.value) return;\n isSubmitting.value = true;\n\n try {\n const valid = await validate();\n if (!valid) return;\n\n if (config.onSubmit) {\n await config.onSubmit(getValues());\n }\n } finally {\n isSubmitting.value = false;\n }\n };\n\n /**\n * Reset every field to its initial value and clear all errors.\n */\n const reset = (): void => {\n for (const name of Object.keys(fields)) {\n (fields as Record<string, FormField>)[name].reset();\n }\n };\n\n /**\n * Return a plain object snapshot of all current field values.\n */\n const getValues = (): T => {\n const values = {} as Record<string, unknown>;\n for (const name of Object.keys(fields)) {\n values[name] = (fields as Record<string, FormField>)[name].value.value;\n }\n return values as T;\n };\n\n /**\n * Bulk-set field values from a partial object.\n * Only fields present in the object are updated; missing keys are left unchanged.\n */\n const setValues = (values: Partial<T>): void => {\n for (const [name, val] of Object.entries(values)) {\n // Ignore inherited keys and prototype-pollution vectors before mutating field state.\n if (isPrototypePollutionKey(name) || !Object.prototype.hasOwnProperty.call(fields, name)) {\n continue;\n }\n\n const field = (fields as Record<string, FormField>)[name];\n if (!field) {\n continue;\n }\n field.value.value = val;\n }\n };\n\n /**\n * Bulk-set field error messages from a partial object.\n * Useful for applying server-side validation errors.\n * Only fields present in the object are updated; missing keys are left unchanged.\n */\n const setErrors = (errorMap: Partial<Record<keyof T & string, string>>): void => {\n for (const [name, msg] of Object.entries(errorMap)) {\n // Ignore inherited keys and prototype-pollution vectors before mutating field state.\n if (isPrototypePollutionKey(name) || !Object.prototype.hasOwnProperty.call(fields, name)) {\n continue;\n }\n\n const field = (fields as Record<string, FormField>)[name];\n if (!field) {\n continue;\n }\n field.error.value = (msg as string) ?? '';\n }\n };\n\n return {\n fields,\n errors,\n isValid: isFormValid,\n isDirty: isFormDirty,\n isSubmitting,\n handleSubmit,\n validateField,\n validate,\n reset,\n getValues,\n setValues,\n setErrors,\n };\n};\n","/**\n * Standalone reactive field composable.\n *\n * @module bquery/forms\n */\n\nimport { debounce } from '../core/utils/function';\nimport { isPromise } from '../core/utils/type-guards';\nimport { Computed } from '../reactive/computed';\nimport { Signal } from '../reactive/core';\nimport { computed, effect, signal } from '../reactive/index';\nimport type { MaybeSignal } from '../reactive/index';\nimport { isReadonlySignal } from '../reactive/readonly';\nimport type { UseFormFieldOptions, UseFormFieldReturn, ValidationResult, Validator } from './types';\n\n/**\n * Determines whether a validator returned a valid result.\n * @internal\n */\nconst isValidationSuccess = (result: ValidationResult): boolean =>\n result === true || result === undefined;\n\n/**\n * Runs a single validator, normalising sync and async results.\n * @internal\n */\nconst runValidator = async <T>(validator: Validator<T>, value: T): Promise<string | undefined> => {\n const result = validator(value);\n const resolved = isPromise(result) ? await result : result;\n return isValidationSuccess(resolved) ? undefined : (resolved as string);\n};\n\n/**\n * Creates a standalone reactive form field with optional automatic validation.\n *\n * This helper is useful when you want field-level state without creating a full form,\n * or when you want to bind an existing signal to the forms validation model.\n *\n * @template T - The type of the field value\n * @param initialValue - Plain initial value, an existing writable signal to reuse, or a\n * computed / readonly reactive source to snapshot\n * @param options - Validation mode, validators, debounce, and initial error configuration\n * @returns A reactive field handle with validation helpers\n *\n * @example\n * ```ts\n * import { useFormField, required } from '@bquery/bquery/forms';\n *\n * const email = useFormField('', {\n * validators: [required()],\n * validateOn: 'blur',\n * });\n *\n * email.value.value = 'ada@example.com';\n * email.touch();\n * ```\n */\nexport const useFormField = <T>(\n initialValue: MaybeSignal<T>,\n options: UseFormFieldOptions<T> = {}\n): UseFormFieldReturn<T> => {\n let value: Signal<T>;\n\n if (isSignal(initialValue)) {\n value = initialValue as Signal<T>;\n } else {\n const startingValue: T =\n isReadonlySignal<T>(initialValue) || isComputedValue<T>(initialValue)\n ? initialValue.peek()\n : (initialValue as T);\n value = signal(startingValue);\n }\n\n const initial = value.peek();\n const error = signal(options.initialError ?? '');\n const isTouched = signal(false);\n const isValidating = signal(false);\n const isDirty = computed(() => !Object.is(value.value, initial));\n const isPristine = computed(() => !isDirty.value);\n const isValid = computed(() => error.value === '');\n const validateOn = options.validateOn ?? 'manual';\n const debounceMs = Math.max(0, options.debounceMs ?? 0);\n\n let validationId = 0;\n let changeInitialized = false;\n let suppressNextChangeValidation = false;\n let isDestroyed = false;\n let stopChangeValidationEffect: (() => void) | undefined;\n\n const logValidationError = (validationError: unknown): void => {\n console.error('bQuery forms: Error in scheduled field validation', validationError);\n };\n\n const runValidation = async (): Promise<boolean> => {\n const currentValidationId = ++validationId;\n const validators = options.validators;\n\n if (!validators || validators.length === 0) {\n error.value = '';\n isValidating.value = false;\n return true;\n }\n\n isValidating.value = true;\n\n try {\n const currentValue = value.peek();\n\n for (const validator of validators) {\n const nextError = await runValidator(validator, currentValue);\n\n if (currentValidationId !== validationId) {\n return error.peek() === '';\n }\n\n if (nextError) {\n error.value = nextError;\n return false;\n }\n }\n\n if (currentValidationId === validationId) {\n error.value = '';\n }\n return true;\n } finally {\n if (currentValidationId === validationId) {\n isValidating.value = false;\n }\n }\n };\n\n const debouncedValidate = debounce(() => {\n void runValidation().catch(logValidationError);\n }, debounceMs);\n\n const scheduleValidation = (): void => {\n if (isDestroyed) {\n return;\n }\n\n if (debounceMs > 0) {\n debouncedValidate();\n return;\n }\n\n void runValidation().catch(logValidationError);\n };\n\n if (validateOn === 'change' || validateOn === 'both') {\n stopChangeValidationEffect = effect(() => {\n void value.value;\n\n if (!changeInitialized) {\n changeInitialized = true;\n return;\n }\n\n if (suppressNextChangeValidation) {\n suppressNextChangeValidation = false;\n return;\n }\n\n scheduleValidation();\n });\n }\n\n const destroy = (): void => {\n if (isDestroyed) {\n return;\n }\n\n isDestroyed = true;\n validationId += 1;\n debouncedValidate.cancel();\n stopChangeValidationEffect?.();\n stopChangeValidationEffect = undefined;\n isDirty.dispose();\n isPristine.dispose();\n isValid.dispose();\n isValidating.value = false;\n };\n\n return {\n value,\n error,\n isDirty,\n isTouched,\n isPristine,\n isValid,\n isValidating,\n touch: () => {\n isTouched.value = true;\n if (validateOn === 'blur' || validateOn === 'both') {\n scheduleValidation();\n }\n },\n reset: () => {\n validationId += 1;\n debouncedValidate.cancel();\n if (!Object.is(value.peek(), initial)) {\n suppressNextChangeValidation = true;\n }\n value.value = initial;\n error.value = options.initialError ?? '';\n isTouched.value = false;\n isValidating.value = false;\n },\n validate: async () => {\n debouncedValidate.cancel();\n return runValidation();\n },\n destroy,\n };\n};\n\n/**\n * Determines whether a value looks like a writable signal.\n * @internal\n */\nconst isSignal = (value: unknown): value is Signal<unknown> => {\n return value instanceof Signal;\n};\n\n/**\n * Determines whether a value is a computed reactive source.\n * @internal\n */\nconst isComputedValue = <T>(value: unknown): value is Computed<T> => {\n return value instanceof Computed;\n};\n","/**\n * Built-in validation functions for form fields.\n *\n * Each factory returns a {@link SyncValidator} that can be passed\n * to a field's `validators` array in {@link FormConfig}.\n *\n * @module bquery/forms\n */\n\nimport type { AsyncValidator, SyncValidator } from './types';\n\n/**\n * Requires a non-empty value.\n *\n * Fails for `undefined`, `null`, empty strings (after trim), and empty arrays.\n *\n * @param message - Custom error message (default: `'This field is required'`)\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { required } from '@bquery/bquery/forms';\n * const validate = required('Name is required');\n * validate(''); // 'Name is required'\n * validate('Ada'); // true\n * ```\n */\nexport const required = (message = 'This field is required'): SyncValidator => {\n return (value: unknown) => {\n if (value == null) return message;\n if (typeof value === 'string' && value.trim() === '') return message;\n if (Array.isArray(value) && value.length === 0) return message;\n return true;\n };\n};\n\n/**\n * Requires a string to have at least `len` characters.\n *\n * Non-string values are coerced via `String()` before checking length.\n *\n * @param len - Minimum length\n * @param message - Custom error message\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { minLength } from '@bquery/bquery/forms';\n * const validate = minLength(3);\n * validate('ab'); // 'Must be at least 3 characters'\n * validate('abc'); // true\n * ```\n */\nexport const minLength = (len: number, message?: string): SyncValidator<unknown> => {\n const msg = message ?? `Must be at least ${len} characters`;\n return (value: unknown) => {\n const str = typeof value === 'string' ? value : String(value ?? '');\n return str.length >= len ? true : msg;\n };\n};\n\n/**\n * Requires a string to have at most `len` characters.\n *\n * Non-string values are coerced via `String()` before checking length.\n *\n * @param len - Maximum length\n * @param message - Custom error message\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { maxLength } from '@bquery/bquery/forms';\n * const validate = maxLength(10);\n * validate('hello world!!'); // 'Must be at most 10 characters'\n * validate('hello'); // true\n * ```\n */\nexport const maxLength = (len: number, message?: string): SyncValidator<unknown> => {\n const msg = message ?? `Must be at most ${len} characters`;\n return (value: unknown) => {\n const str = typeof value === 'string' ? value : String(value ?? '');\n return str.length <= len ? true : msg;\n };\n};\n\n/**\n * Requires a string to match a regular expression pattern.\n *\n * Non-string values are coerced via `String()` before testing.\n *\n * @param regex - Pattern to test against\n * @param message - Custom error message (default: `'Invalid format'`)\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { pattern } from '@bquery/bquery/forms';\n * const validate = pattern(/^\\d+$/, 'Numbers only');\n * validate('abc'); // 'Numbers only'\n * validate('123'); // true\n * ```\n */\nexport const pattern = (regex: RegExp, message = 'Invalid format'): SyncValidator<unknown> => {\n const safeRegex =\n regex.global || regex.sticky\n ? new RegExp(regex.source, regex.flags.replace(/[gy]/g, ''))\n : regex;\n\n return (value: unknown) => {\n const str = typeof value === 'string' ? value : String(value ?? '');\n safeRegex.lastIndex = 0;\n return safeRegex.test(str) ? true : message;\n };\n};\n\n/**\n * RFC 5322–simplified email validation.\n *\n * @param message - Custom error message (default: `'Invalid email address'`)\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { email } from '@bquery/bquery/forms';\n * const validate = email();\n * validate('nope'); // 'Invalid email address'\n * validate('ada@lovelace'); // 'Invalid email address'\n * validate('ada@love.co'); // true\n * ```\n */\nexport const email = (message = 'Invalid email address'): SyncValidator<unknown> => {\n // Intentionally simple — covers the vast majority of valid addresses\n // without re-implementing the full RFC 5322 grammar.\n const re = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return (value: unknown) => {\n const str = typeof value === 'string' ? value : String(value ?? '');\n if (str === '') return true; // empty is handled by `required`\n return re.test(str) ? true : message;\n };\n};\n\n/**\n * Requires a string to be a valid URL.\n *\n * Uses the native `URL` constructor for validation.\n *\n * @param message - Custom error message (default: `'Invalid URL'`)\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { url } from '@bquery/bquery/forms';\n * const validate = url();\n * validate('not-a-url'); // 'Invalid URL'\n * validate('https://example.com'); // true\n * ```\n */\nexport const url = (message = 'Invalid URL'): SyncValidator<unknown> => {\n return (value: unknown) => {\n const str = typeof value === 'string' ? value : String(value ?? '');\n if (str === '') return true; // empty is handled by `required`\n try {\n new URL(str);\n return true;\n } catch {\n return message;\n }\n };\n};\n\n/**\n * Requires a numeric value to be at least `limit`.\n *\n * @param limit - Minimum allowed value (inclusive)\n * @param message - Custom error message\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { min } from '@bquery/bquery/forms';\n * const validate = min(1, 'Must be positive');\n * validate(0); // 'Must be positive'\n * validate(1); // true\n * ```\n */\nexport const min = (limit: number, message?: string): SyncValidator<unknown> => {\n const msg = message ?? `Must be at least ${limit}`;\n return (value: unknown) => {\n if (value == null) return true;\n if (typeof value === 'string' && value.trim() === '') return true;\n const num = typeof value === 'number' ? value : Number(value);\n return num >= limit ? true : msg;\n };\n};\n\n/**\n * Requires a numeric value to be at most `limit`.\n *\n * @param limit - Maximum allowed value (inclusive)\n * @param message - Custom error message\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { max } from '@bquery/bquery/forms';\n * const validate = max(100, 'Too high');\n * validate(101); // 'Too high'\n * validate(100); // true\n * ```\n */\nexport const max = (limit: number, message?: string): SyncValidator<unknown> => {\n const msg = message ?? `Must be at most ${limit}`;\n return (value: unknown) => {\n if (value == null) return true;\n if (typeof value === 'string' && value.trim() === '') return true;\n const num = typeof value === 'number' ? value : Number(value);\n return num <= limit ? true : msg;\n };\n};\n\n/**\n * Creates a custom synchronous validator from any predicate function.\n *\n * @param fn - Predicate that returns `true` when the value is valid\n * @param message - Error message when the predicate returns `false`\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { custom } from '@bquery/bquery/forms';\n * const isEven = custom((v: number) => v % 2 === 0, 'Must be even');\n * isEven(3); // 'Must be even'\n * isEven(4); // true\n * ```\n */\nexport const custom = <T = unknown>(\n fn: (value: T) => boolean,\n message: string\n): SyncValidator<T> => {\n return (value: T) => (fn(value) ? true : message);\n};\n\n/**\n * Creates a custom asynchronous validator.\n *\n * @param fn - Async predicate that resolves to `true` when valid\n * @param message - Error message when the predicate resolves to `false`\n * @returns An async validator function\n *\n * @example\n * ```ts\n * import { customAsync } from '@bquery/bquery/forms';\n * const isUnique = customAsync(\n * async (name: string) => !(await checkExists(name)),\n * 'Already taken',\n * );\n * ```\n */\nexport const customAsync = <T = unknown>(\n fn: (value: T) => Promise<boolean>,\n message: string\n): AsyncValidator<T> => {\n return async (value: T) => ((await fn(value)) ? true : message);\n};\n\n/**\n * Requires a field's value to match the current value of a reference signal.\n *\n * Typically used for \"confirm password\" or \"confirm email\" patterns where\n * one field must have the same value as another.\n *\n * @param ref - A reactive signal whose current value is the comparison target\n * @param message - Custom error message (default: `'Fields do not match'`)\n * @returns A sync validator function\n *\n * @example\n * ```ts\n * import { signal } from '@bquery/bquery/reactive';\n * import { matchField } from '@bquery/bquery/forms';\n *\n * const password = signal('secret');\n * const confirmPassword = signal('');\n * const validateConfirmPassword = matchField(password, 'Passwords must match');\n *\n * validateConfirmPassword(confirmPassword.value);\n * ```\n */\nexport const matchField = <T>(\n ref: { readonly value: T },\n message = 'Fields do not match'\n): SyncValidator<T> => {\n return (value: T) => (Object.is(value, ref.value) ? true : message);\n};\n","/**\n * Number and date formatting helpers using Intl APIs.\n * @module bquery/i18n\n */\n\nimport type { DateFormatOptions, NumberFormatOptions } from './types';\n\n/**\n * Formats a number using the Intl.NumberFormat API.\n *\n * @param value - The number to format\n * @param locale - The locale code (e.g. 'en-US', 'de-DE')\n * @param options - Intl.NumberFormat options\n * @returns The formatted number string\n *\n * @example\n * ```ts\n * formatNumber(1234.56, 'en-US'); // '1,234.56'\n * formatNumber(1234.56, 'de-DE'); // '1.234,56'\n * formatNumber(0.42, 'en-US', { style: 'percent' }); // '42%'\n * formatNumber(9.99, 'en-US', { style: 'currency', currency: 'USD' }); // '$9.99'\n * ```\n */\nexport const formatNumber = (\n value: number,\n locale: string,\n options?: NumberFormatOptions\n): string => {\n const { locale: _ignored, ...intlOptions } = options ?? {};\n try {\n return new Intl.NumberFormat(locale, intlOptions).format(value);\n } catch {\n // Fall back to basic toString on Intl errors\n return String(value);\n }\n};\n\n/**\n * Formats a date using the Intl.DateTimeFormat API.\n *\n * @param value - The date to format (Date object or timestamp)\n * @param locale - The locale code\n * @param options - Intl.DateTimeFormat options\n * @returns The formatted date string\n *\n * @example\n * ```ts\n * const date = new Date('2026-03-26');\n * formatDate(date, 'en-US'); // '3/26/2026'\n * formatDate(date, 'de-DE'); // '26.3.2026'\n * formatDate(date, 'en-US', { dateStyle: 'long' }); // 'March 26, 2026'\n * ```\n */\nexport const formatDate = (\n value: Date | number,\n locale: string,\n options?: DateFormatOptions\n): string => {\n const { locale: _ignored, ...intlOptions } = options ?? {};\n const date = typeof value === 'number' ? new Date(value) : value;\n try {\n return new Intl.DateTimeFormat(locale, intlOptions).format(date);\n } catch {\n // Fall back to toLocaleString on Intl errors\n return date.toLocaleString();\n }\n};\n","/**\n * Translation resolution helpers.\n * @module bquery/i18n\n * @internal\n */\n\nimport { isPlainObject, isPrototypePollutionKey, merge } from '../core/utils/object';\nimport type { LocaleMessages, TranslateParams } from './types';\n\n/**\n * Resolves a dot-delimited key path against a messages object.\n *\n * @param messages - The locale messages\n * @param key - Dot-delimited key (e.g. 'user.welcome')\n * @returns The resolved string, or `undefined` if not found\n *\n * @internal\n */\nexport const resolveKey = (messages: LocaleMessages, key: string): string | undefined => {\n const parts = key.split('.');\n let current: LocaleMessages | string = messages;\n\n for (const part of parts) {\n if (typeof current === 'string') return undefined;\n if (current[part] === undefined) return undefined;\n current = current[part];\n }\n\n return typeof current === 'string' ? current : undefined;\n};\n\n/**\n * Interpolates `{param}` placeholders in a string.\n *\n * @param template - The template string with `{key}` placeholders\n * @param params - Key-value pairs for replacement\n * @returns The interpolated string\n *\n * @example\n * ```ts\n * interpolate('Hello, {name}!', { name: 'Ada' });\n * // → 'Hello, Ada!'\n * ```\n *\n * @internal\n */\nexport const interpolate = (template: string, params: TranslateParams): string => {\n return template.replace(/\\{(\\w+)\\}/g, (match, key: string) => {\n if (key in params) {\n return String(params[key]);\n }\n return match; // Leave unmatched placeholders as-is\n });\n};\n\n/**\n * Selects the correct plural form from a pipe-delimited string.\n *\n * Supports two formats:\n * - **Two forms:** `\"singular | plural\"` — singular when count === 1\n * - **Three forms:** `\"zero | one | many\"` — zero when count === 0,\n * one when count === 1, many otherwise\n *\n * The `count` parameter must be present in `params` for pluralization.\n * If no `count` param exists or the string has no pipes, the string is\n * returned as-is.\n *\n * @param template - Pipe-delimited plural forms\n * @param params - Must include a `count` key for plural selection\n * @returns The selected form\n *\n * @example\n * ```ts\n * pluralize('{count} item | {count} items', { count: 1 });\n * // → '{count} item'\n *\n * pluralize('no items | {count} item | {count} items', { count: 0 });\n * // → 'no items'\n * ```\n *\n * @internal\n */\nexport const pluralize = (template: string, params: TranslateParams): string => {\n if (!template.includes('|')) return template;\n if (!('count' in params)) return template;\n\n const count = Number(params.count);\n const forms = template.split('|').map((s) => s.trim());\n\n if (forms.length === 3) {\n // zero | one | many\n if (count === 0) return forms[0];\n if (count === 1) return forms[1];\n return forms[2];\n }\n\n if (forms.length === 2) {\n // singular | plural\n return count === 1 ? forms[0] : forms[1];\n }\n\n // More than 3 forms: use last form for \"many\"\n if (count === 0 && forms.length > 0) return forms[0];\n if (count === 1 && forms.length > 1) return forms[1];\n return forms[forms.length - 1];\n};\n\n/**\n * Full translation pipeline: resolve → pluralize → interpolate.\n *\n * @param messages - Locale messages\n * @param key - Dot-delimited key path\n * @param params - Interpolation + pluralization params\n * @param fallbackMessages - Optional fallback locale messages\n * @returns The translated string, or the key if not found\n *\n * @internal\n */\nexport const translate = (\n messages: LocaleMessages | undefined,\n key: string,\n params: TranslateParams,\n fallbackMessages?: LocaleMessages\n): string => {\n let template: string | undefined;\n\n // Try current locale\n if (messages) {\n template = resolveKey(messages, key);\n }\n\n // Fallback locale\n if (template === undefined && fallbackMessages) {\n template = resolveKey(fallbackMessages, key);\n }\n\n // Key not found — return key as-is\n if (template === undefined) {\n return key;\n }\n\n // Pluralize first, then interpolate\n const pluralized = pluralize(template, params);\n return interpolate(pluralized, params);\n};\n\n/**\n * Deep merges source into target and returns a sanitized, prototype-safe copy.\n *\n * @param target - Target messages object\n * @param source - Source messages to merge\n * @returns A new merged, sanitized messages object\n *\n * @internal\n */\nexport const deepMerge = (target: LocaleMessages, source: LocaleMessages): LocaleMessages => {\n const merged = merge(\n target as Record<string, unknown>,\n source as Record<string, unknown>\n ) as LocaleMessages;\n\n const cloneSafeMessages = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneSafeMessages(entry));\n }\n\n if (!isPlainObject(value)) {\n return value;\n }\n\n const safeObject = Object.create(null) as Record<string, unknown>;\n for (const [key, entry] of Object.entries(value)) {\n if (isPrototypePollutionKey(key)) {\n continue;\n }\n safeObject[key] = cloneSafeMessages(entry);\n }\n return safeObject;\n };\n\n return cloneSafeMessages(merged) as LocaleMessages;\n};\n","/**\n * Core i18n factory function.\n * @module bquery/i18n\n */\n\nimport { computed, signal } from '../reactive/index';\nimport { isPrototypePollutionKey } from '../core/utils/object';\nimport { formatDate, formatNumber } from './formatting';\nimport { deepMerge, translate } from './translate';\nimport type {\n DateFormatOptions,\n I18nConfig,\n I18nInstance,\n LocaleLoader,\n LocaleMessages,\n Messages,\n NumberFormatOptions,\n TranslateParams,\n} from './types';\n\n/**\n * Creates a reactive internationalization instance.\n *\n * The returned object provides:\n * - `$locale` — a reactive signal for the current locale\n * - `t()` — translation with interpolation and pluralization\n * - `tc()` — reactive translation that auto-updates on locale change\n * - `loadLocale()` — register lazy-loaded locale files\n * - `n()` — locale-aware number formatting\n * - `d()` — locale-aware date formatting\n *\n * @param config - Initial configuration\n * @returns An i18n instance\n *\n * @example\n * ```ts\n * import { createI18n } from '@bquery/bquery/i18n';\n *\n * const i18n = createI18n({\n * locale: 'en',\n * fallbackLocale: 'en',\n * messages: {\n * en: {\n * greeting: 'Hello, {name}!',\n * items: '{count} item | {count} items',\n * },\n * de: {\n * greeting: 'Hallo, {name}!',\n * items: '{count} Gegenstand | {count} Gegenstände',\n * },\n * },\n * });\n *\n * i18n.t('greeting', { name: 'Ada' }); // 'Hello, Ada!'\n * i18n.t('items', { count: 3 }); // '3 items'\n *\n * // Switch locale reactively\n * i18n.$locale.value = 'de';\n * i18n.t('greeting', { name: 'Ada' }); // 'Hallo, Ada!'\n * ```\n */\nexport const createI18n = (config: I18nConfig): I18nInstance => {\n const { locale: initialLocale, messages: initialMessages, fallbackLocale } = config;\n\n const sanitizeLocaleMessages = (localeMessages: LocaleMessages): LocaleMessages =>\n deepMerge(Object.create(null) as LocaleMessages, localeMessages);\n\n // Deep-clone initial messages to prevent external mutation\n const messages = Object.create(null) as Messages;\n for (const [loc, msgs] of Object.entries(initialMessages)) {\n if (isPrototypePollutionKey(loc)) {\n continue;\n }\n messages[loc] = sanitizeLocaleMessages(msgs);\n }\n\n // Reactive locale signal\n const $locale = signal(initialLocale);\n\n // Lazy-loader registry\n const loaders = new Map<string, LocaleLoader>();\n\n // Track which loaders have been invoked to avoid duplicate loads\n const loadedLocales = new Set<string>(Object.keys(messages));\n\n /**\n * Get messages for a locale, or undefined if not loaded.\n */\n const getMessages = (loc: string): LocaleMessages | undefined => {\n if (isPrototypePollutionKey(loc)) {\n return undefined;\n }\n return messages[loc];\n };\n\n /**\n * Register a lazy-loader for a locale.\n */\n const loadLocale = (loc: string, loader: LocaleLoader): void => {\n if (isPrototypePollutionKey(loc)) {\n return;\n }\n loaders.set(loc, loader);\n };\n\n /**\n * Ensure a locale's messages are loaded.\n */\n const ensureLocale = async (loc: string): Promise<void> => {\n if (isPrototypePollutionKey(loc)) return;\n if (loadedLocales.has(loc)) return;\n\n const loader = loaders.get(loc);\n if (!loader) {\n throw new Error(`bQuery i18n: No messages or loader registered for locale \"${loc}\".`);\n }\n\n const loaded = await loader();\n // Handle both default exports and direct objects\n const msgs = (loaded as { default?: LocaleMessages }).default ?? (loaded as LocaleMessages);\n messages[loc] = sanitizeLocaleMessages(msgs);\n loadedLocales.add(loc);\n };\n\n /**\n * Translate a key path.\n */\n const t = (key: string, params: TranslateParams = {}): string => {\n const currentLocale = $locale.value;\n const currentMessages = messages[currentLocale];\n const fallbackMessages = fallbackLocale ? messages[fallbackLocale] : undefined;\n\n return translate(currentMessages, key, params, fallbackMessages);\n };\n\n /**\n * Reactive translation — returns a computed signal.\n */\n const tc = (key: string, params: TranslateParams = {}) => {\n return computed(() => {\n // Reading $locale.value creates a reactive dependency\n const currentLocale = $locale.value;\n const currentMessages = messages[currentLocale];\n const fallbackMessages = fallbackLocale ? messages[fallbackLocale] : undefined;\n\n return translate(currentMessages, key, params, fallbackMessages);\n });\n };\n\n /**\n * Format a number with the current (or overridden) locale.\n */\n const n = (value: number, options?: NumberFormatOptions): string => {\n const loc = options?.locale ?? $locale.value;\n return formatNumber(value, loc, options);\n };\n\n /**\n * Format a date with the current (or overridden) locale.\n */\n const d = (value: Date | number, options?: DateFormatOptions): string => {\n const loc = options?.locale ?? $locale.value;\n return formatDate(value, loc, options);\n };\n\n /**\n * Merge additional messages into a locale.\n */\n const mergeMessages = (loc: string, newMessages: LocaleMessages): void => {\n if (isPrototypePollutionKey(loc)) {\n return;\n }\n if (!messages[loc]) {\n messages[loc] = Object.create(null) as LocaleMessages;\n loadedLocales.add(loc);\n }\n messages[loc] = deepMerge(messages[loc], sanitizeLocaleMessages(newMessages));\n };\n\n /**\n * List all available locales (loaded + registered loaders).\n */\n const availableLocales = (): string[] => {\n const locales = new Set<string>([...loadedLocales, ...loaders.keys()]);\n return Array.from(locales).sort();\n };\n\n return {\n $locale,\n t,\n tc,\n loadLocale,\n ensureLocale,\n n,\n d,\n getMessages,\n mergeMessages,\n availableLocales,\n };\n};\n","/**\n * Screen reader announcement utility using ARIA live regions.\n *\n * Creates and manages off-screen live regions to announce dynamic\n * content changes to assistive technologies.\n *\n * @module bquery/a11y\n */\n\nimport type { AnnouncePriority } from './types';\n\n/** Cache for live region containers, keyed by priority. */\nconst liveRegions = new Map<AnnouncePriority, HTMLElement>();\nconst pendingAnnouncements = new Map<AnnouncePriority, ReturnType<typeof setTimeout>>();\n\n/**\n * Delay in milliseconds before updating the live region text.\n * This ensures screen readers detect the content change even when\n * the same message is announced consecutively — clearing first and\n * setting after a short timer delay forces a new live-region mutation event.\n * @internal\n */\nconst ANNOUNCEMENT_DELAY_MS = 50;\n\n/**\n * Gets or creates a visually-hidden ARIA live region for the given priority.\n *\n * @param priority - The aria-live priority level\n * @returns The live region element\n * @internal\n */\nconst getOrCreateLiveRegion = (priority: AnnouncePriority): HTMLElement => {\n const existing = liveRegions.get(priority);\n if (existing && existing.isConnected) {\n return existing;\n }\n\n const el = document.createElement('div');\n el.setAttribute('aria-live', priority);\n el.setAttribute('aria-atomic', 'true');\n el.setAttribute('role', priority === 'assertive' ? 'alert' : 'status');\n\n // Visually hidden but accessible to screen readers\n Object.assign(el.style, {\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: '0',\n });\n\n document.body.appendChild(el);\n liveRegions.set(priority, el);\n\n return el;\n};\n\n/**\n * Announces a message to screen readers via an ARIA live region.\n *\n * The message is injected into a visually-hidden live region element.\n * Screen readers will pick up the change and announce it to the user.\n *\n * @param message - The text message to announce\n * @param priority - The urgency level: `'polite'` (default) or `'assertive'`\n *\n * @example\n * ```ts\n * import { announceToScreenReader } from '@bquery/bquery/a11y';\n *\n * // Polite announcement (waits for idle)\n * announceToScreenReader('3 search results found');\n *\n * // Assertive announcement (interrupts current speech)\n * announceToScreenReader('Error: Please fix the form', 'assertive');\n * ```\n */\nexport const announceToScreenReader = (\n message: string,\n priority: AnnouncePriority = 'polite'\n): void => {\n if (!message) return;\n if (typeof document === 'undefined' || !document.body) return;\n\n const region = getOrCreateLiveRegion(priority);\n const pendingTimeout = pendingAnnouncements.get(priority);\n if (pendingTimeout !== undefined) {\n clearTimeout(pendingTimeout);\n }\n\n // Clear first, then set after a short timer delay to ensure screen readers\n // detect the change even if the same message is announced twice.\n region.textContent = '';\n\n // Use setTimeout to ensure the DOM update triggers a live region change event\n const timeout = setTimeout(() => {\n pendingAnnouncements.delete(priority);\n if (region.isConnected) {\n region.textContent = message;\n }\n }, ANNOUNCEMENT_DELAY_MS);\n\n pendingAnnouncements.set(priority, timeout);\n};\n\n/**\n * Removes all live region elements created by `announceToScreenReader`.\n * Useful for cleanup in tests or when unmounting an application.\n *\n * @example\n * ```ts\n * import { clearAnnouncements } from '@bquery/bquery/a11y';\n *\n * clearAnnouncements();\n * ```\n */\nexport const clearAnnouncements = (): void => {\n for (const timeout of pendingAnnouncements.values()) {\n clearTimeout(timeout);\n }\n pendingAnnouncements.clear();\n\n for (const [, el] of liveRegions) {\n el.remove();\n }\n liveRegions.clear();\n};\n","/**\n * Development-time accessibility audit utility.\n *\n * Scans DOM elements for common accessibility issues such as missing\n * alt text on images, missing labels on form inputs, empty links/buttons,\n * and incorrect ARIA usage.\n *\n * @module bquery/a11y\n */\n\nimport type { AuditFinding, AuditResult, AuditSeverity } from './types';\n\n/**\n * Creates a finding object.\n * @internal\n */\nconst finding = (\n severity: AuditSeverity,\n message: string,\n element: Element,\n rule: string\n): AuditFinding => ({\n severity,\n message,\n element,\n rule,\n});\n\n/**\n * Checks images for missing alt attributes.\n * @internal\n */\nconst auditImages = (container: Element): AuditFinding[] => {\n const findings: AuditFinding[] = [];\n const images = container.querySelectorAll('img');\n\n for (const img of images) {\n if (!img.hasAttribute('alt')) {\n findings.push(\n finding(\n 'error',\n 'Image is missing an alt attribute. Add alt=\"\" for decorative images or a descriptive alt text.',\n img,\n 'img-alt'\n )\n );\n } else if (img.getAttribute('alt') === '' && !img.hasAttribute('role')) {\n findings.push(\n finding(\n 'info',\n 'Image has empty alt text. Consider adding role=\"presentation\" if decorative.',\n img,\n 'img-decorative'\n )\n );\n }\n }\n\n return findings;\n};\n\n/**\n * Checks form inputs for missing labels.\n * @internal\n */\nconst auditFormInputs = (container: Element): AuditFinding[] => {\n const findings: AuditFinding[] = [];\n const inputs = container.querySelectorAll('input, select, textarea');\n\n for (const input of inputs) {\n const type = input.getAttribute('type');\n\n // Hidden, submit, and button inputs don't need labels\n if (type === 'hidden' || type === 'submit' || type === 'button' || type === 'reset') {\n continue;\n }\n\n const id = input.getAttribute('id');\n const hasLabel = id ? !!container.querySelector(`label[for=\"${id}\"]`) : false;\n const hasAriaLabel = input.hasAttribute('aria-label') || input.hasAttribute('aria-labelledby');\n const hasTitle = input.hasAttribute('title');\n const isWrappedInLabel = input.closest('label') !== null;\n\n if (!hasLabel && !hasAriaLabel && !hasTitle && !isWrappedInLabel) {\n findings.push(\n finding(\n 'error',\n `Form input is missing a label. Add a <label for=\"id\">, aria-label, or aria-labelledby attribute.`,\n input,\n 'input-label'\n )\n );\n }\n }\n\n return findings;\n};\n\n/**\n * Checks for empty interactive elements (buttons, links).\n * @internal\n */\nconst auditInteractiveElements = (container: Element): AuditFinding[] => {\n const findings: AuditFinding[] = [];\n\n // Check buttons\n const buttons = container.querySelectorAll('button');\n for (const btn of buttons) {\n const hasText = (btn.textContent ?? '').trim().length > 0;\n const hasAriaLabel = btn.hasAttribute('aria-label') || btn.hasAttribute('aria-labelledby');\n const hasTitle = btn.hasAttribute('title');\n\n if (!hasText && !hasAriaLabel && !hasTitle) {\n findings.push(\n finding(\n 'error',\n 'Button has no accessible name. Add text content, aria-label, or title.',\n btn,\n 'button-name'\n )\n );\n }\n }\n\n // Check links\n const links = container.querySelectorAll('a[href]');\n for (const link of links) {\n const hasText = (link.textContent ?? '').trim().length > 0;\n const hasAriaLabel = link.hasAttribute('aria-label') || link.hasAttribute('aria-labelledby');\n const hasTitle = link.hasAttribute('title');\n const hasImage = link.querySelector('img[alt]') !== null;\n\n if (!hasText && !hasAriaLabel && !hasTitle && !hasImage) {\n findings.push(\n finding(\n 'error',\n 'Link has no accessible name. Add text content, aria-label, or title.',\n link,\n 'link-name'\n )\n );\n }\n }\n\n return findings;\n};\n\n/**\n * Checks heading hierarchy for skipped levels.\n * @internal\n */\nconst auditHeadings = (container: Element): AuditFinding[] => {\n const findings: AuditFinding[] = [];\n const headings = container.querySelectorAll('h1, h2, h3, h4, h5, h6');\n\n let previousLevel = 0;\n\n for (const heading of headings) {\n const level = parseInt(heading.tagName.charAt(1), 10);\n\n if (previousLevel > 0 && level > previousLevel + 1) {\n findings.push(\n finding(\n 'warning',\n `Heading level skipped: <${heading.tagName.toLowerCase()}> follows <h${previousLevel}>. Don't skip heading levels.`,\n heading,\n 'heading-order'\n )\n );\n }\n\n if ((heading.textContent ?? '').trim().length === 0) {\n findings.push(finding('warning', 'Heading element is empty.', heading, 'heading-empty'));\n }\n\n previousLevel = level;\n }\n\n return findings;\n};\n\n/**\n * Checks for valid ARIA attribute usage.\n * @internal\n */\nconst auditAria = (container: Element): AuditFinding[] => {\n const findings: AuditFinding[] = [];\n\n // Check aria-labelledby references exist\n const labelled = container.querySelectorAll('[aria-labelledby]');\n for (const el of labelled) {\n const ids = (el.getAttribute('aria-labelledby') ?? '').split(/\\s+/);\n for (const id of ids) {\n if (id && !document.getElementById(id)) {\n findings.push(\n finding(\n 'error',\n `aria-labelledby references \"${id}\" which does not exist in the document.`,\n el,\n 'aria-labelledby-ref'\n )\n );\n }\n }\n }\n\n // Check aria-describedby references exist\n const described = container.querySelectorAll('[aria-describedby]');\n for (const el of described) {\n const ids = (el.getAttribute('aria-describedby') ?? '').split(/\\s+/);\n for (const id of ids) {\n if (id && !document.getElementById(id)) {\n findings.push(\n finding(\n 'error',\n `aria-describedby references \"${id}\" which does not exist in the document.`,\n el,\n 'aria-describedby-ref'\n )\n );\n }\n }\n }\n\n return findings;\n};\n\n/**\n * Checks for sufficient document landmarks.\n * @internal\n */\nconst auditLandmarks = (container: Element): AuditFinding[] => {\n const findings: AuditFinding[] = [];\n\n // Only audit the document body or top-level container\n if (container === document.body || container === document.documentElement) {\n const hasMain = !!container.querySelector('main') || !!container.querySelector('[role=\"main\"]');\n\n if (!hasMain) {\n findings.push(\n finding(\n 'warning',\n 'Page is missing a <main> landmark. Add <main> or role=\"main\" to the primary content area.',\n container,\n 'landmark-main'\n )\n );\n }\n }\n\n return findings;\n};\n\n/**\n * Runs a development-time accessibility audit on a container element.\n *\n * Checks for common accessibility issues including:\n * - Missing alt text on images\n * - Missing labels on form inputs\n * - Empty buttons and links\n * - Heading hierarchy issues\n * - Invalid ARIA references\n * - Missing document landmarks\n *\n * This is intended as a development tool — not a replacement for\n * manual testing or professional accessibility audits.\n *\n * @param container - The element to audit (defaults to `document.body`)\n * @returns An audit result with findings, counts, and pass/fail status\n *\n * @example\n * ```ts\n * import { auditA11y } from '@bquery/bquery/a11y';\n *\n * const result = auditA11y();\n * if (!result.passed) {\n * console.warn(`Found ${result.errors} accessibility errors:`);\n * for (const f of result.findings) {\n * console.warn(`[${f.severity}] ${f.message}`, f.element);\n * }\n * }\n * ```\n */\nexport const auditA11y = (container?: Element): AuditResult => {\n if (typeof document === 'undefined' || !document.body) {\n return {\n findings: [],\n errors: 0,\n warnings: 0,\n passed: true,\n };\n }\n\n const target = container ?? document.body;\n\n const allFindings: AuditFinding[] = [\n ...auditImages(target),\n ...auditFormInputs(target),\n ...auditInteractiveElements(target),\n ...auditHeadings(target),\n ...auditAria(target),\n ...auditLandmarks(target),\n ];\n\n const errors = allFindings.filter((f) => f.severity === 'error').length;\n const warnings = allFindings.filter((f) => f.severity === 'warning').length;\n\n return {\n findings: allFindings,\n errors,\n warnings,\n passed: errors === 0,\n };\n};\n","/**\n * Reactive media preference signals for accessibility.\n *\n * Provides reactive signals that track the user's system-level\n * accessibility preferences (reduced motion, color scheme, contrast).\n *\n * @module bquery/a11y\n */\n\nimport { readonly, signal, type ReadonlySignal } from '../reactive/index';\nimport type { ColorScheme, ContrastPreference, MediaPreferenceSignal } from './types';\n\ntype LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\n};\n\nconst bindMediaQueryListener = (\n mql: MediaQueryList,\n handler: (event: MediaQueryListEvent | MediaQueryList) => void\n): (() => void) | undefined => {\n if (typeof mql.addEventListener === 'function') {\n mql.addEventListener('change', handler);\n return (): void => {\n mql.removeEventListener('change', handler);\n };\n }\n\n const legacyMql = mql as LegacyMediaQueryList;\n if (typeof legacyMql.addListener === 'function') {\n legacyMql.addListener(handler);\n return (): void => {\n legacyMql.removeListener?.(handler);\n };\n }\n\n return undefined;\n};\n\nconst withDestroy = <T>(\n signalHandle: ReadonlySignal<T>,\n cleanup: () => void\n): MediaPreferenceSignal<T> => {\n let destroyImpl = cleanup;\n const handle = signalHandle as MediaPreferenceSignal<T>;\n Object.defineProperty(handle, 'destroy', {\n configurable: true,\n enumerable: false,\n value: (): void => {\n const currentDestroy = destroyImpl;\n // Make cleanup idempotent so repeated destroy() calls from user code stay safe.\n destroyImpl = (): void => {};\n currentDestroy();\n },\n });\n return handle;\n};\n\n/**\n * Creates a reactive signal that tracks a CSS media query.\n *\n * @param query - The media query string\n * @param initialValue - Fallback value when `matchMedia` is unavailable\n * @returns A readonly signal handle that updates when the query match changes\n * @internal\n */\nconst createMediaSignal = (\n query: string,\n initialValue: boolean\n): MediaPreferenceSignal<boolean> => {\n const s = signal(initialValue);\n let destroy = (): void => {\n s.dispose();\n };\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n try {\n const mql = window.matchMedia(query);\n s.value = mql.matches;\n\n const handler = (e: MediaQueryListEvent | MediaQueryList): void => {\n s.value = e.matches;\n };\n\n const cleanupMql = bindMediaQueryListener(mql, handler);\n if (cleanupMql) {\n destroy = (): void => {\n cleanupMql();\n s.dispose();\n };\n }\n } catch {\n // matchMedia may throw in non-browser environments\n }\n }\n\n return withDestroy(readonly(s), destroy);\n};\n\n/**\n * Returns a reactive signal indicating whether the user prefers reduced motion.\n *\n * Tracks the `(prefers-reduced-motion: reduce)` media query. Returns `true`\n * when the user has requested reduced motion in their system settings.\n *\n * @returns A readonly reactive signal handle. Call `destroy()` to remove listeners.\n *\n * @example\n * ```ts\n * import { prefersReducedMotion } from '@bquery/bquery/a11y';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const reduced = prefersReducedMotion();\n * effect(() => {\n * if (reduced.value) {\n * console.log('User prefers reduced motion');\n * }\n * });\n * ```\n */\nexport const prefersReducedMotion = (): MediaPreferenceSignal<boolean> => {\n return createMediaSignal('(prefers-reduced-motion: reduce)', false);\n};\n\n/**\n * Returns a reactive signal tracking the user's preferred color scheme.\n *\n * Tracks the `(prefers-color-scheme: dark)` media query. Returns `'dark'`\n * when the user prefers a dark color scheme, `'light'` otherwise.\n *\n * @returns A readonly reactive signal handle with `'light'` or `'dark'`\n *\n * @example\n * ```ts\n * import { prefersColorScheme } from '@bquery/bquery/a11y';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const scheme = prefersColorScheme();\n * effect(() => {\n * document.body.dataset.theme = scheme.value;\n * });\n * ```\n */\nexport const prefersColorScheme = (): MediaPreferenceSignal<ColorScheme> => {\n const s = signal<ColorScheme>('light');\n let destroy = (): void => {\n s.dispose();\n };\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n try {\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n s.value = mql.matches ? 'dark' : 'light';\n\n const handler = (e: MediaQueryListEvent | MediaQueryList): void => {\n s.value = e.matches ? 'dark' : 'light';\n };\n\n const cleanupMql = bindMediaQueryListener(mql, handler);\n if (cleanupMql) {\n destroy = (): void => {\n cleanupMql();\n s.dispose();\n };\n }\n } catch {\n // matchMedia may throw in non-browser environments\n }\n }\n\n return withDestroy(readonly(s), destroy);\n};\n\n/**\n * Returns a reactive signal tracking the user's contrast preference.\n *\n * Tracks the `(prefers-contrast)` media query. Returns:\n * - `'more'` — user prefers higher contrast\n * - `'less'` — user prefers lower contrast\n * - `'custom'` — user has set a custom contrast level\n * - `'no-preference'` — no explicit preference\n *\n * @returns A readonly reactive signal handle\n *\n * @example\n * ```ts\n * import { prefersContrast } from '@bquery/bquery/a11y';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const contrast = prefersContrast();\n * effect(() => {\n * if (contrast.value === 'more') {\n * document.body.classList.add('high-contrast');\n * }\n * });\n * ```\n */\nexport const prefersContrast = (): MediaPreferenceSignal<ContrastPreference> => {\n const s = signal<ContrastPreference>('no-preference');\n let destroy = (): void => {\n s.dispose();\n };\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n let mql: MediaQueryList | undefined;\n let mqlLess: MediaQueryList | undefined;\n let mqlCustom: MediaQueryList | undefined;\n\n const update = (): void => {\n // Defensive guard for environments where matchMedia setup fails before\n // listeners are attached; update() is only expected to run after init.\n if (!mql || !mqlLess || !mqlCustom) {\n return;\n }\n\n if (mql.matches) {\n s.value = 'more';\n } else if (mqlLess.matches) {\n s.value = 'less';\n } else if (mqlCustom.matches) {\n s.value = 'custom';\n } else {\n s.value = 'no-preference';\n }\n };\n\n // Listen for changes on the contrast preference variants\n try {\n mql = window.matchMedia('(prefers-contrast: more)');\n mqlLess = window.matchMedia('(prefers-contrast: less)');\n mqlCustom = window.matchMedia('(prefers-contrast: custom)');\n update();\n const cleanupFns = [mql, mqlLess, mqlCustom]\n .map((entry) =>\n bindMediaQueryListener(entry, () => {\n update();\n })\n )\n .filter((cleanup): cleanup is () => void => cleanup !== undefined);\n\n if (cleanupFns.length > 0) {\n destroy = (): void => {\n for (const cleanup of cleanupFns) {\n cleanup();\n }\n s.dispose();\n };\n }\n } catch {\n // matchMedia may throw in non-browser environments\n }\n }\n\n return withDestroy(readonly(s), destroy);\n};\n","/**\n * Roving tab index utility for arrow-key navigation within groups.\n *\n * Implements the WAI-ARIA roving tabindex pattern: only one item\n * in the group has tabindex=\"0\" (the active item), while all others\n * have tabindex=\"-1\". Arrow keys move focus between items.\n *\n * @module bquery/a11y\n */\n\nimport type { RovingTabIndexHandle, RovingTabIndexOptions } from './types';\n\n/**\n * Sets up roving tab index navigation for a group of elements.\n *\n * Only the active item receives `tabindex=\"0\"`, making it the only\n * tabbable element in the group. Arrow keys move focus between items,\n * and Home/End jump to the first/last item.\n *\n * @param container - The parent element containing the navigable items\n * @param itemSelector - CSS selector for the navigable items within the container\n * @param options - Configuration options\n * @returns A handle with `destroy()`, `focusItem()`, and `activeIndex()`\n *\n * @example\n * ```ts\n * import { rovingTabIndex } from '@bquery/bquery/a11y';\n *\n * const toolbar = document.querySelector('[role=\"toolbar\"]');\n * const handle = rovingTabIndex(toolbar, 'button', {\n * orientation: 'horizontal',\n * wrap: true,\n * });\n *\n * // Later, clean up\n * handle.destroy();\n * ```\n */\nexport const rovingTabIndex = (\n container: HTMLElement,\n itemSelector: string,\n options: RovingTabIndexOptions = {}\n): RovingTabIndexHandle => {\n const { wrap = true, orientation = 'vertical', onActivate } = options;\n\n let currentIndex = 0;\n const originalTabIndexes = new Map<HTMLElement, string | null>();\n\n const getItems = (): HTMLElement[] => {\n return Array.from(container.querySelectorAll(itemSelector)) as HTMLElement[];\n };\n\n const trackItems = (items: HTMLElement[]): void => {\n for (const item of items) {\n if (!originalTabIndexes.has(item)) {\n originalTabIndexes.set(item, item.getAttribute('tabindex'));\n }\n }\n };\n\n const setActiveItem = (index: number): void => {\n const items = getItems();\n if (items.length === 0) return;\n trackItems(items);\n\n // Clamp index\n const clampedIndex = Math.max(0, Math.min(index, items.length - 1));\n\n // Update tabindex on all items\n for (let i = 0; i < items.length; i++) {\n items[i].setAttribute('tabindex', i === clampedIndex ? '0' : '-1');\n }\n\n currentIndex = clampedIndex;\n items[clampedIndex].focus();\n onActivate?.(items[clampedIndex], clampedIndex);\n };\n\n const isRelevantKey = (key: string): boolean => {\n if (key === 'Home' || key === 'End') return true;\n\n switch (orientation) {\n case 'horizontal':\n return key === 'ArrowLeft' || key === 'ArrowRight';\n case 'vertical':\n return key === 'ArrowUp' || key === 'ArrowDown';\n case 'both':\n return (\n key === 'ArrowLeft' || key === 'ArrowRight' || key === 'ArrowUp' || key === 'ArrowDown'\n );\n default:\n return false;\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent): void => {\n if (!isRelevantKey(event.key)) return;\n\n const items = getItems();\n if (items.length === 0) return;\n\n event.preventDefault();\n\n let nextIndex = currentIndex;\n\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowRight':\n nextIndex = currentIndex + 1;\n if (nextIndex >= items.length) {\n nextIndex = wrap ? 0 : items.length - 1;\n }\n break;\n\n case 'ArrowUp':\n case 'ArrowLeft':\n nextIndex = currentIndex - 1;\n if (nextIndex < 0) {\n nextIndex = wrap ? items.length - 1 : 0;\n }\n break;\n\n case 'Home':\n nextIndex = 0;\n break;\n\n case 'End':\n nextIndex = items.length - 1;\n break;\n }\n\n setActiveItem(nextIndex);\n };\n\n // Initialize: set tabindex on all items\n const items = getItems();\n trackItems(items);\n for (let i = 0; i < items.length; i++) {\n items[i].setAttribute('tabindex', i === 0 ? '0' : '-1');\n }\n\n container.addEventListener('keydown', handleKeyDown);\n\n return {\n destroy: () => {\n container.removeEventListener('keydown', handleKeyDown);\n // Restore original tabindex values\n for (const [item, originalTabIndex] of originalTabIndexes) {\n if (originalTabIndex === null) {\n item.removeAttribute('tabindex');\n } else {\n item.setAttribute('tabindex', originalTabIndex);\n }\n }\n originalTabIndexes.clear();\n },\n\n focusItem: (index: number) => {\n setActiveItem(index);\n },\n\n activeIndex: () => currentIndex,\n };\n};\n","/**\n * Auto-generated skip navigation link utility.\n *\n * Creates a visually-hidden (but keyboard-focusable) \"Skip to content\"\n * link that becomes visible on focus, letting keyboard users bypass\n * repeated navigation.\n *\n * @module bquery/a11y\n */\n\nimport type { SkipLinkHandle, SkipLinkOptions } from './types';\n\n/** Default CSS for the skip link — visually hidden until focused. */\nconst DEFAULT_STYLES = `\n position: absolute;\n top: -9999px;\n left: -9999px;\n z-index: 999999;\n padding: 0.5em 1em;\n background: #000;\n color: #fff;\n font-size: 1rem;\n text-decoration: none;\n border-radius: 0 0 4px 0;\n outline: 2px solid #4A90D9;\n outline-offset: 2px;\n`;\n\nconst FOCUSED_STYLES = `\n top: 0;\n left: 0;\n`;\n\nlet skipTargetIdCounter = 0;\nconst generatedSkipTargetRefs = new Map<string, { count: number; target: HTMLElement }>();\n\nconst hasSkipLinkEnvironment = (): boolean => {\n if (typeof document === 'undefined') {\n return false;\n }\n\n return (\n typeof document.createElement === 'function' &&\n typeof document.querySelector === 'function' &&\n typeof document.getElementById === 'function' &&\n document.body !== null &&\n document.body !== undefined\n );\n};\n\nconst createNoopSkipLinkHandle = (): SkipLinkHandle => ({\n destroy: () => {},\n element: null,\n});\n\n/**\n * Creates a skip navigation link that jumps to the specified target.\n *\n * The link is visually hidden by default and becomes visible when\n * it receives keyboard focus. This follows the WCAG 2.4.1 \"Bypass Blocks\"\n * success criterion.\n *\n * @param targetSelector - CSS selector for the main content area (e.g. `'#main'`, `'main'`)\n * @param options - Configuration options\n * @returns A handle with `destroy()` method and reference to the created element\n *\n * @example\n * ```ts\n * import { skipLink } from '@bquery/bquery/a11y';\n *\n * // Creates a \"Skip to main content\" link pointing to <main>\n * const handle = skipLink('#main-content');\n *\n * // Custom text\n * const handle2 = skipLink('#content', { text: 'Jump to content' });\n *\n * // Remove when no longer needed\n * handle.destroy();\n * ```\n */\nexport const skipLink = (targetSelector: string, options: SkipLinkOptions = {}): SkipLinkHandle => {\n if (!hasSkipLinkEnvironment()) {\n return createNoopSkipLinkHandle();\n }\n\n const { text = 'Skip to main content', className = 'bq-skip-link' } = options;\n let trackedGeneratedTargetId: string | undefined;\n let trackedFocusTarget:\n | { target: HTMLElement; hadTabIndex: boolean; previousTabIndex: string | null }\n | undefined;\n const safeQuerySelector = (selector: string): HTMLElement | null => {\n try {\n return document.querySelector(selector) as HTMLElement | null;\n } catch {\n return null;\n }\n };\n const releaseTrackedGeneratedTargetId = (): void => {\n if (!trackedGeneratedTargetId) return;\n\n const entry = generatedSkipTargetRefs.get(trackedGeneratedTargetId);\n const remainingRefs = (entry?.count ?? 0) - 1;\n if (remainingRefs <= 0) {\n generatedSkipTargetRefs.delete(trackedGeneratedTargetId);\n if (entry?.target.isConnected && entry.target.id === trackedGeneratedTargetId) {\n entry.target.removeAttribute('id');\n }\n } else {\n generatedSkipTargetRefs.set(trackedGeneratedTargetId, {\n count: remainingRefs,\n target: entry!.target,\n });\n }\n\n trackedGeneratedTargetId = undefined;\n };\n const restoreTrackedFocusTarget = (): void => {\n if (!trackedFocusTarget) return;\n\n const { target, hadTabIndex, previousTabIndex } = trackedFocusTarget;\n if (target.isConnected) {\n if (hadTabIndex) {\n target.setAttribute('tabindex', previousTabIndex ?? '');\n } else {\n target.removeAttribute('tabindex');\n }\n }\n\n trackedFocusTarget = undefined;\n };\n const ensureTargetFocusable = (target: HTMLElement): void => {\n if (trackedFocusTarget?.target === target) {\n return;\n }\n\n restoreTrackedFocusTarget();\n\n if (target.hasAttribute('tabindex')) {\n trackedFocusTarget = {\n target,\n hadTabIndex: true,\n previousTabIndex: target.getAttribute('tabindex'),\n };\n return;\n }\n\n if (target.tabIndex !== -1) {\n return;\n }\n\n trackedFocusTarget = {\n target,\n hadTabIndex: false,\n previousTabIndex: null,\n };\n target.setAttribute('tabindex', '-1');\n };\n const trackGeneratedTargetId = (target: HTMLElement, id: string): void => {\n if (trackedGeneratedTargetId === id) return;\n releaseTrackedGeneratedTargetId();\n const entry = generatedSkipTargetRefs.get(id);\n generatedSkipTargetRefs.set(id, {\n count: (entry?.count ?? 0) + 1,\n target,\n });\n trackedGeneratedTargetId = id;\n };\n const resolveTarget = (): HTMLElement | null => {\n if (targetSelector.startsWith('#')) {\n const id = targetSelector.slice(1);\n const byId = id ? (document.getElementById(id) as HTMLElement | null) : null;\n if (byId) {\n return byId;\n }\n\n return safeQuerySelector(targetSelector);\n }\n\n const byId = document.getElementById(targetSelector) as HTMLElement | null;\n if (byId) {\n return byId;\n }\n\n return safeQuerySelector(targetSelector);\n };\n\n const ensureTargetId = (target: HTMLElement): string => {\n if (target.id) {\n const generatedTarget = generatedSkipTargetRefs.get(target.id);\n if (generatedTarget?.target === target) {\n trackGeneratedTargetId(target, target.id);\n }\n return target.id;\n }\n\n let generatedTargetId: string;\n do {\n skipTargetIdCounter += 1;\n generatedTargetId = `bq-skip-target-${skipTargetIdCounter}`;\n } while (document.getElementById(generatedTargetId) !== null);\n\n target.id = generatedTargetId;\n trackGeneratedTargetId(target, generatedTargetId);\n return generatedTargetId;\n };\n\n const link = document.createElement('a');\n const initialTarget = resolveTarget();\n link.href = targetSelector.startsWith('#')\n ? targetSelector\n : initialTarget\n ? `#${ensureTargetId(initialTarget)}`\n : `#${targetSelector}`;\n link.textContent = text;\n link.className = className;\n link.setAttribute('style', DEFAULT_STYLES);\n\n link.addEventListener('focus', () => {\n link.setAttribute('style', DEFAULT_STYLES + FOCUSED_STYLES);\n });\n\n link.addEventListener('blur', () => {\n link.setAttribute('style', DEFAULT_STYLES);\n });\n\n link.addEventListener('click', (e) => {\n e.preventDefault();\n\n const target = resolveTarget();\n if (!target) {\n return;\n }\n\n link.href = `#${ensureTargetId(target)}`;\n // Make the target focusable if it isn't already\n ensureTargetFocusable(target);\n target.focus();\n });\n\n // Insert as the first child of <body>\n if (document.body.firstChild) {\n document.body.insertBefore(link, document.body.firstChild);\n } else {\n document.body.appendChild(link);\n }\n\n return {\n destroy: () => {\n restoreTrackedFocusTarget();\n releaseTrackedGeneratedTargetId();\n link.remove();\n },\n element: link,\n };\n};\n","/**\n * Focus trapping utility for modals, dialogs, and popover content.\n *\n * Constrains keyboard focus within a container so that Tab and Shift+Tab\n * cycle only through the container's focusable elements.\n *\n * @module bquery/a11y\n */\n\nimport type { FocusTrapHandle, TrapFocusOptions } from './types';\n\n/** Selector for elements that can receive focus. */\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n 'details > summary',\n 'audio[controls]',\n 'video[controls]',\n].join(', ');\n\n/**\n * Gets all focusable elements within a container.\n *\n * @param container - The container element\n * @returns Array of focusable elements\n * @internal\n */\nexport const getFocusableElements = (container: Element): HTMLElement[] => {\n const elements = Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)) as HTMLElement[];\n return elements.filter(\n (el) => !el.hasAttribute('disabled') && el.tabIndex !== -1 && el.getClientRects().length > 0\n );\n};\n\n/**\n * Resolves an element from a string selector or returns the element directly.\n * @internal\n */\nconst resolveElement = (\n target: HTMLElement | string | undefined,\n container: Element\n): HTMLElement | null => {\n if (!target) return null;\n if (typeof target === 'string') {\n return container.querySelector(target) as HTMLElement | null;\n }\n return target;\n};\n\n/**\n * Traps keyboard focus within a container element.\n *\n * When activated, Tab and Shift+Tab will cycle only through focusable\n * elements within the container. Useful for modals, dialogs, and\n * dropdown menus.\n *\n * @param container - The DOM element to trap focus within\n * @param options - Configuration options\n * @returns A handle with a `release()` method to deactivate the trap\n *\n * @example\n * ```ts\n * import { trapFocus } from '@bquery/bquery/a11y';\n *\n * const dialog = document.querySelector('#my-dialog');\n * const trap = trapFocus(dialog, { escapeDeactivates: true });\n *\n * // Later, release the trap\n * trap.release();\n * ```\n */\nexport const trapFocus = (\n container: HTMLElement,\n options: TrapFocusOptions = {}\n): FocusTrapHandle => {\n const { escapeDeactivates = true, onEscape, initialFocus, returnFocus } = options;\n\n if (\n typeof document === 'undefined' ||\n typeof document.addEventListener !== 'function' ||\n typeof document.removeEventListener !== 'function'\n ) {\n let active = false;\n return {\n get active() {\n return active;\n },\n release: () => {\n active = false;\n },\n };\n }\n\n const previouslyFocused = document.activeElement as HTMLElement | null;\n let active = true;\n\n const handleKeyDown = (event: KeyboardEvent): void => {\n if (!active) return;\n\n if (event.key === 'Escape' && escapeDeactivates) {\n event.preventDefault();\n handle.release();\n onEscape?.();\n return;\n }\n\n if (event.key !== 'Tab') return;\n\n const focusable = getFocusableElements(container);\n if (focusable.length === 0) {\n event.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (event.shiftKey) {\n // Shift+Tab: if at first element, wrap to last\n if (document.activeElement === first || !container.contains(document.activeElement)) {\n event.preventDefault();\n last.focus();\n }\n } else {\n // Tab: if at last element, wrap to first\n if (document.activeElement === last || !container.contains(document.activeElement)) {\n event.preventDefault();\n first.focus();\n }\n }\n };\n\n // Attach the event listener\n document.addEventListener('keydown', handleKeyDown, true);\n\n // Set initial focus\n const initialEl = resolveElement(initialFocus, container);\n if (initialEl) {\n initialEl.focus();\n } else {\n const focusable = getFocusableElements(container);\n if (focusable.length > 0) {\n focusable[0].focus();\n }\n }\n\n const handle: FocusTrapHandle = {\n get active() {\n return active;\n },\n\n release: () => {\n if (!active) return;\n active = false;\n document.removeEventListener('keydown', handleKeyDown, true);\n\n // Return focus\n const returnEl = resolveElement(returnFocus, document.body);\n if (returnEl) {\n returnEl.focus();\n } else if (previouslyFocused && previouslyFocused.focus) {\n previouslyFocused.focus();\n }\n },\n };\n\n return handle;\n};\n\n/**\n * Releases a focus trap handle.\n * This is a convenience function — in most cases, use the `release()`\n * method on the individual trap handle directly.\n *\n * @deprecated Prefer using the handle returned by `trapFocus()` directly.\n */\nexport const releaseFocus = (handle: FocusTrapHandle): void => {\n handle.release();\n};\n","/**\n * Make an element draggable using pointer events.\n *\n * Uses Pointer Events (not HTML5 Drag & Drop) for reliable\n * cross-platform behavior including touch support.\n *\n * @module bquery/dnd\n */\n\nimport type {\n BoundsRect,\n DragBounds,\n DragEventData,\n DragPosition,\n DraggableHandle,\n DraggableOptions,\n} from './types';\n\n/** Global registry of active draggable elements for drop zone detection. */\nconst activeDrags = new Map<HTMLElement, { element: HTMLElement; position: DragPosition }>();\n\n/**\n * Returns the currently active drag state, if any.\n * Used internally by `droppable()` to detect drag interactions.\n * @internal\n */\nexport const getActiveDrag = (): { element: HTMLElement; position: DragPosition } | undefined => {\n const entries = Array.from(activeDrags.values());\n return entries[entries.length - 1];\n};\n\n/**\n * Resolves a `DragBounds` value to an absolute `BoundsRect`.\n * @internal\n */\nconst resolveBounds = (el: HTMLElement, bounds: DragBounds): BoundsRect | null => {\n if (typeof bounds === 'object') {\n return bounds;\n }\n\n let target: HTMLElement | null = null;\n\n if (bounds === 'parent') {\n target = el.parentElement;\n } else {\n target = document.querySelector(bounds) as HTMLElement | null;\n }\n\n if (!target) return null;\n\n const rect = target.getBoundingClientRect();\n const elRect = el.getBoundingClientRect();\n const rawLeft = parseFloat(el.style.left || '0');\n const rawTop = parseFloat(el.style.top || '0');\n const leftOffset = Number.isNaN(rawLeft) ? 0 : rawLeft;\n const topOffset = Number.isNaN(rawTop) ? 0 : rawTop;\n\n return {\n left: rect.left - elRect.left + leftOffset,\n top: rect.top - elRect.top + topOffset,\n right: rect.right - elRect.right + leftOffset + (rect.width - elRect.width),\n bottom: rect.bottom - elRect.bottom + topOffset + (rect.height - elRect.height),\n };\n};\n\n/**\n * Clamp a position within bounds.\n * @internal\n */\nconst clampPosition = (pos: DragPosition, bounds: BoundsRect | null): DragPosition => {\n if (!bounds) return pos;\n return {\n x: Math.max(bounds.left, Math.min(bounds.right, pos.x)),\n y: Math.max(bounds.top, Math.min(bounds.bottom, pos.y)),\n };\n};\n\n/**\n * Makes an element draggable using pointer events.\n *\n * Features:\n * - Touch and mouse support via Pointer Events\n * - Axis locking (`x`, `y`, or `both`)\n * - Bounds constraint (parent, selector, or explicit rect)\n * - Optional drag handle\n * - Ghost/clone preview during drag\n * - Callbacks: `onDragStart`, `onDrag`, `onDragEnd`\n *\n * @param el - The element to make draggable\n * @param options - Configuration options\n * @returns A handle with `destroy()`, `disable()`, and `enable()` methods\n *\n * @example\n * ```ts\n * import { draggable } from '@bquery/bquery/dnd';\n *\n * const handle = draggable(document.querySelector('#box'), {\n * axis: 'both',\n * bounds: 'parent',\n * onDragEnd: ({ position }) => {\n * console.log('Dropped at', position.x, position.y);\n * },\n * });\n *\n * // Later:\n * handle.destroy();\n * ```\n */\nexport const draggable = (el: HTMLElement, options: DraggableOptions = {}): DraggableHandle => {\n const {\n axis = 'both',\n bounds,\n handle,\n ghost = false,\n ghostClass = 'bq-drag-ghost',\n draggingClass = 'bq-dragging',\n onDragStart,\n onDrag,\n onDragEnd,\n } = options;\n\n let enabled = !options.disabled;\n let isDragging = false;\n let startPointer: DragPosition = { x: 0, y: 0 };\n let currentPosition: DragPosition = { x: 0, y: 0 };\n let previousPosition: DragPosition = { x: 0, y: 0 };\n let ghostEl: HTMLElement | null = null;\n let ghostStartPosition: DragPosition | null = null;\n const previousTouchAction = el.style.touchAction;\n const previousUserSelect = el.style.userSelect;\n\n const createEventData = (event: PointerEvent): DragEventData => ({\n element: el,\n position: { ...currentPosition },\n delta: {\n x: currentPosition.x - previousPosition.x,\n y: currentPosition.y - previousPosition.y,\n },\n event,\n });\n\n const createGhost = (): HTMLElement => {\n const clone = el.cloneNode(true) as HTMLElement;\n const rect = el.getBoundingClientRect();\n clone.classList.add(ghostClass);\n clone.style.position = 'fixed';\n clone.style.left = `${rect.left}px`;\n clone.style.top = `${rect.top}px`;\n clone.style.width = `${rect.width}px`;\n clone.style.height = `${rect.height}px`;\n clone.style.pointerEvents = 'none';\n clone.style.zIndex = '999999';\n clone.style.opacity = '0.7';\n clone.style.margin = '0';\n document.body.appendChild(clone);\n return clone;\n };\n\n const removeGhost = (): void => {\n if (ghostEl) {\n ghostEl.remove();\n ghostEl = null;\n }\n ghostStartPosition = null;\n };\n\n const onPointerDown = (e: PointerEvent): void => {\n if (!enabled) return;\n\n // Check handle constraint\n if (handle) {\n const target = e.target as Element;\n if (!target.closest(handle)) return;\n }\n\n e.preventDefault();\n isDragging = true;\n startPointer = { x: e.clientX, y: e.clientY };\n previousPosition = { ...currentPosition };\n\n el.classList.add(draggingClass);\n el.setPointerCapture(e.pointerId);\n\n if (ghost) {\n const rect = el.getBoundingClientRect();\n ghostStartPosition = { x: rect.left, y: rect.top };\n ghostEl = createGhost();\n }\n\n // Register in global active drags\n activeDrags.set(el, { element: el, position: currentPosition });\n\n onDragStart?.(createEventData(e));\n };\n\n const onPointerMove = (e: PointerEvent): void => {\n if (!isDragging) return;\n\n e.preventDefault();\n previousPosition = { ...currentPosition };\n\n let newX = currentPosition.x + (e.clientX - startPointer.x);\n let newY = currentPosition.y + (e.clientY - startPointer.y);\n\n // Reset start pointer to current for delta calculation\n startPointer = { x: e.clientX, y: e.clientY };\n\n // Apply axis constraint\n if (axis === 'x') newY = currentPosition.y;\n if (axis === 'y') newX = currentPosition.x;\n\n let newPos: DragPosition = { x: newX, y: newY };\n\n // Apply bounds constraint\n if (bounds) {\n const resolvedBounds = resolveBounds(el, bounds);\n newPos = clampPosition(newPos, resolvedBounds);\n }\n\n currentPosition = newPos;\n\n // Update active drag position\n activeDrags.set(el, { element: el, position: currentPosition });\n\n // Apply the position\n if (ghost && ghostEl) {\n const start = ghostStartPosition ?? {\n x: el.getBoundingClientRect().left,\n y: el.getBoundingClientRect().top,\n };\n ghostEl.style.left = `${start.x + currentPosition.x}px`;\n ghostEl.style.top = `${start.y + currentPosition.y}px`;\n } else {\n el.style.transform = `translate(${currentPosition.x}px, ${currentPosition.y}px)`;\n }\n\n onDrag?.(createEventData(e));\n };\n\n const onPointerUp = (e: PointerEvent): void => {\n if (!isDragging) return;\n\n isDragging = false;\n el.classList.remove(draggingClass);\n try {\n if (\n typeof el.releasePointerCapture === 'function' &&\n (typeof el.hasPointerCapture !== 'function' || el.hasPointerCapture(e.pointerId))\n ) {\n el.releasePointerCapture(e.pointerId);\n }\n } catch {\n // Pointer capture may already be released in some interrupted drag flows.\n } finally {\n removeGhost();\n\n // Remove from active drags\n activeDrags.delete(el);\n\n onDragEnd?.(createEventData(e));\n }\n };\n\n // Attach listeners\n el.addEventListener('pointerdown', onPointerDown);\n el.addEventListener('pointermove', onPointerMove);\n el.addEventListener('pointerup', onPointerUp);\n el.addEventListener('pointercancel', onPointerUp);\n\n // Prevent default drag behavior\n el.style.touchAction = 'none';\n el.style.userSelect = 'none';\n\n return {\n destroy: () => {\n el.removeEventListener('pointerdown', onPointerDown);\n el.removeEventListener('pointermove', onPointerMove);\n el.removeEventListener('pointerup', onPointerUp);\n el.removeEventListener('pointercancel', onPointerUp);\n removeGhost();\n activeDrags.delete(el);\n el.style.touchAction = previousTouchAction;\n el.style.userSelect = previousUserSelect;\n el.classList.remove(draggingClass);\n },\n disable: () => {\n enabled = false;\n },\n enable: () => {\n enabled = true;\n },\n get enabled() {\n return enabled;\n },\n };\n};\n","/**\n * Define drop zones for draggable elements.\n *\n * Drop zones detect when draggable elements enter, move over,\n * leave, or are dropped onto them using pointer event hit-testing.\n *\n * @module bquery/dnd\n */\n\nimport { getActiveDrag } from './draggable';\nimport type { DropEventData, DroppableHandle, DroppableOptions } from './types';\n\ntype DroppableListener = {\n handlePointerMove: (event: PointerEvent) => void;\n handlePointerUp: (event: PointerEvent) => void;\n};\n\nconst passivePointerMoveListenerOptions = { passive: true } as const;\n\nconst droppableListeners = new Set<DroppableListener>();\nlet queuedPointerMove: PointerEvent | null = null;\nlet pointerMoveFrame: number | null = null;\n\nconst getDroppableListenersSnapshot = (): DroppableListener[] => Array.from(droppableListeners);\n\nconst hasDroppableEnvironment = (): boolean => {\n return (\n typeof document !== 'undefined' &&\n typeof document.addEventListener === 'function' &&\n typeof document.removeEventListener === 'function' &&\n typeof requestAnimationFrame === 'function' &&\n typeof cancelAnimationFrame === 'function'\n );\n};\n\nconst dispatchPointerMove = (event: PointerEvent): void => {\n for (const listener of getDroppableListenersSnapshot()) {\n listener.handlePointerMove(event);\n }\n};\n\nconst flushPointerMove = (): void => {\n pointerMoveFrame = null;\n const event = queuedPointerMove;\n queuedPointerMove = null;\n if (!event) return;\n dispatchPointerMove(event);\n};\n\nconst handleDocumentPointerMove = (event: PointerEvent): void => {\n queuedPointerMove = event;\n if (pointerMoveFrame === null) {\n pointerMoveFrame = requestAnimationFrame(flushPointerMove);\n }\n};\n\nconst handleDocumentPointerUp = (event: PointerEvent): void => {\n if (pointerMoveFrame !== null) {\n cancelAnimationFrame(pointerMoveFrame);\n pointerMoveFrame = null;\n queuedPointerMove = null;\n }\n\n for (const listener of getDroppableListenersSnapshot()) {\n listener.handlePointerUp(event);\n }\n};\n\nconst registerDroppableListener = (listener: DroppableListener): void => {\n if (droppableListeners.size === 0) {\n document.addEventListener(\n 'pointermove',\n handleDocumentPointerMove,\n passivePointerMoveListenerOptions\n );\n document.addEventListener('pointerup', handleDocumentPointerUp);\n }\n\n droppableListeners.add(listener);\n};\n\nconst unregisterDroppableListener = (listener: DroppableListener): void => {\n droppableListeners.delete(listener);\n\n if (droppableListeners.size !== 0) return;\n\n document.removeEventListener('pointermove', handleDocumentPointerMove);\n document.removeEventListener('pointerup', handleDocumentPointerUp);\n if (pointerMoveFrame !== null) {\n cancelAnimationFrame(pointerMoveFrame);\n pointerMoveFrame = null;\n }\n queuedPointerMove = null;\n};\n\n/**\n * Checks whether a dragged element is accepted by the drop zone.\n * @internal\n */\nconst isAccepted = (dragged: HTMLElement, accept: DroppableOptions['accept']): boolean => {\n if (!accept) return true;\n if (typeof accept === 'string') return dragged.matches(accept);\n return accept(dragged);\n};\n\n/**\n * Defines an element as a drop zone.\n *\n * Drop zones respond to draggable elements being moved over them\n * by firing callbacks and applying CSS classes. They work with\n * the `draggable()` function from this module.\n *\n * @param el - The drop zone element\n * @param options - Configuration options\n * @returns A handle with a `destroy()` method\n *\n * @example\n * ```ts\n * import { droppable } from '@bquery/bquery/dnd';\n *\n * const handle = droppable(document.querySelector('#dropzone'), {\n * accept: '.draggable-item',\n * overClass: 'drop-active',\n * onDrop: ({ dragged }) => {\n * console.log('Dropped:', dragged);\n * },\n * });\n *\n * // Later:\n * handle.destroy();\n * ```\n */\nexport const droppable = (el: HTMLElement, options: DroppableOptions = {}): DroppableHandle => {\n const {\n overClass = 'bq-drop-over',\n accept,\n onDragEnter,\n onDragOver,\n onDragLeave,\n onDrop,\n } = options;\n\n if (!hasDroppableEnvironment()) {\n return {\n destroy: () => {},\n };\n }\n\n let isOver = false;\n let currentDragged: HTMLElement | null = null;\n\n const createEventData = (dragged: HTMLElement, event: PointerEvent): DropEventData => ({\n zone: el,\n dragged,\n event,\n });\n\n const isPointerInside = (event: PointerEvent): boolean => {\n const rect = el.getBoundingClientRect();\n return (\n event.clientX >= rect.left &&\n event.clientX <= rect.right &&\n event.clientY >= rect.top &&\n event.clientY <= rect.bottom\n );\n };\n\n const resolveDraggedElement = (): HTMLElement | null => {\n return getActiveDrag()?.element ?? currentDragged;\n };\n\n const clearOverState = (event: PointerEvent, dragged = currentDragged): void => {\n if (!isOver) return;\n isOver = false;\n el.classList.remove(overClass);\n if (dragged) {\n onDragLeave?.(createEventData(dragged, event));\n }\n currentDragged = null;\n };\n\n const handlePointerMove = (e: PointerEvent): void => {\n const dragged = getActiveDrag()?.element ?? null;\n const isInside = isPointerInside(e);\n const acceptsDragged = dragged !== null && dragged !== el && isAccepted(dragged, accept);\n\n if (!acceptsDragged || !isInside) {\n clearOverState(e, dragged ?? currentDragged);\n return;\n }\n\n if (!isOver) {\n isOver = true;\n currentDragged = dragged;\n el.classList.add(overClass);\n onDragEnter?.(createEventData(dragged, e));\n } else {\n onDragOver?.(createEventData(dragged, e));\n }\n };\n\n const handlePointerUp = (e: PointerEvent): void => {\n const dragged = resolveDraggedElement();\n const isInside = isPointerInside(e);\n const acceptsDragged = dragged !== null && dragged !== el && isAccepted(dragged, accept);\n\n if (isInside && acceptsDragged && dragged) {\n onDrop?.(createEventData(dragged, e));\n }\n\n if (isOver) {\n isOver = false;\n el.classList.remove(overClass);\n }\n currentDragged = null;\n };\n\n const listener: DroppableListener = { handlePointerMove, handlePointerUp };\n registerDroppableListener(listener);\n\n return {\n destroy: () => {\n unregisterDroppableListener(listener);\n el.classList.remove(overClass);\n currentDragged = null;\n },\n };\n};\n","/**\n * Sortable list with animated reordering via pointer events.\n *\n * Makes children of a container sortable by dragging. Items are\n * rearranged in the DOM with optional CSS animation.\n *\n * @module bquery/dnd\n */\n\nimport type { SortEventData, SortableHandle, SortableOptions } from './types';\n\n/**\n * Gets the sortable items within a container.\n * @internal\n */\nconst getItems = (container: HTMLElement, selector: string): HTMLElement[] => {\n return Array.from(container.querySelectorAll(selector)) as HTMLElement[];\n};\n\n/**\n * Finds the closest sortable item to a given Y (or X) position.\n * @internal\n */\nconst getClosestItem = (\n items: HTMLElement[],\n clientPos: number,\n axis: 'x' | 'y',\n dragged: HTMLElement\n): { element: HTMLElement; index: number } | null => {\n let closest: { element: HTMLElement; index: number; distance: number } | null = null;\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (item === dragged) continue;\n\n const rect = item.getBoundingClientRect();\n const mid = axis === 'y' ? rect.top + rect.height / 2 : rect.left + rect.width / 2;\n const distance = clientPos - mid;\n\n if (\n closest === null ||\n (distance < 0 && distance > closest.distance) ||\n (closest.distance >= 0 && distance < 0 && Math.abs(distance) < Math.abs(closest.distance))\n ) {\n // Find the item we're just before\n if (distance < 0) {\n closest = { element: item, index: i, distance };\n }\n }\n }\n\n return closest ? { element: closest.element, index: closest.index } : null;\n};\n\n/**\n * Makes the children of a container sortable by dragging.\n *\n * Features:\n * - Pointer event based (touch + mouse)\n * - Animated reordering with configurable duration\n * - Axis constraint (vertical or horizontal)\n * - Optional drag handle\n * - Placeholder element during sort\n * - Callbacks: `onSortStart`, `onSortMove`, `onSortEnd`\n *\n * @param container - The container element whose children will be sortable\n * @param options - Configuration options\n * @returns A handle with `destroy()`, `disable()`, and `enable()` methods\n *\n * @example\n * ```ts\n * import { sortable } from '@bquery/bquery/dnd';\n *\n * const handle = sortable(document.querySelector('#list'), {\n * items: 'li',\n * axis: 'y',\n * animationDuration: 200,\n * onSortEnd: ({ oldIndex, newIndex }) => {\n * console.log(`Moved from ${oldIndex} to ${newIndex}`);\n * },\n * });\n *\n * // Later:\n * handle.destroy();\n * ```\n */\nexport const sortable = (container: HTMLElement, options: SortableOptions = {}): SortableHandle => {\n const {\n items: itemSelector = ':scope > *',\n axis = 'y',\n handle,\n placeholderClass = 'bq-sort-placeholder',\n sortingClass = 'bq-sorting',\n animationDuration = 200,\n onSortStart,\n onSortMove,\n onSortEnd,\n } = options;\n\n let enabled = !options.disabled;\n let isDragging = false;\n let dragItem: HTMLElement | null = null;\n let placeholder: HTMLElement | null = null;\n let startIndex = -1;\n let startPointerY = 0;\n let startPointerX = 0;\n let itemStartTop = 0;\n let itemStartLeft = 0;\n\n const createEventData = (item: HTMLElement, oldIdx: number, newIdx: number): SortEventData => ({\n container,\n item,\n oldIndex: oldIdx,\n newIndex: newIdx,\n });\n\n const onPointerDown = (e: PointerEvent): void => {\n if (!enabled) return;\n\n const target = e.target as HTMLElement;\n\n // Find the item being dragged\n const items = getItems(container, itemSelector);\n let item: HTMLElement | null = null;\n\n for (const it of items) {\n if (it.contains(target)) {\n item = it;\n break;\n }\n }\n\n if (!item) return;\n\n // Check handle constraint\n if (handle && !target.closest(handle)) return;\n\n e.preventDefault();\n\n isDragging = true;\n dragItem = item;\n startIndex = items.indexOf(item);\n startPointerY = e.clientY;\n startPointerX = e.clientX;\n\n const rect = item.getBoundingClientRect();\n itemStartTop = rect.top;\n itemStartLeft = rect.left;\n\n // Create placeholder\n placeholder = document.createElement('div');\n placeholder.classList.add(placeholderClass);\n placeholder.style.width = `${rect.width}px`;\n placeholder.style.height = `${rect.height}px`;\n placeholder.style.boxSizing = 'border-box';\n\n // Style the dragged item\n item.classList.add(sortingClass);\n item.style.position = 'fixed';\n item.style.width = `${rect.width}px`;\n item.style.height = `${rect.height}px`;\n item.style.left = `${rect.left}px`;\n item.style.top = `${rect.top}px`;\n item.style.zIndex = '999999';\n item.style.pointerEvents = 'none';\n item.style.margin = '0';\n\n // Insert placeholder where the item was\n item.parentNode?.insertBefore(placeholder, item);\n\n container.setPointerCapture(e.pointerId);\n\n onSortStart?.(createEventData(item, startIndex, startIndex));\n };\n\n const onPointerMove = (e: PointerEvent): void => {\n if (!isDragging || !dragItem || !placeholder) return;\n\n e.preventDefault();\n\n const deltaX = e.clientX - startPointerX;\n const deltaY = e.clientY - startPointerY;\n\n // Move the dragged item\n if (axis === 'y') {\n dragItem.style.top = `${itemStartTop + deltaY}px`;\n } else {\n dragItem.style.left = `${itemStartLeft + deltaX}px`;\n }\n\n // Find the closest item to determine insertion point\n const items = getItems(container, itemSelector);\n const clientPos = axis === 'y' ? e.clientY : e.clientX;\n const closest = getClosestItem(items, clientPos, axis, dragItem);\n\n if (closest) {\n // Move placeholder before the closest element\n container.insertBefore(placeholder, closest.element);\n } else {\n // Append to end\n container.appendChild(placeholder);\n }\n\n const currentIndex = Array.from(container.children).indexOf(placeholder);\n onSortMove?.(createEventData(dragItem, startIndex, currentIndex));\n };\n\n const onPointerUp = (e: PointerEvent): void => {\n if (!isDragging || !dragItem || !placeholder) return;\n\n isDragging = false;\n const draggedItem = dragItem;\n\n // Get final index\n const newIndex = Array.from(container.children).indexOf(placeholder);\n\n // Animate the item back to the placeholder position\n const placeholderRect = placeholder.getBoundingClientRect();\n const itemRect = draggedItem.getBoundingClientRect();\n\n if (animationDuration > 0) {\n const deltaX = placeholderRect.left - itemRect.left;\n const deltaY = placeholderRect.top - itemRect.top;\n\n draggedItem.style.transition = `transform ${animationDuration}ms ease`;\n draggedItem.style.transform = `translate(${deltaX}px, ${deltaY}px)`;\n\n let finalized = false;\n let timeoutId: number | null = null;\n const finalize = (): void => {\n if (finalized) return;\n finalized = true;\n if (timeoutId !== null) {\n window.clearTimeout(timeoutId);\n timeoutId = null;\n }\n resetDragItem();\n onSortEnd?.(createEventData(draggedItem, startIndex, newIndex));\n };\n timeoutId = window.setTimeout(() => {\n finalize();\n }, animationDuration + 50);\n\n draggedItem.addEventListener('transitionend', finalize, { once: true });\n } else {\n resetDragItem();\n onSortEnd?.(createEventData(draggedItem, startIndex, newIndex));\n }\n\n container.releasePointerCapture(e.pointerId);\n };\n\n const resetDragItem = (): void => {\n if (!dragItem || !placeholder) return;\n\n // Insert the real item where the placeholder is\n placeholder.parentNode?.insertBefore(dragItem, placeholder);\n placeholder.remove();\n placeholder = null;\n\n // Reset styles\n dragItem.classList.remove(sortingClass);\n dragItem.style.position = '';\n dragItem.style.width = '';\n dragItem.style.height = '';\n dragItem.style.left = '';\n dragItem.style.top = '';\n dragItem.style.zIndex = '';\n dragItem.style.pointerEvents = '';\n dragItem.style.margin = '';\n dragItem.style.transition = '';\n dragItem.style.transform = '';\n\n dragItem = null;\n };\n\n container.addEventListener('pointerdown', onPointerDown);\n container.addEventListener('pointermove', onPointerMove);\n container.addEventListener('pointerup', onPointerUp);\n container.addEventListener('pointercancel', onPointerUp);\n\n // Prevent default touch behavior on container\n container.style.touchAction = 'none';\n\n return {\n destroy: () => {\n container.removeEventListener('pointerdown', onPointerDown);\n container.removeEventListener('pointermove', onPointerMove);\n container.removeEventListener('pointerup', onPointerUp);\n container.removeEventListener('pointercancel', onPointerUp);\n container.style.touchAction = '';\n\n if (isDragging) {\n resetDragItem();\n }\n },\n disable: () => {\n enabled = false;\n },\n enable: () => {\n enabled = true;\n },\n get enabled() {\n return enabled;\n },\n };\n};\n","/**\n * Reactive media query matching.\n *\n * Returns a reactive boolean signal that tracks whether a CSS media query matches.\n *\n * @module bquery/media\n */\n\nimport { readonly, signal } from '../reactive/index';\nimport type { MediaSignalHandle } from './types';\n\n/**\n * Creates a reactive signal that tracks whether a CSS media query matches.\n *\n * Uses `window.matchMedia()` under the hood and automatically updates\n * when the match state changes (e.g., on window resize, device orientation change).\n *\n * @param query - A valid CSS media query string (e.g., `'(min-width: 768px)'`)\n * @returns A readonly reactive signal that is `true` when the query matches,\n * plus a `destroy()` method to remove the media query listener\n *\n * @example\n * ```ts\n * import { mediaQuery } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const isDark = mediaQuery('(prefers-color-scheme: dark)');\n * effect(() => {\n * document.body.classList.toggle('dark', isDark.value);\n * });\n *\n * const isWide = mediaQuery('(min-width: 1024px)');\n * effect(() => {\n * console.log('Wide screen:', isWide.value);\n * });\n * ```\n */\nexport const mediaQuery = (query: string): MediaSignalHandle<boolean> => {\n const s = signal(false);\n let cleanup: (() => void) | undefined;\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n try {\n const mql = window.matchMedia(query);\n s.value = mql.matches;\n\n const handler = (e: MediaQueryListEvent): void => {\n s.value = e.matches;\n };\n\n if (typeof mql.addEventListener === 'function') {\n mql.addEventListener('change', handler);\n cleanup = () => {\n mql.removeEventListener('change', handler);\n };\n } else if (\n typeof (\n mql as MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;\n }\n ).addListener === 'function'\n ) {\n const legacyMql = mql as MediaQueryList & {\n addListener: (listener: (event: MediaQueryListEvent) => void) => void;\n removeListener: (listener: (event: MediaQueryListEvent) => void) => void;\n };\n legacyMql.addListener(handler);\n cleanup = () => {\n legacyMql.removeListener(handler);\n };\n }\n } catch {\n // matchMedia may throw in non-browser environments\n }\n }\n\n const ro = readonly(s) as MediaSignalHandle<boolean>;\n let destroyed = false;\n Object.defineProperty(ro, 'destroy', {\n enumerable: false,\n configurable: true,\n value(): void {\n if (destroyed) return;\n destroyed = true;\n cleanup?.();\n s.dispose();\n },\n });\n\n return ro;\n};\n","/**\n * Named breakpoint signals.\n *\n * Defines named breakpoints that return reactive boolean signals,\n * making it easy to respond to viewport size changes.\n *\n * @module bquery/media\n */\n\nimport { readonly, signal } from '../reactive/index';\nimport type { BreakpointMap, MediaSignalHandle } from './types';\n\ntype BreakpointSignals<T extends BreakpointMap> = { [K in keyof T]: MediaSignalHandle<boolean> } & {\n destroyAll(): void;\n} & ('destroy' extends keyof T ? Record<never, never> : { destroy(): void });\n\n/**\n * Defines named breakpoints and returns reactive boolean signals for each.\n *\n * Each breakpoint is a minimum-width media query. The returned object maps\n * each breakpoint name to a `ReadonlySignal<boolean>` that is `true` when\n * the viewport width is at or above the breakpoint value.\n *\n * @param bp - An object mapping breakpoint names to minimum widths in pixels\n * @returns An object with the same keys, each a reactive boolean signal with\n * `destroy()`, plus a top-level `destroyAll()` method to clean up all listeners.\n * When no breakpoint is named `destroy`, a `destroy()` alias is also provided.\n *\n * @example\n * ```ts\n * import { breakpoints } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const bp = breakpoints({ sm: 640, md: 768, lg: 1024, xl: 1280 });\n *\n * effect(() => {\n * if (bp.xl.value) {\n * console.log('Extra large viewport');\n * } else if (bp.lg.value) {\n * console.log('Large viewport');\n * } else if (bp.md.value) {\n * console.log('Medium viewport');\n * } else {\n * console.log('Small viewport');\n * }\n * });\n * ```\n */\nexport const breakpoints = <T extends BreakpointMap>(bp: T): BreakpointSignals<T> => {\n const signals = {} as { [K in keyof T]: MediaSignalHandle<boolean> };\n const destroyers: Array<() => void> = [];\n\n type LegacyMediaQueryList = MediaQueryList & {\n addListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\n removeListener?: (listener: (event: MediaQueryListEvent | MediaQueryList) => void) => void;\n };\n\n for (const key of Object.keys(bp) as Array<keyof T>) {\n const width = bp[key];\n const s = signal(false);\n let cleanup: (() => void) | undefined;\n\n if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n try {\n const mql = window.matchMedia(`(min-width: ${width}px)`);\n s.value = mql.matches;\n\n const handler = (e: MediaQueryListEvent | MediaQueryList): void => {\n s.value = e.matches;\n };\n\n if (typeof mql.addEventListener === 'function') {\n mql.addEventListener('change', handler);\n cleanup = () => {\n mql.removeEventListener('change', handler);\n };\n } else {\n const legacyMql = mql as LegacyMediaQueryList;\n if (typeof legacyMql.addListener === 'function') {\n legacyMql.addListener(handler);\n cleanup = () => {\n legacyMql.removeListener?.(handler);\n };\n }\n }\n } catch {\n // matchMedia may throw in non-browser environments\n }\n }\n\n const ro = readonly(s) as MediaSignalHandle<boolean>;\n let destroyed = false;\n Object.defineProperty(ro, 'destroy', {\n enumerable: false,\n configurable: true,\n value(): void {\n if (destroyed) return;\n destroyed = true;\n cleanup?.();\n s.dispose();\n },\n });\n destroyers.push(ro.destroy);\n signals[key] = ro;\n }\n\n let destroyed = false;\n const result = Object.defineProperty(signals, 'destroyAll', {\n enumerable: false,\n configurable: true,\n value(): void {\n if (destroyed) return;\n destroyed = true;\n destroyers.forEach((destroy) => {\n destroy();\n });\n },\n }) as BreakpointSignals<T>;\n\n if (!Object.prototype.hasOwnProperty.call(signals, 'destroy')) {\n Object.defineProperty(result, 'destroy', {\n enumerable: false,\n configurable: true,\n value: result.destroyAll,\n });\n }\n\n return result;\n};\n","/**\n * Reactive viewport dimensions.\n *\n * Provides a reactive signal tracking the browser viewport's\n * width, height, and orientation.\n *\n * @module bquery/media\n */\n\nimport { readonly, signal } from '../reactive/index';\nimport type { ViewportSignal, ViewportState } from './types';\n\n/**\n * Computes orientation from width and height.\n * @internal\n */\nconst getOrientation = (w: number, h: number): 'portrait' | 'landscape' =>\n h >= w ? 'portrait' : 'landscape';\n\n/**\n * Returns a reactive signal tracking the current viewport dimensions and orientation.\n *\n * Updates automatically when the window is resized. Uses `window.innerWidth`\n * and `window.innerHeight` under the hood.\n *\n * @returns A readonly reactive signal with `{ width, height, orientation }`\n * and a `destroy()` method to remove the resize listener\n *\n * @example\n * ```ts\n * import { useViewport } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const viewport = useViewport();\n * effect(() => {\n * console.log(`Viewport: ${viewport.value.width}x${viewport.value.height}`);\n * console.log(`Orientation: ${viewport.value.orientation}`);\n * });\n * ```\n */\nexport const useViewport = (): ViewportSignal => {\n const initial: ViewportState = {\n width: typeof window !== 'undefined' ? window.innerWidth : 0,\n height: typeof window !== 'undefined' ? window.innerHeight : 0,\n orientation:\n typeof window !== 'undefined'\n ? getOrientation(window.innerWidth, window.innerHeight)\n : 'portrait',\n };\n\n const s = signal<ViewportState>(initial);\n\n let cleanup: (() => void) | undefined;\n\n if (typeof window !== 'undefined') {\n const handler = (): void => {\n s.value = {\n width: window.innerWidth,\n height: window.innerHeight,\n orientation: getOrientation(window.innerWidth, window.innerHeight),\n };\n };\n\n window.addEventListener('resize', handler);\n cleanup = () => {\n window.removeEventListener('resize', handler);\n };\n }\n\n const ro = readonly(s) as ViewportSignal;\n let destroyed = false;\n Object.defineProperty(ro, 'destroy', {\n enumerable: false,\n configurable: true,\n value: (): void => {\n if (destroyed) return;\n destroyed = true;\n cleanup?.();\n s.dispose();\n },\n });\n\n return ro;\n};\n","/**\n * Reactive network status.\n *\n * Provides a reactive signal tracking the browser's network connectivity\n * and connection quality via the Network Information API.\n *\n * @module bquery/media\n */\n\nimport { readonly, signal } from '../reactive/index';\nimport type { NetworkSignal, NetworkState } from './types';\n\n/**\n * Navigator connection interface for the Network Information API.\n * @internal\n */\ninterface NavigatorConnection extends EventTarget {\n effectiveType?: string;\n downlink?: number;\n rtt?: number;\n}\n\n/**\n * Extended Navigator with connection property.\n * @internal\n */\ninterface NavigatorWithConnection extends Navigator {\n connection?: NavigatorConnection;\n}\n\n/**\n * Reads current network state from browser APIs.\n * @internal\n */\nconst getNetworkState = (): NetworkState => {\n const online =\n typeof navigator !== 'undefined' && navigator.onLine !== undefined ? navigator.onLine : true;\n\n const nav = typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;\n const conn = nav?.connection;\n\n return {\n online,\n effectiveType: conn?.effectiveType ?? 'unknown',\n downlink: conn?.downlink ?? 0,\n rtt: conn?.rtt ?? 0,\n };\n};\n\n/**\n * Returns a reactive signal tracking network connectivity and quality.\n *\n * Tracks whether the browser is online/offline and, where supported,\n * the effective connection type, downlink speed, and round-trip time\n * via the Network Information API.\n *\n * @returns A readonly reactive signal with `{ online, effectiveType, downlink, rtt }`\n * and a `destroy()` method to remove attached listeners\n *\n * @example\n * ```ts\n * import { useNetworkStatus } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const net = useNetworkStatus();\n * effect(() => {\n * if (!net.value.online) {\n * console.warn('You are offline!');\n * }\n * console.log(`Connection: ${net.value.effectiveType}, RTT: ${net.value.rtt}ms`);\n * });\n * ```\n */\nexport const useNetworkStatus = (): NetworkSignal => {\n const s = signal<NetworkState>(getNetworkState());\n let cleanup: (() => void) | undefined;\n\n if (typeof window !== 'undefined') {\n const update = (): void => {\n s.value = getNetworkState();\n };\n\n window.addEventListener('online', update);\n window.addEventListener('offline', update);\n\n const nav =\n typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;\n if (nav?.connection && typeof nav.connection.addEventListener === 'function') {\n nav.connection.addEventListener('change', update);\n }\n\n cleanup = () => {\n window.removeEventListener('online', update);\n window.removeEventListener('offline', update);\n if (nav?.connection && typeof nav.connection.removeEventListener === 'function') {\n nav.connection.removeEventListener('change', update);\n }\n };\n }\n\n const ro = readonly(s) as NetworkSignal;\n let destroyed = false;\n Object.defineProperty(ro, 'destroy', {\n value(): void {\n if (destroyed) return;\n destroyed = true;\n cleanup?.();\n s.dispose();\n },\n enumerable: false,\n configurable: true,\n });\n\n return ro;\n};\n","/**\n * Reactive battery status.\n *\n * Provides a reactive signal tracking the device's battery status\n * via the Battery Status API.\n *\n * @module bquery/media\n */\n\nimport { signal, readonly } from '../reactive/index';\nimport type { BatterySignal, BatteryState } from './types';\n\n/**\n * BatteryManager interface for the Battery Status API.\n * @internal\n */\ninterface BatteryManager extends EventTarget {\n charging: boolean;\n chargingTime: number;\n dischargingTime: number;\n level: number;\n}\n\n/** Default battery state when API is unavailable. */\nconst DEFAULT_BATTERY_STATE: BatteryState = {\n supported: false,\n charging: false,\n chargingTime: 0,\n dischargingTime: 0,\n level: 1,\n};\n\n/**\n * Returns a reactive signal tracking the device's battery status.\n *\n * Uses the Battery Status API (`navigator.getBattery()`) where available.\n * Falls back gracefully to a default state with `supported: false` when\n * the API is not available.\n *\n * @returns A readonly reactive signal with battery state and a `destroy()` method\n * to remove Battery Status API listeners\n *\n * @example\n * ```ts\n * import { useBattery } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const battery = useBattery();\n * effect(() => {\n * if (battery.value.supported) {\n * console.log(`Battery: ${(battery.value.level * 100).toFixed(0)}%`);\n * console.log(`Charging: ${battery.value.charging}`);\n * }\n * });\n * ```\n */\nexport const useBattery = (): BatterySignal => {\n const s = signal<BatteryState>({ ...DEFAULT_BATTERY_STATE });\n let cleanup: (() => void) | undefined;\n let destroyed = false;\n\n if (\n typeof navigator !== 'undefined' &&\n 'getBattery' in navigator &&\n typeof (navigator as Navigator & { getBattery: () => Promise<BatteryManager> }).getBattery ===\n 'function'\n ) {\n const nav = navigator as Navigator & { getBattery: () => Promise<BatteryManager> };\n\n nav\n .getBattery()\n .then((battery) => {\n if (destroyed) return;\n\n const update = (): void => {\n s.value = {\n supported: true,\n charging: battery.charging,\n chargingTime: battery.chargingTime,\n dischargingTime: battery.dischargingTime,\n level: battery.level,\n };\n };\n\n update();\n\n battery.addEventListener('chargingchange', update);\n battery.addEventListener('chargingtimechange', update);\n battery.addEventListener('dischargingtimechange', update);\n battery.addEventListener('levelchange', update);\n cleanup = () => {\n battery.removeEventListener('chargingchange', update);\n battery.removeEventListener('chargingtimechange', update);\n battery.removeEventListener('dischargingtimechange', update);\n battery.removeEventListener('levelchange', update);\n };\n })\n .catch(() => {\n // Battery API rejected — keep default state\n });\n }\n\n const ro = readonly(s) as BatterySignal;\n Object.defineProperty(ro, 'destroy', {\n enumerable: false,\n configurable: true,\n value(): void {\n if (destroyed) return;\n destroyed = true;\n cleanup?.();\n s.dispose();\n },\n });\n\n return ro;\n};\n","/**\n * Reactive geolocation.\n *\n * Provides a reactive signal tracking the device's geographic position\n * via the Geolocation API.\n *\n * @module bquery/media\n */\n\nimport { signal, readonly } from '../reactive/index';\nimport type { GeolocationOptions, GeolocationSignal, GeolocationState } from './types';\n\n/** Default geolocation state. */\nconst DEFAULT_GEO_STATE: GeolocationState = {\n supported: false,\n loading: false,\n latitude: null,\n longitude: null,\n accuracy: null,\n altitude: null,\n altitudeAccuracy: null,\n heading: null,\n speed: null,\n timestamp: null,\n error: null,\n};\n\n/**\n * Returns a reactive signal tracking the device's geographic position.\n *\n * Uses the Geolocation API (`navigator.geolocation`) where available.\n * Can operate in one-shot mode (default) or continuous watch mode.\n *\n * @param options - Configuration for the geolocation request\n * @returns A readonly reactive signal with position data and loading/error state,\n * plus a `destroy()` method to stop an active watcher\n *\n * @example\n * ```ts\n * import { useGeolocation } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * // One-shot position\n * const geo = useGeolocation();\n * effect(() => {\n * if (geo.value.loading) return console.log('Getting position...');\n * if (geo.value.error) return console.error(geo.value.error);\n * console.log(`Lat: ${geo.value.latitude}, Lng: ${geo.value.longitude}`);\n * });\n *\n * // Continuous watch with high accuracy\n * const geoWatch = useGeolocation({ watch: true, enableHighAccuracy: true });\n * ```\n */\nexport const useGeolocation = (options: GeolocationOptions = {}): GeolocationSignal => {\n const { enableHighAccuracy = false, maximumAge = 0, timeout = Infinity, watch = false } = options;\n\n const s = signal<GeolocationState>({ ...DEFAULT_GEO_STATE });\n\n let destroyWatcher: (() => void) | undefined;\n\n if (typeof navigator !== 'undefined' && 'geolocation' in navigator) {\n s.value = { ...DEFAULT_GEO_STATE, supported: true, loading: true };\n\n const posOptions: PositionOptions = {\n enableHighAccuracy,\n maximumAge,\n timeout: timeout === Infinity ? undefined : timeout,\n };\n\n const onSuccess = (pos: GeolocationPosition): void => {\n s.value = {\n supported: true,\n loading: false,\n latitude: pos.coords.latitude,\n longitude: pos.coords.longitude,\n accuracy: pos.coords.accuracy,\n altitude: pos.coords.altitude,\n altitudeAccuracy: pos.coords.altitudeAccuracy,\n heading: pos.coords.heading,\n speed: pos.coords.speed,\n timestamp: pos.timestamp,\n error: null,\n };\n };\n\n const onError = (err: GeolocationPositionError): void => {\n s.value = {\n ...s.value,\n loading: false,\n error: err.message,\n };\n };\n\n if (watch) {\n const watchId = navigator.geolocation.watchPosition(onSuccess, onError, posOptions);\n destroyWatcher = () => {\n navigator.geolocation.clearWatch(watchId);\n };\n } else {\n navigator.geolocation.getCurrentPosition(onSuccess, onError, posOptions);\n }\n }\n\n const ro = readonly(s) as GeolocationSignal;\n let destroyed = false;\n Object.defineProperty(ro, 'destroy', {\n enumerable: false,\n configurable: true,\n value(): void {\n if (destroyed) return;\n destroyed = true;\n destroyWatcher?.();\n s.dispose();\n },\n });\n\n return ro;\n};\n","/**\n * Reactive device motion and orientation sensors.\n *\n * Provides reactive signals for accelerometer, gyroscope, and\n * compass data via the DeviceMotion and DeviceOrientation APIs.\n *\n * @module bquery/media\n */\n\nimport { signal, readonly } from '../reactive/index';\nimport type {\n DeviceMotionSignal,\n DeviceMotionState,\n DeviceOrientationSignal,\n DeviceOrientationState,\n} from './types';\n\n/** Default device motion state. */\nconst DEFAULT_MOTION_STATE: DeviceMotionState = {\n acceleration: { x: null, y: null, z: null },\n accelerationIncludingGravity: { x: null, y: null, z: null },\n rotationRate: { alpha: null, beta: null, gamma: null },\n interval: 0,\n};\n\n/** Default device orientation state. */\nconst DEFAULT_ORIENTATION_STATE: DeviceOrientationState = {\n alpha: null,\n beta: null,\n gamma: null,\n absolute: false,\n};\n\n/**\n * Returns a reactive signal tracking device motion (accelerometer + gyroscope).\n *\n * Uses the `devicemotion` event to provide acceleration, acceleration\n * including gravity, and rotation rate data.\n *\n * @returns A readonly reactive signal with motion sensor data and a `destroy()`\n * method to remove the underlying event listener\n *\n * @example\n * ```ts\n * import { useDeviceMotion } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const motion = useDeviceMotion();\n * effect(() => {\n * const { acceleration } = motion.value;\n * console.log(`Acceleration: x=${acceleration.x}, y=${acceleration.y}, z=${acceleration.z}`);\n * });\n * ```\n */\nexport const useDeviceMotion = (): DeviceMotionSignal => {\n const s = signal<DeviceMotionState>({ ...DEFAULT_MOTION_STATE });\n let cleanup: (() => void) | undefined;\n\n if (typeof window !== 'undefined') {\n const handler = (e: DeviceMotionEvent): void => {\n s.value = {\n acceleration: {\n x: e.acceleration?.x ?? null,\n y: e.acceleration?.y ?? null,\n z: e.acceleration?.z ?? null,\n },\n accelerationIncludingGravity: {\n x: e.accelerationIncludingGravity?.x ?? null,\n y: e.accelerationIncludingGravity?.y ?? null,\n z: e.accelerationIncludingGravity?.z ?? null,\n },\n rotationRate: {\n alpha: e.rotationRate?.alpha ?? null,\n beta: e.rotationRate?.beta ?? null,\n gamma: e.rotationRate?.gamma ?? null,\n },\n interval: e.interval ?? 0,\n };\n };\n\n window.addEventListener('devicemotion', handler);\n cleanup = () => {\n window.removeEventListener('devicemotion', handler);\n };\n }\n\n const ro = readonly(s) as DeviceMotionSignal;\n let destroyed = false;\n Object.defineProperty(ro, 'destroy', {\n enumerable: false,\n configurable: true,\n value(): void {\n if (destroyed) return;\n destroyed = true;\n cleanup?.();\n s.dispose();\n },\n });\n\n return ro;\n};\n\n/**\n * Returns a reactive signal tracking device orientation (compass/gyroscope).\n *\n * Uses the `deviceorientation` event to provide alpha (compass heading),\n * beta (front-to-back tilt), and gamma (left-to-right tilt) data.\n *\n * @returns A readonly reactive signal with orientation data and a `destroy()`\n * method to remove the underlying event listener\n *\n * @example\n * ```ts\n * import { useDeviceOrientation } from '@bquery/bquery/media';\n * import { effect } from '@bquery/bquery/reactive';\n *\n * const orientation = useDeviceOrientation();\n * effect(() => {\n * console.log(`Compass heading: ${orientation.value.alpha}°`);\n * console.log(`Tilt: ${orientation.value.beta}° / ${orientation.value.gamma}°`);\n * });\n * ```\n */\nexport const useDeviceOrientation = (): DeviceOrientationSignal => {\n const s = signal<DeviceOrientationState>({ ...DEFAULT_ORIENTATION_STATE });\n let cleanup: (() => void) | undefined;\n\n if (typeof window !== 'undefined') {\n const handler = (e: DeviceOrientationEvent): void => {\n s.value = {\n alpha: e.alpha ?? null,\n beta: e.beta ?? null,\n gamma: e.gamma ?? null,\n absolute: e.absolute ?? false,\n };\n };\n\n window.addEventListener('deviceorientation', handler);\n cleanup = () => {\n window.removeEventListener('deviceorientation', handler);\n };\n }\n\n const ro = readonly(s) as DeviceOrientationSignal;\n let destroyed = false;\n Object.defineProperty(ro, 'destroy', {\n enumerable: false,\n configurable: true,\n value(): void {\n if (destroyed) return;\n destroyed = true;\n cleanup?.();\n s.dispose();\n },\n });\n\n return ro;\n};\n","/**\n * Async clipboard API wrappers.\n *\n * Provides simple read/write access to the system clipboard\n * via the Async Clipboard API.\n *\n * @module bquery/media\n */\n\nimport type { ClipboardAPI } from './types';\n\nconst CLIPBOARD_UNAVAILABLE_ERROR =\n 'bQuery media: Clipboard API is unavailable. Use a secure context (HTTPS or localhost) and ensure clipboard permissions or user-activation requirements are met.';\n\n/**\n * Clipboard API wrapper providing simple async read/write access.\n *\n * Uses the modern Async Clipboard API (`navigator.clipboard`) under the hood.\n * Both methods are `Promise`-based and will reject if the API is unavailable\n * or permission is denied.\n *\n * @example\n * ```ts\n * import { clipboard } from '@bquery/bquery/media';\n *\n * // Write text to clipboard\n * await clipboard.write('Hello, world!');\n *\n * // Read text from clipboard\n * const text = await clipboard.read();\n * console.log(text); // \"Hello, world!\"\n * ```\n */\nexport const clipboard: ClipboardAPI = {\n /**\n * Reads text from the system clipboard.\n *\n * @returns A promise that resolves with the clipboard text content\n * @throws Error if the Clipboard API is not available or permission is denied\n *\n * @example\n * ```ts\n * const text = await clipboard.read();\n * console.log('Clipboard contains:', text);\n * ```\n */\n read: async (): Promise<string> => {\n if (\n typeof navigator === 'undefined' ||\n !navigator.clipboard ||\n typeof navigator.clipboard.readText !== 'function'\n ) {\n throw new Error(CLIPBOARD_UNAVAILABLE_ERROR);\n }\n return navigator.clipboard.readText();\n },\n\n /**\n * Writes text to the system clipboard.\n *\n * @param text - The text to write to the clipboard\n * @returns A promise that resolves when the text has been written\n * @throws Error if the Clipboard API is not available or permission is denied\n *\n * @example\n * ```ts\n * await clipboard.write('Copied!');\n * ```\n */\n write: async (text: string): Promise<void> => {\n if (\n typeof navigator === 'undefined' ||\n !navigator.clipboard ||\n typeof navigator.clipboard.writeText !== 'function'\n ) {\n throw new Error(CLIPBOARD_UNAVAILABLE_ERROR);\n }\n return navigator.clipboard.writeText(text);\n },\n};\n","/**\n * Global plugin registry for bQuery.\n *\n * Provides `use()` to register plugins and query helpers consumed by\n * other modules (e.g. the view module reads custom directives from here).\n *\n * @module bquery/plugin\n */\n\nimport { registerCustomDirectiveResolver } from '../view/custom-directives';\nimport type {\n BQueryPlugin,\n CustomDirective,\n CustomDirectiveHandler,\n PluginInstallContext,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Internal registries\n// ---------------------------------------------------------------------------\n\n/** Set of installed plugin names — prevents double-install. */\nconst installedPlugins = new Set<string>();\n\n/** Custom directives contributed by plugins. */\nconst customDirectives = new Map<string, CustomDirectiveHandler>();\n\ntype PendingComponentRegistration = {\n tagName: string;\n constructor: CustomElementConstructor;\n options?: ElementDefinitionOptions;\n};\n\n/**\n * Ensure the view pipeline resolves plugin directives against the current registry.\n *\n * This is intentionally idempotent so tests or internal modules can temporarily\n * clear the resolver without leaving plugin/view integration in a broken state.\n *\n * @internal\n */\nconst attachCustomDirectiveResolver = (): void => {\n registerCustomDirectiveResolver((name) => customDirectives.get(name));\n};\n\nattachCustomDirectiveResolver();\n\n/**\n * Restore the directive registry to a previously captured snapshot.\n *\n * Used to roll back partial plugin installation when `install()` or staged\n * `customElements.define()` calls fail after directives were already registered.\n *\n * @internal\n */\nconst restoreDirectiveSnapshot = (\n directivesSnapshot: ReadonlyMap<string, CustomDirectiveHandler>\n): void => {\n customDirectives.clear();\n for (const [name, handler] of directivesSnapshot) {\n customDirectives.set(name, handler);\n }\n};\n\n// ---------------------------------------------------------------------------\n// Install context factory\n// ---------------------------------------------------------------------------\n\n/**\n * Build the `PluginInstallContext` handed to each plugin's `install()`.\n * @internal\n */\nconst createInstallContext = (\n pendingComponents: PendingComponentRegistration[]\n): PluginInstallContext => ({\n directive(name: string, handler: CustomDirectiveHandler): void {\n if (typeof name !== 'string' || name.length === 0) {\n throw new Error('bQuery plugin directive: name must be a non-empty string');\n }\n if (name.startsWith('bq-')) {\n const suggestedName = name.slice(3);\n throw new Error(\n `bQuery plugin directive: name \"${name}\" must be provided without the \"bq-\" prefix` +\n (suggestedName ? ` (use \"${suggestedName}\")` : '')\n );\n }\n if (typeof handler !== 'function') {\n throw new Error(`bQuery plugin directive: handler for \"${name}\" must be a function`);\n }\n if (customDirectives.has(name)) {\n throw new Error(`bQuery plugin directive: a directive named \"${name}\" is already registered`);\n }\n customDirectives.set(name, handler);\n },\n\n component(\n tagName: string,\n constructor: CustomElementConstructor,\n options?: ElementDefinitionOptions\n ): void {\n if (typeof tagName !== 'string' || tagName.length === 0) {\n throw new Error('bQuery plugin component: tagName must be a non-empty string');\n }\n if (!tagName.includes('-')) {\n throw new Error(\n `bQuery plugin component: tagName \"${tagName}\" must be a valid custom element name containing a hyphen`\n );\n }\n if (typeof constructor !== 'function') {\n throw new Error(`bQuery plugin component: constructor for \"${tagName}\" must be a function`);\n }\n if (typeof customElements === 'undefined') {\n if (typeof console !== 'undefined' && typeof console.warn === 'function') {\n console.warn(\n `[bQuery] plugin component \"${tagName}\" was not registered because customElements is not available in this environment.`\n );\n }\n return;\n }\n // Idempotent — skip if already defined or already staged during this install\n if (\n !customElements.get(tagName) &&\n !pendingComponents.some((entry) => entry.tagName === tagName)\n ) {\n pendingComponents.push({ tagName, constructor, options });\n }\n },\n});\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Register a bQuery plugin.\n *\n * Plugins are installed at most once (identified by `plugin.name`).\n * Duplicate calls with the same name are silently ignored.\n *\n * @param plugin - The plugin object implementing `{ name, install }`.\n * @param options - Optional configuration forwarded to `plugin.install()`.\n * @throws If `plugin` is not a valid plugin object.\n *\n * @example\n * ```ts\n * import { use } from '@bquery/bquery/plugin';\n *\n * use({\n * name: 'highlight',\n * install(ctx) {\n * ctx.directive('highlight', (el, expr) => {\n * (el as HTMLElement).style.background = String(expr);\n * });\n * },\n * });\n * ```\n */\nexport const use = <TOptions = unknown>(\n plugin: BQueryPlugin<TOptions>,\n options?: TOptions\n): void => {\n attachCustomDirectiveResolver();\n\n if (!plugin || typeof plugin !== 'object') {\n throw new Error('bQuery plugin: use() expects a plugin object with { name, install }');\n }\n if (typeof plugin.name !== 'string' || plugin.name.length === 0) {\n throw new Error('bQuery plugin: plugin must have a non-empty \"name\" property');\n }\n if (typeof plugin.install !== 'function') {\n throw new Error(`bQuery plugin: plugin \"${plugin.name}\" must have an \"install\" function`);\n }\n\n // Deduplicate\n if (installedPlugins.has(plugin.name)) return;\n\n const pendingComponents: PendingComponentRegistration[] = [];\n const ctx = createInstallContext(pendingComponents);\n const directivesSnapshot = new Map(customDirectives);\n\n try {\n plugin.install(ctx, options);\n } catch (error) {\n restoreDirectiveSnapshot(directivesSnapshot);\n throw error;\n }\n\n try {\n for (const entry of pendingComponents) {\n if (!customElements.get(entry.tagName)) {\n customElements.define(entry.tagName, entry.constructor, entry.options);\n }\n }\n } catch (error) {\n restoreDirectiveSnapshot(directivesSnapshot);\n throw error;\n }\n\n installedPlugins.add(plugin.name);\n};\n\n/**\n * Check whether a plugin with the given name has been installed.\n *\n * @param name - The plugin name to check.\n * @returns `true` if the plugin was previously installed via `use()`.\n *\n * @example\n * ```ts\n * import { isInstalled } from '@bquery/bquery/plugin';\n *\n * if (!isInstalled('my-plugin')) {\n * use(myPlugin);\n * }\n * ```\n */\nexport const isInstalled = (name: string): boolean => installedPlugins.has(name);\n\n/**\n * Return a read-only snapshot of all installed plugin names.\n *\n * @returns Array of plugin name strings.\n *\n * @example\n * ```ts\n * import { getInstalledPlugins } from '@bquery/bquery/plugin';\n * console.log(getInstalledPlugins()); // ['my-plugin', 'other-plugin']\n * ```\n */\nexport const getInstalledPlugins = (): readonly string[] => [...installedPlugins];\n\n/**\n * Retrieve the handler for a custom directive registered by a plugin.\n *\n * This is used internally by the view module's `processElement` to\n * resolve directives that aren't built-in.\n *\n * @param name - Directive name **without** prefix (e.g. `'tooltip'`).\n * @returns The handler, or `undefined` if none is registered.\n *\n * @example\n * ```ts\n * import { getCustomDirective } from '@bquery/bquery/plugin';\n * const handler = getCustomDirective('tooltip');\n * ```\n */\nexport const getCustomDirective = (name: string): CustomDirectiveHandler | undefined =>\n customDirectives.get(name);\n\n/**\n * Return a read-only snapshot of all registered custom directives.\n *\n * @returns Array of `{ name, handler }` descriptors.\n *\n * @example\n * ```ts\n * import { getCustomDirectives } from '@bquery/bquery/plugin';\n * for (const { name, handler } of getCustomDirectives()) {\n * console.log(`Directive: bq-${name}`);\n * }\n * ```\n */\nexport const getCustomDirectives = (): readonly CustomDirective[] =>\n [...customDirectives.entries()].map(([name, handler]) => ({ name, handler }));\n\n/**\n * Reset all plugin registrations.\n *\n * Clears all installed plugins and custom directives.\n *\n * This utility is primarily intended for tests and other isolated environments\n * that need to reinitialize plugin state between runs.\n *\n * @example\n * ```ts\n * import { resetPlugins } from '@bquery/bquery/plugin';\n * afterEach(() => resetPlugins());\n * ```\n */\nexport const resetPlugins = (): void => {\n installedPlugins.clear();\n customDirectives.clear();\n attachCustomDirectiveResolver();\n};\n","/**\n * bQuery DevTools — runtime debugging utilities.\n *\n * Enable devtools to inspect signals, stores, components, and view a\n * timeline of reactive events.\n *\n * @module bquery/devtools\n */\n\nimport type {\n ComponentSnapshot,\n DevtoolsOptions,\n DevtoolsState,\n SignalSnapshot,\n StoreSnapshot,\n TimelineEntry,\n TimelineEventType,\n} from './types';\nimport { listStores as _listStores, getStore as _getStore } from '../store/registry';\n\n// ---------------------------------------------------------------------------\n// Internal state\n// ---------------------------------------------------------------------------\n\nlet _enabled = false;\nlet _options: DevtoolsOptions = {};\nconst _timeline: TimelineEntry[] = [];\n\n/** Registered signals keyed by label. */\nconst _trackedSignals = new Map<string, { peek: () => unknown; subscriberCount: () => number }>();\n\n/** Monotonic counter for auto-labelling anonymous signals. */\nlet _signalCounter = 0;\n\n// ---------------------------------------------------------------------------\n// Enable / disable\n// ---------------------------------------------------------------------------\n\n/**\n * Enable bQuery development mode.\n *\n * When enabled the devtools module records timeline events and\n * allows inspection of signals, stores, and components.\n *\n * @param enabled - `true` to enable, `false` to disable.\n * @param options - Optional configuration.\n *\n * @example\n * ```ts\n * import { enableDevtools } from '@bquery/bquery/devtools';\n * enableDevtools(true, { logToConsole: true });\n * ```\n */\nexport const enableDevtools = (enabled: boolean, options?: DevtoolsOptions): void => {\n _enabled = enabled;\n _options = options ?? {};\n\n if (!enabled) {\n _timeline.length = 0;\n _trackedSignals.clear();\n _signalCounter = 0;\n }\n};\n\n/**\n * Returns `true` when devtools are active.\n *\n * @example\n * ```ts\n * import { isDevtoolsEnabled } from '@bquery/bquery/devtools';\n * if (isDevtoolsEnabled()) { ... }\n * ```\n */\nexport const isDevtoolsEnabled = (): boolean => _enabled;\n\n// ---------------------------------------------------------------------------\n// Signal tracking\n// ---------------------------------------------------------------------------\n\n/**\n * Register a signal for devtools inspection.\n *\n * @param label - Human-readable label (must be unique).\n * @param peek - Returns the signal's value without tracking.\n * @param subscriberCount - Returns the current subscriber count.\n * @throws If a signal with the same label is already tracked.\n *\n * @example\n * ```ts\n * import { trackSignal } from '@bquery/bquery/devtools';\n * import { signal } from '@bquery/bquery/reactive';\n *\n * const count = signal(0);\n * trackSignal('count', () => count.peek(), () => 0);\n * ```\n */\nexport const trackSignal = (\n label: string,\n peek: () => unknown,\n subscriberCount: () => number\n): void => {\n if (!_enabled) return;\n if (typeof label !== 'string' || label.length === 0) {\n throw new Error('bQuery devtools: trackSignal() requires a non-empty label');\n }\n _trackedSignals.set(label, { peek, subscriberCount });\n};\n\n/**\n * Remove a previously tracked signal.\n *\n * @param label - The label used during registration.\n *\n * @example\n * ```ts\n * import { untrackSignal } from '@bquery/bquery/devtools';\n * untrackSignal('count');\n * ```\n */\nexport const untrackSignal = (label: string): void => {\n _trackedSignals.delete(label);\n};\n\n/**\n * Generate a unique label for anonymous signals.\n *\n * @returns A label such as `signal_0`, `signal_1`, …\n *\n * @example\n * ```ts\n * import { generateSignalLabel } from '@bquery/bquery/devtools';\n * const label = generateSignalLabel(); // 'signal_0'\n * ```\n */\nexport const generateSignalLabel = (): string => `signal_${_signalCounter++}`;\n\n// ---------------------------------------------------------------------------\n// Signal inspector\n// ---------------------------------------------------------------------------\n\n/**\n * List all tracked signals with their current values.\n *\n * @returns An array of {@link SignalSnapshot} objects.\n *\n * @example\n * ```ts\n * import { inspectSignals } from '@bquery/bquery/devtools';\n * console.table(inspectSignals());\n * ```\n */\nexport const inspectSignals = (): SignalSnapshot[] => {\n const result: SignalSnapshot[] = [];\n for (const [label, entry] of _trackedSignals) {\n result.push({\n label,\n value: entry.peek(),\n subscriberCount: entry.subscriberCount(),\n });\n }\n return result;\n};\n\n// ---------------------------------------------------------------------------\n// Store inspector\n// ---------------------------------------------------------------------------\n\n/**\n * List all stores with their current state.\n *\n * Reads from the store registry (`listStores` / `getStore`) that is\n * already maintained by the store module.\n *\n * @returns An array of {@link StoreSnapshot} objects.\n *\n * @example\n * ```ts\n * import { inspectStores } from '@bquery/bquery/devtools';\n * console.table(inspectStores());\n * ```\n */\nexport const inspectStores = (): StoreSnapshot[] => {\n try {\n const ids: string[] = _listStores();\n return ids.map((id: string) => {\n const store = _getStore(id) as Record<string, unknown> | undefined;\n const state: Record<string, unknown> = {};\n if (store && typeof store === 'object' && '$state' in store) {\n const raw = (store as { $state: unknown }).$state;\n if (raw && typeof raw === 'object') {\n Object.assign(state, raw);\n }\n }\n return { id, state };\n });\n } catch {\n return [];\n }\n};\n\n// ---------------------------------------------------------------------------\n// Component inspector\n// ---------------------------------------------------------------------------\n\n/**\n * List all bQuery-registered custom elements visible in the document.\n *\n * @returns An array of {@link ComponentSnapshot} objects.\n *\n * @example\n * ```ts\n * import { inspectComponents } from '@bquery/bquery/devtools';\n * console.table(inspectComponents());\n * ```\n */\nexport const inspectComponents = (): ComponentSnapshot[] => {\n if (typeof document === 'undefined') return [];\n\n const result: ComponentSnapshot[] = [];\n const seen = new Set<string>();\n\n // Walk every custom element in the DOM (they must contain a hyphen)\n const all = document.querySelectorAll('*');\n for (let i = 0; i < all.length; i++) {\n const el = all[i];\n const tag = el.tagName.toLowerCase();\n if (!tag.includes('-')) continue;\n if (seen.has(tag)) continue;\n\n // Only include if registered via customElements\n if (typeof customElements !== 'undefined' && customElements.get(tag)) {\n seen.add(tag);\n const instances = document.querySelectorAll(tag);\n result.push({ tagName: tag, instanceCount: instances.length });\n }\n }\n return result;\n};\n\n// ---------------------------------------------------------------------------\n// Timeline\n// ---------------------------------------------------------------------------\n\n/**\n * Record a timeline event.\n *\n * This is called internally by bQuery modules (signals, store, router)\n * or can be called from user code / plugins to add custom entries.\n *\n * @param type - The event category.\n * @param detail - A human-readable description.\n *\n * @example\n * ```ts\n * import { recordEvent } from '@bquery/bquery/devtools';\n * recordEvent('signal:update', 'count changed to 5');\n * ```\n */\nexport const recordEvent = (type: TimelineEventType, detail: string): void => {\n if (!_enabled) return;\n\n const entry: TimelineEntry = {\n timestamp: Date.now(),\n type,\n detail,\n };\n _timeline.push(entry);\n\n if (_options.logToConsole) {\n console.log(`[bq:devtools] ${type} — ${detail}`);\n }\n};\n\n/**\n * Returns the full timeline log.\n *\n * @returns A read-only array of {@link TimelineEntry} objects.\n *\n * @example\n * ```ts\n * import { getTimeline } from '@bquery/bquery/devtools';\n * for (const e of getTimeline()) {\n * console.log(e.type, e.detail);\n * }\n * ```\n */\nexport const getTimeline = (): readonly TimelineEntry[] => _timeline;\n\n/**\n * Clear all timeline entries.\n *\n * @example\n * ```ts\n * import { clearTimeline } from '@bquery/bquery/devtools';\n * clearTimeline();\n * ```\n */\nexport const clearTimeline = (): void => {\n _timeline.length = 0;\n};\n\n// ---------------------------------------------------------------------------\n// Combined state\n// ---------------------------------------------------------------------------\n\n/**\n * Returns a snapshot of the full devtools state.\n *\n * @returns A {@link DevtoolsState} object.\n *\n * @example\n * ```ts\n * import { getDevtoolsState } from '@bquery/bquery/devtools';\n * const state = getDevtoolsState();\n * console.log(state.enabled, state.timeline.length);\n * ```\n */\nexport const getDevtoolsState = (): DevtoolsState => ({\n enabled: _enabled,\n options: { ..._options },\n timeline: [..._timeline],\n});\n\n// ---------------------------------------------------------------------------\n// Log helpers (convenience for interactive debugging)\n// ---------------------------------------------------------------------------\n\n/**\n * Pretty-print all tracked signals to the console.\n *\n * @example\n * ```ts\n * import { logSignals } from '@bquery/bquery/devtools';\n * logSignals(); // → table output\n * ```\n */\nexport const logSignals = (): void => {\n const signals = inspectSignals();\n if (signals.length === 0) {\n console.log('[bq:devtools] No tracked signals.');\n return;\n }\n\n console.table(signals);\n};\n\n/**\n * Pretty-print all stores to the console.\n *\n * @example\n * ```ts\n * import { logStores } from '@bquery/bquery/devtools';\n * logStores(); // → table output\n * ```\n */\nexport const logStores = (): void => {\n const stores = inspectStores();\n if (stores.length === 0) {\n console.log('[bq:devtools] No stores registered.');\n return;\n }\n\n console.table(stores.map((s) => ({ id: s.id, state: JSON.stringify(s.state) })));\n};\n\n/**\n * Pretty-print all registered components to the console.\n *\n * @example\n * ```ts\n * import { logComponents } from '@bquery/bquery/devtools';\n * logComponents(); // → table output\n * ```\n */\nexport const logComponents = (): void => {\n const components = inspectComponents();\n if (components.length === 0) {\n console.log('[bq:devtools] No custom elements found.');\n return;\n }\n\n console.table(components);\n};\n\n/**\n * Pretty-print the timeline to the console.\n *\n * @param last - Only show the last N entries (default: all).\n *\n * @example\n * ```ts\n * import { logTimeline } from '@bquery/bquery/devtools';\n * logTimeline(10);\n * ```\n */\nexport const logTimeline = (last?: number): void => {\n const entries = typeof last === 'number' && last > 0 ? _timeline.slice(-last) : _timeline;\n if (entries.length === 0) {\n console.log('[bq:devtools] Timeline is empty.');\n return;\n }\n\n console.table(\n entries.map((e) => ({\n time: new Date(e.timestamp).toISOString(),\n type: e.type,\n detail: e.detail,\n }))\n );\n};\n","/**\n * Testing utilities for bQuery.js.\n *\n * Provides helpers for mounting components, controlling signals, mocking\n * the router, dispatching events, and asserting async conditions — all\n * designed for use with `bun:test` and happy-dom.\n *\n * @module bquery/testing\n */\n\nimport { batch, Signal, signal } from '../reactive/index';\nimport { getNormalizedRouteConstraint } from '../router/constraints';\nimport type {\n FireEventOptions,\n MockRouteDefinition,\n MockRouter,\n MockRouterOptions,\n MockSignal,\n RenderComponentOptions,\n RenderResult,\n TestRoute,\n WaitForOptions,\n} from './types';\n\n// ============================================================================\n// renderComponent\n// ============================================================================\n\nconst isWordChar = (char: string | undefined): boolean =>\n char !== undefined &&\n ((char >= 'a' && char <= 'z') ||\n (char >= 'A' && char <= 'Z') ||\n (char >= '0' && char <= '9') ||\n char === '_');\n\nconst readRouteConstraint = (\n pattern: string,\n startIndex: number\n): { constraint: string; endIndex: number } | null => {\n let depth = 1;\n let constraint = '';\n let i = startIndex + 1;\n\n while (i < pattern.length) {\n const char = pattern[i];\n\n if (char === '\\\\' && i + 1 < pattern.length) {\n constraint += char + pattern[i + 1];\n i += 2;\n continue;\n }\n\n if (char === '(') {\n depth++;\n } else if (char === ')') {\n depth--;\n if (depth === 0) {\n return { constraint, endIndex: i + 1 };\n }\n }\n\n constraint += char;\n i++;\n }\n\n return null;\n};\n\nconst routeConstraintRegexCache = new Map<string, RegExp>();\n\nconst getRouteConstraintRegex = (constraint: string): RegExp => {\n const normalized = getNormalizedRouteConstraint(constraint);\n const cached = routeConstraintRegexCache.get(normalized);\n if (cached) {\n return cached;\n }\n\n const compiled = new RegExp(`^(?:${normalized})$`);\n routeConstraintRegexCache.set(normalized, compiled);\n return compiled;\n};\n\n/**\n * Mounts a custom element by tag name for testing and returns a handle\n * to interact with it.\n *\n * The element is created, configured with the given props and slots,\n * and appended to the container (defaults to `document.body`). Call\n * `unmount()` to remove the element and trigger its `disconnectedCallback`.\n *\n * @param tagName - The custom element tag name (must already be registered)\n * @param options - Props, slots, and container configuration\n * @returns A {@link RenderResult} with the element and an unmount function\n * @throws {Error} If the tag name is not a valid custom element name\n *\n * @example\n * ```ts\n * import { renderComponent } from '@bquery/bquery/testing';\n *\n * const { el, unmount } = renderComponent('my-counter', {\n * props: { start: '5' },\n * });\n * expect(el.shadowRoot?.textContent).toContain('5');\n * unmount();\n * ```\n */\nexport function renderComponent(\n tagName: string,\n options: RenderComponentOptions = {}\n): RenderResult {\n if (!tagName || !tagName.includes('-')) {\n throw new Error(\n `bQuery testing: \"${tagName}\" is not a valid custom element tag name (must contain a hyphen)`\n );\n }\n\n const { props, slots, container = document.body } = options;\n\n const el = document.createElement(tagName);\n\n // Set attributes (props) before connecting\n if (props) {\n for (const [key, value] of Object.entries(props)) {\n if (value === null || value === undefined) continue;\n el.setAttribute(key, String(value));\n }\n }\n\n // Inject slot content before connecting so the component can discover it\n if (slots) {\n if (typeof slots === 'string') {\n el.innerHTML = slots;\n } else {\n const parts: string[] = [];\n for (const [slotName, html] of Object.entries(slots)) {\n if (slotName === 'default') {\n parts.push(html);\n } else {\n const safeSlotName = slotName\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n parts.push(`<div slot=\"${safeSlotName}\">${html}</div>`);\n }\n }\n el.innerHTML = parts.join('');\n }\n }\n\n // Connect — triggers connectedCallback\n container.appendChild(el);\n\n const unmount = (): void => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n };\n\n return { el, unmount };\n}\n\n// ============================================================================\n// flushEffects\n// ============================================================================\n\n/**\n * Synchronously flushes any pending reactive effects.\n *\n * In bQuery's reactive system, effects outside of a batch are executed\n * synchronously. This helper exists primarily for clarity and for\n * flushing effects that may have been deferred inside a batch.\n *\n * Internally it performs a no-op batch to trigger the flush of any\n * pending observers that were queued during a prior `batch()` call.\n *\n * @example\n * ```ts\n * import { signal, batch } from '@bquery/bquery/reactive';\n * import { flushEffects } from '@bquery/bquery/testing';\n *\n * const count = signal(0);\n * let observed = 0;\n * effect(() => { observed = count.value; });\n *\n * batch(() => { count.value = 42; });\n * flushEffects();\n * expect(observed).toBe(42);\n * ```\n */\nexport function flushEffects(): void {\n // A no-op batch triggers endBatch which flushes any pending observers.\n // Since bQuery's effects are synchronous outside of batches, this is\n // mainly useful after manual batch calls or micro-task boundaries.\n batch(() => {\n /* intentionally empty — triggers pending observer flush */\n });\n}\n\n// ============================================================================\n// mockSignal\n// ============================================================================\n\n/**\n * Creates a controllable signal for tests with `set()` and `reset()` helpers.\n *\n * This is a thin wrapper around `signal()` that records the initial value\n * and adds explicit `set()` / `reset()` methods for clearer test intent.\n *\n * @template T - The type of the signal value\n * @param initialValue - The initial value\n * @returns A {@link MockSignal} instance\n *\n * @example\n * ```ts\n * import { mockSignal } from '@bquery/bquery/testing';\n *\n * const count = mockSignal(0);\n * count.set(5);\n * expect(count.value).toBe(5);\n * count.reset();\n * expect(count.value).toBe(0);\n * ```\n */\nexport function mockSignal<T>(initialValue: T): MockSignal<T> {\n const s = signal(initialValue) as Signal<T> & {\n set: (value: T) => void;\n reset: () => void;\n initialValue: T;\n };\n\n Object.defineProperty(s, 'initialValue', {\n value: initialValue,\n writable: false,\n enumerable: true,\n });\n\n s.set = function (value: T): void {\n s.value = value;\n };\n\n s.reset = function (): void {\n s.value = initialValue;\n };\n\n return s as MockSignal<T>;\n}\n\n// ============================================================================\n// mockRouter\n// ============================================================================\n\n/**\n * Parses a path string into the route's `path`, `query`, and `hash` parts.\n * @internal\n */\nfunction parsePath(\n fullPath: string,\n base: string\n): { path: string; query: Record<string, string | string[]>; hash: string } {\n let working = fullPath;\n\n // Strip base prefix\n if (base && working.startsWith(base)) {\n working = working.slice(base.length) || '/';\n }\n\n // Extract hash\n let hash = '';\n const hashIdx = working.indexOf('#');\n if (hashIdx >= 0) {\n hash = working.slice(hashIdx + 1);\n working = working.slice(0, hashIdx);\n }\n\n // Extract query string\n const query: Record<string, string | string[]> = {};\n const qIdx = working.indexOf('?');\n if (qIdx >= 0) {\n const qs = working.slice(qIdx + 1);\n working = working.slice(0, qIdx);\n for (const pair of qs.split('&')) {\n const eqIdx = pair.indexOf('=');\n const key = eqIdx >= 0 ? decodeURIComponent(pair.slice(0, eqIdx)) : decodeURIComponent(pair);\n const val = eqIdx >= 0 ? decodeURIComponent(pair.slice(eqIdx + 1)) : '';\n const existing = query[key];\n if (existing !== undefined) {\n if (Array.isArray(existing)) {\n existing.push(val);\n } else {\n query[key] = [existing, val];\n }\n } else {\n query[key] = val;\n }\n }\n }\n\n return { path: working || '/', query, hash };\n}\n\n/**\n * Matches a path against a route definition, extracting params.\n * @internal\n */\nfunction matchRoute(\n path: string,\n routes: MockRouteDefinition[]\n): { matched: MockRouteDefinition | null; params: Record<string, string> } {\n for (const route of routes) {\n const params = matchRoutePattern(route.path, path);\n if (params) {\n return { matched: route, params };\n }\n }\n return { matched: null, params: {} };\n}\n\n/**\n * Builds param matches from a route path pattern without compiling the full path into a regex.\n * @internal\n */\nfunction matchRoutePattern(pattern: string, path: string): Record<string, string> | null {\n if (pattern === '*') {\n return {};\n }\n\n // Memoization keeps wildcard/param backtracking linear for repeated subproblems\n // within a single pattern/path match attempt.\n const memo = new Map<string, Record<string, string> | null>();\n\n const findSegmentBoundary = (value: string, startIndex: number): number => {\n const slashIndex = value.indexOf('/', startIndex);\n return slashIndex === -1 ? value.length : slashIndex;\n };\n\n const matchFrom = (patternIndex: number, pathIndex: number): Record<string, string> | null => {\n const memoKey = `${patternIndex}:${pathIndex}`;\n if (memo.has(memoKey)) {\n return memo.get(memoKey) ?? null;\n }\n\n if (patternIndex === pattern.length) {\n const result = pathIndex === path.length ? {} : null;\n memo.set(memoKey, result);\n return result;\n }\n\n const patternChar = pattern[patternIndex];\n\n if (patternChar === '*') {\n for (let candidateEnd = path.length; candidateEnd >= pathIndex; candidateEnd--) {\n const suffixMatch = matchFrom(patternIndex + 1, candidateEnd);\n if (suffixMatch) {\n memo.set(memoKey, suffixMatch);\n return suffixMatch;\n }\n }\n\n memo.set(memoKey, null);\n return null;\n }\n\n if (patternChar === ':' && isWordChar(pattern[patternIndex + 1])) {\n let nameEnd = patternIndex + 2;\n while (nameEnd < pattern.length && isWordChar(pattern[nameEnd])) {\n nameEnd++;\n }\n\n const name = pattern.slice(patternIndex + 1, nameEnd);\n let nextPatternIndex = nameEnd;\n let constraint: string | undefined;\n let catchAll = false;\n\n if (pattern[nameEnd] === '(') {\n const parsedConstraint = readRouteConstraint(pattern, nameEnd);\n if (parsedConstraint) {\n constraint = parsedConstraint.constraint;\n nextPatternIndex = parsedConstraint.endIndex;\n }\n }\n\n if (pattern[nextPatternIndex] === '*') {\n catchAll = true;\n nextPatternIndex++;\n }\n\n const candidateLimit = catchAll\n ? path.length\n : constraint\n ? path.length\n : findSegmentBoundary(path, pathIndex);\n\n for (let candidateEnd = candidateLimit; candidateEnd > pathIndex; candidateEnd--) {\n const candidateValue = path.slice(pathIndex, candidateEnd);\n if (constraint) {\n const constraintRegex = getRouteConstraintRegex(constraint);\n if (!constraintRegex.test(candidateValue)) {\n continue;\n }\n }\n\n const suffixMatch = matchFrom(nextPatternIndex, candidateEnd);\n if (suffixMatch) {\n const result = {\n [name]: candidateValue,\n ...suffixMatch,\n };\n memo.set(memoKey, result);\n return result;\n }\n }\n\n memo.set(memoKey, null);\n return null;\n }\n\n if (pathIndex >= path.length || patternChar !== path[pathIndex]) {\n memo.set(memoKey, null);\n return null;\n }\n\n const result = matchFrom(patternIndex + 1, pathIndex + 1);\n memo.set(memoKey, result);\n return result;\n };\n\n return matchFrom(0, 0);\n}\n\n/**\n * Creates a lightweight mock router for testing that does not interact\n * with the browser History API.\n *\n * The mock router provides a reactive `currentRoute` signal that updates\n * when `push()` or `replace()` is called, making it ideal for testing\n * components or logic that depend on route state.\n *\n * @param options - Mock router configuration\n * @returns A {@link MockRouter} instance\n *\n * @example\n * ```ts\n * import { mockRouter } from '@bquery/bquery/testing';\n *\n * const router = mockRouter({\n * routes: [\n * { path: '/', component: () => null },\n * { path: '/user/:id', component: () => null },\n * ],\n * initialPath: '/',\n * });\n *\n * router.push('/user/42');\n * expect(router.currentRoute.value.params.id).toBe('42');\n * router.destroy();\n * ```\n */\nexport function mockRouter(options: MockRouterOptions = {}): MockRouter {\n const routes = options.routes ?? [{ path: '*', component: () => null }];\n const base = options.base ?? '';\n const initialPath = options.initialPath ?? '/';\n\n const resolveRoute = (fullPath: string): TestRoute => {\n const { path, query, hash } = parsePath(fullPath, base);\n const { matched, params } = matchRoute(path, routes);\n return { path, params, query, matched, hash };\n };\n\n const routeSignal = signal<TestRoute>(resolveRoute(initialPath));\n\n return {\n push(path: string): void {\n routeSignal.value = resolveRoute(path);\n },\n replace(path: string): void {\n routeSignal.value = resolveRoute(path);\n },\n get currentRoute(): Signal<TestRoute> {\n return routeSignal;\n },\n get routes(): MockRouteDefinition[] {\n return routes;\n },\n destroy(): void {\n routeSignal.dispose();\n },\n };\n}\n\n// ============================================================================\n// fireEvent\n// ============================================================================\n\n/**\n * Dispatches a synthetic event on an element and flushes pending effects.\n *\n * By default the event bubbles, is cancelable, and is composed (crosses\n * shadow DOM boundaries). Pass a `detail` option to create a `CustomEvent`.\n *\n * @param el - The target element\n * @param eventName - The event type (e.g. 'click', 'input', 'my-event')\n * @param options - Event configuration\n * @returns `true` if the event was not cancelled\n *\n * @example\n * ```ts\n * import { fireEvent } from '@bquery/bquery/testing';\n *\n * const button = document.createElement('button');\n * let clicked = false;\n * button.addEventListener('click', () => { clicked = true; });\n * fireEvent(button, 'click');\n * expect(clicked).toBe(true);\n * ```\n */\nexport function fireEvent(el: Element, eventName: string, options: FireEventOptions = {}): boolean {\n if (!el) {\n throw new Error('bQuery testing: fireEvent requires a valid element');\n }\n if (!eventName) {\n throw new Error('bQuery testing: fireEvent requires an event name');\n }\n\n const { bubbles = true, cancelable = true, composed = true, detail } = options;\n\n let event: Event;\n if (detail !== undefined) {\n event = new CustomEvent(eventName, { bubbles, cancelable, composed, detail });\n } else {\n event = new Event(eventName, { bubbles, cancelable, composed });\n }\n\n const result = el.dispatchEvent(event);\n\n // Flush any effects triggered by event handlers\n flushEffects();\n\n return result;\n}\n\n// ============================================================================\n// waitFor\n// ============================================================================\n\n/**\n * Waits for a predicate to return `true`, polling at a configurable interval.\n *\n * Useful for asserting conditions that depend on asynchronous operations,\n * timers, or deferred reactive updates.\n *\n * @param predicate - A function that returns `true` when the condition is met\n * @param options - Timeout and interval configuration\n * @returns A promise that resolves when the predicate returns `true`\n * @throws {Error} If the predicate does not return `true` within the timeout\n *\n * @example\n * ```ts\n * import { waitFor } from '@bquery/bquery/testing';\n *\n * await waitFor(() => document.querySelector('.loaded') !== null, {\n * timeout: 2000,\n * });\n * ```\n */\nexport async function waitFor(\n predicate: () => boolean | Promise<boolean>,\n options: WaitForOptions = {}\n): Promise<void> {\n if (typeof predicate !== 'function') {\n throw new Error('bQuery testing: waitFor requires a predicate function');\n }\n\n const { timeout = 1000, interval = 10 } = options;\n const start = Date.now();\n\n while (true) {\n try {\n const result = await predicate();\n if (result) return;\n } catch {\n // Predicate threw — treat as not-yet-met and keep polling\n }\n\n if (Date.now() - start >= timeout) {\n throw new Error(\n `bQuery testing: waitFor timed out after ${timeout}ms — predicate never returned true`\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, interval));\n }\n}\n","/**\n * Hydration support for server-rendered DOM.\n *\n * Enables the client-side view system to reuse existing server-rendered DOM\n * elements instead of re-rendering them, by attaching reactive bindings\n * to the pre-existing DOM structure.\n *\n * @module bquery/ssr\n */\n\nimport type { BindingContext, MountOptions, View } from '../view/types';\nimport { mount } from '../view/mount';\n\n/**\n * Extended mount options that include hydration mode.\n */\nexport type HydrateMountOptions = MountOptions & {\n /**\n * When present, must be `true` so the mount operation reuses existing DOM elements\n * instead of re-rendering them. Reactive bindings (effects) are\n * still attached so the DOM updates reactively from that point on.\n *\n * @default true\n */\n hydrate?: true;\n};\n\n/**\n * Mounts a reactive view with optional hydration support.\n *\n * When `hydrate: true` is set, the existing server-rendered DOM is preserved\n * and reactive bindings are attached on top. The DOM is NOT re-rendered;\n * instead, effects begin tracking signals so future changes update the DOM.\n *\n * This is the client-side counterpart to `renderToString()`. The typical flow:\n * 1. Server: `renderToString(template, data)` → send HTML to client\n * 2. Client: `hydrateMount('#app', reactiveContext, { hydrate: true })`\n *\n * Under the hood, `hydrateMount` simply delegates to the standard `mount()`\n * function. The `mount()` function already processes existing DOM elements\n * and attaches reactive effects to them — it does not clear/replace content.\n * The `hydrate` flag is a semantic marker indicating developer intent and\n * ensures the existing DOM structure is preserved.\n *\n * @param selector - CSS selector or Element to hydrate\n * @param context - Binding context with signals, computed values, and functions\n * @param options - Mount options with `hydrate: true`\n * @returns The mounted View instance\n *\n * @example\n * ```ts\n * import { hydrateMount } from '@bquery/bquery/ssr';\n * import { signal, computed } from '@bquery/bquery/reactive';\n *\n * // Server rendered:\n * // <div id=\"app\"><h1>Welcome</h1><p>Hello, World!</p></div>\n *\n * // Client hydration — attaches reactivity to existing DOM:\n * const name = signal('World');\n * const greeting = computed(() => `Hello, ${name.value}!`);\n *\n * const view = hydrateMount('#app', { name, greeting }, { hydrate: true });\n *\n * // Now updating `name.value` will reactively update the DOM\n * name.value = 'Alice'; // <p> updates to \"Hello, Alice!\"\n * ```\n */\nexport const hydrateMount = (\n selector: string | Element,\n context: BindingContext,\n options: HydrateMountOptions = {}\n): View => {\n const { hydrate = true, ...mountOptions } = options;\n\n if (!hydrate) {\n throw new Error(\n 'bQuery ssr: hydrateMount() requires { hydrate: true } when options are provided.'\n );\n }\n\n // Hydration uses the standard mount which processes existing DOM\n // and attaches reactive effects without clearing content.\n return mount(selector, context, mountOptions);\n};\n","/**\n * Store state serialization for SSR.\n *\n * Provides utilities to serialize store state into a `<script>` tag\n * for client-side hydration, and to deserialize state on the client.\n *\n * @module bquery/ssr\n */\n\nimport { getStore, listStores } from '../store/index';\nimport { isPrototypePollutionKey } from '../core/utils/object';\nimport type { DeserializedStoreState, SerializeOptions } from './types';\n\nconst isStoreStateObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst sanitizeHydrationState = (value: Record<string, unknown>): Record<string, unknown> => {\n const sanitized: Record<string, unknown> = {};\n for (const [key, entryValue] of Object.entries(value)) {\n if (isPrototypePollutionKey(key)) continue;\n sanitized[key] = entryValue;\n }\n return sanitized;\n};\n\n/**\n * Result of store state serialization.\n */\nexport type SerializeResult = {\n /** JSON string of the state map */\n stateJson: string;\n /** Complete `<script>` tag ready to embed in HTML */\n scriptTag: string;\n};\n\n/**\n * Escapes a string for safe embedding in a `<script>` tag.\n * Prevents XSS via `</script>` injection and HTML entities.\n *\n * @internal\n */\nconst escapeForScript = (str: string): string => {\n return str\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/\\//g, '\\\\u002f')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n};\n\n/**\n * Escapes a string for safe embedding in an HTML attribute value.\n * @internal\n */\nconst escapeForHtmlAttribute = (str: string): string => {\n return str\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n};\n\n/**\n * Serializes the state of registered stores into a JSON string and\n * a `<script>` tag suitable for embedding in server-rendered HTML.\n *\n * The serialized state can be picked up on the client using\n * `deserializeStoreState()` to restore stores to their server-side values.\n *\n * @param options - Serialization options\n * @returns Object with JSON string and ready-to-use script tag\n *\n * @example\n * ```ts\n * import { serializeStoreState } from '@bquery/bquery/ssr';\n * import { createStore } from '@bquery/bquery/store';\n *\n * const store = createStore({\n * id: 'counter',\n * state: () => ({ count: 42 }),\n * });\n *\n * const { scriptTag } = serializeStoreState();\n * // '<script id=\"__BQUERY_STORE_STATE__\">window.__BQUERY_INITIAL_STATE__={\"counter\":{\"count\":42}}</script>'\n * ```\n *\n * @example\n * ```ts\n * // Serialize only specific stores\n * const { scriptTag } = serializeStoreState({ storeIds: ['counter'] });\n * ```\n */\nexport const serializeStoreState = (options: SerializeOptions = {}): SerializeResult => {\n const {\n scriptId = '__BQUERY_STORE_STATE__',\n globalKey = '__BQUERY_INITIAL_STATE__',\n storeIds,\n serialize = JSON.stringify,\n } = options;\n\n if (isPrototypePollutionKey(globalKey)) {\n throw new Error(\n `serializeStoreState: invalid globalKey \"${globalKey}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n if (isPrototypePollutionKey(scriptId)) {\n throw new Error(\n `serializeStoreState: invalid scriptId \"${scriptId}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n const ids = storeIds ?? listStores();\n const stateMap = Object.create(null) as Record<string, Record<string, unknown>>;\n\n for (const id of ids) {\n if (isPrototypePollutionKey(id)) {\n continue;\n }\n\n const store = getStore<{ $state: Record<string, unknown> }>(id);\n if (store) {\n stateMap[id] = sanitizeHydrationState(store.$state);\n }\n }\n\n const stateJson = serialize(stateMap);\n if (typeof stateJson !== 'string') {\n throw new Error('serializeStoreState: custom serialize function must return a string.');\n }\n\n if (serialize !== JSON.stringify) {\n let parsedStateJson: unknown;\n try {\n parsedStateJson = JSON.parse(stateJson);\n } catch {\n throw new Error('serializeStoreState: custom serialize function returned invalid JSON.');\n }\n\n if (!isStoreStateObject(parsedStateJson)) {\n throw new Error(\n 'serializeStoreState: custom serialize function must return a JSON object string.'\n );\n }\n }\n\n const escapedJson = escapeForScript(stateJson);\n const escapedGlobalKey = escapeForScript(JSON.stringify(globalKey));\n const escapedScriptId = escapeForHtmlAttribute(scriptId);\n const scriptTag = `<script id=\"${escapedScriptId}\">window[${escapedGlobalKey}]=${escapedJson}</script>`;\n\n return { stateJson, scriptTag };\n};\n\n/**\n * Deserializes store state from the global variable set by the SSR script tag.\n *\n * Call this on the client before creating stores to pre-populate them with\n * server-rendered state. After deserialization, the script tag and global\n * variable are cleaned up automatically.\n *\n * @param globalKey - The global variable name where state was serialized\n * @param scriptId - The ID of the SSR script tag to remove after hydration\n * @returns The deserialized state map, or an empty object if not found\n *\n * @example\n * ```ts\n * import { deserializeStoreState } from '@bquery/bquery/ssr';\n *\n * // Call before creating stores\n * const state = deserializeStoreState();\n * // state = { counter: { count: 42 } }\n * ```\n */\nexport const deserializeStoreState = (\n globalKey = '__BQUERY_INITIAL_STATE__',\n scriptId = '__BQUERY_STORE_STATE__'\n): DeserializedStoreState => {\n if (isPrototypePollutionKey(globalKey)) {\n throw new Error(\n `deserializeStoreState: invalid globalKey \"${globalKey}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n if (isPrototypePollutionKey(scriptId)) {\n throw new Error(\n `deserializeStoreState: invalid scriptId \"${scriptId}\" - prototype-pollution keys are not allowed.`\n );\n }\n\n if (typeof window === 'undefined') {\n return {};\n }\n\n const state = (window as unknown as Record<string, unknown>)[globalKey];\n if (!state) {\n return {};\n }\n\n // Clean up global variable\n try {\n delete (window as unknown as Record<string, unknown>)[globalKey];\n } catch {\n // In strict mode on some environments, delete may fail\n (window as unknown as Record<string, unknown>)[globalKey] = undefined;\n }\n\n // Clean up script tag\n if (typeof document !== 'undefined' && typeof document.getElementById === 'function') {\n const scriptEl = document.getElementById(scriptId);\n if (scriptEl) {\n scriptEl.remove();\n }\n }\n\n if (!isStoreStateObject(state)) {\n return {};\n }\n\n for (const value of Object.values(state)) {\n if (!isStoreStateObject(value)) {\n return {};\n }\n }\n\n const sanitizedStateMap = Object.create(null) as DeserializedStoreState;\n\n for (const [storeId, storeState] of Object.entries(state)) {\n if (isPrototypePollutionKey(storeId) || !isStoreStateObject(storeState)) {\n continue;\n }\n\n sanitizedStateMap[storeId] = sanitizeHydrationState(storeState);\n }\n\n return sanitizedStateMap;\n};\n\n/**\n * Hydrates a store with pre-serialized state from SSR.\n *\n * If the store exists and has a `$patch` method, this applies the\n * deserialized state as a patch. Otherwise, the state is ignored.\n *\n * @param storeId - The store ID to hydrate\n * @param state - The plain state object to apply\n *\n * @example\n * ```ts\n * import { hydrateStore, deserializeStoreState } from '@bquery/bquery/ssr';\n * import { createStore } from '@bquery/bquery/store';\n *\n * // 1. Deserialize state from SSR script tag\n * const ssrState = deserializeStoreState();\n *\n * // 2. Create store (gets initial values from factory)\n * const store = createStore({\n * id: 'counter',\n * state: () => ({ count: 0 }),\n * });\n *\n * // 3. Apply SSR state\n * if (ssrState.counter) {\n * hydrateStore('counter', ssrState.counter);\n * }\n * // store.count is now 42 (from SSR)\n * ```\n */\nexport const hydrateStore = (storeId: string, state: Record<string, unknown>): void => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const store = getStore<{ $patch?: (partial: any) => void }>(storeId);\n if (store && typeof store.$patch === 'function') {\n store.$patch(sanitizeHydrationState(state));\n }\n};\n\n/**\n * Hydrates all stores at once from a deserialized state map.\n *\n * Convenience wrapper that calls `hydrateStore` for each entry in the state map.\n *\n * @param stateMap - Map of store IDs to their state objects\n *\n * @example\n * ```ts\n * import { hydrateStores, deserializeStoreState } from '@bquery/bquery/ssr';\n *\n * const ssrState = deserializeStoreState();\n * hydrateStores(ssrState);\n * ```\n */\nexport const hydrateStores = (stateMap: DeserializedStoreState): void => {\n for (const [storeId, state] of Object.entries(stateMap)) {\n hydrateStore(storeId, state);\n }\n};\n","/**\n * SSR rendering utilities.\n *\n * Server-side renders bQuery templates to HTML strings by evaluating\n * directive attributes against a plain data context. Uses a lightweight\n * DOM implementation to process templates without a browser.\n *\n * @module bquery/ssr\n */\n\nimport { isComputed, isSignal, type Signal } from '../reactive/index';\nimport { DANGEROUS_PROTOCOLS } from '../security/constants';\nimport { sanitizeHtml } from '../security/sanitize';\nimport type { BindingContext } from '../view/types';\nimport type { RenderOptions, SSRResult } from './types';\nimport { serializeStoreState } from './serialize';\n\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\nconst escapeHtmlText = (value: string): string =>\n value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\nconst escapeHtmlAttribute = (value: string): string =>\n escapeHtmlText(value).replace(/\"/g, '&quot;');\n\nconst isUnsafeUrlAttribute = (name: string): boolean => {\n const normalized = name.toLowerCase();\n return (\n normalized === 'href' ||\n normalized === 'src' ||\n normalized === 'xlink:href' ||\n normalized === 'formaction' ||\n normalized === 'action' ||\n normalized === 'poster' ||\n normalized === 'background' ||\n normalized === 'cite' ||\n normalized === 'data'\n );\n};\n\nconst sanitizeUrlForProtocolCheck = (value: string): string =>\n value\n .trim()\n .replace(/[\\u0000-\\u001F\\u007F]+/g, '')\n .replace(/[\\u200B-\\u200D\\uFEFF\\u2028\\u2029]+/g, '')\n .replace(/\\\\u[\\da-fA-F]{4}/g, '')\n .replace(/\\s+/g, '')\n .toLowerCase();\n\nconst isUnsafeUrlValue = (value: string): boolean => {\n const normalized = sanitizeUrlForProtocolCheck(value);\n return DANGEROUS_PROTOCOLS.some((protocol) => normalized.startsWith(protocol));\n};\n\nconst serializeSSRNode = (node: Node): string => {\n if (node.nodeType === Node.TEXT_NODE) {\n return escapeHtmlText(node.textContent ?? '');\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const el = node as Element;\n const tagName = el.tagName.toLowerCase();\n\n if (tagName === 'script') {\n return '';\n }\n\n let attrs = '';\n for (const attr of el.attributes) {\n const attrName = attr.name.toLowerCase();\n if (attrName.startsWith('on')) {\n continue;\n }\n if (isUnsafeUrlAttribute(attrName) && isUnsafeUrlValue(attr.value)) {\n continue;\n }\n attrs += ` ${attr.name}=\"${escapeHtmlAttribute(attr.value)}\"`;\n }\n\n if (VOID_ELEMENTS.has(tagName)) {\n return `<${tagName}${attrs}>`;\n }\n\n let childrenHtml = '';\n for (const child of el.childNodes) {\n childrenHtml += serializeSSRNode(child);\n }\n\n return `<${tagName}${attrs}>${childrenHtml}</${tagName}>`;\n};\n\n/**\n * Unwraps a value — if it's a signal/computed, returns `.value`, otherwise returns as-is.\n * @internal\n */\nconst unwrap = (value: unknown): unknown => {\n if (isSignal(value) || isComputed(value)) {\n return (value as Signal<unknown>).value;\n }\n return value;\n};\n\n/**\n * Evaluates a simple expression against a context.\n * Supports dot-notation property access, negation, ternary, and basic comparisons.\n * Unlike the view module's `evaluate()`, this does NOT use `new Function()` —\n * it uses a safe subset for SSR to avoid `unsafe-eval` in server environments.\n *\n * Falls back to `new Function()` for complex expressions.\n *\n * @internal\n */\nconst evaluateSSR = <T = unknown>(expression: string, context: BindingContext): T => {\n const trimmed = expression.trim();\n\n // Handle negation: !expr\n if (trimmed.startsWith('!')) {\n return !evaluateSSR(trimmed.slice(1).trim(), context) as T;\n }\n\n // Handle string literals\n if (\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) ||\n (trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n ) {\n return trimmed.slice(1, -1) as T;\n }\n\n // Handle numeric literals\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n return Number(trimmed) as T;\n }\n\n // Handle boolean literals\n if (trimmed === 'true') return true as T;\n if (trimmed === 'false') return false as T;\n if (trimmed === 'null') return null as T;\n if (trimmed === 'undefined') return undefined as T;\n\n // Handle dot-notation property access: a.b.c\n if (/^[\\w$]+(?:\\.[\\w$]+)*$/.test(trimmed)) {\n const parts = trimmed.split('.');\n let current: unknown = context;\n for (const part of parts) {\n if (current == null) return undefined as T;\n // First level: unwrap signals\n if (current === context) {\n current = unwrap((current as Record<string, unknown>)[part]);\n } else {\n current = (current as Record<string, unknown>)[part];\n }\n }\n return current as T;\n }\n\n // For complex expressions, fall back to Function-based evaluation\n try {\n const keys = Object.keys(context);\n const values = keys.map((k) => unwrap(context[k]));\n const fn = new Function(...keys, `return (${trimmed});`);\n return fn(...values) as T;\n } catch {\n return undefined as T;\n }\n};\n\n/**\n * Parses a `bq-for` expression like `item in items` or `(item, index) in items`.\n * @internal\n */\nconst parseForExpression = (\n expression: string\n): { itemName: string; indexName?: string; listExpr: string } | null => {\n const match = expression.match(/^\\(?(\\w+)(?:\\s*,\\s*(\\w+))?\\)?\\s+in\\s+(\\S.*)$/);\n if (!match) return null;\n return {\n itemName: match[1],\n indexName: match[2] || undefined,\n listExpr: match[3].trim(),\n };\n};\n\n/**\n * Processes an element's SSR directives, modifying it in place.\n * Returns `false` if the element should be removed from output (bq-if = false).\n * @internal\n */\nconst processSSRElement = (\n el: Element,\n context: BindingContext,\n prefix: string,\n doc: Document\n): boolean => {\n // Handle bq-if: remove element if condition is falsy\n const ifExpr = el.getAttribute(`${prefix}-if`);\n if (ifExpr !== null) {\n const condition = evaluateSSR<boolean>(ifExpr, context);\n if (!condition) {\n return false; // Signal to remove this element\n }\n }\n\n // Handle bq-show: set display:none if falsy\n const showExpr = el.getAttribute(`${prefix}-show`);\n if (showExpr !== null) {\n const condition = evaluateSSR<boolean>(showExpr, context);\n if (!condition) {\n const htmlEl = el as unknown as { style?: { display?: string } };\n if (htmlEl.style) {\n htmlEl.style.display = 'none';\n } else {\n el.setAttribute('style', 'display: none;');\n }\n }\n }\n\n // Handle bq-text: set text content\n const textExpr = el.getAttribute(`${prefix}-text`);\n if (textExpr !== null) {\n const value = evaluateSSR(textExpr, context);\n el.textContent = String(value ?? '');\n }\n\n // Handle bq-html: sanitize to match client-side default behavior\n const htmlExpr = el.getAttribute(`${prefix}-html`);\n if (htmlExpr !== null) {\n const value = evaluateSSR(htmlExpr, context);\n el.innerHTML = String(sanitizeHtml(String(value ?? '')));\n }\n\n // Handle bq-class: add classes\n const classExpr = el.getAttribute(`${prefix}-class`);\n if (classExpr !== null) {\n const trimmedClass = classExpr.trim();\n if (trimmedClass.startsWith('{')) {\n // Object syntax: { active: isActive, disabled: !enabled }\n const inner = trimmedClass.slice(1, -1).trim();\n const pairs = inner.split(',');\n for (const pair of pairs) {\n const colonIdx = pair.indexOf(':');\n if (colonIdx > -1) {\n const className = pair\n .slice(0, colonIdx)\n .trim()\n .replace(/^['\"]|['\"]$/g, '');\n const condExpr = pair.slice(colonIdx + 1).trim();\n const condition = evaluateSSR<boolean>(condExpr, context);\n if (condition) {\n el.classList.add(className);\n }\n }\n }\n } else {\n const result = evaluateSSR<string | string[]>(classExpr, context);\n if (typeof result === 'string') {\n result\n .split(/\\s+/)\n .filter(Boolean)\n .forEach((cls) => el.classList.add(cls));\n } else if (Array.isArray(result)) {\n result.filter(Boolean).forEach((cls) => el.classList.add(cls));\n }\n }\n }\n\n // Handle bq-style: set inline styles\n const styleExpr = el.getAttribute(`${prefix}-style`);\n if (styleExpr !== null) {\n const result = evaluateSSR<Record<string, string>>(styleExpr, context);\n if (result && typeof result === 'object') {\n const htmlEl = el as HTMLElement;\n for (const [prop, val] of Object.entries(result)) {\n // Convert camelCase to kebab-case\n const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();\n htmlEl.style.setProperty(cssProp, String(val));\n }\n }\n }\n\n // Handle bq-bind:attr — set arbitrary attributes\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name.startsWith(`${prefix}-bind:`)) {\n const attrName = attr.name.slice(`${prefix}-bind:`.length);\n const value = evaluateSSR(attr.value, context);\n if (value === false || value === null || value === undefined) {\n el.removeAttribute(attrName);\n } else if (value === true) {\n el.setAttribute(attrName, '');\n } else {\n el.setAttribute(attrName, String(value));\n }\n }\n }\n\n // Handle bq-for: list rendering\n const forExpr = el.getAttribute(`${prefix}-for`);\n if (forExpr !== null) {\n const parsed = parseForExpression(forExpr);\n if (parsed) {\n const list = evaluateSSR<unknown[]>(parsed.listExpr, context);\n if (Array.isArray(list) && el.parentNode) {\n const parent = el.parentNode;\n for (let i = 0; i < list.length; i++) {\n const item = list[i];\n const clone = el.cloneNode(true) as Element;\n\n // Remove the bq-for attribute from clones\n clone.removeAttribute(`${prefix}-for`);\n clone.removeAttribute(':key');\n clone.removeAttribute(`${prefix}-key`);\n\n // Create item context\n const itemContext: BindingContext = {\n ...context,\n [parsed.itemName]: item,\n };\n if (parsed.indexName) {\n itemContext[parsed.indexName] = i;\n }\n\n // Recursively process the clone\n processSSRElement(clone, itemContext, prefix, doc);\n processSSRChildren(clone, itemContext, prefix, doc);\n\n parent.insertBefore(clone, el);\n }\n\n // Remove the original template element\n parent.removeChild(el);\n return true; // Already handled children\n }\n }\n }\n\n return true;\n};\n\n/**\n * Recursively processes children of an element for SSR.\n * @internal\n */\nconst processSSRChildren = (\n parent: Element,\n context: BindingContext,\n prefix: string,\n doc: Document\n): void => {\n // Process children in reverse to handle removals safely\n const children = Array.from(parent.children);\n for (const child of children) {\n // Skip bq-for elements — they're handled by parent\n if (child.hasAttribute(`${prefix}-for`)) {\n // Process the for directive on this element\n const keep = processSSRElement(child, context, prefix, doc);\n if (!keep) {\n child.remove();\n }\n continue;\n }\n\n const keep = processSSRElement(child, context, prefix, doc);\n if (!keep) {\n child.remove();\n continue;\n }\n\n // Recurse into children\n processSSRChildren(child, context, prefix, doc);\n }\n};\n\n/**\n * Strips all directive attributes (bq-*) from an element and its descendants.\n * @internal\n */\nconst stripDirectiveAttributes = (el: Element, prefix: string): void => {\n // Remove directive attributes from this element\n const attrs = Array.from(el.attributes);\n for (const attr of attrs) {\n if (attr.name.startsWith(`${prefix}-`) || attr.name.startsWith(':') || attr.name === ':key') {\n el.removeAttribute(attr.name);\n }\n }\n\n // Recurse into children\n for (const child of Array.from(el.children)) {\n stripDirectiveAttributes(child, prefix);\n }\n};\n\n/**\n * Server-side renders a bQuery template to an HTML string.\n *\n * Takes an HTML template with bQuery directives (bq-text, bq-if, bq-for, etc.)\n * and a data context, then evaluates the directives to produce a static HTML string.\n * This HTML can be sent to the client and later hydrated with `mount()` using\n * `{ hydrate: true }`.\n *\n * Supported directives:\n * - `bq-text` — Sets text content\n * - `bq-html` — Sets innerHTML\n * - `bq-if` — Conditional rendering (removes element if falsy)\n * - `bq-show` — Toggle visibility via `display: none`\n * - `bq-class` — Dynamic class binding (object or expression syntax)\n * - `bq-style` — Dynamic inline styles\n * - `bq-for` — List rendering\n * - `bq-bind:attr` — Dynamic attribute binding\n *\n * @param template - HTML template string with bq-* directives\n * @param data - Plain data object (signals will be unwrapped automatically)\n * @param options - Rendering options\n * @returns SSR result with HTML string and optional store state\n *\n * @example\n * ```ts\n * import { renderToString } from '@bquery/bquery/ssr';\n * import { signal } from '@bquery/bquery/reactive';\n *\n * const result = renderToString(\n * '<div><h1 bq-text=\"title\"></h1><p bq-if=\"showBody\">Hello!</p></div>',\n * { title: 'Welcome', showBody: true }\n * );\n *\n * console.log(result.html);\n * // '<div><h1>Welcome</h1><p>Hello!</p></div>'\n * ```\n *\n * @example\n * ```ts\n * // With bq-for list rendering\n * const result = renderToString(\n * '<ul><li bq-for=\"item in items\" bq-text=\"item.name\"></li></ul>',\n * { items: [{ name: 'Alice' }, { name: 'Bob' }] }\n * );\n *\n * console.log(result.html);\n * // '<ul><li>Alice</li><li>Bob</li></ul>'\n * ```\n */\nexport const renderToString = (\n template: string,\n data: BindingContext,\n options: RenderOptions = {}\n): SSRResult => {\n const { prefix = 'bq', stripDirectives = false, includeStoreState = false } = options;\n\n if (!template || typeof template !== 'string') {\n throw new Error('bQuery SSR: template must be a non-empty string.');\n }\n\n if (typeof DOMParser === 'undefined') {\n throw new Error(\n 'bQuery SSR: DOMParser is not available in this environment. Provide a DOMParser-compatible implementation before calling renderToString().'\n );\n }\n\n // Create a DOM document for processing\n const parser = new DOMParser();\n const doc = parser.parseFromString(template.trim(), 'text/html');\n const body = doc.body || doc.documentElement;\n\n if (!body) {\n throw new Error('bQuery SSR: Failed to parse template.');\n }\n\n // Process all children of the body\n processSSRChildren(body, data, prefix, doc);\n\n // Strip directive attributes if requested\n if (stripDirectives) {\n for (const child of Array.from(body.children)) {\n stripDirectiveAttributes(child, prefix);\n }\n }\n\n let html = '';\n for (const child of body.childNodes) {\n html += serializeSSRNode(child);\n }\n\n // Handle store state serialization\n let storeState: string | undefined;\n if (includeStoreState) {\n const storeIds = Array.isArray(includeStoreState) ? includeStoreState : undefined;\n storeState = serializeStoreState({ storeIds }).stateJson;\n }\n\n return { html, storeState };\n};\n"],"mappings":"kRASA,IAAa,GAAc,mBAKd,GAAuB,IAAI,IAAI,CAC1C,IACA,OACA,UACA,UACA,QACA,IACA,MACA,MACA,aACA,KACA,SACA,UACA,OACA,OACA,MACA,WACA,OACA,KACA,MACA,UACA,MACA,MACA,KACA,KACA,KACA,aACA,SACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,SACA,SACA,KACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,OACA,MACA,KACA,WACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,UACA,SACA,QACA,SACA,OACA,SACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,QACA,KACA,QACA,OACA,KACA,IACA,KACA,MACA,MACD,EAMY,GAAiB,IAAI,IAAI,CACpC,SACA,SACA,QACA,WACA,SACA,QACA,SACA,OACA,OACA,QACA,OACA,WAIA,OACA,MACA,gBACA,WACD,EAMY,GAAe,IAAI,IAAI,CAElC,WACA,SACA,WACA,MACA,OACA,SACA,SACA,UACA,YACA,SAEA,QACA,UACA,SACA,OACA,WAEA,SACA,SACA,WACA,OACA,OACA,QACA,SACA,QACA,UAEA,WACA,aACA,aACA,YAEA,YACA,YACA,cACD,EAWY,GAA6B,IAAI,IAAI,CAChD,MACA,QACA,MACA,SACA,SACA,OACA,KACA,OACA,UACA,OACA,MACA,OACA,MACA,SACA,WACA,SACA,QACA,OACA,QACA,SACD,EAKY,GAA0B,CAAC,KAAM,aAAc,SAAU,UAKzD,GAAsB,CAAC,cAAe,QAAS,YAAa,SC7LnE,GAAA,CACJ,EACA,EACA,IACY,CACZ,MAAM,EAAY,EAAK,YAAA,EAGvB,UAAW,KAAU,GACnB,GAAI,EAAU,WAAW,CAAA,EAAS,MAAO,GAO3C,OAHI,GAAkB,EAAU,WAAW,OAAA,GAGvC,EAAU,WAAW,OAAA,EAAiB,GAGnC,EAAW,IAAI,CAAA,GAOlB,GAAkB,GAA2B,CACjD,MAAM,EAAa,EAAM,YAAA,EAAc,KAAA,EACvC,MAAO,CAA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"}