@bquery/bquery 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. package/README.md +716 -586
  2. package/dist/a11y/announce.d.ts +43 -0
  3. package/dist/a11y/announce.d.ts.map +1 -0
  4. package/dist/a11y/audit.d.ts +42 -0
  5. package/dist/a11y/audit.d.ts.map +1 -0
  6. package/dist/a11y/index.d.ts +53 -0
  7. package/dist/a11y/index.d.ts.map +1 -0
  8. package/dist/a11y/media-preferences.d.ts +77 -0
  9. package/dist/a11y/media-preferences.d.ts.map +1 -0
  10. package/dist/a11y/roving-tab-index.d.ts +38 -0
  11. package/dist/a11y/roving-tab-index.d.ts.map +1 -0
  12. package/dist/a11y/skip-link.d.ts +37 -0
  13. package/dist/a11y/skip-link.d.ts.map +1 -0
  14. package/dist/a11y/trap-focus.d.ts +49 -0
  15. package/dist/a11y/trap-focus.d.ts.map +1 -0
  16. package/dist/a11y/types.d.ts +152 -0
  17. package/dist/a11y/types.d.ts.map +1 -0
  18. package/dist/a11y-C5QOVvRn.js +421 -0
  19. package/dist/a11y-C5QOVvRn.js.map +1 -0
  20. package/dist/a11y.es.mjs +14 -0
  21. package/dist/component/component.d.ts.map +1 -1
  22. package/dist/component/html.d.ts.map +1 -1
  23. package/dist/component/index.d.ts +2 -1
  24. package/dist/component/index.d.ts.map +1 -1
  25. package/dist/component/library.d.ts.map +1 -1
  26. package/dist/component/scope.d.ts +138 -0
  27. package/dist/component/scope.d.ts.map +1 -0
  28. package/dist/component/types.d.ts +53 -1
  29. package/dist/component/types.d.ts.map +1 -1
  30. package/dist/component-CuuTijA6.js +684 -0
  31. package/dist/component-CuuTijA6.js.map +1 -0
  32. package/dist/component.es.mjs +9 -6
  33. package/dist/{config-DRmZZno3.js → config-BW35FKuA.js} +4 -4
  34. package/dist/{config-DRmZZno3.js.map → config-BW35FKuA.js.map} +1 -1
  35. package/dist/constraints-3lV9yyBw.js +100 -0
  36. package/dist/constraints-3lV9yyBw.js.map +1 -0
  37. package/dist/core/collection.d.ts +48 -0
  38. package/dist/core/collection.d.ts.map +1 -1
  39. package/dist/core/element.d.ts +92 -0
  40. package/dist/core/element.d.ts.map +1 -1
  41. package/dist/core/env.d.ts +18 -0
  42. package/dist/core/env.d.ts.map +1 -0
  43. package/dist/core/index.d.ts +1 -0
  44. package/dist/core/index.d.ts.map +1 -1
  45. package/dist/core/shared.d.ts +8 -0
  46. package/dist/core/shared.d.ts.map +1 -1
  47. package/dist/core/utils/index.d.ts +52 -41
  48. package/dist/core/utils/index.d.ts.map +1 -1
  49. package/dist/core-Cjl7GUu8.js +717 -0
  50. package/dist/core-Cjl7GUu8.js.map +1 -0
  51. package/dist/core-DnlyjbF2.js +112 -0
  52. package/dist/core-DnlyjbF2.js.map +1 -0
  53. package/dist/core.es.mjs +45 -44
  54. package/dist/custom-directives-7wAShnnd.js +9 -0
  55. package/dist/custom-directives-7wAShnnd.js.map +1 -0
  56. package/dist/devtools/devtools.d.ts +212 -0
  57. package/dist/devtools/devtools.d.ts.map +1 -0
  58. package/dist/devtools/index.d.ts +20 -0
  59. package/dist/devtools/index.d.ts.map +1 -0
  60. package/dist/devtools/types.d.ts +69 -0
  61. package/dist/devtools/types.d.ts.map +1 -0
  62. package/dist/devtools-D2fQLhDN.js +122 -0
  63. package/dist/devtools-D2fQLhDN.js.map +1 -0
  64. package/dist/devtools.es.mjs +19 -0
  65. package/dist/dnd/draggable.d.ts +51 -0
  66. package/dist/dnd/draggable.d.ts.map +1 -0
  67. package/dist/dnd/droppable.d.ts +38 -0
  68. package/dist/dnd/droppable.d.ts.map +1 -0
  69. package/dist/dnd/index.d.ts +47 -0
  70. package/dist/dnd/index.d.ts.map +1 -0
  71. package/dist/dnd/sortable.d.ts +43 -0
  72. package/dist/dnd/sortable.d.ts.map +1 -0
  73. package/dist/dnd/types.d.ts +250 -0
  74. package/dist/dnd/types.d.ts.map +1 -0
  75. package/dist/dnd-B8EgyzaI.js +244 -0
  76. package/dist/dnd-B8EgyzaI.js.map +1 -0
  77. package/dist/dnd.es.mjs +6 -0
  78. package/dist/env-NeVmr4Gf.js +19 -0
  79. package/dist/env-NeVmr4Gf.js.map +1 -0
  80. package/dist/forms/create-form.d.ts +49 -0
  81. package/dist/forms/create-form.d.ts.map +1 -0
  82. package/dist/forms/index.d.ts +39 -0
  83. package/dist/forms/index.d.ts.map +1 -0
  84. package/dist/forms/types.d.ts +139 -0
  85. package/dist/forms/types.d.ts.map +1 -0
  86. package/dist/forms/validators.d.ts +179 -0
  87. package/dist/forms/validators.d.ts.map +1 -0
  88. package/dist/forms-C3yovgH9.js +141 -0
  89. package/dist/forms-C3yovgH9.js.map +1 -0
  90. package/dist/forms.es.mjs +14 -0
  91. package/dist/full.d.ts +35 -7
  92. package/dist/full.d.ts.map +1 -1
  93. package/dist/full.es.mjs +182 -91
  94. package/dist/full.iife.js +47 -31
  95. package/dist/full.iife.js.map +1 -1
  96. package/dist/full.umd.js +47 -31
  97. package/dist/full.umd.js.map +1 -1
  98. package/dist/i18n/formatting.d.ts +40 -0
  99. package/dist/i18n/formatting.d.ts.map +1 -0
  100. package/dist/i18n/i18n.d.ts +48 -0
  101. package/dist/i18n/i18n.d.ts.map +1 -0
  102. package/dist/i18n/index.d.ts +57 -0
  103. package/dist/i18n/index.d.ts.map +1 -0
  104. package/dist/i18n/translate.d.ts +83 -0
  105. package/dist/i18n/translate.d.ts.map +1 -0
  106. package/dist/i18n/types.d.ts +156 -0
  107. package/dist/i18n/types.d.ts.map +1 -0
  108. package/dist/i18n-BnnhTFOS.js +89 -0
  109. package/dist/i18n-BnnhTFOS.js.map +1 -0
  110. package/dist/i18n.es.mjs +6 -0
  111. package/dist/index.d.ts +11 -0
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.es.mjs +227 -136
  114. package/dist/media/battery.d.ts +35 -0
  115. package/dist/media/battery.d.ts.map +1 -0
  116. package/dist/media/breakpoints.d.ts +51 -0
  117. package/dist/media/breakpoints.d.ts.map +1 -0
  118. package/dist/media/clipboard.d.ts +30 -0
  119. package/dist/media/clipboard.d.ts.map +1 -0
  120. package/dist/media/device-sensors.d.ts +54 -0
  121. package/dist/media/device-sensors.d.ts.map +1 -0
  122. package/dist/media/geolocation.d.ts +38 -0
  123. package/dist/media/geolocation.d.ts.map +1 -0
  124. package/dist/media/index.d.ts +42 -0
  125. package/dist/media/index.d.ts.map +1 -0
  126. package/dist/media/media-query.d.ts +36 -0
  127. package/dist/media/media-query.d.ts.map +1 -0
  128. package/dist/media/network.d.ts +35 -0
  129. package/dist/media/network.d.ts.map +1 -0
  130. package/dist/media/types.d.ts +173 -0
  131. package/dist/media/types.d.ts.map +1 -0
  132. package/dist/media/viewport.d.ts +32 -0
  133. package/dist/media/viewport.d.ts.map +1 -0
  134. package/dist/media-Di2Ta22s.js +340 -0
  135. package/dist/media-Di2Ta22s.js.map +1 -0
  136. package/dist/media.es.mjs +12 -0
  137. package/dist/motion/index.d.ts +7 -3
  138. package/dist/motion/index.d.ts.map +1 -1
  139. package/dist/motion/morph.d.ts +27 -0
  140. package/dist/motion/morph.d.ts.map +1 -0
  141. package/dist/motion/parallax.d.ts +30 -0
  142. package/dist/motion/parallax.d.ts.map +1 -0
  143. package/dist/motion/reduced-motion.d.ts +36 -3
  144. package/dist/motion/reduced-motion.d.ts.map +1 -1
  145. package/dist/motion/types.d.ts +58 -0
  146. package/dist/motion/types.d.ts.map +1 -1
  147. package/dist/motion/typewriter.d.ts +31 -0
  148. package/dist/motion/typewriter.d.ts.map +1 -0
  149. package/dist/motion-qPj_TYGv.js +530 -0
  150. package/dist/motion-qPj_TYGv.js.map +1 -0
  151. package/dist/motion.es.mjs +27 -23
  152. package/dist/{view-C70lA3vf.js → mount-SM07RUa6.js} +166 -160
  153. package/dist/mount-SM07RUa6.js.map +1 -0
  154. package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
  155. package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
  156. package/dist/{platform-Dr9b6fsq.js → platform-CPbCprb6.js} +21 -22
  157. package/dist/{platform-Dr9b6fsq.js.map → platform-CPbCprb6.js.map} +1 -1
  158. package/dist/platform.es.mjs +2 -2
  159. package/dist/plugin/index.d.ts +22 -0
  160. package/dist/plugin/index.d.ts.map +1 -0
  161. package/dist/plugin/registry.d.ts +108 -0
  162. package/dist/plugin/registry.d.ts.map +1 -0
  163. package/dist/plugin/types.d.ts +110 -0
  164. package/dist/plugin/types.d.ts.map +1 -0
  165. package/dist/plugin-cPoOHFLY.js +64 -0
  166. package/dist/plugin-cPoOHFLY.js.map +1 -0
  167. package/dist/plugin.es.mjs +9 -0
  168. package/dist/reactive/computed.d.ts +7 -0
  169. package/dist/reactive/computed.d.ts.map +1 -1
  170. package/dist/reactive-Cfv0RK6x.js +233 -0
  171. package/dist/reactive-Cfv0RK6x.js.map +1 -0
  172. package/dist/reactive.es.mjs +19 -20
  173. package/dist/registry-CWf368tT.js +26 -0
  174. package/dist/registry-CWf368tT.js.map +1 -0
  175. package/dist/router/bq-link.d.ts +112 -0
  176. package/dist/router/bq-link.d.ts.map +1 -0
  177. package/dist/router/constraints.d.ts +9 -0
  178. package/dist/router/constraints.d.ts.map +1 -0
  179. package/dist/router/index.d.ts +14 -6
  180. package/dist/router/index.d.ts.map +1 -1
  181. package/dist/router/match.d.ts +0 -1
  182. package/dist/router/match.d.ts.map +1 -1
  183. package/dist/router/path-pattern.d.ts +14 -0
  184. package/dist/router/path-pattern.d.ts.map +1 -0
  185. package/dist/router/query.d.ts.map +1 -1
  186. package/dist/router/router.d.ts +3 -1
  187. package/dist/router/router.d.ts.map +1 -1
  188. package/dist/router/types.d.ts +48 -4
  189. package/dist/router/types.d.ts.map +1 -1
  190. package/dist/router/use-route.d.ts +50 -0
  191. package/dist/router/use-route.d.ts.map +1 -0
  192. package/dist/router/utils.d.ts +3 -0
  193. package/dist/router/utils.d.ts.map +1 -1
  194. package/dist/router-BrthaP_z.js +473 -0
  195. package/dist/router-BrthaP_z.js.map +1 -0
  196. package/dist/router.es.mjs +13 -10
  197. package/dist/{sanitize-Bs2dkMby.js → sanitize-B1V4JswB.js} +2 -1
  198. package/dist/{sanitize-Bs2dkMby.js.map → sanitize-B1V4JswB.js.map} +1 -1
  199. package/dist/security/index.d.ts +2 -2
  200. package/dist/security/index.d.ts.map +1 -1
  201. package/dist/security.es.mjs +1 -1
  202. package/dist/ssr/hydrate.d.ts +65 -0
  203. package/dist/ssr/hydrate.d.ts.map +1 -0
  204. package/dist/ssr/index.d.ts +59 -0
  205. package/dist/ssr/index.d.ts.map +1 -0
  206. package/dist/ssr/render.d.ts +62 -0
  207. package/dist/ssr/render.d.ts.map +1 -0
  208. package/dist/ssr/serialize.d.ts +118 -0
  209. package/dist/ssr/serialize.d.ts.map +1 -0
  210. package/dist/ssr/types.d.ts +70 -0
  211. package/dist/ssr/types.d.ts.map +1 -0
  212. package/dist/ssr-B2qd_WBB.js +248 -0
  213. package/dist/ssr-B2qd_WBB.js.map +1 -0
  214. package/dist/ssr.es.mjs +9 -0
  215. package/dist/store/create-store.d.ts.map +1 -1
  216. package/dist/store/index.d.ts +1 -1
  217. package/dist/store/index.d.ts.map +1 -1
  218. package/dist/store/persisted.d.ts +38 -4
  219. package/dist/store/persisted.d.ts.map +1 -1
  220. package/dist/store/types.d.ts +138 -1
  221. package/dist/store/types.d.ts.map +1 -1
  222. package/dist/store/utils.d.ts +2 -2
  223. package/dist/store/utils.d.ts.map +1 -1
  224. package/dist/store-DWpyH6p5.js +338 -0
  225. package/dist/store-DWpyH6p5.js.map +1 -0
  226. package/dist/store.es.mjs +11 -10
  227. package/dist/storybook/index.d.ts.map +1 -1
  228. package/dist/storybook.es.mjs +1 -1
  229. package/dist/storybook.es.mjs.map +1 -1
  230. package/dist/testing/index.d.ts +23 -0
  231. package/dist/testing/index.d.ts.map +1 -0
  232. package/dist/testing/testing.d.ts +156 -0
  233. package/dist/testing/testing.d.ts.map +1 -0
  234. package/dist/testing/types.d.ts +134 -0
  235. package/dist/testing/types.d.ts.map +1 -0
  236. package/dist/testing-CsqjNUyy.js +224 -0
  237. package/dist/testing-CsqjNUyy.js.map +1 -0
  238. package/dist/testing.es.mjs +9 -0
  239. package/dist/type-guards-Do9DWgNp.js +44 -0
  240. package/dist/type-guards-Do9DWgNp.js.map +1 -0
  241. package/dist/untrack-DJVQQ2WM.js +33 -0
  242. package/dist/untrack-DJVQQ2WM.js.map +1 -0
  243. package/dist/view/custom-directives.d.ts +20 -0
  244. package/dist/view/custom-directives.d.ts.map +1 -0
  245. package/dist/view/evaluate.d.ts.map +1 -1
  246. package/dist/view/process.d.ts.map +1 -1
  247. package/dist/view.es.mjs +9 -9
  248. package/package.json +177 -141
  249. package/src/a11y/announce.ts +131 -0
  250. package/src/a11y/audit.ts +314 -0
  251. package/src/a11y/index.ts +68 -0
  252. package/src/a11y/media-preferences.ts +255 -0
  253. package/src/a11y/roving-tab-index.ts +164 -0
  254. package/src/a11y/skip-link.ts +255 -0
  255. package/src/a11y/trap-focus.ts +184 -0
  256. package/src/a11y/types.ts +183 -0
  257. package/src/component/component.ts +104 -29
  258. package/src/component/html.ts +5 -5
  259. package/src/component/index.ts +2 -0
  260. package/src/component/library.ts +26 -2
  261. package/src/component/scope.ts +212 -0
  262. package/src/component/types.ts +94 -40
  263. package/src/core/collection.ts +707 -628
  264. package/src/core/element.ts +981 -774
  265. package/src/core/env.ts +60 -0
  266. package/src/core/index.ts +49 -48
  267. package/src/core/shared.ts +62 -13
  268. package/src/core/utils/index.ts +148 -83
  269. package/src/devtools/devtools.ts +410 -0
  270. package/src/devtools/index.ts +48 -0
  271. package/src/devtools/types.ts +104 -0
  272. package/src/dnd/draggable.ts +296 -0
  273. package/src/dnd/droppable.ts +228 -0
  274. package/src/dnd/index.ts +62 -0
  275. package/src/dnd/sortable.ts +307 -0
  276. package/src/dnd/types.ts +293 -0
  277. package/src/forms/create-form.ts +278 -0
  278. package/src/forms/index.ts +65 -0
  279. package/src/forms/types.ts +154 -0
  280. package/src/forms/validators.ts +265 -0
  281. package/src/full.ts +253 -2
  282. package/src/i18n/formatting.ts +67 -0
  283. package/src/i18n/i18n.ts +200 -0
  284. package/src/i18n/index.ts +67 -0
  285. package/src/i18n/translate.ts +182 -0
  286. package/src/i18n/types.ts +171 -0
  287. package/src/index.ts +108 -36
  288. package/src/media/battery.ts +116 -0
  289. package/src/media/breakpoints.ts +131 -0
  290. package/src/media/clipboard.ts +80 -0
  291. package/src/media/device-sensors.ts +158 -0
  292. package/src/media/geolocation.ts +119 -0
  293. package/src/media/index.ts +76 -0
  294. package/src/media/media-query.ts +92 -0
  295. package/src/media/network.ts +115 -0
  296. package/src/media/types.ts +177 -0
  297. package/src/media/viewport.ts +84 -0
  298. package/src/motion/index.ts +57 -48
  299. package/src/motion/morph.ts +151 -0
  300. package/src/motion/parallax.ts +120 -0
  301. package/src/motion/reduced-motion.ts +66 -17
  302. package/src/motion/types.ts +271 -208
  303. package/src/motion/typewriter.ts +164 -0
  304. package/src/plugin/index.ts +37 -0
  305. package/src/plugin/registry.ts +269 -0
  306. package/src/plugin/types.ts +137 -0
  307. package/src/reactive/computed.ts +130 -92
  308. package/src/router/bq-link.ts +279 -0
  309. package/src/router/constraints.ts +201 -0
  310. package/src/router/index.ts +49 -41
  311. package/src/router/match.ts +312 -106
  312. package/src/router/path-pattern.ts +52 -0
  313. package/src/router/query.ts +38 -35
  314. package/src/router/router.ts +402 -211
  315. package/src/router/types.ts +139 -93
  316. package/src/router/use-route.ts +68 -0
  317. package/src/router/utils.ts +157 -116
  318. package/src/security/index.ts +2 -7
  319. package/src/security/sanitize.ts +70 -70
  320. package/src/security/trusted-html.ts +71 -71
  321. package/src/ssr/hydrate.ts +82 -0
  322. package/src/ssr/index.ts +70 -0
  323. package/src/ssr/render.ts +508 -0
  324. package/src/ssr/serialize.ts +296 -0
  325. package/src/ssr/types.ts +81 -0
  326. package/src/store/create-store.ts +467 -329
  327. package/src/store/define-store.ts +49 -49
  328. package/src/store/index.ts +27 -22
  329. package/src/store/mapping.ts +74 -74
  330. package/src/store/persisted.ts +206 -19
  331. package/src/store/types.ts +157 -2
  332. package/src/store/utils.ts +135 -141
  333. package/src/store/watch.ts +53 -53
  334. package/src/storybook/index.ts +2 -1
  335. package/src/testing/index.ts +42 -0
  336. package/src/testing/testing.ts +593 -0
  337. package/src/testing/types.ts +170 -0
  338. package/src/view/custom-directives.ts +30 -0
  339. package/src/view/evaluate.ts +292 -290
  340. package/src/view/process.ts +108 -92
  341. package/dist/component-BEQgt5hl.js +0 -600
  342. package/dist/component-BEQgt5hl.js.map +0 -1
  343. package/dist/core-BGQJVw0-.js +0 -35
  344. package/dist/core-BGQJVw0-.js.map +0 -1
  345. package/dist/core-CCEabVHl.js +0 -648
  346. package/dist/core-CCEabVHl.js.map +0 -1
  347. package/dist/effect-AFRW_Plg.js +0 -84
  348. package/dist/effect-AFRW_Plg.js.map +0 -1
  349. package/dist/motion-D9TcHxOF.js +0 -415
  350. package/dist/motion-D9TcHxOF.js.map +0 -1
  351. package/dist/reactive-DSkct0dO.js +0 -254
  352. package/dist/reactive-DSkct0dO.js.map +0 -1
  353. package/dist/router-CbDhl8rS.js +0 -188
  354. package/dist/router-CbDhl8rS.js.map +0 -1
  355. package/dist/store-BwDvI45q.js +0 -263
  356. package/dist/store-BwDvI45q.js.map +0 -1
  357. package/dist/untrack-B0rVscTc.js +0 -7
  358. package/dist/untrack-B0rVscTc.js.map +0 -1
  359. package/dist/view-C70lA3vf.js.map +0 -1
package/README.md CHANGED
@@ -1,586 +1,716 @@
1
- <p align="center">
2
- <img src="assets/bquerry-logo.svg" alt="bQuery.js Logo" width="120" />
3
- </p>
4
-
5
- <h1 align="center">bQuery.js</h1>
6
-
7
- <p align="center">
8
-
9
- [![Repo](https://img.shields.io/badge/github-bquery%2Fbquery-24292f?logo=github)](https://github.com/bQuery/bQuery)
10
- [![Stars](https://img.shields.io/github/stars/bquery/bquery?style=flat&logo=github)](https://github.com/bQuery/bQuery/stargazers)
11
- [![Issues](https://img.shields.io/github/issues/bquery/bquery?style=flat&logo=github)](https://github.com/bQuery/bQuery/issues)
12
- [![License](https://img.shields.io/github/license/bquery/bquery?style=flat)](https://github.com/bQuery/bQuery/blob/main/LICENSE.md)
13
- [![npm](https://img.shields.io/npm/v/@bquery/bquery)](https://www.npmjs.com/package/@bquery/bquery)
14
- [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@bquery/bquery)](https://bundlephobia.com/package/@bquery/bquery)
15
- [![unpkg](https://img.shields.io/badge/unpkg-browse-blue?logo=unpkg)](https://unpkg.com/@bquery/bquery)
16
- [![CodeFactor](https://www.codefactor.io/repository/github/bquery/bquery/badge)](https://www.codefactor.io/repository/github/bquery/bquery)
17
- [![JsDelivr](https://data.jsdelivr.com/v1/package/npm/@bquery/bquery/badge)](https://www.jsdelivr.com/package/npm/@bquery/bquery)
18
-
19
- </p>
20
-
21
- **The jQuery for the modern Web Platform.**
22
-
23
- bQuery.js is a slim, TypeScript-first library that combines jQuery's direct DOM workflow with modern features like reactivity, async data composables, Web Components, motion utilities, routing, stores, and declarative views — without a mandatory build step.
24
-
25
- ## Highlights
26
-
27
- - **Zero-build capable**: runs directly in the browser; build tools are optional.
28
- - **Async data built-in**: fetch and async state composables integrate directly with signals.
29
- - **Security-focused**: DOM writes are sanitized by default; Trusted Types supported.
30
- - **Modular**: the core stays small; extra modules are opt-in.
31
- - **TypeScript-first**: clear types and strong IDE support.
32
- - **Tree-shakeable**: import only what you need.
33
- - **Storybook-ready**: default components can be previewed and developed in Storybook with dedicated story template helpers.
34
-
35
- ## Installation
36
-
37
- ### Via npm/bun/pnpm
38
-
39
- ```bash
40
- # npm
41
- npm install @bquery/bquery
42
-
43
- # bun
44
- bun add @bquery/bquery
45
-
46
- # pnpm
47
- pnpm add @bquery/bquery
48
- ```
49
-
50
- ### Via CDN (Zero-build)
51
-
52
- #### ES Modules (recommended)
53
-
54
- ```html
55
- <script type="module">
56
- import { $, signal } from 'https://unpkg.com/@bquery/bquery@1/dist/full.es.mjs';
57
-
58
- const count = signal(0);
59
- $('#counter').text(`Count: ${count.value}`);
60
- </script>
61
- ```
62
-
63
- #### UMD (global variable)
64
-
65
- ```html
66
- <script src="https://unpkg.com/@bquery/bquery@1/dist/full.umd.js"></script>
67
- <script>
68
- const { $, signal } = bQuery;
69
- const count = signal(0);
70
- </script>
71
- ```
72
-
73
- #### IIFE (self-executing)
74
-
75
- ```html
76
- <script src="https://unpkg.com/@bquery/bquery@1/dist/full.iife.js"></script>
77
- <script>
78
- const { $, $$ } = bQuery;
79
- $$('.items').addClass('loaded');
80
- </script>
81
- ```
82
-
83
- ## Import Strategies
84
-
85
- ```ts
86
- // Full bundle (all modules)
87
- import {
88
- $,
89
- signal,
90
- component,
91
- registerDefaultComponents,
92
- defineBqueryConfig,
93
- } from '@bquery/bquery';
94
-
95
- // Core only
96
- import { $, $$ } from '@bquery/bquery/core';
97
-
98
- // Core utilities (named exports, tree-shakeable)
99
- import { debounce, merge, uid, once, utils } from '@bquery/bquery/core';
100
-
101
- // Reactive only
102
- import {
103
- signal,
104
- computed,
105
- effect,
106
- linkedSignal,
107
- persistedSignal,
108
- useAsyncData,
109
- useFetch,
110
- createUseFetch,
111
- } from '@bquery/bquery/reactive';
112
-
113
- // Components only
114
- import {
115
- bool,
116
- component,
117
- defineComponent,
118
- html,
119
- registerDefaultComponents,
120
- } from '@bquery/bquery/component';
121
-
122
- // Motion only
123
- import { transition, spring, animate, timeline } from '@bquery/bquery/motion';
124
-
125
- // Security only
126
- import { sanitize, sanitizeHtml, trusted } from '@bquery/bquery/security';
127
-
128
- // Platform only
129
- import { storage, cache, useCookie, definePageMeta, useAnnouncer } from '@bquery/bquery/platform';
130
-
131
- // Router, Store, View
132
- import { createRouter, navigate } from '@bquery/bquery/router';
133
- import { createStore, defineStore } from '@bquery/bquery/store';
134
- import { mount, createTemplate } from '@bquery/bquery/view';
135
-
136
- // Storybook helpers
137
- import { storyHtml, when } from '@bquery/bquery/storybook';
138
- ```
139
-
140
- ## Modules at a glance
141
-
142
- | Module | Description | Size (gzip) |
143
- | ------------- | -------------------------------------------------- | ----------- |
144
- | **Core** | Selectors, DOM manipulation, events, utilities | ~11.3 KB |
145
- | **Reactive** | `signal`, `computed`, `effect`, async data/fetch | ~0.3 KB |
146
- | **Component** | Lightweight Web Components with props + defaults | ~1.9 KB |
147
- | **Motion** | View transitions, FLIP, timelines, scroll, springs | ~4.0 KB |
148
- | **Security** | HTML sanitizing, Trusted Types, CSP | ~0.7 KB |
149
- | **Platform** | Storage, cache, cookies, meta, announcers, config | ~2.2 KB |
150
- | **Router** | SPA routing, navigation guards, history API | ~2.2 KB |
151
- | **Store** | Signal-based state management, persistence | ~0.3 KB |
152
- | **View** | Declarative DOM bindings, directives | ~4.3 KB |
153
-
154
- Storybook authoring helpers are also available as a dedicated entry point via `@bquery/bquery/storybook`.
155
-
156
- ## Quick examples
157
-
158
- ### Core DOM & events
159
-
160
- ```ts
161
- import { $, $$ } from '@bquery/bquery/core';
162
-
163
- $('#save').on('click', (event) => {
164
- console.log('Saved', event.type);
165
- });
166
-
167
- $('#list').delegate('click', '.item', (event, target) => {
168
- console.log('Item clicked', target.textContent);
169
- });
170
-
171
- $('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready');
172
-
173
- const color = $('#box').css('color');
174
-
175
- if ($('#el').is('.active')) {
176
- console.log('Element is active');
177
- }
178
-
179
- $$('.container').find('.item').addClass('found');
180
- ```
181
-
182
- ### Reactive – signals
183
-
184
- ```ts
185
- import {
186
- signal,
187
- computed,
188
- effect,
189
- batch,
190
- watch,
191
- readonly,
192
- linkedSignal,
193
- } from '@bquery/bquery/reactive';
194
-
195
- const count = signal(0);
196
- const doubled = computed(() => count.value * 2);
197
-
198
- effect(() => {
199
- console.log('Count changed', count.value);
200
- });
201
-
202
- watch(count, (newVal, oldVal) => {
203
- console.log(`Changed from ${oldVal} to ${newVal}`);
204
- });
205
-
206
- const readOnlyCount = readonly(count);
207
-
208
- batch(() => {
209
- count.value++;
210
- count.value++;
211
- });
212
-
213
- count.dispose();
214
-
215
- const first = signal('Ada');
216
- const last = signal('Lovelace');
217
- const fullName = linkedSignal(
218
- () => `${first.value} ${last.value}`,
219
- (next) => {
220
- const [nextFirst, nextLast] = next.split(' ');
221
- first.value = nextFirst ?? '';
222
- last.value = nextLast ?? '';
223
- }
224
- );
225
-
226
- fullName.value = 'Grace Hopper';
227
- ```
228
-
229
- ### Reactive async data & fetch
230
-
231
- ```ts
232
- import { signal, useFetch, createUseFetch } from '@bquery/bquery/reactive';
233
-
234
- const userId = signal(1);
235
-
236
- const user = useFetch<{ id: number; name: string }>(() => `/users/${userId.value}`, {
237
- baseUrl: 'https://api.example.com',
238
- watch: [userId],
239
- query: { include: 'profile' },
240
- });
241
-
242
- const useApiFetch = createUseFetch({
243
- baseUrl: 'https://api.example.com',
244
- headers: { 'x-client': 'bquery-readme' },
245
- });
246
-
247
- const settings = useApiFetch<{ theme: string }>('/settings');
248
-
249
- console.log(user.pending.value, user.data.value, settings.error.value);
250
- ```
251
-
252
- ### ComponentsWeb Components
253
-
254
- ```ts
255
- import {
256
- bool,
257
- component,
258
- defineComponent,
259
- html,
260
- registerDefaultComponents,
261
- safeHtml,
262
- } from '@bquery/bquery/component';
263
- import { sanitizeHtml, trusted } from '@bquery/bquery/security';
264
-
265
- const badge = trusted(sanitizeHtml('<span class="badge">Active</span>'));
266
-
267
- component('user-card', {
268
- props: {
269
- username: { type: String, required: true },
270
- age: { type: Number, validator: (v) => v >= 0 && v <= 150 },
271
- },
272
- state: { count: 0 },
273
- beforeMount() {
274
- console.log('About to mount');
275
- },
276
- connected() {
277
- console.log('Mounted');
278
- },
279
- beforeUpdate(newProps, oldProps) {
280
- return newProps.username !== oldProps.username;
281
- },
282
- updated(change) {
283
- console.log('Updated because of', change?.name ?? 'state/signal change');
284
- },
285
- onError(error) {
286
- console.error('Component error:', error);
287
- },
288
- render({ props, state }) {
289
- return safeHtml`
290
- <button class="user-card" ${bool('disabled', state.count > 3)}>
291
- ${badge}
292
- <span>Hello ${props.username}</span>
293
- </button>
294
- `;
295
- },
296
- });
297
-
298
- const UserCard = defineComponent('user-card-manual', {
299
- props: { username: { type: String, required: true } },
300
- render: ({ props }) => html`<div>Hello ${props.username}</div>`,
301
- });
302
-
303
- customElements.define('user-card-manual', UserCard);
304
-
305
- const tags = registerDefaultComponents({ prefix: 'ui' });
306
- console.log(tags.button); // ui-button
307
- ```
308
-
309
- ### Storybook – authoring helpers
310
-
311
- ```ts
312
- import { storyHtml, when } from '@bquery/bquery/storybook';
313
-
314
- export const Primary = {
315
- args: { disabled: false, label: 'Save' },
316
- render: ({ disabled, label }) =>
317
- storyHtml`
318
- <ui-card>
319
- <ui-button ?disabled=${disabled}>${label}</ui-button>
320
- ${when(!disabled, '<small>Ready to submit</small>')}
321
- </ui-card>
322
- `,
323
- };
324
- ```
325
-
326
- ### Motion – animations
327
-
328
- ```ts
329
- import { animate, keyframePresets, spring, transition } from '@bquery/bquery/motion';
330
-
331
- await transition({
332
- update: () => {
333
- $('#content').text('Updated');
334
- },
335
- classes: ['page-transition'],
336
- types: ['navigation'],
337
- skipOnReducedMotion: true,
338
- });
339
-
340
- await animate(card, {
341
- keyframes: keyframePresets.pop(),
342
- options: { duration: 240, easing: 'ease-out' },
343
- });
344
-
345
- const x = spring(0, { stiffness: 120, damping: 14 });
346
- x.onChange((value) => {
347
- element.style.transform = `translateX(${value}px)`;
348
- });
349
- await x.to(100);
350
- ```
351
-
352
- ### Security sanitizing
353
-
354
- ```ts
355
- import { sanitize, escapeHtml, sanitizeHtml, trusted } from '@bquery/bquery/security';
356
- import { safeHtml } from '@bquery/bquery/component';
357
-
358
- const safeMarkup = sanitize(userInput);
359
- const safe = sanitize('<form id="cookie">...</form>');
360
- const urlSafe = sanitize('<a href="java\u200Bscript:alert(1)">click</a>');
361
- const secureLink = sanitize('<a href="https://external.com" target="_blank">Link</a>');
362
- const safeSrcset = sanitize('<img srcset="safe.jpg 1x, javascript:alert(1) 2x">');
363
- const safeForm = sanitize('<form action="javascript:alert(1)">...</form>');
364
- const escaped = escapeHtml('<script>alert(1)</script>');
365
- const icon = trusted(sanitizeHtml('<span class="icon">♥</span>'));
366
- const button = safeHtml`<button>${icon}<span>Save</span></button>`;
367
- ```
368
-
369
- ### Platform – config, cookies & accessibility
370
-
371
- ```ts
372
- import {
373
- defineBqueryConfig,
374
- useCookie,
375
- definePageMeta,
376
- useAnnouncer,
377
- storage,
378
- notifications,
379
- } from '@bquery/bquery/platform';
380
-
381
- defineBqueryConfig({
382
- fetch: { baseUrl: 'https://api.example.com' },
383
- transitions: { skipOnReducedMotion: true, classes: ['page-transition'] },
384
- components: { prefix: 'ui' },
385
- });
386
-
387
- const theme = useCookie<'light' | 'dark'>('theme', { defaultValue: 'light' });
388
- const cleanupMeta = definePageMeta({ title: 'Dashboard' });
389
- const announcer = useAnnouncer();
390
-
391
- theme.value = 'dark';
392
- announcer.announce('Preferences saved');
393
- cleanupMeta();
394
-
395
- const local = storage.local();
396
- await local.set('theme', theme.value);
397
-
398
- const permission = await notifications.requestPermission();
399
- if (permission === 'granted') {
400
- notifications.send('Build complete', {
401
- body: 'Your docs are ready.',
402
- });
403
- }
404
- ```
405
-
406
- ### Router SPA navigation
407
-
408
- ```ts
409
- import { effect } from '@bquery/bquery/reactive';
410
- import { createRouter, navigate, currentRoute } from '@bquery/bquery/router';
411
-
412
- const router = createRouter({
413
- routes: [
414
- { path: '/', name: 'home', component: HomePage },
415
- { path: '/user/:id', name: 'user', component: UserPage },
416
- { path: '*', component: NotFound },
417
- ],
418
- });
419
-
420
- router.beforeEach(async (to) => {
421
- if (to.path === '/admin' && !isAuthenticated()) {
422
- await navigate('/login');
423
- return false;
424
- }
425
- });
426
-
427
- effect(() => {
428
- console.log('Current path:', currentRoute.value.path);
429
- });
430
- ```
431
-
432
- ### Store state management
433
-
434
- ```ts
435
- import {
436
- createStore,
437
- createPersistedStore,
438
- defineStore,
439
- mapGetters,
440
- watchStore,
441
- } from '@bquery/bquery/store';
442
-
443
- const counterStore = createStore({
444
- id: 'counter',
445
- state: () => ({ count: 0, name: 'Counter' }),
446
- getters: {
447
- doubled: (state) => state.count * 2,
448
- },
449
- actions: {
450
- increment() {
451
- this.count++;
452
- },
453
- },
454
- });
455
-
456
- const settingsStore = createPersistedStore({
457
- id: 'settings',
458
- state: () => ({ theme: 'dark', language: 'en' }),
459
- });
460
-
461
- const useCounter = defineStore('counter', {
462
- state: () => ({ count: 0 }),
463
- getters: {
464
- doubled: (state) => state.count * 2,
465
- },
466
- actions: {
467
- increment() {
468
- this.count++;
469
- },
470
- },
471
- });
472
-
473
- const counter = useCounter();
474
- const getters = mapGetters(counter, ['doubled']);
475
-
476
- watchStore(
477
- counter,
478
- (state) => state.count,
479
- (value) => {
480
- console.log('Count changed:', value, getters.doubled);
481
- }
482
- );
483
- ```
484
-
485
- ### View – declarative bindings
486
-
487
- ```ts
488
- import { mount, createTemplate } from '@bquery/bquery/view';
489
- import { signal } from '@bquery/bquery/reactive';
490
-
491
- const count = signal(0);
492
- const items = signal(['Apple', 'Banana', 'Cherry']);
493
-
494
- mount('#app', {
495
- count,
496
- items,
497
- increment: () => count.value++,
498
- });
499
- ```
500
-
501
- ## Browser Support
502
-
503
- | Browser | Version | Support |
504
- | ------- | ------- | ------- |
505
- | Chrome | 90+ | Full |
506
- | Firefox | 90+ | ✅ Full |
507
- | Safari | 15+ | Full |
508
- | Edge | 90+ | ✅ Full |
509
-
510
- > **No IE support** by design.
511
-
512
- ## Documentation
513
-
514
- - **Getting Started**: [docs/guide/getting-started.md](docs/guide/getting-started.md)
515
- - **Core API**: [docs/guide/api-core.md](docs/guide/api-core.md)
516
- - **Agents**: [docs/guide/agents.md](docs/guide/agents.md)
517
- - **Components**: [docs/guide/components.md](docs/guide/components.md)
518
- - **Reactivity**: [docs/guide/reactive.md](docs/guide/reactive.md)
519
- - **Motion**: [docs/guide/motion.md](docs/guide/motion.md)
520
- - **Security**: [docs/guide/security.md](docs/guide/security.md)
521
- - **Platform**: [docs/guide/platform.md](docs/guide/platform.md)
522
- - **Router**: [docs/guide/router.md](docs/guide/router.md)
523
- - **Store**: [docs/guide/store.md](docs/guide/store.md)
524
- - **View**: [docs/guide/view.md](docs/guide/view.md)
525
-
526
- ## Local Development
527
-
528
- ```bash
529
- # Install dependencies
530
- bun install
531
-
532
- # Start VitePress docs
533
- bun run dev
534
-
535
- # Run Storybook
536
- bun run storybook
537
-
538
- # Run tests
539
- bun test
540
-
541
- # Build library
542
- bun run build
543
-
544
- # Build docs
545
- bun run build:docs
546
-
547
- # Generate API documentation
548
- bun run docs:api
549
- ```
550
-
551
- ## Project Structure
552
-
553
- ```text
554
- bQuery.js
555
- ├── src/
556
- │ ├── core/ # Selectors, DOM ops, events, utils
557
- │ ├── reactive/ # Signals, computed, effects, async data
558
- │ ├── component/ # Web Components helper + default library
559
- │ ├── motion/ # View transitions, FLIP, springs
560
- │ ├── security/ # Sanitizer, CSP, Trusted Types
561
- │ ├── platform/ # Storage, cache, cookies, meta, config
562
- │ ├── router/ # SPA routing, navigation guards
563
- │ ├── store/ # State management, persistence
564
- │ └── view/ # Declarative DOM bindings
565
- ├── docs/ # VitePress documentation
566
- ├── .storybook/ # Storybook config
567
- ├── stories/ # Component stories
568
- ├── tests/ # bun:test suites
569
- └── dist/ # Built files (ESM, UMD, IIFE)
570
- ```
571
-
572
- ## Contributing
573
-
574
- See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
575
-
576
- ## AI Agent Support
577
-
578
- This project provides dedicated context files for AI coding agents:
579
-
580
- - **[AGENT.md](AGENT.md)** — Architecture, module API reference, coding conventions, common tasks
581
- - **[llms.txt](llms.txt)** — Compact LLM-optimized project summary
582
- - **[.github/copilot-instructions.md](.github/copilot-instructions.md)** — GitHub Copilot context
583
-
584
- ## License
585
-
586
- MIT – See [LICENSE.md](LICENSE.md) for details.
1
+ <p align="center">
2
+ <img src="assets/bquerry-logo.svg" alt="bQuery.js Logo" width="120" />
3
+ </p>
4
+
5
+ <h1 align="center">bQuery.js</h1>
6
+
7
+ <p align="center">
8
+
9
+ [![Repo](https://img.shields.io/badge/github-bquery%2Fbquery-24292f?logo=github)](https://github.com/bQuery/bQuery)
10
+ [![Stars](https://img.shields.io/github/stars/bquery/bquery?style=flat&logo=github)](https://github.com/bQuery/bQuery/stargazers)
11
+ [![Issues](https://img.shields.io/github/issues/bquery/bquery?style=flat&logo=github)](https://github.com/bQuery/bQuery/issues)
12
+ [![License](https://img.shields.io/github/license/bquery/bquery?style=flat)](https://github.com/bQuery/bQuery/blob/main/LICENSE.md)
13
+ [![npm](https://img.shields.io/npm/v/@bquery/bquery)](https://www.npmjs.com/package/@bquery/bquery)
14
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@bquery/bquery)](https://bundlephobia.com/package/@bquery/bquery)
15
+ [![unpkg](https://img.shields.io/badge/unpkg-browse-blue?logo=unpkg)](https://unpkg.com/@bquery/bquery)
16
+ [![CodeFactor](https://www.codefactor.io/repository/github/bquery/bquery/badge)](https://www.codefactor.io/repository/github/bquery/bquery)
17
+ [![JsDelivr](https://data.jsdelivr.com/v1/package/npm/@bquery/bquery/badge)](https://www.jsdelivr.com/package/npm/@bquery/bquery)
18
+
19
+ </p>
20
+
21
+ **The jQuery for the modern Web Platform.**
22
+
23
+ bQuery.js is a slim, TypeScript-first library that combines jQuery's direct DOM workflow with modern features like reactivity, async data composables, Web Components, motion utilities, routing, stores, declarative views, accessibility helpers, forms, i18n, media signals, drag-and-drop, plugins, devtools, testing utilities, and SSR — without a mandatory build step.
24
+
25
+ ## Highlights
26
+
27
+ - **Zero-build capable**: runs directly in the browser; build tools are optional.
28
+ - **Async data built-in**: fetch and async state composables integrate directly with signals.
29
+ - **Security-focused**: DOM writes are sanitized by default; Trusted Types supported.
30
+ - **Modular**: the core stays small; extra modules are opt-in.
31
+ - **TypeScript-first**: clear types and strong IDE support.
32
+ - **Tree-shakeable**: import only what you need.
33
+ - **Storybook-ready**: default components can be previewed and developed in Storybook with dedicated story template helpers.
34
+
35
+ ## Installation
36
+
37
+ ### Via npm/bun/pnpm
38
+
39
+ ```bash
40
+ # npm
41
+ npm install @bquery/bquery
42
+
43
+ # bun
44
+ bun add @bquery/bquery
45
+
46
+ # pnpm
47
+ pnpm add @bquery/bquery
48
+ ```
49
+
50
+ ### Via CDN (Zero-build)
51
+
52
+ #### ES Modules (recommended)
53
+
54
+ ```html
55
+ <script type="module">
56
+ import { $, signal } from 'https://unpkg.com/@bquery/bquery@1/dist/full.es.mjs';
57
+
58
+ const count = signal(0);
59
+ $('#counter').text(`Count: ${count.value}`);
60
+ </script>
61
+ ```
62
+
63
+ #### UMD (global variable)
64
+
65
+ ```html
66
+ <script src="https://unpkg.com/@bquery/bquery@1/dist/full.umd.js"></script>
67
+ <script>
68
+ const { $, signal } = bQuery;
69
+ const count = signal(0);
70
+ </script>
71
+ ```
72
+
73
+ #### IIFE (self-executing)
74
+
75
+ ```html
76
+ <script src="https://unpkg.com/@bquery/bquery@1/dist/full.iife.js"></script>
77
+ <script>
78
+ const { $, $$ } = bQuery;
79
+ $$('.items').addClass('loaded');
80
+ </script>
81
+ ```
82
+
83
+ ## Import Strategies
84
+
85
+ ```ts
86
+ // Full bundle (all modules)
87
+ import {
88
+ $,
89
+ signal,
90
+ component,
91
+ registerDefaultComponents,
92
+ defineBqueryConfig,
93
+ } from '@bquery/bquery';
94
+
95
+ // Core only
96
+ import { $, $$ } from '@bquery/bquery/core';
97
+
98
+ // Core utilities (named exports, tree-shakeable)
99
+ import { debounce, merge, uid, once, utils } from '@bquery/bquery/core';
100
+
101
+ // Reactive only
102
+ import {
103
+ signal,
104
+ computed,
105
+ effect,
106
+ linkedSignal,
107
+ persistedSignal,
108
+ useAsyncData,
109
+ useFetch,
110
+ createUseFetch,
111
+ } from '@bquery/bquery/reactive';
112
+
113
+ // Components only
114
+ import {
115
+ bool,
116
+ component,
117
+ defineComponent,
118
+ html,
119
+ registerDefaultComponents,
120
+ } from '@bquery/bquery/component';
121
+
122
+ // Motion only
123
+ import { transition, spring, animate, timeline } from '@bquery/bquery/motion';
124
+
125
+ // Security only
126
+ import { sanitize, sanitizeHtml, trusted } from '@bquery/bquery/security';
127
+
128
+ // Platform only
129
+ import { storage, cache, useCookie, definePageMeta, useAnnouncer } from '@bquery/bquery/platform';
130
+
131
+ // Router, Store, View
132
+ import { createRouter, navigate } from '@bquery/bquery/router';
133
+ import { createStore, defineStore } from '@bquery/bquery/store';
134
+ import { mount, createTemplate } from '@bquery/bquery/view';
135
+
136
+ // Forms, i18n, accessibility, drag & drop, media
137
+ import { createForm, required, email } from '@bquery/bquery/forms';
138
+ import { createI18n } from '@bquery/bquery/i18n';
139
+ import { trapFocus, rovingTabIndex } from '@bquery/bquery/a11y';
140
+ import { draggable, droppable, sortable } from '@bquery/bquery/dnd';
141
+ import { mediaQuery, useViewport, clipboard } from '@bquery/bquery/media';
142
+
143
+ // Plugins, devtools, testing, SSR
144
+ import { use } from '@bquery/bquery/plugin';
145
+ import { enableDevtools, inspectSignals } from '@bquery/bquery/devtools';
146
+ import { renderComponent, fireEvent, waitFor } from '@bquery/bquery/testing';
147
+ import { renderToString, hydrateMount, serializeStoreState } from '@bquery/bquery/ssr';
148
+
149
+ // Storybook helpers
150
+ import { storyHtml, when } from '@bquery/bquery/storybook';
151
+ ```
152
+
153
+ ## Modules at a glance
154
+
155
+ | Module | Description |
156
+ | ------------- | ------------------------------------------------------------------------------------- |
157
+ | **Core** | Selectors, DOM manipulation, events, traversal, and typed utilities |
158
+ | **Reactive** | `signal`, `computed`, `effect`, batching, async data, and fetch composables |
159
+ | **Component** | Typed Web Components with scoped reactivity and configurable Shadow DOM |
160
+ | **Storybook** | Safe story template helpers with boolean-attribute shorthand |
161
+ | **Motion** | View transitions, FLIP, morphing, parallax, typewriter, springs, and timelines |
162
+ | **Security** | HTML sanitization, Trusted Types, CSP helpers, and trusted fragment composition |
163
+ | **Platform** | Storage, cache, cookies, page metadata, announcers, and shared runtime config |
164
+ | **Router** | SPA routing, constrained params, redirects, guards, `useRoute()`, and `<bq-link>` |
165
+ | **Store** | Signal-based state management, persistence, migrations, and action hooks |
166
+ | **View** | Declarative DOM bindings, directives, and plugin-provided custom directives |
167
+ | **Forms** | Reactive form state with sync/async validation and submit handling |
168
+ | **i18n** | Reactive locales, interpolation, pluralization, lazy loading, and Intl formatting |
169
+ | **A11y** | Focus traps, live-region announcements, roving tabindex, skip links, and audits |
170
+ | **DnD** | Draggable elements, droppable zones, and sortable lists |
171
+ | **Media** | Reactive browser/device signals for viewport, network, battery, geolocation, and more |
172
+ | **Plugin** | Global plugin registration for custom directives and Web Components |
173
+ | **Devtools** | Runtime inspection helpers for signals, stores, components, and timelines |
174
+ | **Testing** | Component mounting, mock signals/router helpers, and async test utilities |
175
+ | **SSR** | Server-side rendering, hydration, and store-state serialization |
176
+
177
+ Storybook authoring helpers are also available as a dedicated entry point via `@bquery/bquery/storybook`.
178
+
179
+ ## Quick examples
180
+
181
+ ### Core – DOM & events
182
+
183
+ ```ts
184
+ import { $, $$ } from '@bquery/bquery/core';
185
+
186
+ $('#save').on('click', (event) => {
187
+ console.log('Saved', event.type);
188
+ });
189
+
190
+ $('#list').delegate('click', '.item', (event, target) => {
191
+ console.log('Item clicked', target.textContent);
192
+ });
193
+
194
+ $('#box').addClass('active').css({ opacity: '0.8' }).attr('data-state', 'ready');
195
+
196
+ const color = $('#box').css('color');
197
+
198
+ if ($('#el').is('.active')) {
199
+ console.log('Element is active');
200
+ }
201
+
202
+ $$('.container').find('.item').addClass('found');
203
+ ```
204
+
205
+ ### Reactive – signals
206
+
207
+ ```ts
208
+ import {
209
+ signal,
210
+ computed,
211
+ effect,
212
+ batch,
213
+ watch,
214
+ readonly,
215
+ linkedSignal,
216
+ } from '@bquery/bquery/reactive';
217
+
218
+ const count = signal(0);
219
+ const doubled = computed(() => count.value * 2);
220
+
221
+ effect(() => {
222
+ console.log('Count changed', count.value);
223
+ });
224
+
225
+ watch(count, (newVal, oldVal) => {
226
+ console.log(`Changed from ${oldVal} to ${newVal}`);
227
+ });
228
+
229
+ const readOnlyCount = readonly(count);
230
+
231
+ batch(() => {
232
+ count.value++;
233
+ count.value++;
234
+ });
235
+
236
+ count.dispose();
237
+
238
+ const first = signal('Ada');
239
+ const last = signal('Lovelace');
240
+ const fullName = linkedSignal(
241
+ () => `${first.value} ${last.value}`,
242
+ (next) => {
243
+ const [nextFirst, nextLast] = next.split(' ');
244
+ first.value = nextFirst ?? '';
245
+ last.value = nextLast ?? '';
246
+ }
247
+ );
248
+
249
+ fullName.value = 'Grace Hopper';
250
+ ```
251
+
252
+ ### Reactiveasync data & fetch
253
+
254
+ ```ts
255
+ import { signal, useFetch, createUseFetch } from '@bquery/bquery/reactive';
256
+
257
+ const userId = signal(1);
258
+
259
+ const user = useFetch<{ id: number; name: string }>(() => `/users/${userId.value}`, {
260
+ baseUrl: 'https://api.example.com',
261
+ watch: [userId],
262
+ query: { include: 'profile' },
263
+ });
264
+
265
+ const useApiFetch = createUseFetch({
266
+ baseUrl: 'https://api.example.com',
267
+ headers: { 'x-client': 'bquery-readme' },
268
+ });
269
+
270
+ const settings = useApiFetch<{ theme: string }>('/settings');
271
+
272
+ console.log(user.pending.value, user.data.value, settings.error.value);
273
+ ```
274
+
275
+ ### Components – Web Components
276
+
277
+ ```ts
278
+ import {
279
+ bool,
280
+ component,
281
+ defineComponent,
282
+ html,
283
+ registerDefaultComponents,
284
+ safeHtml,
285
+ } from '@bquery/bquery/component';
286
+ import { sanitizeHtml, trusted } from '@bquery/bquery/security';
287
+
288
+ const badge = trusted(sanitizeHtml('<span class="badge">Active</span>'));
289
+
290
+ component('user-card', {
291
+ props: {
292
+ username: { type: String, required: true },
293
+ age: { type: Number, validator: (v) => v >= 0 && v <= 150 },
294
+ },
295
+ state: { count: 0 },
296
+ beforeMount() {
297
+ console.log('About to mount');
298
+ },
299
+ connected() {
300
+ console.log('Mounted');
301
+ },
302
+ beforeUpdate(newProps, oldProps) {
303
+ return newProps.username !== oldProps.username;
304
+ },
305
+ updated(change) {
306
+ console.log('Updated because of', change?.name ?? 'state/signal change');
307
+ },
308
+ onError(error) {
309
+ console.error('Component error:', error);
310
+ },
311
+ render({ props, state }) {
312
+ return safeHtml`
313
+ <button class="user-card" ${bool('disabled', state.count > 3)}>
314
+ ${badge}
315
+ <span>Hello ${props.username}</span>
316
+ </button>
317
+ `;
318
+ },
319
+ });
320
+
321
+ const UserCard = defineComponent('user-card-manual', {
322
+ props: { username: { type: String, required: true } },
323
+ render: ({ props }) => html`<div>Hello ${props.username}</div>`,
324
+ });
325
+
326
+ customElements.define('user-card-manual', UserCard);
327
+
328
+ const tags = registerDefaultComponents({ prefix: 'ui' });
329
+ console.log(tags.button); // ui-button
330
+ ```
331
+
332
+ ### Storybook authoring helpers
333
+
334
+ ```ts
335
+ import { storyHtml, when } from '@bquery/bquery/storybook';
336
+
337
+ export const Primary = {
338
+ args: { disabled: false, label: 'Save' },
339
+ render: ({ disabled, label }) =>
340
+ storyHtml`
341
+ <ui-card>
342
+ <ui-button ?disabled=${disabled}>${label}</ui-button>
343
+ ${when(!disabled, '<small>Ready to submit</small>')}
344
+ </ui-card>
345
+ `,
346
+ };
347
+ ```
348
+
349
+ ### Motion – animations
350
+
351
+ ```ts
352
+ import { animate, keyframePresets, spring, transition } from '@bquery/bquery/motion';
353
+
354
+ await transition({
355
+ update: () => {
356
+ $('#content').text('Updated');
357
+ },
358
+ classes: ['page-transition'],
359
+ types: ['navigation'],
360
+ skipOnReducedMotion: true,
361
+ });
362
+
363
+ await animate(card, {
364
+ keyframes: keyframePresets.pop(),
365
+ options: { duration: 240, easing: 'ease-out' },
366
+ });
367
+
368
+ const x = spring(0, { stiffness: 120, damping: 14 });
369
+ x.onChange((value) => {
370
+ element.style.transform = `translateX(${value}px)`;
371
+ });
372
+ await x.to(100);
373
+ ```
374
+
375
+ ### Security – sanitizing
376
+
377
+ ```ts
378
+ import { sanitize, escapeHtml, sanitizeHtml, trusted } from '@bquery/bquery/security';
379
+ import { safeHtml } from '@bquery/bquery/component';
380
+
381
+ const safeMarkup = sanitize(userInput);
382
+ const safe = sanitize('<form id="cookie">...</form>');
383
+ const urlSafe = sanitize('<a href="java\u200Bscript:alert(1)">click</a>');
384
+ const secureLink = sanitize('<a href="https://external.com" target="_blank">Link</a>');
385
+ const safeSrcset = sanitize('<img srcset="safe.jpg 1x, javascript:alert(1) 2x">');
386
+ const safeForm = sanitize('<form action="javascript:alert(1)">...</form>');
387
+ const escaped = escapeHtml('<script>alert(1)</script>');
388
+ const icon = trusted(sanitizeHtml('<span class="icon">♥</span>'));
389
+ const button = safeHtml`<button>${icon}<span>Save</span></button>`;
390
+ ```
391
+
392
+ ### Platform – config, cookies & accessibility
393
+
394
+ ```ts
395
+ import {
396
+ defineBqueryConfig,
397
+ useCookie,
398
+ definePageMeta,
399
+ useAnnouncer,
400
+ storage,
401
+ notifications,
402
+ } from '@bquery/bquery/platform';
403
+
404
+ defineBqueryConfig({
405
+ fetch: { baseUrl: 'https://api.example.com' },
406
+ transitions: { skipOnReducedMotion: true, classes: ['page-transition'] },
407
+ components: { prefix: 'ui' },
408
+ });
409
+
410
+ const theme = useCookie<'light' | 'dark'>('theme', { defaultValue: 'light' });
411
+ const cleanupMeta = definePageMeta({ title: 'Dashboard' });
412
+ const announcer = useAnnouncer();
413
+
414
+ theme.value = 'dark';
415
+ announcer.announce('Preferences saved');
416
+ cleanupMeta();
417
+
418
+ const local = storage.local();
419
+ await local.set('theme', theme.value);
420
+
421
+ const permission = await notifications.requestPermission();
422
+ if (permission === 'granted') {
423
+ notifications.send('Build complete', {
424
+ body: 'Your docs are ready.',
425
+ });
426
+ }
427
+ ```
428
+
429
+ ### Router – SPA navigation
430
+
431
+ ```ts
432
+ import { effect } from '@bquery/bquery/reactive';
433
+ import { createRouter, navigate, currentRoute } from '@bquery/bquery/router';
434
+
435
+ const router = createRouter({
436
+ routes: [
437
+ { path: '/', name: 'home', component: HomePage },
438
+ { path: '/user/:id', name: 'user', component: UserPage },
439
+ { path: '*', component: NotFound },
440
+ ],
441
+ });
442
+
443
+ router.beforeEach(async (to) => {
444
+ if (to.path === '/admin' && !isAuthenticated()) {
445
+ await navigate('/login');
446
+ return false;
447
+ }
448
+ });
449
+
450
+ effect(() => {
451
+ console.log('Current path:', currentRoute.value.path);
452
+ });
453
+ ```
454
+
455
+ ### Forms – reactive validation
456
+
457
+ ```ts
458
+ import { createForm, email, required } from '@bquery/bquery/forms';
459
+
460
+ const form = createForm({
461
+ fields: {
462
+ name: { initialValue: '', validators: [required()] },
463
+ email: { initialValue: '', validators: [required(), email()] },
464
+ },
465
+ onSubmit: async (values) => {
466
+ await fetch('/api/signup', {
467
+ method: 'POST',
468
+ body: JSON.stringify(values),
469
+ });
470
+ },
471
+ });
472
+
473
+ await form.handleSubmit();
474
+ console.log(form.isValid.value, form.fields.email.error.value);
475
+ ```
476
+
477
+ ### i18n – locale-aware content
478
+
479
+ ```ts
480
+ import { createI18n } from '@bquery/bquery/i18n';
481
+
482
+ const i18n = createI18n({
483
+ locale: 'en',
484
+ fallbackLocale: 'en',
485
+ messages: {
486
+ en: { greeting: 'Hello, {name}!' },
487
+ de: { greeting: 'Hallo, {name}!' },
488
+ },
489
+ });
490
+
491
+ console.log(i18n.t('greeting', { name: 'Ada' }));
492
+ i18n.$locale.value = 'de';
493
+ ```
494
+
495
+ ### Accessibility, media, and drag & drop
496
+
497
+ ```ts
498
+ import { trapFocus, announceToScreenReader } from '@bquery/bquery/a11y';
499
+ import { mediaQuery, useViewport } from '@bquery/bquery/media';
500
+ import { draggable } from '@bquery/bquery/dnd';
501
+
502
+ const modalTrap = trapFocus(document.querySelector('#dialog')!);
503
+ announceToScreenReader('Dialog opened');
504
+
505
+ const isDark = mediaQuery('(prefers-color-scheme: dark)');
506
+ const viewport = useViewport();
507
+ const drag = draggable(document.querySelector('#card')!, { bounds: 'parent' });
508
+
509
+ console.log(isDark.value, viewport.value.width);
510
+
511
+ drag.destroy();
512
+ modalTrap.release();
513
+ ```
514
+
515
+ ### Plugins, devtools, testing, and SSR
516
+
517
+ ```ts
518
+ import { use } from '@bquery/bquery/plugin';
519
+ import { enableDevtools, getTimeline } from '@bquery/bquery/devtools';
520
+ import { renderComponent, fireEvent } from '@bquery/bquery/testing';
521
+ import { renderToString } from '@bquery/bquery/ssr';
522
+
523
+ use({
524
+ name: 'focus-plugin',
525
+ install(ctx) {
526
+ ctx.directive('focus', (el) => (el as HTMLElement).focus());
527
+ },
528
+ });
529
+
530
+ enableDevtools(true, { logToConsole: true });
531
+ console.log(getTimeline());
532
+
533
+ const mounted = renderComponent('ui-button', { props: { variant: 'primary' } });
534
+ fireEvent(mounted.el, 'click');
535
+
536
+ const { html } = renderToString('<p bq-text="label"></p>', { label: 'Hello SSR' });
537
+ console.log(html);
538
+
539
+ mounted.unmount();
540
+ ```
541
+
542
+ ### Store – state management
543
+
544
+ ```ts
545
+ import {
546
+ createStore,
547
+ createPersistedStore,
548
+ defineStore,
549
+ mapGetters,
550
+ watchStore,
551
+ } from '@bquery/bquery/store';
552
+
553
+ const counterStore = createStore({
554
+ id: 'counter',
555
+ state: () => ({ count: 0, name: 'Counter' }),
556
+ getters: {
557
+ doubled: (state) => state.count * 2,
558
+ },
559
+ actions: {
560
+ increment() {
561
+ this.count++;
562
+ },
563
+ },
564
+ });
565
+
566
+ const settingsStore = createPersistedStore({
567
+ id: 'settings',
568
+ state: () => ({ theme: 'dark', language: 'en' }),
569
+ });
570
+
571
+ const useCounter = defineStore('counter', {
572
+ state: () => ({ count: 0 }),
573
+ getters: {
574
+ doubled: (state) => state.count * 2,
575
+ },
576
+ actions: {
577
+ increment() {
578
+ this.count++;
579
+ },
580
+ },
581
+ });
582
+
583
+ const counter = useCounter();
584
+ const getters = mapGetters(counter, ['doubled']);
585
+
586
+ watchStore(
587
+ counter,
588
+ (state) => state.count,
589
+ (value) => {
590
+ console.log('Count changed:', value, getters.doubled);
591
+ }
592
+ );
593
+ ```
594
+
595
+ ### View – declarative bindings
596
+
597
+ ```ts
598
+ import { mount, createTemplate } from '@bquery/bquery/view';
599
+ import { signal } from '@bquery/bquery/reactive';
600
+
601
+ const count = signal(0);
602
+ const items = signal(['Apple', 'Banana', 'Cherry']);
603
+
604
+ mount('#app', {
605
+ count,
606
+ items,
607
+ increment: () => count.value++,
608
+ });
609
+ ```
610
+
611
+ ## Browser Support
612
+
613
+ | Browser | Version | Support |
614
+ | ------- | ------- | ------- |
615
+ | Chrome | 90+ | ✅ Full |
616
+ | Firefox | 90+ | ✅ Full |
617
+ | Safari | 15+ | ✅ Full |
618
+ | Edge | 90+ | ✅ Full |
619
+
620
+ > **No IE support** by design.
621
+
622
+ ## Documentation
623
+
624
+ - **Getting Started**: [docs/guide/getting-started.md](docs/guide/getting-started.md)
625
+ - **Core API**: [docs/guide/api-core.md](docs/guide/api-core.md)
626
+ - **Agents**: [docs/guide/agents.md](docs/guide/agents.md)
627
+ - **Components**: [docs/guide/components.md](docs/guide/components.md)
628
+ - **Storybook**: [docs/guide/storybook.md](docs/guide/storybook.md)
629
+ - **Reactivity**: [docs/guide/reactive.md](docs/guide/reactive.md)
630
+ - **Motion**: [docs/guide/motion.md](docs/guide/motion.md)
631
+ - **Security**: [docs/guide/security.md](docs/guide/security.md)
632
+ - **Platform**: [docs/guide/platform.md](docs/guide/platform.md)
633
+ - **Router**: [docs/guide/router.md](docs/guide/router.md)
634
+ - **Store**: [docs/guide/store.md](docs/guide/store.md)
635
+ - **View**: [docs/guide/view.md](docs/guide/view.md)
636
+ - **Forms**: [docs/guide/forms.md](docs/guide/forms.md)
637
+ - **i18n**: [docs/guide/i18n.md](docs/guide/i18n.md)
638
+ - **Accessibility**: [docs/guide/a11y.md](docs/guide/a11y.md)
639
+ - **Drag & Drop**: [docs/guide/dnd.md](docs/guide/dnd.md)
640
+ - **Media**: [docs/guide/media.md](docs/guide/media.md)
641
+ - **Plugin System**: [docs/guide/plugin.md](docs/guide/plugin.md)
642
+ - **Devtools**: [docs/guide/devtools.md](docs/guide/devtools.md)
643
+ - **Testing Utilities**: [docs/guide/testing.md](docs/guide/testing.md)
644
+ - **SSR / Hydration**: [docs/guide/ssr.md](docs/guide/ssr.md)
645
+
646
+ ## Local Development
647
+
648
+ ```bash
649
+ # Install dependencies
650
+ bun install
651
+
652
+ # Start VitePress docs
653
+ bun run dev
654
+
655
+ # Run Storybook
656
+ bun run storybook
657
+
658
+ # Run tests
659
+ bun test
660
+
661
+ # Build library
662
+ bun run build
663
+
664
+ # Build docs
665
+ bun run build:docs
666
+
667
+ # Generate API documentation
668
+ bun run docs:api
669
+ ```
670
+
671
+ ## Project Structure
672
+
673
+ ```text
674
+ bQuery.js
675
+ ├── src/
676
+ │ ├── core/ # Selectors, DOM ops, events, utils
677
+ │ ├── reactive/ # Signals, computed, effects, async data
678
+ │ ├── component/ # Web Components helper + default library
679
+ │ ├── storybook/ # Story template helpers
680
+ │ ├── motion/ # View transitions, FLIP, springs
681
+ │ ├── security/ # Sanitizer, CSP, Trusted Types
682
+ │ ├── platform/ # Storage, cache, cookies, meta, config
683
+ │ ├── router/ # SPA routing, navigation guards
684
+ │ ├── store/ # State management, persistence
685
+ │ ├── view/ # Declarative DOM bindings
686
+ │ ├── forms/ # Reactive forms + validators
687
+ │ ├── i18n/ # Internationalization + formatting
688
+ │ ├── a11y/ # Accessibility utilities
689
+ │ ├── dnd/ # Drag & drop helpers
690
+ │ ├── media/ # Browser and device reactive signals
691
+ │ ├── plugin/ # Global plugin system
692
+ │ ├── devtools/ # Runtime inspection helpers
693
+ │ ├── testing/ # Test utilities
694
+ │ └── ssr/ # Server-side rendering + hydration
695
+ ├── docs/ # VitePress documentation
696
+ ├── .storybook/ # Storybook config
697
+ ├── stories/ # Component stories
698
+ ├── tests/ # bun:test suites
699
+ └── dist/ # Built files (ESM, UMD, IIFE)
700
+ ```
701
+
702
+ ## Contributing
703
+
704
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
705
+
706
+ ## AI Agent Support
707
+
708
+ This project provides dedicated context files for AI coding agents:
709
+
710
+ - **[AGENT.md](AGENT.md)** — Architecture, module API reference, coding conventions, common tasks
711
+ - **[llms.txt](llms.txt)** — Compact LLM-optimized project summary
712
+ - **[.github/copilot-instructions.md](.github/copilot-instructions.md)** — GitHub Copilot context
713
+
714
+ ## License
715
+
716
+ MIT – See [LICENSE.md](LICENSE.md) for details.