@bquery/bquery 1.5.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 (380) hide show
  1. package/README.md +193 -23
  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 +13 -5
  22. package/dist/component/component.d.ts.map +1 -1
  23. package/dist/component/html.d.ts +40 -3
  24. package/dist/component/html.d.ts.map +1 -1
  25. package/dist/component/index.d.ts +3 -2
  26. package/dist/component/index.d.ts.map +1 -1
  27. package/dist/component/library.d.ts.map +1 -1
  28. package/dist/component/scope.d.ts +138 -0
  29. package/dist/component/scope.d.ts.map +1 -0
  30. package/dist/component/types.d.ts +184 -17
  31. package/dist/component/types.d.ts.map +1 -1
  32. package/dist/component-CuuTijA6.js +684 -0
  33. package/dist/component-CuuTijA6.js.map +1 -0
  34. package/dist/component.es.mjs +10 -6
  35. package/dist/{config-DRmZZno3.js → config-BW35FKuA.js} +4 -4
  36. package/dist/config-BW35FKuA.js.map +1 -0
  37. package/dist/constraints-3lV9yyBw.js +100 -0
  38. package/dist/constraints-3lV9yyBw.js.map +1 -0
  39. package/dist/core/collection.d.ts +48 -0
  40. package/dist/core/collection.d.ts.map +1 -1
  41. package/dist/core/element.d.ts +92 -0
  42. package/dist/core/element.d.ts.map +1 -1
  43. package/dist/core/env.d.ts +18 -0
  44. package/dist/core/env.d.ts.map +1 -0
  45. package/dist/core/index.d.ts +1 -0
  46. package/dist/core/index.d.ts.map +1 -1
  47. package/dist/core/shared.d.ts +8 -0
  48. package/dist/core/shared.d.ts.map +1 -1
  49. package/dist/core/utils/index.d.ts +52 -41
  50. package/dist/core/utils/index.d.ts.map +1 -1
  51. package/dist/core-Cjl7GUu8.js +717 -0
  52. package/dist/core-Cjl7GUu8.js.map +1 -0
  53. package/dist/{core-DPdbItcq.js → core-DnlyjbF2.js} +1 -1
  54. package/dist/{core-DPdbItcq.js.map → core-DnlyjbF2.js.map} +1 -1
  55. package/dist/core.es.mjs +45 -44
  56. package/dist/custom-directives-7wAShnnd.js +9 -0
  57. package/dist/custom-directives-7wAShnnd.js.map +1 -0
  58. package/dist/devtools/devtools.d.ts +212 -0
  59. package/dist/devtools/devtools.d.ts.map +1 -0
  60. package/dist/devtools/index.d.ts +20 -0
  61. package/dist/devtools/index.d.ts.map +1 -0
  62. package/dist/devtools/types.d.ts +69 -0
  63. package/dist/devtools/types.d.ts.map +1 -0
  64. package/dist/devtools-D2fQLhDN.js +122 -0
  65. package/dist/devtools-D2fQLhDN.js.map +1 -0
  66. package/dist/devtools.es.mjs +19 -0
  67. package/dist/dnd/draggable.d.ts +51 -0
  68. package/dist/dnd/draggable.d.ts.map +1 -0
  69. package/dist/dnd/droppable.d.ts +38 -0
  70. package/dist/dnd/droppable.d.ts.map +1 -0
  71. package/dist/dnd/index.d.ts +47 -0
  72. package/dist/dnd/index.d.ts.map +1 -0
  73. package/dist/dnd/sortable.d.ts +43 -0
  74. package/dist/dnd/sortable.d.ts.map +1 -0
  75. package/dist/dnd/types.d.ts +250 -0
  76. package/dist/dnd/types.d.ts.map +1 -0
  77. package/dist/dnd-B8EgyzaI.js +244 -0
  78. package/dist/dnd-B8EgyzaI.js.map +1 -0
  79. package/dist/dnd.es.mjs +6 -0
  80. package/dist/env-NeVmr4Gf.js +19 -0
  81. package/dist/env-NeVmr4Gf.js.map +1 -0
  82. package/dist/forms/create-form.d.ts +49 -0
  83. package/dist/forms/create-form.d.ts.map +1 -0
  84. package/dist/forms/index.d.ts +39 -0
  85. package/dist/forms/index.d.ts.map +1 -0
  86. package/dist/forms/types.d.ts +139 -0
  87. package/dist/forms/types.d.ts.map +1 -0
  88. package/dist/forms/validators.d.ts +179 -0
  89. package/dist/forms/validators.d.ts.map +1 -0
  90. package/dist/forms-C3yovgH9.js +141 -0
  91. package/dist/forms-C3yovgH9.js.map +1 -0
  92. package/dist/forms.es.mjs +14 -0
  93. package/dist/full.d.ts +37 -9
  94. package/dist/full.d.ts.map +1 -1
  95. package/dist/full.es.mjs +186 -91
  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/i18n/formatting.d.ts +40 -0
  101. package/dist/i18n/formatting.d.ts.map +1 -0
  102. package/dist/i18n/i18n.d.ts +48 -0
  103. package/dist/i18n/i18n.d.ts.map +1 -0
  104. package/dist/i18n/index.d.ts +57 -0
  105. package/dist/i18n/index.d.ts.map +1 -0
  106. package/dist/i18n/translate.d.ts +83 -0
  107. package/dist/i18n/translate.d.ts.map +1 -0
  108. package/dist/i18n/types.d.ts +156 -0
  109. package/dist/i18n/types.d.ts.map +1 -0
  110. package/dist/i18n-BnnhTFOS.js +89 -0
  111. package/dist/i18n-BnnhTFOS.js.map +1 -0
  112. package/dist/i18n.es.mjs +6 -0
  113. package/dist/index.d.ts +11 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.es.mjs +233 -138
  116. package/dist/media/battery.d.ts +35 -0
  117. package/dist/media/battery.d.ts.map +1 -0
  118. package/dist/media/breakpoints.d.ts +51 -0
  119. package/dist/media/breakpoints.d.ts.map +1 -0
  120. package/dist/media/clipboard.d.ts +30 -0
  121. package/dist/media/clipboard.d.ts.map +1 -0
  122. package/dist/media/device-sensors.d.ts +54 -0
  123. package/dist/media/device-sensors.d.ts.map +1 -0
  124. package/dist/media/geolocation.d.ts +38 -0
  125. package/dist/media/geolocation.d.ts.map +1 -0
  126. package/dist/media/index.d.ts +42 -0
  127. package/dist/media/index.d.ts.map +1 -0
  128. package/dist/media/media-query.d.ts +36 -0
  129. package/dist/media/media-query.d.ts.map +1 -0
  130. package/dist/media/network.d.ts +35 -0
  131. package/dist/media/network.d.ts.map +1 -0
  132. package/dist/media/types.d.ts +173 -0
  133. package/dist/media/types.d.ts.map +1 -0
  134. package/dist/media/viewport.d.ts +32 -0
  135. package/dist/media/viewport.d.ts.map +1 -0
  136. package/dist/media-Di2Ta22s.js +340 -0
  137. package/dist/media-Di2Ta22s.js.map +1 -0
  138. package/dist/media.es.mjs +12 -0
  139. package/dist/motion/index.d.ts +7 -3
  140. package/dist/motion/index.d.ts.map +1 -1
  141. package/dist/motion/morph.d.ts +27 -0
  142. package/dist/motion/morph.d.ts.map +1 -0
  143. package/dist/motion/parallax.d.ts +30 -0
  144. package/dist/motion/parallax.d.ts.map +1 -0
  145. package/dist/motion/reduced-motion.d.ts +36 -3
  146. package/dist/motion/reduced-motion.d.ts.map +1 -1
  147. package/dist/motion/types.d.ts +58 -0
  148. package/dist/motion/types.d.ts.map +1 -1
  149. package/dist/motion/typewriter.d.ts +31 -0
  150. package/dist/motion/typewriter.d.ts.map +1 -0
  151. package/dist/motion-qPj_TYGv.js +530 -0
  152. package/dist/motion-qPj_TYGv.js.map +1 -0
  153. package/dist/motion.es.mjs +27 -23
  154. package/dist/mount-SM07RUa6.js +403 -0
  155. package/dist/mount-SM07RUa6.js.map +1 -0
  156. package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
  157. package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
  158. package/dist/{platform-B7JhGBc7.js → platform-CPbCprb6.js} +3 -3
  159. package/dist/platform-CPbCprb6.js.map +1 -0
  160. package/dist/platform.es.mjs +2 -2
  161. package/dist/plugin/index.d.ts +22 -0
  162. package/dist/plugin/index.d.ts.map +1 -0
  163. package/dist/plugin/registry.d.ts +108 -0
  164. package/dist/plugin/registry.d.ts.map +1 -0
  165. package/dist/plugin/types.d.ts +110 -0
  166. package/dist/plugin/types.d.ts.map +1 -0
  167. package/dist/plugin-cPoOHFLY.js +64 -0
  168. package/dist/plugin-cPoOHFLY.js.map +1 -0
  169. package/dist/plugin.es.mjs +9 -0
  170. package/dist/reactive/computed.d.ts +7 -0
  171. package/dist/reactive/computed.d.ts.map +1 -1
  172. package/dist/reactive-Cfv0RK6x.js +233 -0
  173. package/dist/reactive-Cfv0RK6x.js.map +1 -0
  174. package/dist/reactive.es.mjs +18 -17
  175. package/dist/registry-CWf368tT.js +26 -0
  176. package/dist/registry-CWf368tT.js.map +1 -0
  177. package/dist/router/bq-link.d.ts +112 -0
  178. package/dist/router/bq-link.d.ts.map +1 -0
  179. package/dist/router/constraints.d.ts +9 -0
  180. package/dist/router/constraints.d.ts.map +1 -0
  181. package/dist/router/index.d.ts +14 -6
  182. package/dist/router/index.d.ts.map +1 -1
  183. package/dist/router/match.d.ts +0 -1
  184. package/dist/router/match.d.ts.map +1 -1
  185. package/dist/router/path-pattern.d.ts +14 -0
  186. package/dist/router/path-pattern.d.ts.map +1 -0
  187. package/dist/router/query.d.ts.map +1 -1
  188. package/dist/router/router.d.ts +3 -1
  189. package/dist/router/router.d.ts.map +1 -1
  190. package/dist/router/types.d.ts +48 -4
  191. package/dist/router/types.d.ts.map +1 -1
  192. package/dist/router/use-route.d.ts +50 -0
  193. package/dist/router/use-route.d.ts.map +1 -0
  194. package/dist/router/utils.d.ts +3 -0
  195. package/dist/router/utils.d.ts.map +1 -1
  196. package/dist/router-BrthaP_z.js +473 -0
  197. package/dist/router-BrthaP_z.js.map +1 -0
  198. package/dist/router.es.mjs +13 -10
  199. package/dist/{sanitize-jyJ2ryE2.js → sanitize-B1V4JswB.js} +95 -83
  200. package/dist/sanitize-B1V4JswB.js.map +1 -0
  201. package/dist/security/index.d.ts +2 -0
  202. package/dist/security/index.d.ts.map +1 -1
  203. package/dist/security/sanitize.d.ts +4 -1
  204. package/dist/security/sanitize.d.ts.map +1 -1
  205. package/dist/security/trusted-html.d.ts +53 -0
  206. package/dist/security/trusted-html.d.ts.map +1 -0
  207. package/dist/security.es.mjs +10 -9
  208. package/dist/ssr/hydrate.d.ts +65 -0
  209. package/dist/ssr/hydrate.d.ts.map +1 -0
  210. package/dist/ssr/index.d.ts +59 -0
  211. package/dist/ssr/index.d.ts.map +1 -0
  212. package/dist/ssr/render.d.ts +62 -0
  213. package/dist/ssr/render.d.ts.map +1 -0
  214. package/dist/ssr/serialize.d.ts +118 -0
  215. package/dist/ssr/serialize.d.ts.map +1 -0
  216. package/dist/ssr/types.d.ts +70 -0
  217. package/dist/ssr/types.d.ts.map +1 -0
  218. package/dist/ssr-B2qd_WBB.js +248 -0
  219. package/dist/ssr-B2qd_WBB.js.map +1 -0
  220. package/dist/ssr.es.mjs +9 -0
  221. package/dist/store/create-store.d.ts.map +1 -1
  222. package/dist/store/define-store.d.ts +1 -1
  223. package/dist/store/define-store.d.ts.map +1 -1
  224. package/dist/store/index.d.ts +1 -1
  225. package/dist/store/index.d.ts.map +1 -1
  226. package/dist/store/mapping.d.ts +1 -1
  227. package/dist/store/mapping.d.ts.map +1 -1
  228. package/dist/store/persisted.d.ts +38 -4
  229. package/dist/store/persisted.d.ts.map +1 -1
  230. package/dist/store/types.d.ts +140 -3
  231. package/dist/store/types.d.ts.map +1 -1
  232. package/dist/store/utils.d.ts +2 -2
  233. package/dist/store/utils.d.ts.map +1 -1
  234. package/dist/store/watch.d.ts +1 -1
  235. package/dist/store/watch.d.ts.map +1 -1
  236. package/dist/store-DWpyH6p5.js +338 -0
  237. package/dist/store-DWpyH6p5.js.map +1 -0
  238. package/dist/store.es.mjs +11 -10
  239. package/dist/storybook/index.d.ts +37 -0
  240. package/dist/storybook/index.d.ts.map +1 -0
  241. package/dist/storybook.es.mjs +151 -0
  242. package/dist/storybook.es.mjs.map +1 -0
  243. package/dist/testing/index.d.ts +23 -0
  244. package/dist/testing/index.d.ts.map +1 -0
  245. package/dist/testing/testing.d.ts +156 -0
  246. package/dist/testing/testing.d.ts.map +1 -0
  247. package/dist/testing/types.d.ts +134 -0
  248. package/dist/testing/types.d.ts.map +1 -0
  249. package/dist/testing-CsqjNUyy.js +224 -0
  250. package/dist/testing-CsqjNUyy.js.map +1 -0
  251. package/dist/testing.es.mjs +9 -0
  252. package/dist/type-guards-Do9DWgNp.js +44 -0
  253. package/dist/type-guards-Do9DWgNp.js.map +1 -0
  254. package/dist/untrack-DJVQQ2WM.js +33 -0
  255. package/dist/untrack-DJVQQ2WM.js.map +1 -0
  256. package/dist/view/custom-directives.d.ts +20 -0
  257. package/dist/view/custom-directives.d.ts.map +1 -0
  258. package/dist/view/evaluate.d.ts.map +1 -1
  259. package/dist/view/process.d.ts.map +1 -1
  260. package/dist/view.es.mjs +11 -10
  261. package/package.json +52 -11
  262. package/src/a11y/announce.ts +131 -0
  263. package/src/a11y/audit.ts +314 -0
  264. package/src/a11y/index.ts +68 -0
  265. package/src/a11y/media-preferences.ts +255 -0
  266. package/src/a11y/roving-tab-index.ts +164 -0
  267. package/src/a11y/skip-link.ts +255 -0
  268. package/src/a11y/trap-focus.ts +184 -0
  269. package/src/a11y/types.ts +183 -0
  270. package/src/component/component.ts +345 -65
  271. package/src/component/html.ts +153 -53
  272. package/src/component/index.ts +12 -2
  273. package/src/component/library.ts +66 -28
  274. package/src/component/scope.ts +212 -0
  275. package/src/component/types.ts +238 -19
  276. package/src/core/collection.ts +707 -628
  277. package/src/core/element.ts +981 -774
  278. package/src/core/env.ts +60 -0
  279. package/src/core/index.ts +49 -48
  280. package/src/core/shared.ts +62 -13
  281. package/src/core/utils/index.ts +148 -83
  282. package/src/devtools/devtools.ts +410 -0
  283. package/src/devtools/index.ts +48 -0
  284. package/src/devtools/types.ts +104 -0
  285. package/src/dnd/draggable.ts +296 -0
  286. package/src/dnd/droppable.ts +228 -0
  287. package/src/dnd/index.ts +62 -0
  288. package/src/dnd/sortable.ts +307 -0
  289. package/src/dnd/types.ts +293 -0
  290. package/src/forms/create-form.ts +278 -0
  291. package/src/forms/index.ts +65 -0
  292. package/src/forms/types.ts +154 -0
  293. package/src/forms/validators.ts +265 -0
  294. package/src/full.ts +260 -3
  295. package/src/i18n/formatting.ts +67 -0
  296. package/src/i18n/i18n.ts +200 -0
  297. package/src/i18n/index.ts +67 -0
  298. package/src/i18n/translate.ts +182 -0
  299. package/src/i18n/types.ts +171 -0
  300. package/src/index.ts +108 -36
  301. package/src/media/battery.ts +116 -0
  302. package/src/media/breakpoints.ts +131 -0
  303. package/src/media/clipboard.ts +80 -0
  304. package/src/media/device-sensors.ts +158 -0
  305. package/src/media/geolocation.ts +119 -0
  306. package/src/media/index.ts +76 -0
  307. package/src/media/media-query.ts +92 -0
  308. package/src/media/network.ts +115 -0
  309. package/src/media/types.ts +177 -0
  310. package/src/media/viewport.ts +84 -0
  311. package/src/motion/index.ts +57 -48
  312. package/src/motion/morph.ts +151 -0
  313. package/src/motion/parallax.ts +120 -0
  314. package/src/motion/reduced-motion.ts +66 -17
  315. package/src/motion/transition.ts +97 -97
  316. package/src/motion/types.ts +63 -0
  317. package/src/motion/typewriter.ts +164 -0
  318. package/src/platform/announcer.ts +208 -208
  319. package/src/platform/config.ts +163 -163
  320. package/src/platform/cookies.ts +165 -165
  321. package/src/platform/index.ts +39 -39
  322. package/src/platform/meta.ts +168 -168
  323. package/src/plugin/index.ts +37 -0
  324. package/src/plugin/registry.ts +269 -0
  325. package/src/plugin/types.ts +137 -0
  326. package/src/reactive/async-data.ts +486 -486
  327. package/src/reactive/computed.ts +130 -92
  328. package/src/reactive/index.ts +37 -37
  329. package/src/reactive/signal.ts +29 -29
  330. package/src/router/bq-link.ts +279 -0
  331. package/src/router/constraints.ts +201 -0
  332. package/src/router/index.ts +49 -41
  333. package/src/router/match.ts +312 -106
  334. package/src/router/path-pattern.ts +52 -0
  335. package/src/router/query.ts +38 -35
  336. package/src/router/router.ts +402 -211
  337. package/src/router/types.ts +139 -93
  338. package/src/router/use-route.ts +68 -0
  339. package/src/router/utils.ts +157 -116
  340. package/src/security/constants.ts +211 -211
  341. package/src/security/index.ts +12 -10
  342. package/src/security/sanitize.ts +6 -2
  343. package/src/security/trusted-html.ts +71 -0
  344. package/src/ssr/hydrate.ts +82 -0
  345. package/src/ssr/index.ts +70 -0
  346. package/src/ssr/render.ts +508 -0
  347. package/src/ssr/serialize.ts +296 -0
  348. package/src/ssr/types.ts +81 -0
  349. package/src/store/create-store.ts +467 -329
  350. package/src/store/define-store.ts +2 -1
  351. package/src/store/index.ts +27 -22
  352. package/src/store/mapping.ts +2 -1
  353. package/src/store/persisted.ts +249 -61
  354. package/src/store/types.ts +247 -94
  355. package/src/store/utils.ts +135 -141
  356. package/src/store/watch.ts +2 -1
  357. package/src/storybook/index.ts +480 -0
  358. package/src/testing/index.ts +42 -0
  359. package/src/testing/testing.ts +593 -0
  360. package/src/testing/types.ts +170 -0
  361. package/src/view/custom-directives.ts +30 -0
  362. package/src/view/evaluate.ts +292 -290
  363. package/src/view/process.ts +108 -92
  364. package/dist/component-CY5MVoYN.js +0 -531
  365. package/dist/component-CY5MVoYN.js.map +0 -1
  366. package/dist/config-DRmZZno3.js.map +0 -1
  367. package/dist/core-CK2Mfpf4.js +0 -648
  368. package/dist/core-CK2Mfpf4.js.map +0 -1
  369. package/dist/motion-C5DRdPnO.js +0 -415
  370. package/dist/motion-C5DRdPnO.js.map +0 -1
  371. package/dist/platform-B7JhGBc7.js.map +0 -1
  372. package/dist/reactive-BDya-ia8.js +0 -253
  373. package/dist/reactive-BDya-ia8.js.map +0 -1
  374. package/dist/router-CijiICxt.js +0 -188
  375. package/dist/router-CijiICxt.js.map +0 -1
  376. package/dist/sanitize-jyJ2ryE2.js.map +0 -1
  377. package/dist/store-CPK9E62U.js +0 -262
  378. package/dist/store-CPK9E62U.js.map +0 -1
  379. package/dist/view-Cdi0g-qo.js +0 -396
  380. package/dist/view-Cdi0g-qo.js.map +0 -1
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Built-in validation functions for form fields.
3
+ *
4
+ * Each factory returns a {@link SyncValidator} that can be passed
5
+ * to a field's `validators` array in {@link FormConfig}.
6
+ *
7
+ * @module bquery/forms
8
+ */
9
+
10
+ import type { AsyncValidator, SyncValidator } from './types';
11
+
12
+ /**
13
+ * Requires a non-empty value.
14
+ *
15
+ * Fails for `undefined`, `null`, empty strings (after trim), and empty arrays.
16
+ *
17
+ * @param message - Custom error message (default: `'This field is required'`)
18
+ * @returns A sync validator function
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { required } from '@bquery/bquery/forms';
23
+ * const validate = required('Name is required');
24
+ * validate(''); // 'Name is required'
25
+ * validate('Ada'); // true
26
+ * ```
27
+ */
28
+ export const required = (message = 'This field is required'): SyncValidator => {
29
+ return (value: unknown) => {
30
+ if (value == null) return message;
31
+ if (typeof value === 'string' && value.trim() === '') return message;
32
+ if (Array.isArray(value) && value.length === 0) return message;
33
+ return true;
34
+ };
35
+ };
36
+
37
+ /**
38
+ * Requires a string to have at least `len` characters.
39
+ *
40
+ * Non-string values are coerced via `String()` before checking length.
41
+ *
42
+ * @param len - Minimum length
43
+ * @param message - Custom error message
44
+ * @returns A sync validator function
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import { minLength } from '@bquery/bquery/forms';
49
+ * const validate = minLength(3);
50
+ * validate('ab'); // 'Must be at least 3 characters'
51
+ * validate('abc'); // true
52
+ * ```
53
+ */
54
+ export const minLength = (len: number, message?: string): SyncValidator<unknown> => {
55
+ const msg = message ?? `Must be at least ${len} characters`;
56
+ return (value: unknown) => {
57
+ const str = typeof value === 'string' ? value : String(value ?? '');
58
+ return str.length >= len ? true : msg;
59
+ };
60
+ };
61
+
62
+ /**
63
+ * Requires a string to have at most `len` characters.
64
+ *
65
+ * Non-string values are coerced via `String()` before checking length.
66
+ *
67
+ * @param len - Maximum length
68
+ * @param message - Custom error message
69
+ * @returns A sync validator function
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * import { maxLength } from '@bquery/bquery/forms';
74
+ * const validate = maxLength(10);
75
+ * validate('hello world!!'); // 'Must be at most 10 characters'
76
+ * validate('hello'); // true
77
+ * ```
78
+ */
79
+ export const maxLength = (len: number, message?: string): SyncValidator<unknown> => {
80
+ const msg = message ?? `Must be at most ${len} characters`;
81
+ return (value: unknown) => {
82
+ const str = typeof value === 'string' ? value : String(value ?? '');
83
+ return str.length <= len ? true : msg;
84
+ };
85
+ };
86
+
87
+ /**
88
+ * Requires a string to match a regular expression pattern.
89
+ *
90
+ * Non-string values are coerced via `String()` before testing.
91
+ *
92
+ * @param regex - Pattern to test against
93
+ * @param message - Custom error message (default: `'Invalid format'`)
94
+ * @returns A sync validator function
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * import { pattern } from '@bquery/bquery/forms';
99
+ * const validate = pattern(/^\d+$/, 'Numbers only');
100
+ * validate('abc'); // 'Numbers only'
101
+ * validate('123'); // true
102
+ * ```
103
+ */
104
+ export const pattern = (regex: RegExp, message = 'Invalid format'): SyncValidator<unknown> => {
105
+ const safeRegex =
106
+ regex.global || regex.sticky
107
+ ? new RegExp(regex.source, regex.flags.replace(/[gy]/g, ''))
108
+ : regex;
109
+
110
+ return (value: unknown) => {
111
+ const str = typeof value === 'string' ? value : String(value ?? '');
112
+ safeRegex.lastIndex = 0;
113
+ return safeRegex.test(str) ? true : message;
114
+ };
115
+ };
116
+
117
+ /**
118
+ * RFC 5322–simplified email validation.
119
+ *
120
+ * @param message - Custom error message (default: `'Invalid email address'`)
121
+ * @returns A sync validator function
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * import { email } from '@bquery/bquery/forms';
126
+ * const validate = email();
127
+ * validate('nope'); // 'Invalid email address'
128
+ * validate('ada@lovelace'); // 'Invalid email address'
129
+ * validate('ada@love.co'); // true
130
+ * ```
131
+ */
132
+ export const email = (message = 'Invalid email address'): SyncValidator<unknown> => {
133
+ // Intentionally simple — covers the vast majority of valid addresses
134
+ // without re-implementing the full RFC 5322 grammar.
135
+ const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
136
+ return (value: unknown) => {
137
+ const str = typeof value === 'string' ? value : String(value ?? '');
138
+ if (str === '') return true; // empty is handled by `required`
139
+ return re.test(str) ? true : message;
140
+ };
141
+ };
142
+
143
+ /**
144
+ * Requires a string to be a valid URL.
145
+ *
146
+ * Uses the native `URL` constructor for validation.
147
+ *
148
+ * @param message - Custom error message (default: `'Invalid URL'`)
149
+ * @returns A sync validator function
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * import { url } from '@bquery/bquery/forms';
154
+ * const validate = url();
155
+ * validate('not-a-url'); // 'Invalid URL'
156
+ * validate('https://example.com'); // true
157
+ * ```
158
+ */
159
+ export const url = (message = 'Invalid URL'): SyncValidator<unknown> => {
160
+ return (value: unknown) => {
161
+ const str = typeof value === 'string' ? value : String(value ?? '');
162
+ if (str === '') return true; // empty is handled by `required`
163
+ try {
164
+ new URL(str);
165
+ return true;
166
+ } catch {
167
+ return message;
168
+ }
169
+ };
170
+ };
171
+
172
+ /**
173
+ * Requires a numeric value to be at least `limit`.
174
+ *
175
+ * @param limit - Minimum allowed value (inclusive)
176
+ * @param message - Custom error message
177
+ * @returns A sync validator function
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * import { min } from '@bquery/bquery/forms';
182
+ * const validate = min(1, 'Must be positive');
183
+ * validate(0); // 'Must be positive'
184
+ * validate(1); // true
185
+ * ```
186
+ */
187
+ export const min = (limit: number, message?: string): SyncValidator<unknown> => {
188
+ const msg = message ?? `Must be at least ${limit}`;
189
+ return (value: unknown) => {
190
+ if (value == null) return true;
191
+ if (typeof value === 'string' && value.trim() === '') return true;
192
+ const num = typeof value === 'number' ? value : Number(value);
193
+ return num >= limit ? true : msg;
194
+ };
195
+ };
196
+
197
+ /**
198
+ * Requires a numeric value to be at most `limit`.
199
+ *
200
+ * @param limit - Maximum allowed value (inclusive)
201
+ * @param message - Custom error message
202
+ * @returns A sync validator function
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * import { max } from '@bquery/bquery/forms';
207
+ * const validate = max(100, 'Too high');
208
+ * validate(101); // 'Too high'
209
+ * validate(100); // true
210
+ * ```
211
+ */
212
+ export const max = (limit: number, message?: string): SyncValidator<unknown> => {
213
+ const msg = message ?? `Must be at most ${limit}`;
214
+ return (value: unknown) => {
215
+ if (value == null) return true;
216
+ if (typeof value === 'string' && value.trim() === '') return true;
217
+ const num = typeof value === 'number' ? value : Number(value);
218
+ return num <= limit ? true : msg;
219
+ };
220
+ };
221
+
222
+ /**
223
+ * Creates a custom synchronous validator from any predicate function.
224
+ *
225
+ * @param fn - Predicate that returns `true` when the value is valid
226
+ * @param message - Error message when the predicate returns `false`
227
+ * @returns A sync validator function
228
+ *
229
+ * @example
230
+ * ```ts
231
+ * import { custom } from '@bquery/bquery/forms';
232
+ * const isEven = custom((v: number) => v % 2 === 0, 'Must be even');
233
+ * isEven(3); // 'Must be even'
234
+ * isEven(4); // true
235
+ * ```
236
+ */
237
+ export const custom = <T = unknown>(
238
+ fn: (value: T) => boolean,
239
+ message: string
240
+ ): SyncValidator<T> => {
241
+ return (value: T) => (fn(value) ? true : message);
242
+ };
243
+
244
+ /**
245
+ * Creates a custom asynchronous validator.
246
+ *
247
+ * @param fn - Async predicate that resolves to `true` when valid
248
+ * @param message - Error message when the predicate resolves to `false`
249
+ * @returns An async validator function
250
+ *
251
+ * @example
252
+ * ```ts
253
+ * import { customAsync } from '@bquery/bquery/forms';
254
+ * const isUnique = customAsync(
255
+ * async (name: string) => !(await checkExists(name)),
256
+ * 'Already taken',
257
+ * );
258
+ * ```
259
+ */
260
+ export const customAsync = <T = unknown>(
261
+ fn: (value: T) => Promise<boolean>,
262
+ message: string
263
+ ): AsyncValidator<T> => {
264
+ return async (value: T) => ((await fn(value)) ? true : message);
265
+ };
package/src/full.ts CHANGED
@@ -39,6 +39,7 @@
39
39
  // Core Module: Selectors, DOM operations, events, utilities
40
40
  // ============================================================================
41
41
  export { $, $$, BQueryCollection, BQueryElement, utils } from './core/index';
42
+ export type { BQueryUtils } from './core/index';
42
43
 
43
44
  // ============================================================================
44
45
  // Reactive Module: Signals, computed values, effects, batching
@@ -77,12 +78,28 @@ export type {
77
78
  // ============================================================================
78
79
  // Component Module: Web Components helper with Shadow DOM
79
80
  // ============================================================================
80
- export { component, html, registerDefaultComponents, safeHtml } from './component/index';
81
+ export {
82
+ bool,
83
+ component,
84
+ defineComponent,
85
+ html,
86
+ registerDefaultComponents,
87
+ safeHtml,
88
+ useComputed,
89
+ useEffect,
90
+ useSignal,
91
+ } from './component/index';
81
92
  export type {
93
+ AttributeChange,
82
94
  ComponentDefinition,
95
+ ComponentRenderContext,
96
+ ComponentStateKey,
97
+ ComponentSignalLike,
98
+ ComponentSignals,
83
99
  DefaultComponentLibraryOptions,
84
100
  PropDefinition,
85
101
  RegisteredDefaultComponents,
102
+ ShadowMode,
86
103
  } from './component/index';
87
104
 
88
105
  // ============================================================================
@@ -105,14 +122,18 @@ export {
105
122
  flipList,
106
123
  keyframePresets,
107
124
  linear,
125
+ morphElement,
126
+ parallax,
108
127
  prefersReducedMotion,
109
128
  scrollAnimate,
110
129
  sequence,
130
+ setReducedMotion,
111
131
  spring,
112
132
  springPresets,
113
133
  stagger,
114
134
  timeline,
115
135
  transition,
136
+ typewriter,
116
137
  } from './motion/index';
117
138
  export type {
118
139
  AnimateOptions,
@@ -120,6 +141,9 @@ export type {
120
141
  ElementBounds,
121
142
  FlipGroupOptions,
122
143
  FlipOptions,
144
+ MorphOptions,
145
+ ParallaxCleanup,
146
+ ParallaxOptions,
123
147
  ScrollAnimateCleanup,
124
148
  ScrollAnimateOptions,
125
149
  SequenceOptions,
@@ -132,6 +156,8 @@ export type {
132
156
  TimelineControls,
133
157
  TimelineStep,
134
158
  TransitionOptions,
159
+ TypewriterControls,
160
+ TypewriterOptions,
135
161
  } from './motion/index';
136
162
 
137
163
  // ============================================================================
@@ -147,8 +173,9 @@ export {
147
173
  sanitize,
148
174
  sanitizeHtml,
149
175
  stripTags,
176
+ trusted,
150
177
  } from './security/index';
151
- export type { SanitizeOptions } from './security/index';
178
+ export type { SanitizedHtml, SanitizeOptions, TrustedHtml } from './security/index';
152
179
 
153
180
  // ============================================================================
154
181
  // Platform Module: Storage, buckets, notifications, cache
@@ -183,6 +210,7 @@ export type {
183
210
  // ============================================================================
184
211
  export {
185
212
  back,
213
+ BqLinkElement,
186
214
  createRouter,
187
215
  currentRoute,
188
216
  forward,
@@ -191,7 +219,9 @@ export {
191
219
  isActiveSignal,
192
220
  link,
193
221
  navigate,
222
+ registerBqLink,
194
223
  resolve,
224
+ useRoute,
195
225
  } from './router/index';
196
226
  export type {
197
227
  NavigationGuard,
@@ -199,6 +229,7 @@ export type {
199
229
  RouteDefinition,
200
230
  Router,
201
231
  RouterOptions,
232
+ UseRouteReturn,
202
233
  } from './router/index';
203
234
 
204
235
  // ============================================================================
@@ -214,10 +245,236 @@ export {
214
245
  mapState,
215
246
  registerPlugin,
216
247
  } from './store/index';
217
- export type { StateFactory, Store, StoreDefinition, StorePlugin } from './store/index';
248
+ export type {
249
+ ActionContext,
250
+ OnActionCallback,
251
+ PersistedStoreOptions,
252
+ StateFactory,
253
+ StorageBackend,
254
+ Store,
255
+ StoreDefinition,
256
+ StorePlugin,
257
+ StoreSerializer,
258
+ } from './store/index';
218
259
 
219
260
  // ============================================================================
220
261
  // View Module: Declarative DOM bindings without compiler
221
262
  // ============================================================================
222
263
  export { createTemplate, mount } from './view/index';
223
264
  export type { BindingContext, MountOptions, View } from './view/index';
265
+
266
+ // ============================================================================
267
+ // Forms Module: Reactive form handling and validation
268
+ // ============================================================================
269
+ export {
270
+ createForm,
271
+ custom,
272
+ customAsync,
273
+ email,
274
+ max,
275
+ maxLength,
276
+ min,
277
+ minLength,
278
+ pattern,
279
+ required,
280
+ url,
281
+ } from './forms/index';
282
+ export type {
283
+ AsyncValidator,
284
+ CrossFieldValidator,
285
+ FieldConfig,
286
+ Form,
287
+ FormConfig,
288
+ FormErrors,
289
+ FormField,
290
+ FormFields,
291
+ SubmitHandler,
292
+ SyncValidator,
293
+ ValidationResult,
294
+ Validator,
295
+ } from './forms/index';
296
+
297
+ // ============================================================================
298
+ // i18n Module: Internationalization, translations, formatting
299
+ // ============================================================================
300
+ export { createI18n, formatDate, formatNumber } from './i18n/index';
301
+ export type {
302
+ DateFormatOptions,
303
+ I18nConfig,
304
+ I18nInstance,
305
+ LocaleLoader,
306
+ LocaleMessages,
307
+ Messages,
308
+ NumberFormatOptions,
309
+ TranslateParams,
310
+ } from './i18n/index';
311
+
312
+ // ============================================================================
313
+ // a11y Module: Accessibility utilities
314
+ // ============================================================================
315
+ // Note: prefersReducedMotion is not re-exported here to avoid naming conflict
316
+ // with the motion module's prefersReducedMotion(). Use @bquery/bquery/a11y for
317
+ // the reactive signal version.
318
+ export {
319
+ announceToScreenReader,
320
+ auditA11y,
321
+ clearAnnouncements,
322
+ getFocusableElements,
323
+ prefersColorScheme,
324
+ prefersContrast,
325
+ releaseFocus,
326
+ rovingTabIndex,
327
+ skipLink,
328
+ trapFocus,
329
+ } from './a11y/index';
330
+ export type {
331
+ AnnouncePriority,
332
+ AuditFinding,
333
+ AuditResult,
334
+ AuditSeverity,
335
+ ColorScheme,
336
+ ContrastPreference,
337
+ FocusTrapHandle,
338
+ RovingTabIndexHandle,
339
+ RovingTabIndexOptions,
340
+ SkipLinkHandle,
341
+ SkipLinkOptions,
342
+ TrapFocusOptions,
343
+ } from './a11y/index';
344
+
345
+ // ============================================================================
346
+ // DnD Module: Drag-and-drop, drop zones, sortable lists
347
+ // ============================================================================
348
+ export { draggable } from './dnd/index';
349
+ export { droppable } from './dnd/index';
350
+ export { sortable } from './dnd/index';
351
+ export type {
352
+ BoundsRect,
353
+ DragAxis,
354
+ DragBounds,
355
+ DragEventData,
356
+ DragPosition,
357
+ DraggableHandle,
358
+ DraggableOptions,
359
+ DropEventData,
360
+ DroppableHandle,
361
+ DroppableOptions,
362
+ SortEventData,
363
+ SortableHandle,
364
+ SortableOptions,
365
+ } from './dnd/index';
366
+
367
+ // ============================================================================
368
+ // Media Module: Reactive browser and device API signals
369
+ // ============================================================================
370
+ export { mediaQuery } from './media/index';
371
+ export { breakpoints } from './media/index';
372
+ export { useViewport } from './media/index';
373
+ export { useNetworkStatus } from './media/index';
374
+ export { useBattery } from './media/index';
375
+ export { useGeolocation } from './media/index';
376
+ export { useDeviceMotion, useDeviceOrientation } from './media/index';
377
+ export { clipboard } from './media/index';
378
+ export type {
379
+ BatteryState,
380
+ BreakpointMap,
381
+ ClipboardAPI,
382
+ DeviceMotionState,
383
+ DeviceOrientationState,
384
+ GeolocationOptions,
385
+ GeolocationState,
386
+ NetworkState,
387
+ ViewportState,
388
+ } from './media/index';
389
+
390
+ // ---------------------------------------------------------------------------
391
+ // Plugin module
392
+ // ---------------------------------------------------------------------------
393
+ export {
394
+ use,
395
+ isInstalled,
396
+ getInstalledPlugins,
397
+ getCustomDirective,
398
+ getCustomDirectives,
399
+ resetPlugins,
400
+ } from './plugin/index';
401
+ export type {
402
+ BQueryPlugin,
403
+ CustomDirective,
404
+ CustomDirectiveHandler,
405
+ PluginInstallContext,
406
+ } from './plugin/index';
407
+
408
+ // ---------------------------------------------------------------------------
409
+ // DevTools module
410
+ // ---------------------------------------------------------------------------
411
+ export {
412
+ enableDevtools,
413
+ isDevtoolsEnabled,
414
+ trackSignal,
415
+ untrackSignal,
416
+ generateSignalLabel,
417
+ inspectSignals,
418
+ inspectStores,
419
+ inspectComponents,
420
+ recordEvent,
421
+ getTimeline,
422
+ clearTimeline,
423
+ getDevtoolsState,
424
+ logSignals,
425
+ logStores,
426
+ logComponents,
427
+ logTimeline,
428
+ } from './devtools/index';
429
+ export type {
430
+ ComponentSnapshot,
431
+ DevtoolsOptions,
432
+ DevtoolsState,
433
+ SignalSnapshot,
434
+ StoreSnapshot,
435
+ TimelineEntry,
436
+ TimelineEventType,
437
+ } from './devtools/index';
438
+
439
+ // ---------------------------------------------------------------------------
440
+ // Testing module
441
+ // ---------------------------------------------------------------------------
442
+ export {
443
+ renderComponent,
444
+ flushEffects,
445
+ mockSignal,
446
+ mockRouter,
447
+ fireEvent,
448
+ waitFor,
449
+ } from './testing/index';
450
+ export type {
451
+ FireEventOptions,
452
+ MockRouter,
453
+ MockRouterOptions,
454
+ MockSignal,
455
+ RenderComponentOptions,
456
+ RenderResult,
457
+ TestRoute,
458
+ WaitForOptions,
459
+ } from './testing/index';
460
+
461
+ // ---------------------------------------------------------------------------
462
+ // SSR module
463
+ // ---------------------------------------------------------------------------
464
+ export {
465
+ renderToString,
466
+ hydrateMount,
467
+ serializeStoreState,
468
+ deserializeStoreState,
469
+ hydrateStore,
470
+ hydrateStores,
471
+ } from './ssr/index';
472
+ export type {
473
+ DeserializedStoreState,
474
+ HydrateMountOptions,
475
+ HydrationOptions,
476
+ RenderOptions,
477
+ SSRResult,
478
+ SerializeOptions,
479
+ SerializeResult,
480
+ } from './ssr/index';
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Number and date formatting helpers using Intl APIs.
3
+ * @module bquery/i18n
4
+ */
5
+
6
+ import type { DateFormatOptions, NumberFormatOptions } from './types';
7
+
8
+ /**
9
+ * Formats a number using the Intl.NumberFormat API.
10
+ *
11
+ * @param value - The number to format
12
+ * @param locale - The locale code (e.g. 'en-US', 'de-DE')
13
+ * @param options - Intl.NumberFormat options
14
+ * @returns The formatted number string
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * formatNumber(1234.56, 'en-US'); // '1,234.56'
19
+ * formatNumber(1234.56, 'de-DE'); // '1.234,56'
20
+ * formatNumber(0.42, 'en-US', { style: 'percent' }); // '42%'
21
+ * formatNumber(9.99, 'en-US', { style: 'currency', currency: 'USD' }); // '$9.99'
22
+ * ```
23
+ */
24
+ export const formatNumber = (
25
+ value: number,
26
+ locale: string,
27
+ options?: NumberFormatOptions
28
+ ): string => {
29
+ const { locale: _ignored, ...intlOptions } = options ?? {};
30
+ try {
31
+ return new Intl.NumberFormat(locale, intlOptions).format(value);
32
+ } catch {
33
+ // Fall back to basic toString on Intl errors
34
+ return String(value);
35
+ }
36
+ };
37
+
38
+ /**
39
+ * Formats a date using the Intl.DateTimeFormat API.
40
+ *
41
+ * @param value - The date to format (Date object or timestamp)
42
+ * @param locale - The locale code
43
+ * @param options - Intl.DateTimeFormat options
44
+ * @returns The formatted date string
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const date = new Date('2026-03-26');
49
+ * formatDate(date, 'en-US'); // '3/26/2026'
50
+ * formatDate(date, 'de-DE'); // '26.3.2026'
51
+ * formatDate(date, 'en-US', { dateStyle: 'long' }); // 'March 26, 2026'
52
+ * ```
53
+ */
54
+ export const formatDate = (
55
+ value: Date | number,
56
+ locale: string,
57
+ options?: DateFormatOptions
58
+ ): string => {
59
+ const { locale: _ignored, ...intlOptions } = options ?? {};
60
+ const date = typeof value === 'number' ? new Date(value) : value;
61
+ try {
62
+ return new Intl.DateTimeFormat(locale, intlOptions).format(date);
63
+ } catch {
64
+ // Fall back to toLocaleString on Intl errors
65
+ return date.toLocaleString();
66
+ }
67
+ };