@bquery/bquery 1.6.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/README.md +192 -18
  2. package/dist/a11y/announce.d.ts +43 -0
  3. package/dist/a11y/announce.d.ts.map +1 -0
  4. package/dist/a11y/audit.d.ts +42 -0
  5. package/dist/a11y/audit.d.ts.map +1 -0
  6. package/dist/a11y/index.d.ts +53 -0
  7. package/dist/a11y/index.d.ts.map +1 -0
  8. package/dist/a11y/media-preferences.d.ts +77 -0
  9. package/dist/a11y/media-preferences.d.ts.map +1 -0
  10. package/dist/a11y/roving-tab-index.d.ts +38 -0
  11. package/dist/a11y/roving-tab-index.d.ts.map +1 -0
  12. package/dist/a11y/skip-link.d.ts +37 -0
  13. package/dist/a11y/skip-link.d.ts.map +1 -0
  14. package/dist/a11y/trap-focus.d.ts +49 -0
  15. package/dist/a11y/trap-focus.d.ts.map +1 -0
  16. package/dist/a11y/types.d.ts +152 -0
  17. package/dist/a11y/types.d.ts.map +1 -0
  18. package/dist/a11y-DVBCy09c.js +421 -0
  19. package/dist/a11y-DVBCy09c.js.map +1 -0
  20. package/dist/a11y.es.mjs +14 -0
  21. package/dist/component/component.d.ts.map +1 -1
  22. package/dist/component/html.d.ts.map +1 -1
  23. package/dist/component/index.d.ts +2 -1
  24. package/dist/component/index.d.ts.map +1 -1
  25. package/dist/component/library.d.ts.map +1 -1
  26. package/dist/component/scope.d.ts +138 -0
  27. package/dist/component/scope.d.ts.map +1 -0
  28. package/dist/component/types.d.ts +53 -1
  29. package/dist/component/types.d.ts.map +1 -1
  30. package/dist/component-L3-JfOFz.js +684 -0
  31. package/dist/component-L3-JfOFz.js.map +1 -0
  32. package/dist/component.es.mjs +9 -6
  33. package/dist/{config-DRmZZno3.js → config-DhT9auRm.js} +4 -4
  34. package/dist/{config-DRmZZno3.js.map → config-DhT9auRm.js.map} +1 -1
  35. package/dist/constraints-D5RHQLmP.js +100 -0
  36. package/dist/constraints-D5RHQLmP.js.map +1 -0
  37. package/dist/core/collection.d.ts +134 -0
  38. package/dist/core/collection.d.ts.map +1 -1
  39. package/dist/core/element.d.ts +120 -0
  40. package/dist/core/element.d.ts.map +1 -1
  41. package/dist/core/env.d.ts +18 -0
  42. package/dist/core/env.d.ts.map +1 -0
  43. package/dist/core/index.d.ts +1 -0
  44. package/dist/core/index.d.ts.map +1 -1
  45. package/dist/core/shared.d.ts +14 -0
  46. package/dist/core/shared.d.ts.map +1 -1
  47. package/dist/core/utils/index.d.ts +52 -41
  48. package/dist/core/utils/index.d.ts.map +1 -1
  49. package/dist/core-DdtZHzsS.js +168 -0
  50. package/dist/core-DdtZHzsS.js.map +1 -0
  51. package/dist/{core-CCEabVHl.js → core-EMYSLzaT.js} +293 -194
  52. package/dist/core-EMYSLzaT.js.map +1 -0
  53. package/dist/core.es.mjs +48 -46
  54. package/dist/custom-directives-Dr4C5lVV.js +9 -0
  55. package/dist/custom-directives-Dr4C5lVV.js.map +1 -0
  56. package/dist/devtools/devtools.d.ts +212 -0
  57. package/dist/devtools/devtools.d.ts.map +1 -0
  58. package/dist/devtools/index.d.ts +20 -0
  59. package/dist/devtools/index.d.ts.map +1 -0
  60. package/dist/devtools/types.d.ts +69 -0
  61. package/dist/devtools/types.d.ts.map +1 -0
  62. package/dist/devtools-BhB2iDPT.js +122 -0
  63. package/dist/devtools-BhB2iDPT.js.map +1 -0
  64. package/dist/devtools.es.mjs +19 -0
  65. package/dist/dnd/draggable.d.ts +51 -0
  66. package/dist/dnd/draggable.d.ts.map +1 -0
  67. package/dist/dnd/droppable.d.ts +38 -0
  68. package/dist/dnd/droppable.d.ts.map +1 -0
  69. package/dist/dnd/index.d.ts +47 -0
  70. package/dist/dnd/index.d.ts.map +1 -0
  71. package/dist/dnd/sortable.d.ts +43 -0
  72. package/dist/dnd/sortable.d.ts.map +1 -0
  73. package/dist/dnd/types.d.ts +250 -0
  74. package/dist/dnd/types.d.ts.map +1 -0
  75. package/dist/dnd-NwZBYh4l.js +244 -0
  76. package/dist/dnd-NwZBYh4l.js.map +1 -0
  77. package/dist/dnd.es.mjs +6 -0
  78. package/dist/env-CTdvLaH2.js +19 -0
  79. package/dist/env-CTdvLaH2.js.map +1 -0
  80. package/dist/forms/create-form.d.ts +49 -0
  81. package/dist/forms/create-form.d.ts.map +1 -0
  82. package/dist/forms/index.d.ts +40 -0
  83. package/dist/forms/index.d.ts.map +1 -0
  84. package/dist/forms/types.d.ts +185 -0
  85. package/dist/forms/types.d.ts.map +1 -0
  86. package/dist/forms/use-field.d.ts +34 -0
  87. package/dist/forms/use-field.d.ts.map +1 -0
  88. package/dist/forms/validators.d.ts +204 -0
  89. package/dist/forms/validators.d.ts.map +1 -0
  90. package/dist/forms-UcRHsYxC.js +227 -0
  91. package/dist/forms-UcRHsYxC.js.map +1 -0
  92. package/dist/forms.es.mjs +16 -0
  93. package/dist/full.d.ts +30 -11
  94. package/dist/full.d.ts.map +1 -1
  95. package/dist/full.es.mjs +209 -93
  96. package/dist/full.iife.js +47 -31
  97. package/dist/full.iife.js.map +1 -1
  98. package/dist/full.umd.js +47 -31
  99. package/dist/full.umd.js.map +1 -1
  100. package/dist/function-Cybd57JV.js +33 -0
  101. package/dist/function-Cybd57JV.js.map +1 -0
  102. package/dist/i18n/formatting.d.ts +40 -0
  103. package/dist/i18n/formatting.d.ts.map +1 -0
  104. package/dist/i18n/i18n.d.ts +48 -0
  105. package/dist/i18n/i18n.d.ts.map +1 -0
  106. package/dist/i18n/index.d.ts +57 -0
  107. package/dist/i18n/index.d.ts.map +1 -0
  108. package/dist/i18n/translate.d.ts +83 -0
  109. package/dist/i18n/translate.d.ts.map +1 -0
  110. package/dist/i18n/types.d.ts +156 -0
  111. package/dist/i18n/types.d.ts.map +1 -0
  112. package/dist/i18n-kuF6Ekj6.js +89 -0
  113. package/dist/i18n-kuF6Ekj6.js.map +1 -0
  114. package/dist/i18n.es.mjs +6 -0
  115. package/dist/index.d.ts +11 -0
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.es.mjs +257 -143
  118. package/dist/media/battery.d.ts +35 -0
  119. package/dist/media/battery.d.ts.map +1 -0
  120. package/dist/media/breakpoints.d.ts +51 -0
  121. package/dist/media/breakpoints.d.ts.map +1 -0
  122. package/dist/media/clipboard.d.ts +30 -0
  123. package/dist/media/clipboard.d.ts.map +1 -0
  124. package/dist/media/device-sensors.d.ts +54 -0
  125. package/dist/media/device-sensors.d.ts.map +1 -0
  126. package/dist/media/geolocation.d.ts +38 -0
  127. package/dist/media/geolocation.d.ts.map +1 -0
  128. package/dist/media/index.d.ts +42 -0
  129. package/dist/media/index.d.ts.map +1 -0
  130. package/dist/media/media-query.d.ts +36 -0
  131. package/dist/media/media-query.d.ts.map +1 -0
  132. package/dist/media/network.d.ts +35 -0
  133. package/dist/media/network.d.ts.map +1 -0
  134. package/dist/media/types.d.ts +173 -0
  135. package/dist/media/types.d.ts.map +1 -0
  136. package/dist/media/viewport.d.ts +32 -0
  137. package/dist/media/viewport.d.ts.map +1 -0
  138. package/dist/media-i-fB5WxI.js +340 -0
  139. package/dist/media-i-fB5WxI.js.map +1 -0
  140. package/dist/media.es.mjs +12 -0
  141. package/dist/motion/index.d.ts +7 -3
  142. package/dist/motion/index.d.ts.map +1 -1
  143. package/dist/motion/morph.d.ts +27 -0
  144. package/dist/motion/morph.d.ts.map +1 -0
  145. package/dist/motion/parallax.d.ts +30 -0
  146. package/dist/motion/parallax.d.ts.map +1 -0
  147. package/dist/motion/reduced-motion.d.ts +36 -3
  148. package/dist/motion/reduced-motion.d.ts.map +1 -1
  149. package/dist/motion/types.d.ts +58 -0
  150. package/dist/motion/types.d.ts.map +1 -1
  151. package/dist/motion/typewriter.d.ts +31 -0
  152. package/dist/motion/typewriter.d.ts.map +1 -0
  153. package/dist/motion-BJsAuULb.js +530 -0
  154. package/dist/motion-BJsAuULb.js.map +1 -0
  155. package/dist/motion.es.mjs +27 -23
  156. package/dist/{view-C70lA3vf.js → mount-B4Y8bk8Z.js} +166 -160
  157. package/dist/mount-B4Y8bk8Z.js.map +1 -0
  158. package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
  159. package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
  160. package/dist/{platform-Dr9b6fsq.js → platform-Dw2gE3zI.js} +21 -22
  161. package/dist/{platform-Dr9b6fsq.js.map → platform-Dw2gE3zI.js.map} +1 -1
  162. package/dist/platform.es.mjs +2 -2
  163. package/dist/plugin/index.d.ts +22 -0
  164. package/dist/plugin/index.d.ts.map +1 -0
  165. package/dist/plugin/registry.d.ts +108 -0
  166. package/dist/plugin/registry.d.ts.map +1 -0
  167. package/dist/plugin/types.d.ts +110 -0
  168. package/dist/plugin/types.d.ts.map +1 -0
  169. package/dist/plugin-C2WuC8SF.js +66 -0
  170. package/dist/plugin-C2WuC8SF.js.map +1 -0
  171. package/dist/plugin.es.mjs +9 -0
  172. package/dist/reactive/async-data.d.ts +28 -3
  173. package/dist/reactive/async-data.d.ts.map +1 -1
  174. package/dist/reactive/computed.d.ts +10 -0
  175. package/dist/reactive/computed.d.ts.map +1 -1
  176. package/dist/reactive/effect.d.ts +3 -0
  177. package/dist/reactive/effect.d.ts.map +1 -1
  178. package/dist/reactive/http.d.ts +194 -0
  179. package/dist/reactive/http.d.ts.map +1 -0
  180. package/dist/reactive/index.d.ts +2 -2
  181. package/dist/reactive/index.d.ts.map +1 -1
  182. package/dist/reactive/pagination.d.ts +126 -0
  183. package/dist/reactive/pagination.d.ts.map +1 -0
  184. package/dist/reactive/polling.d.ts +55 -0
  185. package/dist/reactive/polling.d.ts.map +1 -0
  186. package/dist/reactive/readonly.d.ts +20 -1
  187. package/dist/reactive/readonly.d.ts.map +1 -1
  188. package/dist/reactive/rest.d.ts +293 -0
  189. package/dist/reactive/rest.d.ts.map +1 -0
  190. package/dist/reactive/scope.d.ts +140 -0
  191. package/dist/reactive/scope.d.ts.map +1 -0
  192. package/dist/reactive/signal.d.ts +16 -2
  193. package/dist/reactive/signal.d.ts.map +1 -1
  194. package/dist/reactive/to-value.d.ts +57 -0
  195. package/dist/reactive/to-value.d.ts.map +1 -0
  196. package/dist/reactive/websocket.d.ts +285 -0
  197. package/dist/reactive/websocket.d.ts.map +1 -0
  198. package/dist/reactive-DwkhUJfP.js +1148 -0
  199. package/dist/reactive-DwkhUJfP.js.map +1 -0
  200. package/dist/reactive.es.mjs +38 -20
  201. package/dist/registry-B08iilIh.js +26 -0
  202. package/dist/registry-B08iilIh.js.map +1 -0
  203. package/dist/router/bq-link.d.ts +112 -0
  204. package/dist/router/bq-link.d.ts.map +1 -0
  205. package/dist/router/constraints.d.ts +9 -0
  206. package/dist/router/constraints.d.ts.map +1 -0
  207. package/dist/router/index.d.ts +15 -7
  208. package/dist/router/index.d.ts.map +1 -1
  209. package/dist/router/match.d.ts +0 -1
  210. package/dist/router/match.d.ts.map +1 -1
  211. package/dist/router/path-pattern.d.ts +14 -0
  212. package/dist/router/path-pattern.d.ts.map +1 -0
  213. package/dist/router/query.d.ts.map +1 -1
  214. package/dist/router/router.d.ts +3 -1
  215. package/dist/router/router.d.ts.map +1 -1
  216. package/dist/router/state.d.ts +25 -2
  217. package/dist/router/state.d.ts.map +1 -1
  218. package/dist/router/types.d.ts +48 -4
  219. package/dist/router/types.d.ts.map +1 -1
  220. package/dist/router/use-route.d.ts +50 -0
  221. package/dist/router/use-route.d.ts.map +1 -0
  222. package/dist/router/utils.d.ts +3 -0
  223. package/dist/router/utils.d.ts.map +1 -1
  224. package/dist/router-CQikC9Ed.js +492 -0
  225. package/dist/router-CQikC9Ed.js.map +1 -0
  226. package/dist/router.es.mjs +14 -10
  227. package/dist/{sanitize-Bs2dkMby.js → sanitize-B1V4JswB.js} +2 -1
  228. package/dist/{sanitize-Bs2dkMby.js.map → sanitize-B1V4JswB.js.map} +1 -1
  229. package/dist/security/index.d.ts +2 -2
  230. package/dist/security/index.d.ts.map +1 -1
  231. package/dist/security.es.mjs +1 -1
  232. package/dist/ssr/hydrate.d.ts +65 -0
  233. package/dist/ssr/hydrate.d.ts.map +1 -0
  234. package/dist/ssr/index.d.ts +59 -0
  235. package/dist/ssr/index.d.ts.map +1 -0
  236. package/dist/ssr/render.d.ts +62 -0
  237. package/dist/ssr/render.d.ts.map +1 -0
  238. package/dist/ssr/serialize.d.ts +118 -0
  239. package/dist/ssr/serialize.d.ts.map +1 -0
  240. package/dist/ssr/types.d.ts +70 -0
  241. package/dist/ssr/types.d.ts.map +1 -0
  242. package/dist/ssr-_dAcGdzu.js +248 -0
  243. package/dist/ssr-_dAcGdzu.js.map +1 -0
  244. package/dist/ssr.es.mjs +9 -0
  245. package/dist/store/create-store.d.ts.map +1 -1
  246. package/dist/store/index.d.ts +1 -1
  247. package/dist/store/index.d.ts.map +1 -1
  248. package/dist/store/persisted.d.ts +38 -4
  249. package/dist/store/persisted.d.ts.map +1 -1
  250. package/dist/store/types.d.ts +138 -1
  251. package/dist/store/types.d.ts.map +1 -1
  252. package/dist/store/utils.d.ts +2 -2
  253. package/dist/store/utils.d.ts.map +1 -1
  254. package/dist/store-Cb3gPRve.js +338 -0
  255. package/dist/store-Cb3gPRve.js.map +1 -0
  256. package/dist/store.es.mjs +11 -10
  257. package/dist/storybook/index.d.ts.map +1 -1
  258. package/dist/storybook.es.mjs +1 -1
  259. package/dist/storybook.es.mjs.map +1 -1
  260. package/dist/testing/index.d.ts +23 -0
  261. package/dist/testing/index.d.ts.map +1 -0
  262. package/dist/testing/testing.d.ts +156 -0
  263. package/dist/testing/testing.d.ts.map +1 -0
  264. package/dist/testing/types.d.ts +134 -0
  265. package/dist/testing/types.d.ts.map +1 -0
  266. package/dist/testing-C5Sjfsna.js +224 -0
  267. package/dist/testing-C5Sjfsna.js.map +1 -0
  268. package/dist/testing.es.mjs +9 -0
  269. package/dist/type-guards-BMX2c0LP.js +44 -0
  270. package/dist/type-guards-BMX2c0LP.js.map +1 -0
  271. package/dist/untrack-D0fnO5k2.js +36 -0
  272. package/dist/untrack-D0fnO5k2.js.map +1 -0
  273. package/dist/view/custom-directives.d.ts +20 -0
  274. package/dist/view/custom-directives.d.ts.map +1 -0
  275. package/dist/view/evaluate.d.ts.map +1 -1
  276. package/dist/view/process.d.ts.map +1 -1
  277. package/dist/view.es.mjs +9 -9
  278. package/package.json +47 -11
  279. package/src/a11y/announce.ts +131 -0
  280. package/src/a11y/audit.ts +314 -0
  281. package/src/a11y/index.ts +68 -0
  282. package/src/a11y/media-preferences.ts +255 -0
  283. package/src/a11y/roving-tab-index.ts +164 -0
  284. package/src/a11y/skip-link.ts +255 -0
  285. package/src/a11y/trap-focus.ts +184 -0
  286. package/src/a11y/types.ts +183 -0
  287. package/src/component/component.ts +599 -524
  288. package/src/component/html.ts +153 -153
  289. package/src/component/index.ts +52 -50
  290. package/src/component/library.ts +540 -518
  291. package/src/component/scope.ts +212 -0
  292. package/src/component/types.ts +310 -256
  293. package/src/core/collection.ts +249 -1
  294. package/src/core/element.ts +252 -11
  295. package/src/core/env.ts +60 -0
  296. package/src/core/index.ts +1 -0
  297. package/src/core/shared.ts +64 -0
  298. package/src/core/utils/index.ts +66 -1
  299. package/src/devtools/devtools.ts +410 -0
  300. package/src/devtools/index.ts +48 -0
  301. package/src/devtools/types.ts +104 -0
  302. package/src/dnd/draggable.ts +296 -0
  303. package/src/dnd/droppable.ts +228 -0
  304. package/src/dnd/index.ts +62 -0
  305. package/src/dnd/sortable.ts +307 -0
  306. package/src/dnd/types.ts +293 -0
  307. package/src/forms/create-form.ts +320 -0
  308. package/src/forms/index.ts +70 -0
  309. package/src/forms/types.ts +203 -0
  310. package/src/forms/use-field.ts +231 -0
  311. package/src/forms/validators.ts +294 -0
  312. package/src/full.ts +554 -229
  313. package/src/i18n/formatting.ts +67 -0
  314. package/src/i18n/i18n.ts +200 -0
  315. package/src/i18n/index.ts +67 -0
  316. package/src/i18n/translate.ts +182 -0
  317. package/src/i18n/types.ts +171 -0
  318. package/src/index.ts +72 -0
  319. package/src/media/battery.ts +116 -0
  320. package/src/media/breakpoints.ts +129 -0
  321. package/src/media/clipboard.ts +80 -0
  322. package/src/media/device-sensors.ts +158 -0
  323. package/src/media/geolocation.ts +119 -0
  324. package/src/media/index.ts +76 -0
  325. package/src/media/media-query.ts +92 -0
  326. package/src/media/network.ts +115 -0
  327. package/src/media/types.ts +177 -0
  328. package/src/media/viewport.ts +84 -0
  329. package/src/motion/index.ts +11 -2
  330. package/src/motion/morph.ts +151 -0
  331. package/src/motion/parallax.ts +120 -0
  332. package/src/motion/reduced-motion.ts +52 -3
  333. package/src/motion/types.ts +63 -0
  334. package/src/motion/typewriter.ts +164 -0
  335. package/src/plugin/index.ts +37 -0
  336. package/src/plugin/registry.ts +284 -0
  337. package/src/plugin/types.ts +137 -0
  338. package/src/reactive/async-data.ts +250 -29
  339. package/src/reactive/computed.ts +53 -1
  340. package/src/reactive/effect.ts +29 -6
  341. package/src/reactive/http.ts +790 -0
  342. package/src/reactive/index.ts +60 -0
  343. package/src/reactive/pagination.ts +317 -0
  344. package/src/reactive/polling.ts +179 -0
  345. package/src/reactive/readonly.ts +52 -8
  346. package/src/reactive/rest.ts +859 -0
  347. package/src/reactive/scope.ts +276 -0
  348. package/src/reactive/signal.ts +61 -1
  349. package/src/reactive/to-value.ts +71 -0
  350. package/src/reactive/websocket.ts +849 -0
  351. package/src/router/bq-link.ts +279 -0
  352. package/src/router/constraints.ts +204 -0
  353. package/src/router/index.ts +15 -7
  354. package/src/router/match.ts +255 -49
  355. package/src/router/path-pattern.ts +52 -0
  356. package/src/router/query.ts +3 -0
  357. package/src/router/router.ts +258 -48
  358. package/src/router/state.ts +51 -3
  359. package/src/router/types.ts +50 -4
  360. package/src/router/use-route.ts +68 -0
  361. package/src/router/utils.ts +44 -3
  362. package/src/security/index.ts +12 -17
  363. package/src/security/sanitize.ts +70 -70
  364. package/src/security/trusted-html.ts +71 -71
  365. package/src/ssr/hydrate.ts +84 -0
  366. package/src/ssr/index.ts +70 -0
  367. package/src/ssr/render.ts +508 -0
  368. package/src/ssr/serialize.ts +296 -0
  369. package/src/ssr/types.ts +81 -0
  370. package/src/store/create-store.ts +146 -8
  371. package/src/store/define-store.ts +49 -49
  372. package/src/store/index.ts +5 -0
  373. package/src/store/mapping.ts +74 -74
  374. package/src/store/persisted.ts +245 -62
  375. package/src/store/types.ts +247 -92
  376. package/src/store/utils.ts +4 -10
  377. package/src/store/watch.ts +53 -53
  378. package/src/storybook/index.ts +480 -479
  379. package/src/testing/index.ts +42 -0
  380. package/src/testing/testing.ts +593 -0
  381. package/src/testing/types.ts +170 -0
  382. package/src/view/custom-directives.ts +28 -0
  383. package/src/view/evaluate.ts +2 -0
  384. package/src/view/process.ts +19 -3
  385. package/dist/component-BEQgt5hl.js +0 -600
  386. package/dist/component-BEQgt5hl.js.map +0 -1
  387. package/dist/core-BGQJVw0-.js +0 -35
  388. package/dist/core-BGQJVw0-.js.map +0 -1
  389. package/dist/core-CCEabVHl.js.map +0 -1
  390. package/dist/effect-AFRW_Plg.js +0 -84
  391. package/dist/effect-AFRW_Plg.js.map +0 -1
  392. package/dist/motion-D9TcHxOF.js +0 -415
  393. package/dist/motion-D9TcHxOF.js.map +0 -1
  394. package/dist/reactive-DSkct0dO.js +0 -254
  395. package/dist/reactive-DSkct0dO.js.map +0 -1
  396. package/dist/router-CbDhl8rS.js +0 -188
  397. package/dist/router-CbDhl8rS.js.map +0 -1
  398. package/dist/store-BwDvI45q.js +0 -263
  399. package/dist/store-BwDvI45q.js.map +0 -1
  400. package/dist/untrack-B0rVscTc.js +0 -7
  401. package/dist/untrack-B0rVscTc.js.map +0 -1
  402. package/dist/view-C70lA3vf.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"untrack-D0fnO5k2.js","names":[],"sources":["../src/reactive/computed.ts","../src/reactive/untrack.ts"],"sourcesContent":["/**\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 * 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"],"mappings":";AAuBA,IAAa,IAAb,MAAmD;AAAA,EAsBjD,YAAY,GAAmC;AAAlB,SAAA,UAAA,yBApBJ,iBACT,oBACG,uBACG,oBAAI,IAAA,0BACS;AACjC,UAAI,KAAK,SACP;AAEF,WAAK,QAAQ;AAEb,YAAM,IAAsB,MAAM,KAAK,KAAK,WAAA;AAC5C,iBAAW,KAAc,EACvB,CAAA,EAAiB,CAAA;AAAA;;EAcrB,IAAI,QAAW;AACb,QAAI,KAAK;AACP,aAAK,KAAK,mBACR,KAAK,cAAc,EAAA,MAA6B,KAAK,QAAA,CAAS,GAC9D,KAAK,iBAAiB,KAEjB,KAAK;AAGd,UAAM,IAAU,EAAA;AAChB,WAAI,MACF,KAAK,YAAY,IAAI,CAAA,GACrB,EAAmB,GAAS,IAAA,IAE1B,KAAK,UACP,KAAK,QAAQ,IAEb,EAAkB,KAAK,SAAA,GACvB,KAAK,cAAc,EAAM,KAAK,WAAW,KAAK,OAAA,GAC9C,KAAK,iBAAiB,KAEjB,KAAK;AAAA;EASd,OAAU;AACR,WAAI,KAAK,YACF,KAAK,mBACR,KAAK,cAAc,EAAA,MAA6B,KAAK,QAAA,CAAS,GAC9D,KAAK,iBAAiB,KAEjB,KAAK,gBAGV,KAAK,UACP,KAAK,QAAQ,IAEb,EAAkB,KAAK,SAAA,GACvB,KAAK,cAAc,EAAM,KAAK,WAAW,KAAK,OAAA,GAC9C,KAAK,iBAAiB,KAEjB,KAAK;AAAA;EAOd,YAAY,GAA4B;AACtC,SAAK,YAAY,OAAO,CAAA;AAAA;EAO1B,UAAgB;AACd,SAAK,WAAW,IACZ,KAAK,UACP,KAAK,iBAAiB,KAExB,KAAK,QAAQ,IACb,EAAkB,KAAK,SAAA,GACvB,KAAK,YAAY,MAAA;AAAA;GAcR,IAAA,CAAe,MAA6B;AACvD,QAAM,IAAI,IAAI,EAAS,CAAA,GAGjB,IAAQ,EAAA;AACd,SAAI,EAAiB,CAAA,KACnB,EAAM,aAAA,MAAmB,EAAE,QAAA,CAAS,GAG/B;GChHI,IAAA,CAAc,MAAmB,EAAuB,CAAA"}
@@ -0,0 +1,20 @@
1
+ import type { DirectiveHandler } from './types';
2
+ /**
3
+ * Function signature used to resolve custom directives without coupling the
4
+ * view pipeline directly to the plugin module.
5
+ * @internal
6
+ */
7
+ export type CustomDirectiveResolver = (name: string) => DirectiveHandler | undefined;
8
+ /**
9
+ * Registers the resolver used by the view pipeline for custom directives.
10
+ *
11
+ * Pass `null` to unregister the current resolver and reset to the default behavior.
12
+ * @internal
13
+ */
14
+ export declare const registerCustomDirectiveResolver: (resolver: CustomDirectiveResolver | null) => void;
15
+ /**
16
+ * Returns a custom directive handler when one is registered.
17
+ * @internal
18
+ */
19
+ export declare const getCustomDirective: (name: string) => DirectiveHandler | undefined;
20
+ //# sourceMappingURL=custom-directives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-directives.d.ts","sourceRoot":"","sources":["../../src/view/custom-directives.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,GAAG,SAAS,CAAC;AAIrF;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,GAAI,UAAU,uBAAuB,GAAG,IAAI,KAAG,IAE1F,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,gBAAgB,GAAG,SAEpE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/view/evaluate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA4D9C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,QAAO,IAGvC,CAAC;AA8BF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,SAAS,cAAc,KAAG,CAoBnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,SAAS,cAAc,KAAG,CAiBtF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAqH/E,CAAC"}
1
+ {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/view/evaluate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA4D9C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,QAAO,IAGvC,CAAC;AA8BF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,SAAS,cAAc,KAAG,CAoBnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,SAAS,cAAc,KAAG,CAiBtF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAsH/E,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/view/process.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,EAAE,EAAE,gBAAgB,CAAC;IACrB,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,GAAG,EAAE,gBAAgB,CAAC;IACtB,GAAG,EAAE,gBAAgB,CAAC;IACtB,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,gBAAgB,CAAC;IAC7C,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,gBAAgB,CAAC;CAC7C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,IAAI,OAAO,EACX,SAAS,cAAc,EACvB,QAAQ,MAAM,EACd,UAAU,SAAS,EAAE,EACrB,UAAU,iBAAiB,KAC1B,IAyCF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,IAAI,OAAO,EACX,SAAS,cAAc,EACvB,QAAQ,MAAM,EACd,UAAU,SAAS,EAAE,EACrB,UAAU,iBAAiB,KAC1B,IAWF,CAAC"}
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/view/process.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,EAAE,EAAE,gBAAgB,CAAC;IACrB,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,GAAG,EAAE,gBAAgB,CAAC;IACtB,GAAG,EAAE,gBAAgB,CAAC;IACtB,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,gBAAgB,CAAC;IAC7C,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,gBAAgB,CAAC;CAC7C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,GACzB,IAAI,OAAO,EACX,SAAS,cAAc,EACvB,QAAQ,MAAM,EACd,UAAU,SAAS,EAAE,EACrB,UAAU,iBAAiB,KAC1B,IAuDF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,IAAI,OAAO,EACX,SAAS,cAAc,EACvB,QAAQ,MAAM,EACd,UAAU,SAAS,EAAE,EACrB,UAAU,iBAAiB,KAC1B,IAWF,CAAC"}
package/dist/view.es.mjs CHANGED
@@ -1,13 +1,13 @@
1
- import { t as r } from "./effect-AFRW_Plg.js";
2
- import { d as o, f as e } from "./reactive-DSkct0dO.js";
3
- import { n as s } from "./core-BGQJVw0-.js";
4
- import { n as f, r as c, t as i } from "./view-C70lA3vf.js";
1
+ import { n as a, r as o } from "./core-DdtZHzsS.js";
2
+ import { D as e } from "./reactive-DwkhUJfP.js";
3
+ import { r as s } from "./untrack-D0fnO5k2.js";
4
+ import { n as c, r as f, t as i } from "./mount-B4Y8bk8Z.js";
5
5
  export {
6
6
  e as batch,
7
- c as clearExpressionCache,
8
- o as computed,
7
+ f as clearExpressionCache,
8
+ s as computed,
9
9
  i as createTemplate,
10
- r as effect,
11
- f as mount,
12
- s as signal
10
+ o as effect,
11
+ c as mount,
12
+ a as signal
13
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bquery/bquery",
3
- "version": "1.6.0",
3
+ "version": "1.8.1",
4
4
  "description": "The jQuery for the Modern Web Platform - Zero build, TypeScript-first library with reactivity, components, and motion",
5
5
  "type": "module",
6
6
  "main": "./dist/full.umd.js",
@@ -58,6 +58,42 @@
58
58
  "./storybook": {
59
59
  "import": "./dist/storybook.es.mjs",
60
60
  "types": "./dist/storybook/index.d.ts"
61
+ },
62
+ "./forms": {
63
+ "import": "./dist/forms.es.mjs",
64
+ "types": "./dist/forms/index.d.ts"
65
+ },
66
+ "./i18n": {
67
+ "import": "./dist/i18n.es.mjs",
68
+ "types": "./dist/i18n/index.d.ts"
69
+ },
70
+ "./a11y": {
71
+ "import": "./dist/a11y.es.mjs",
72
+ "types": "./dist/a11y/index.d.ts"
73
+ },
74
+ "./dnd": {
75
+ "import": "./dist/dnd.es.mjs",
76
+ "types": "./dist/dnd/index.d.ts"
77
+ },
78
+ "./media": {
79
+ "import": "./dist/media.es.mjs",
80
+ "types": "./dist/media/index.d.ts"
81
+ },
82
+ "./plugin": {
83
+ "import": "./dist/plugin.es.mjs",
84
+ "types": "./dist/plugin/index.d.ts"
85
+ },
86
+ "./devtools": {
87
+ "import": "./dist/devtools.es.mjs",
88
+ "types": "./dist/devtools/index.d.ts"
89
+ },
90
+ "./testing": {
91
+ "import": "./dist/testing.es.mjs",
92
+ "types": "./dist/testing/index.d.ts"
93
+ },
94
+ "./ssr": {
95
+ "import": "./dist/ssr.es.mjs",
96
+ "types": "./dist/ssr/index.d.ts"
61
97
  }
62
98
  },
63
99
  "files": [
@@ -121,21 +157,21 @@
121
157
  "node": ">=18.0.0"
122
158
  },
123
159
  "devDependencies": {
124
- "@storybook/addon-docs": "^10.2.19",
125
- "@storybook/web-components-vite": "^10.2.19",
126
- "@typescript-eslint/eslint-plugin": "^8.57.0",
127
- "@typescript-eslint/parser": "^8.57.0",
128
- "bun-types": "^1.3.10",
129
- "eslint": "^10.0.3",
160
+ "@storybook/addon-docs": "^10.3.3",
161
+ "@storybook/web-components-vite": "^10.3.3",
162
+ "@typescript-eslint/eslint-plugin": "^8.58.0",
163
+ "@typescript-eslint/parser": "^8.58.0",
164
+ "bun-types": "^1.3.11",
165
+ "eslint": "^10.1.0",
130
166
  "eslint-config-prettier": "^10.1.8",
131
167
  "globals": "^17.4.0",
132
- "happy-dom": "^20.8.4",
168
+ "happy-dom": "^20.8.9",
133
169
  "prettier": "^3.8.1",
134
170
  "rimraf": "^6.1.3",
135
- "storybook": "^10.2.19",
136
- "typedoc": "^0.28.17",
171
+ "storybook": "^10.3.3",
172
+ "typedoc": "^0.28.18",
137
173
  "typescript": "^5.9.3",
138
- "vite": "^8.0.0",
174
+ "vite": "^8.0.3",
139
175
  "vitepress": "^1.6.4"
140
176
  }
141
177
  }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Screen reader announcement utility using ARIA live regions.
3
+ *
4
+ * Creates and manages off-screen live regions to announce dynamic
5
+ * content changes to assistive technologies.
6
+ *
7
+ * @module bquery/a11y
8
+ */
9
+
10
+ import type { AnnouncePriority } from './types';
11
+
12
+ /** Cache for live region containers, keyed by priority. */
13
+ const liveRegions = new Map<AnnouncePriority, HTMLElement>();
14
+ const pendingAnnouncements = new Map<AnnouncePriority, ReturnType<typeof setTimeout>>();
15
+
16
+ /**
17
+ * Delay in milliseconds before updating the live region text.
18
+ * This ensures screen readers detect the content change even when
19
+ * the same message is announced consecutively — clearing first and
20
+ * setting after a short timer delay forces a new live-region mutation event.
21
+ * @internal
22
+ */
23
+ const ANNOUNCEMENT_DELAY_MS = 50;
24
+
25
+ /**
26
+ * Gets or creates a visually-hidden ARIA live region for the given priority.
27
+ *
28
+ * @param priority - The aria-live priority level
29
+ * @returns The live region element
30
+ * @internal
31
+ */
32
+ const getOrCreateLiveRegion = (priority: AnnouncePriority): HTMLElement => {
33
+ const existing = liveRegions.get(priority);
34
+ if (existing && existing.isConnected) {
35
+ return existing;
36
+ }
37
+
38
+ const el = document.createElement('div');
39
+ el.setAttribute('aria-live', priority);
40
+ el.setAttribute('aria-atomic', 'true');
41
+ el.setAttribute('role', priority === 'assertive' ? 'alert' : 'status');
42
+
43
+ // Visually hidden but accessible to screen readers
44
+ Object.assign(el.style, {
45
+ position: 'absolute',
46
+ width: '1px',
47
+ height: '1px',
48
+ padding: '0',
49
+ margin: '-1px',
50
+ overflow: 'hidden',
51
+ clip: 'rect(0, 0, 0, 0)',
52
+ whiteSpace: 'nowrap',
53
+ border: '0',
54
+ });
55
+
56
+ document.body.appendChild(el);
57
+ liveRegions.set(priority, el);
58
+
59
+ return el;
60
+ };
61
+
62
+ /**
63
+ * Announces a message to screen readers via an ARIA live region.
64
+ *
65
+ * The message is injected into a visually-hidden live region element.
66
+ * Screen readers will pick up the change and announce it to the user.
67
+ *
68
+ * @param message - The text message to announce
69
+ * @param priority - The urgency level: `'polite'` (default) or `'assertive'`
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * import { announceToScreenReader } from '@bquery/bquery/a11y';
74
+ *
75
+ * // Polite announcement (waits for idle)
76
+ * announceToScreenReader('3 search results found');
77
+ *
78
+ * // Assertive announcement (interrupts current speech)
79
+ * announceToScreenReader('Error: Please fix the form', 'assertive');
80
+ * ```
81
+ */
82
+ export const announceToScreenReader = (
83
+ message: string,
84
+ priority: AnnouncePriority = 'polite'
85
+ ): void => {
86
+ if (!message) return;
87
+ if (typeof document === 'undefined' || !document.body) return;
88
+
89
+ const region = getOrCreateLiveRegion(priority);
90
+ const pendingTimeout = pendingAnnouncements.get(priority);
91
+ if (pendingTimeout !== undefined) {
92
+ clearTimeout(pendingTimeout);
93
+ }
94
+
95
+ // Clear first, then set after a short timer delay to ensure screen readers
96
+ // detect the change even if the same message is announced twice.
97
+ region.textContent = '';
98
+
99
+ // Use setTimeout to ensure the DOM update triggers a live region change event
100
+ const timeout = setTimeout(() => {
101
+ pendingAnnouncements.delete(priority);
102
+ if (region.isConnected) {
103
+ region.textContent = message;
104
+ }
105
+ }, ANNOUNCEMENT_DELAY_MS);
106
+
107
+ pendingAnnouncements.set(priority, timeout);
108
+ };
109
+
110
+ /**
111
+ * Removes all live region elements created by `announceToScreenReader`.
112
+ * Useful for cleanup in tests or when unmounting an application.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * import { clearAnnouncements } from '@bquery/bquery/a11y';
117
+ *
118
+ * clearAnnouncements();
119
+ * ```
120
+ */
121
+ export const clearAnnouncements = (): void => {
122
+ for (const timeout of pendingAnnouncements.values()) {
123
+ clearTimeout(timeout);
124
+ }
125
+ pendingAnnouncements.clear();
126
+
127
+ for (const [, el] of liveRegions) {
128
+ el.remove();
129
+ }
130
+ liveRegions.clear();
131
+ };
@@ -0,0 +1,314 @@
1
+ /**
2
+ * Development-time accessibility audit utility.
3
+ *
4
+ * Scans DOM elements for common accessibility issues such as missing
5
+ * alt text on images, missing labels on form inputs, empty links/buttons,
6
+ * and incorrect ARIA usage.
7
+ *
8
+ * @module bquery/a11y
9
+ */
10
+
11
+ import type { AuditFinding, AuditResult, AuditSeverity } from './types';
12
+
13
+ /**
14
+ * Creates a finding object.
15
+ * @internal
16
+ */
17
+ const finding = (
18
+ severity: AuditSeverity,
19
+ message: string,
20
+ element: Element,
21
+ rule: string
22
+ ): AuditFinding => ({
23
+ severity,
24
+ message,
25
+ element,
26
+ rule,
27
+ });
28
+
29
+ /**
30
+ * Checks images for missing alt attributes.
31
+ * @internal
32
+ */
33
+ const auditImages = (container: Element): AuditFinding[] => {
34
+ const findings: AuditFinding[] = [];
35
+ const images = container.querySelectorAll('img');
36
+
37
+ for (const img of images) {
38
+ if (!img.hasAttribute('alt')) {
39
+ findings.push(
40
+ finding(
41
+ 'error',
42
+ 'Image is missing an alt attribute. Add alt="" for decorative images or a descriptive alt text.',
43
+ img,
44
+ 'img-alt'
45
+ )
46
+ );
47
+ } else if (img.getAttribute('alt') === '' && !img.hasAttribute('role')) {
48
+ findings.push(
49
+ finding(
50
+ 'info',
51
+ 'Image has empty alt text. Consider adding role="presentation" if decorative.',
52
+ img,
53
+ 'img-decorative'
54
+ )
55
+ );
56
+ }
57
+ }
58
+
59
+ return findings;
60
+ };
61
+
62
+ /**
63
+ * Checks form inputs for missing labels.
64
+ * @internal
65
+ */
66
+ const auditFormInputs = (container: Element): AuditFinding[] => {
67
+ const findings: AuditFinding[] = [];
68
+ const inputs = container.querySelectorAll('input, select, textarea');
69
+
70
+ for (const input of inputs) {
71
+ const type = input.getAttribute('type');
72
+
73
+ // Hidden, submit, and button inputs don't need labels
74
+ if (type === 'hidden' || type === 'submit' || type === 'button' || type === 'reset') {
75
+ continue;
76
+ }
77
+
78
+ const id = input.getAttribute('id');
79
+ const hasLabel = id ? !!container.querySelector(`label[for="${id}"]`) : false;
80
+ const hasAriaLabel = input.hasAttribute('aria-label') || input.hasAttribute('aria-labelledby');
81
+ const hasTitle = input.hasAttribute('title');
82
+ const isWrappedInLabel = input.closest('label') !== null;
83
+
84
+ if (!hasLabel && !hasAriaLabel && !hasTitle && !isWrappedInLabel) {
85
+ findings.push(
86
+ finding(
87
+ 'error',
88
+ `Form input is missing a label. Add a <label for="id">, aria-label, or aria-labelledby attribute.`,
89
+ input,
90
+ 'input-label'
91
+ )
92
+ );
93
+ }
94
+ }
95
+
96
+ return findings;
97
+ };
98
+
99
+ /**
100
+ * Checks for empty interactive elements (buttons, links).
101
+ * @internal
102
+ */
103
+ const auditInteractiveElements = (container: Element): AuditFinding[] => {
104
+ const findings: AuditFinding[] = [];
105
+
106
+ // Check buttons
107
+ const buttons = container.querySelectorAll('button');
108
+ for (const btn of buttons) {
109
+ const hasText = (btn.textContent ?? '').trim().length > 0;
110
+ const hasAriaLabel = btn.hasAttribute('aria-label') || btn.hasAttribute('aria-labelledby');
111
+ const hasTitle = btn.hasAttribute('title');
112
+
113
+ if (!hasText && !hasAriaLabel && !hasTitle) {
114
+ findings.push(
115
+ finding(
116
+ 'error',
117
+ 'Button has no accessible name. Add text content, aria-label, or title.',
118
+ btn,
119
+ 'button-name'
120
+ )
121
+ );
122
+ }
123
+ }
124
+
125
+ // Check links
126
+ const links = container.querySelectorAll('a[href]');
127
+ for (const link of links) {
128
+ const hasText = (link.textContent ?? '').trim().length > 0;
129
+ const hasAriaLabel = link.hasAttribute('aria-label') || link.hasAttribute('aria-labelledby');
130
+ const hasTitle = link.hasAttribute('title');
131
+ const hasImage = link.querySelector('img[alt]') !== null;
132
+
133
+ if (!hasText && !hasAriaLabel && !hasTitle && !hasImage) {
134
+ findings.push(
135
+ finding(
136
+ 'error',
137
+ 'Link has no accessible name. Add text content, aria-label, or title.',
138
+ link,
139
+ 'link-name'
140
+ )
141
+ );
142
+ }
143
+ }
144
+
145
+ return findings;
146
+ };
147
+
148
+ /**
149
+ * Checks heading hierarchy for skipped levels.
150
+ * @internal
151
+ */
152
+ const auditHeadings = (container: Element): AuditFinding[] => {
153
+ const findings: AuditFinding[] = [];
154
+ const headings = container.querySelectorAll('h1, h2, h3, h4, h5, h6');
155
+
156
+ let previousLevel = 0;
157
+
158
+ for (const heading of headings) {
159
+ const level = parseInt(heading.tagName.charAt(1), 10);
160
+
161
+ if (previousLevel > 0 && level > previousLevel + 1) {
162
+ findings.push(
163
+ finding(
164
+ 'warning',
165
+ `Heading level skipped: <${heading.tagName.toLowerCase()}> follows <h${previousLevel}>. Don't skip heading levels.`,
166
+ heading,
167
+ 'heading-order'
168
+ )
169
+ );
170
+ }
171
+
172
+ if ((heading.textContent ?? '').trim().length === 0) {
173
+ findings.push(finding('warning', 'Heading element is empty.', heading, 'heading-empty'));
174
+ }
175
+
176
+ previousLevel = level;
177
+ }
178
+
179
+ return findings;
180
+ };
181
+
182
+ /**
183
+ * Checks for valid ARIA attribute usage.
184
+ * @internal
185
+ */
186
+ const auditAria = (container: Element): AuditFinding[] => {
187
+ const findings: AuditFinding[] = [];
188
+
189
+ // Check aria-labelledby references exist
190
+ const labelled = container.querySelectorAll('[aria-labelledby]');
191
+ for (const el of labelled) {
192
+ const ids = (el.getAttribute('aria-labelledby') ?? '').split(/\s+/);
193
+ for (const id of ids) {
194
+ if (id && !document.getElementById(id)) {
195
+ findings.push(
196
+ finding(
197
+ 'error',
198
+ `aria-labelledby references "${id}" which does not exist in the document.`,
199
+ el,
200
+ 'aria-labelledby-ref'
201
+ )
202
+ );
203
+ }
204
+ }
205
+ }
206
+
207
+ // Check aria-describedby references exist
208
+ const described = container.querySelectorAll('[aria-describedby]');
209
+ for (const el of described) {
210
+ const ids = (el.getAttribute('aria-describedby') ?? '').split(/\s+/);
211
+ for (const id of ids) {
212
+ if (id && !document.getElementById(id)) {
213
+ findings.push(
214
+ finding(
215
+ 'error',
216
+ `aria-describedby references "${id}" which does not exist in the document.`,
217
+ el,
218
+ 'aria-describedby-ref'
219
+ )
220
+ );
221
+ }
222
+ }
223
+ }
224
+
225
+ return findings;
226
+ };
227
+
228
+ /**
229
+ * Checks for sufficient document landmarks.
230
+ * @internal
231
+ */
232
+ const auditLandmarks = (container: Element): AuditFinding[] => {
233
+ const findings: AuditFinding[] = [];
234
+
235
+ // Only audit the document body or top-level container
236
+ if (container === document.body || container === document.documentElement) {
237
+ const hasMain = !!container.querySelector('main') || !!container.querySelector('[role="main"]');
238
+
239
+ if (!hasMain) {
240
+ findings.push(
241
+ finding(
242
+ 'warning',
243
+ 'Page is missing a <main> landmark. Add <main> or role="main" to the primary content area.',
244
+ container,
245
+ 'landmark-main'
246
+ )
247
+ );
248
+ }
249
+ }
250
+
251
+ return findings;
252
+ };
253
+
254
+ /**
255
+ * Runs a development-time accessibility audit on a container element.
256
+ *
257
+ * Checks for common accessibility issues including:
258
+ * - Missing alt text on images
259
+ * - Missing labels on form inputs
260
+ * - Empty buttons and links
261
+ * - Heading hierarchy issues
262
+ * - Invalid ARIA references
263
+ * - Missing document landmarks
264
+ *
265
+ * This is intended as a development tool — not a replacement for
266
+ * manual testing or professional accessibility audits.
267
+ *
268
+ * @param container - The element to audit (defaults to `document.body`)
269
+ * @returns An audit result with findings, counts, and pass/fail status
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * import { auditA11y } from '@bquery/bquery/a11y';
274
+ *
275
+ * const result = auditA11y();
276
+ * if (!result.passed) {
277
+ * console.warn(`Found ${result.errors} accessibility errors:`);
278
+ * for (const f of result.findings) {
279
+ * console.warn(`[${f.severity}] ${f.message}`, f.element);
280
+ * }
281
+ * }
282
+ * ```
283
+ */
284
+ export const auditA11y = (container?: Element): AuditResult => {
285
+ if (typeof document === 'undefined' || !document.body) {
286
+ return {
287
+ findings: [],
288
+ errors: 0,
289
+ warnings: 0,
290
+ passed: true,
291
+ };
292
+ }
293
+
294
+ const target = container ?? document.body;
295
+
296
+ const allFindings: AuditFinding[] = [
297
+ ...auditImages(target),
298
+ ...auditFormInputs(target),
299
+ ...auditInteractiveElements(target),
300
+ ...auditHeadings(target),
301
+ ...auditAria(target),
302
+ ...auditLandmarks(target),
303
+ ];
304
+
305
+ const errors = allFindings.filter((f) => f.severity === 'error').length;
306
+ const warnings = allFindings.filter((f) => f.severity === 'warning').length;
307
+
308
+ return {
309
+ findings: allFindings,
310
+ errors,
311
+ warnings,
312
+ passed: errors === 0,
313
+ };
314
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Accessibility (a11y) utilities module for bQuery.js.
3
+ *
4
+ * Provides essential accessibility helpers for building inclusive
5
+ * web applications: focus trapping, screen reader announcements,
6
+ * keyboard navigation patterns, skip navigation, media preference
7
+ * signals, and development-time auditing.
8
+ *
9
+ * @module bquery/a11y
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import {
14
+ * trapFocus,
15
+ * announceToScreenReader,
16
+ * rovingTabIndex,
17
+ * skipLink,
18
+ * prefersReducedMotion,
19
+ * prefersColorScheme,
20
+ * auditA11y,
21
+ * } from '@bquery/bquery/a11y';
22
+ *
23
+ * // Trap focus in a modal
24
+ * const trap = trapFocus(dialogElement);
25
+ *
26
+ * // Announce changes to screen readers
27
+ * announceToScreenReader('Form submitted successfully');
28
+ *
29
+ * // Arrow key navigation in a toolbar
30
+ * const roving = rovingTabIndex(toolbar, 'button', {
31
+ * orientation: 'horizontal',
32
+ * });
33
+ *
34
+ * // Auto-generate skip navigation
35
+ * const skip = skipLink('#main-content');
36
+ *
37
+ * // Reactive media preferences
38
+ * const reduced = prefersReducedMotion();
39
+ * const scheme = prefersColorScheme();
40
+ *
41
+ * // Development-time audit
42
+ * const result = auditA11y();
43
+ * if (!result.passed) console.warn(result.findings);
44
+ * ```
45
+ */
46
+
47
+ export { announceToScreenReader, clearAnnouncements } from './announce';
48
+ export { auditA11y } from './audit';
49
+ export { prefersColorScheme, prefersContrast, prefersReducedMotion } from './media-preferences';
50
+ export { rovingTabIndex } from './roving-tab-index';
51
+ export { skipLink } from './skip-link';
52
+ export { getFocusableElements, releaseFocus, trapFocus } from './trap-focus';
53
+
54
+ export type {
55
+ AnnouncePriority,
56
+ AuditFinding,
57
+ AuditResult,
58
+ AuditSeverity,
59
+ ColorScheme,
60
+ ContrastPreference,
61
+ FocusTrapHandle,
62
+ MediaPreferenceSignal,
63
+ RovingTabIndexHandle,
64
+ RovingTabIndexOptions,
65
+ SkipLinkHandle,
66
+ SkipLinkOptions,
67
+ TrapFocusOptions,
68
+ } from './types';