@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.
- package/README.md +193 -23
- package/dist/a11y/announce.d.ts +43 -0
- package/dist/a11y/announce.d.ts.map +1 -0
- package/dist/a11y/audit.d.ts +42 -0
- package/dist/a11y/audit.d.ts.map +1 -0
- package/dist/a11y/index.d.ts +53 -0
- package/dist/a11y/index.d.ts.map +1 -0
- package/dist/a11y/media-preferences.d.ts +77 -0
- package/dist/a11y/media-preferences.d.ts.map +1 -0
- package/dist/a11y/roving-tab-index.d.ts +38 -0
- package/dist/a11y/roving-tab-index.d.ts.map +1 -0
- package/dist/a11y/skip-link.d.ts +37 -0
- package/dist/a11y/skip-link.d.ts.map +1 -0
- package/dist/a11y/trap-focus.d.ts +49 -0
- package/dist/a11y/trap-focus.d.ts.map +1 -0
- package/dist/a11y/types.d.ts +152 -0
- package/dist/a11y/types.d.ts.map +1 -0
- package/dist/a11y-C5QOVvRn.js +421 -0
- package/dist/a11y-C5QOVvRn.js.map +1 -0
- package/dist/a11y.es.mjs +14 -0
- package/dist/component/component.d.ts +13 -5
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/html.d.ts +40 -3
- package/dist/component/html.d.ts.map +1 -1
- package/dist/component/index.d.ts +3 -2
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/library.d.ts.map +1 -1
- package/dist/component/scope.d.ts +138 -0
- package/dist/component/scope.d.ts.map +1 -0
- package/dist/component/types.d.ts +184 -17
- package/dist/component/types.d.ts.map +1 -1
- package/dist/component-CuuTijA6.js +684 -0
- package/dist/component-CuuTijA6.js.map +1 -0
- package/dist/component.es.mjs +10 -6
- package/dist/{config-DRmZZno3.js → config-BW35FKuA.js} +4 -4
- package/dist/config-BW35FKuA.js.map +1 -0
- package/dist/constraints-3lV9yyBw.js +100 -0
- package/dist/constraints-3lV9yyBw.js.map +1 -0
- package/dist/core/collection.d.ts +48 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +92 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/env.d.ts +18 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/shared.d.ts +8 -0
- package/dist/core/shared.d.ts.map +1 -1
- package/dist/core/utils/index.d.ts +52 -41
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core-Cjl7GUu8.js +717 -0
- package/dist/core-Cjl7GUu8.js.map +1 -0
- package/dist/{core-DPdbItcq.js → core-DnlyjbF2.js} +1 -1
- package/dist/{core-DPdbItcq.js.map → core-DnlyjbF2.js.map} +1 -1
- package/dist/core.es.mjs +45 -44
- package/dist/custom-directives-7wAShnnd.js +9 -0
- package/dist/custom-directives-7wAShnnd.js.map +1 -0
- package/dist/devtools/devtools.d.ts +212 -0
- package/dist/devtools/devtools.d.ts.map +1 -0
- package/dist/devtools/index.d.ts +20 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/types.d.ts +69 -0
- package/dist/devtools/types.d.ts.map +1 -0
- package/dist/devtools-D2fQLhDN.js +122 -0
- package/dist/devtools-D2fQLhDN.js.map +1 -0
- package/dist/devtools.es.mjs +19 -0
- package/dist/dnd/draggable.d.ts +51 -0
- package/dist/dnd/draggable.d.ts.map +1 -0
- package/dist/dnd/droppable.d.ts +38 -0
- package/dist/dnd/droppable.d.ts.map +1 -0
- package/dist/dnd/index.d.ts +47 -0
- package/dist/dnd/index.d.ts.map +1 -0
- package/dist/dnd/sortable.d.ts +43 -0
- package/dist/dnd/sortable.d.ts.map +1 -0
- package/dist/dnd/types.d.ts +250 -0
- package/dist/dnd/types.d.ts.map +1 -0
- package/dist/dnd-B8EgyzaI.js +244 -0
- package/dist/dnd-B8EgyzaI.js.map +1 -0
- package/dist/dnd.es.mjs +6 -0
- package/dist/env-NeVmr4Gf.js +19 -0
- package/dist/env-NeVmr4Gf.js.map +1 -0
- package/dist/forms/create-form.d.ts +49 -0
- package/dist/forms/create-form.d.ts.map +1 -0
- package/dist/forms/index.d.ts +39 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/types.d.ts +139 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/validators.d.ts +179 -0
- package/dist/forms/validators.d.ts.map +1 -0
- package/dist/forms-C3yovgH9.js +141 -0
- package/dist/forms-C3yovgH9.js.map +1 -0
- package/dist/forms.es.mjs +14 -0
- package/dist/full.d.ts +37 -9
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +186 -91
- package/dist/full.iife.js +47 -31
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +47 -31
- package/dist/full.umd.js.map +1 -1
- package/dist/i18n/formatting.d.ts +40 -0
- package/dist/i18n/formatting.d.ts.map +1 -0
- package/dist/i18n/i18n.d.ts +48 -0
- package/dist/i18n/i18n.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +57 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/translate.d.ts +83 -0
- package/dist/i18n/translate.d.ts.map +1 -0
- package/dist/i18n/types.d.ts +156 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n-BnnhTFOS.js +89 -0
- package/dist/i18n-BnnhTFOS.js.map +1 -0
- package/dist/i18n.es.mjs +6 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.mjs +233 -138
- package/dist/media/battery.d.ts +35 -0
- package/dist/media/battery.d.ts.map +1 -0
- package/dist/media/breakpoints.d.ts +51 -0
- package/dist/media/breakpoints.d.ts.map +1 -0
- package/dist/media/clipboard.d.ts +30 -0
- package/dist/media/clipboard.d.ts.map +1 -0
- package/dist/media/device-sensors.d.ts +54 -0
- package/dist/media/device-sensors.d.ts.map +1 -0
- package/dist/media/geolocation.d.ts +38 -0
- package/dist/media/geolocation.d.ts.map +1 -0
- package/dist/media/index.d.ts +42 -0
- package/dist/media/index.d.ts.map +1 -0
- package/dist/media/media-query.d.ts +36 -0
- package/dist/media/media-query.d.ts.map +1 -0
- package/dist/media/network.d.ts +35 -0
- package/dist/media/network.d.ts.map +1 -0
- package/dist/media/types.d.ts +173 -0
- package/dist/media/types.d.ts.map +1 -0
- package/dist/media/viewport.d.ts +32 -0
- package/dist/media/viewport.d.ts.map +1 -0
- package/dist/media-Di2Ta22s.js +340 -0
- package/dist/media-Di2Ta22s.js.map +1 -0
- package/dist/media.es.mjs +12 -0
- package/dist/motion/index.d.ts +7 -3
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/morph.d.ts +27 -0
- package/dist/motion/morph.d.ts.map +1 -0
- package/dist/motion/parallax.d.ts +30 -0
- package/dist/motion/parallax.d.ts.map +1 -0
- package/dist/motion/reduced-motion.d.ts +36 -3
- package/dist/motion/reduced-motion.d.ts.map +1 -1
- package/dist/motion/types.d.ts +58 -0
- package/dist/motion/types.d.ts.map +1 -1
- package/dist/motion/typewriter.d.ts +31 -0
- package/dist/motion/typewriter.d.ts.map +1 -0
- package/dist/motion-qPj_TYGv.js +530 -0
- package/dist/motion-qPj_TYGv.js.map +1 -0
- package/dist/motion.es.mjs +27 -23
- package/dist/mount-SM07RUa6.js +403 -0
- package/dist/mount-SM07RUa6.js.map +1 -0
- package/dist/{object-qGpWr6-J.js → object-BCk-1c8T.js} +5 -4
- package/dist/{object-qGpWr6-J.js.map → object-BCk-1c8T.js.map} +1 -1
- package/dist/{platform-B7JhGBc7.js → platform-CPbCprb6.js} +3 -3
- package/dist/platform-CPbCprb6.js.map +1 -0
- package/dist/platform.es.mjs +2 -2
- package/dist/plugin/index.d.ts +22 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/registry.d.ts +108 -0
- package/dist/plugin/registry.d.ts.map +1 -0
- package/dist/plugin/types.d.ts +110 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin-cPoOHFLY.js +64 -0
- package/dist/plugin-cPoOHFLY.js.map +1 -0
- package/dist/plugin.es.mjs +9 -0
- package/dist/reactive/computed.d.ts +7 -0
- package/dist/reactive/computed.d.ts.map +1 -1
- package/dist/reactive-Cfv0RK6x.js +233 -0
- package/dist/reactive-Cfv0RK6x.js.map +1 -0
- package/dist/reactive.es.mjs +18 -17
- package/dist/registry-CWf368tT.js +26 -0
- package/dist/registry-CWf368tT.js.map +1 -0
- package/dist/router/bq-link.d.ts +112 -0
- package/dist/router/bq-link.d.ts.map +1 -0
- package/dist/router/constraints.d.ts +9 -0
- package/dist/router/constraints.d.ts.map +1 -0
- package/dist/router/index.d.ts +14 -6
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/match.d.ts +0 -1
- package/dist/router/match.d.ts.map +1 -1
- package/dist/router/path-pattern.d.ts +14 -0
- package/dist/router/path-pattern.d.ts.map +1 -0
- package/dist/router/query.d.ts.map +1 -1
- package/dist/router/router.d.ts +3 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/types.d.ts +48 -4
- package/dist/router/types.d.ts.map +1 -1
- package/dist/router/use-route.d.ts +50 -0
- package/dist/router/use-route.d.ts.map +1 -0
- package/dist/router/utils.d.ts +3 -0
- package/dist/router/utils.d.ts.map +1 -1
- package/dist/router-BrthaP_z.js +473 -0
- package/dist/router-BrthaP_z.js.map +1 -0
- package/dist/router.es.mjs +13 -10
- package/dist/{sanitize-jyJ2ryE2.js → sanitize-B1V4JswB.js} +95 -83
- package/dist/sanitize-B1V4JswB.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/sanitize.d.ts +4 -1
- package/dist/security/sanitize.d.ts.map +1 -1
- package/dist/security/trusted-html.d.ts +53 -0
- package/dist/security/trusted-html.d.ts.map +1 -0
- package/dist/security.es.mjs +10 -9
- package/dist/ssr/hydrate.d.ts +65 -0
- package/dist/ssr/hydrate.d.ts.map +1 -0
- package/dist/ssr/index.d.ts +59 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/render.d.ts +62 -0
- package/dist/ssr/render.d.ts.map +1 -0
- package/dist/ssr/serialize.d.ts +118 -0
- package/dist/ssr/serialize.d.ts.map +1 -0
- package/dist/ssr/types.d.ts +70 -0
- package/dist/ssr/types.d.ts.map +1 -0
- package/dist/ssr-B2qd_WBB.js +248 -0
- package/dist/ssr-B2qd_WBB.js.map +1 -0
- package/dist/ssr.es.mjs +9 -0
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/define-store.d.ts +1 -1
- package/dist/store/define-store.d.ts.map +1 -1
- package/dist/store/index.d.ts +1 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/mapping.d.ts +1 -1
- package/dist/store/mapping.d.ts.map +1 -1
- package/dist/store/persisted.d.ts +38 -4
- package/dist/store/persisted.d.ts.map +1 -1
- package/dist/store/types.d.ts +140 -3
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/utils.d.ts +2 -2
- package/dist/store/utils.d.ts.map +1 -1
- package/dist/store/watch.d.ts +1 -1
- package/dist/store/watch.d.ts.map +1 -1
- package/dist/store-DWpyH6p5.js +338 -0
- package/dist/store-DWpyH6p5.js.map +1 -0
- package/dist/store.es.mjs +11 -10
- package/dist/storybook/index.d.ts +37 -0
- package/dist/storybook/index.d.ts.map +1 -0
- package/dist/storybook.es.mjs +151 -0
- package/dist/storybook.es.mjs.map +1 -0
- package/dist/testing/index.d.ts +23 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/testing.d.ts +156 -0
- package/dist/testing/testing.d.ts.map +1 -0
- package/dist/testing/types.d.ts +134 -0
- package/dist/testing/types.d.ts.map +1 -0
- package/dist/testing-CsqjNUyy.js +224 -0
- package/dist/testing-CsqjNUyy.js.map +1 -0
- package/dist/testing.es.mjs +9 -0
- package/dist/type-guards-Do9DWgNp.js +44 -0
- package/dist/type-guards-Do9DWgNp.js.map +1 -0
- package/dist/untrack-DJVQQ2WM.js +33 -0
- package/dist/untrack-DJVQQ2WM.js.map +1 -0
- package/dist/view/custom-directives.d.ts +20 -0
- package/dist/view/custom-directives.d.ts.map +1 -0
- package/dist/view/evaluate.d.ts.map +1 -1
- package/dist/view/process.d.ts.map +1 -1
- package/dist/view.es.mjs +11 -10
- package/package.json +52 -11
- package/src/a11y/announce.ts +131 -0
- package/src/a11y/audit.ts +314 -0
- package/src/a11y/index.ts +68 -0
- package/src/a11y/media-preferences.ts +255 -0
- package/src/a11y/roving-tab-index.ts +164 -0
- package/src/a11y/skip-link.ts +255 -0
- package/src/a11y/trap-focus.ts +184 -0
- package/src/a11y/types.ts +183 -0
- package/src/component/component.ts +345 -65
- package/src/component/html.ts +153 -53
- package/src/component/index.ts +12 -2
- package/src/component/library.ts +66 -28
- package/src/component/scope.ts +212 -0
- package/src/component/types.ts +238 -19
- package/src/core/collection.ts +707 -628
- package/src/core/element.ts +981 -774
- package/src/core/env.ts +60 -0
- package/src/core/index.ts +49 -48
- package/src/core/shared.ts +62 -13
- package/src/core/utils/index.ts +148 -83
- package/src/devtools/devtools.ts +410 -0
- package/src/devtools/index.ts +48 -0
- package/src/devtools/types.ts +104 -0
- package/src/dnd/draggable.ts +296 -0
- package/src/dnd/droppable.ts +228 -0
- package/src/dnd/index.ts +62 -0
- package/src/dnd/sortable.ts +307 -0
- package/src/dnd/types.ts +293 -0
- package/src/forms/create-form.ts +278 -0
- package/src/forms/index.ts +65 -0
- package/src/forms/types.ts +154 -0
- package/src/forms/validators.ts +265 -0
- package/src/full.ts +260 -3
- package/src/i18n/formatting.ts +67 -0
- package/src/i18n/i18n.ts +200 -0
- package/src/i18n/index.ts +67 -0
- package/src/i18n/translate.ts +182 -0
- package/src/i18n/types.ts +171 -0
- package/src/index.ts +108 -36
- package/src/media/battery.ts +116 -0
- package/src/media/breakpoints.ts +131 -0
- package/src/media/clipboard.ts +80 -0
- package/src/media/device-sensors.ts +158 -0
- package/src/media/geolocation.ts +119 -0
- package/src/media/index.ts +76 -0
- package/src/media/media-query.ts +92 -0
- package/src/media/network.ts +115 -0
- package/src/media/types.ts +177 -0
- package/src/media/viewport.ts +84 -0
- package/src/motion/index.ts +57 -48
- package/src/motion/morph.ts +151 -0
- package/src/motion/parallax.ts +120 -0
- package/src/motion/reduced-motion.ts +66 -17
- package/src/motion/transition.ts +97 -97
- package/src/motion/types.ts +63 -0
- package/src/motion/typewriter.ts +164 -0
- package/src/platform/announcer.ts +208 -208
- package/src/platform/config.ts +163 -163
- package/src/platform/cookies.ts +165 -165
- package/src/platform/index.ts +39 -39
- package/src/platform/meta.ts +168 -168
- package/src/plugin/index.ts +37 -0
- package/src/plugin/registry.ts +269 -0
- package/src/plugin/types.ts +137 -0
- package/src/reactive/async-data.ts +486 -486
- package/src/reactive/computed.ts +130 -92
- package/src/reactive/index.ts +37 -37
- package/src/reactive/signal.ts +29 -29
- package/src/router/bq-link.ts +279 -0
- package/src/router/constraints.ts +201 -0
- package/src/router/index.ts +49 -41
- package/src/router/match.ts +312 -106
- package/src/router/path-pattern.ts +52 -0
- package/src/router/query.ts +38 -35
- package/src/router/router.ts +402 -211
- package/src/router/types.ts +139 -93
- package/src/router/use-route.ts +68 -0
- package/src/router/utils.ts +157 -116
- package/src/security/constants.ts +211 -211
- package/src/security/index.ts +12 -10
- package/src/security/sanitize.ts +6 -2
- package/src/security/trusted-html.ts +71 -0
- package/src/ssr/hydrate.ts +82 -0
- package/src/ssr/index.ts +70 -0
- package/src/ssr/render.ts +508 -0
- package/src/ssr/serialize.ts +296 -0
- package/src/ssr/types.ts +81 -0
- package/src/store/create-store.ts +467 -329
- package/src/store/define-store.ts +2 -1
- package/src/store/index.ts +27 -22
- package/src/store/mapping.ts +2 -1
- package/src/store/persisted.ts +249 -61
- package/src/store/types.ts +247 -94
- package/src/store/utils.ts +135 -141
- package/src/store/watch.ts +2 -1
- package/src/storybook/index.ts +480 -0
- package/src/testing/index.ts +42 -0
- package/src/testing/testing.ts +593 -0
- package/src/testing/types.ts +170 -0
- package/src/view/custom-directives.ts +30 -0
- package/src/view/evaluate.ts +292 -290
- package/src/view/process.ts +108 -92
- package/dist/component-CY5MVoYN.js +0 -531
- package/dist/component-CY5MVoYN.js.map +0 -1
- package/dist/config-DRmZZno3.js.map +0 -1
- package/dist/core-CK2Mfpf4.js +0 -648
- package/dist/core-CK2Mfpf4.js.map +0 -1
- package/dist/motion-C5DRdPnO.js +0 -415
- package/dist/motion-C5DRdPnO.js.map +0 -1
- package/dist/platform-B7JhGBc7.js.map +0 -1
- package/dist/reactive-BDya-ia8.js +0 -253
- package/dist/reactive-BDya-ia8.js.map +0 -1
- package/dist/router-CijiICxt.js +0 -188
- package/dist/router-CijiICxt.js.map +0 -1
- package/dist/sanitize-jyJ2ryE2.js.map +0 -1
- package/dist/store-CPK9E62U.js +0 -262
- package/dist/store-CPK9E62U.js.map +0 -1
- package/dist/view-Cdi0g-qo.js +0 -396
- package/dist/view-Cdi0g-qo.js.map +0 -1
package/src/router/types.ts
CHANGED
|
@@ -1,93 +1,139 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Router types and public contracts.
|
|
3
|
-
* @module bquery/router
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ReadonlySignal } from '../reactive/index';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Represents a parsed route with matched params.
|
|
10
|
-
*/
|
|
11
|
-
export type Route = {
|
|
12
|
-
/** The current path (e.g., '/user/42') */
|
|
13
|
-
path: string;
|
|
14
|
-
/** Extracted route params (e.g., { id: '42' }) */
|
|
15
|
-
params: Record<string, string>;
|
|
16
|
-
/**
|
|
17
|
-
* Query string params.
|
|
18
|
-
* Each key maps to a single string value by default.
|
|
19
|
-
* Only keys that appear multiple times in the query string become arrays.
|
|
20
|
-
* @example
|
|
21
|
-
* // ?foo=1 → { foo: '1' }
|
|
22
|
-
* // ?tag=a&tag=b → { tag: ['a', 'b'] }
|
|
23
|
-
* // ?x=1&y=2&x=3 → { x: ['1', '3'], y: '2' }
|
|
24
|
-
*/
|
|
25
|
-
query: Record<string, string | string[]>;
|
|
26
|
-
/** The matched route definition */
|
|
27
|
-
matched: RouteDefinition | null;
|
|
28
|
-
/** Hash fragment without # */
|
|
29
|
-
hash: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Route definition for configuration.
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
/** Optional
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Router types and public contracts.
|
|
3
|
+
* @module bquery/router
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ReadonlySignal } from '../reactive/index';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents a parsed route with matched params.
|
|
10
|
+
*/
|
|
11
|
+
export type Route = {
|
|
12
|
+
/** The current path (e.g., '/user/42') */
|
|
13
|
+
path: string;
|
|
14
|
+
/** Extracted route params (e.g., { id: '42' }) */
|
|
15
|
+
params: Record<string, string>;
|
|
16
|
+
/**
|
|
17
|
+
* Query string params.
|
|
18
|
+
* Each key maps to a single string value by default.
|
|
19
|
+
* Only keys that appear multiple times in the query string become arrays.
|
|
20
|
+
* @example
|
|
21
|
+
* // ?foo=1 → { foo: '1' }
|
|
22
|
+
* // ?tag=a&tag=b → { tag: ['a', 'b'] }
|
|
23
|
+
* // ?x=1&y=2&x=3 → { x: ['1', '3'], y: '2' }
|
|
24
|
+
*/
|
|
25
|
+
query: Record<string, string | string[]>;
|
|
26
|
+
/** The matched route definition */
|
|
27
|
+
matched: RouteDefinition | null;
|
|
28
|
+
/** Hash fragment without # */
|
|
29
|
+
hash: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Route definition for configuration.
|
|
34
|
+
*/
|
|
35
|
+
type BaseRouteDefinition = {
|
|
36
|
+
/**
|
|
37
|
+
* Path pattern (e.g., '/user/:id', '/posts/*').
|
|
38
|
+
* Supports regex constraints on params: `/user/:id(\\d+)`.
|
|
39
|
+
* Constraint backreferences are not supported.
|
|
40
|
+
*/
|
|
41
|
+
path: string;
|
|
42
|
+
/** Optional route name for programmatic navigation */
|
|
43
|
+
name?: string;
|
|
44
|
+
/** Optional metadata */
|
|
45
|
+
meta?: Record<string, unknown>;
|
|
46
|
+
/** Nested child routes */
|
|
47
|
+
children?: RouteDefinition[];
|
|
48
|
+
/**
|
|
49
|
+
* Per-route navigation guard. Called before entering this route.
|
|
50
|
+
* Return `false` to cancel navigation.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* {
|
|
55
|
+
* path: '/admin',
|
|
56
|
+
* component: () => import('./Admin'),
|
|
57
|
+
* beforeEnter: (to, from) => isAuthenticated() || false,
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
beforeEnter?: NavigationGuard;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type ComponentRouteDefinition = BaseRouteDefinition & {
|
|
65
|
+
/** Component loader (sync or async) */
|
|
66
|
+
component: () => unknown | Promise<unknown>;
|
|
67
|
+
redirectTo?: never;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
type RedirectRouteDefinition = BaseRouteDefinition & {
|
|
71
|
+
/**
|
|
72
|
+
* Redirect target path. When the route is matched, the router
|
|
73
|
+
* automatically navigates to this path instead.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* { path: '/old-page', redirectTo: '/new-page' }
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
redirectTo: string;
|
|
81
|
+
component?: never;
|
|
82
|
+
children?: never;
|
|
83
|
+
beforeEnter?: never;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export type RouteDefinition = ComponentRouteDefinition | RedirectRouteDefinition;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Router configuration options.
|
|
90
|
+
*/
|
|
91
|
+
export type RouterOptions = {
|
|
92
|
+
/** Array of route definitions */
|
|
93
|
+
routes: RouteDefinition[];
|
|
94
|
+
/** Base path for all routes (default: '') */
|
|
95
|
+
base?: string;
|
|
96
|
+
/** Use hash-based routing instead of history (default: false) */
|
|
97
|
+
hash?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Restore scroll position on back/forward navigation (default: false).
|
|
100
|
+
* When enabled, the router saves scroll positions for each history entry
|
|
101
|
+
* and restores them on popstate events.
|
|
102
|
+
*/
|
|
103
|
+
scrollRestoration?: boolean;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Navigation guard function type.
|
|
108
|
+
*/
|
|
109
|
+
export type NavigationGuard = (to: Route, from: Route) => boolean | void | Promise<boolean | void>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Router instance returned by createRouter.
|
|
113
|
+
*/
|
|
114
|
+
export type Router = {
|
|
115
|
+
/** Navigate to a path */
|
|
116
|
+
push: (path: string) => Promise<void>;
|
|
117
|
+
/** Replace current history entry */
|
|
118
|
+
replace: (path: string) => Promise<void>;
|
|
119
|
+
/** Go back in history */
|
|
120
|
+
back: () => void;
|
|
121
|
+
/** Go forward in history */
|
|
122
|
+
forward: () => void;
|
|
123
|
+
/** Go to a specific history entry */
|
|
124
|
+
go: (delta: number) => void;
|
|
125
|
+
/** Add a beforeEach guard */
|
|
126
|
+
beforeEach: (guard: NavigationGuard) => () => void;
|
|
127
|
+
/** Add an afterEach hook */
|
|
128
|
+
afterEach: (hook: (to: Route, from: Route) => void) => () => void;
|
|
129
|
+
/** Current route (reactive) */
|
|
130
|
+
currentRoute: ReadonlySignal<Route>;
|
|
131
|
+
/** All route definitions */
|
|
132
|
+
routes: RouteDefinition[];
|
|
133
|
+
/** Base path for all routes */
|
|
134
|
+
base: string;
|
|
135
|
+
/** Whether hash-based routing is enabled */
|
|
136
|
+
hash: boolean;
|
|
137
|
+
/** Destroy the router and cleanup listeners */
|
|
138
|
+
destroy: () => void;
|
|
139
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive route composable.
|
|
3
|
+
* @module bquery/router
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { computed, type ReadonlySignal } from '../reactive/index';
|
|
7
|
+
import { routeSignal } from './state';
|
|
8
|
+
import type { Route, RouteDefinition } from './types';
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// useRoute Composable
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Return type for {@link useRoute}.
|
|
16
|
+
* Provides reactive access to individual route properties.
|
|
17
|
+
*/
|
|
18
|
+
export type UseRouteReturn = {
|
|
19
|
+
/** Full reactive route object */
|
|
20
|
+
route: ReadonlySignal<Route>;
|
|
21
|
+
/** Reactive current path */
|
|
22
|
+
path: ReadonlySignal<string>;
|
|
23
|
+
/** Reactive route params */
|
|
24
|
+
params: ReadonlySignal<Record<string, string>>;
|
|
25
|
+
/** Reactive query params */
|
|
26
|
+
query: ReadonlySignal<Record<string, string | string[]>>;
|
|
27
|
+
/** Reactive hash fragment (without #) */
|
|
28
|
+
hash: ReadonlySignal<string>;
|
|
29
|
+
/** Reactive matched route definition */
|
|
30
|
+
matched: ReadonlySignal<RouteDefinition | null>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const route = computed(() => routeSignal.value);
|
|
34
|
+
const path = computed(() => route.value.path);
|
|
35
|
+
const params = computed(() => route.value.params);
|
|
36
|
+
const query = computed(() => route.value.query);
|
|
37
|
+
const hash = computed(() => route.value.hash);
|
|
38
|
+
const matched = computed(() => route.value.matched);
|
|
39
|
+
|
|
40
|
+
const routeHandle: UseRouteReturn = { route, path, params, query, hash, matched };
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns reactive access to the current route, params, query, and hash.
|
|
44
|
+
*
|
|
45
|
+
* Each property is a readonly computed signal that updates automatically
|
|
46
|
+
* when the route changes. This is useful for fine-grained reactivity
|
|
47
|
+
* where you only need to subscribe to specific route parts.
|
|
48
|
+
*
|
|
49
|
+
* @returns An object with reactive route properties
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { useRoute } from '@bquery/bquery/router';
|
|
54
|
+
* import { effect } from '@bquery/bquery/reactive';
|
|
55
|
+
*
|
|
56
|
+
* const { path, params, query, hash } = useRoute();
|
|
57
|
+
*
|
|
58
|
+
* effect(() => {
|
|
59
|
+
* console.log('Path:', path.value);
|
|
60
|
+
* console.log('Params:', params.value);
|
|
61
|
+
* console.log('Query:', query.value);
|
|
62
|
+
* console.log('Hash:', hash.value);
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export const useRoute = (): UseRouteReturn => {
|
|
67
|
+
return routeHandle;
|
|
68
|
+
};
|
package/src/router/utils.ts
CHANGED
|
@@ -1,116 +1,157 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Router utilities.
|
|
3
|
-
* @module bquery/router
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { computed, type ReadonlySignal } from '../reactive/index';
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* @
|
|
44
|
-
*
|
|
45
|
-
* @
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* ```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
if (!
|
|
61
|
-
throw new Error(
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Router utilities.
|
|
3
|
+
* @module bquery/router
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { computed, type ReadonlySignal } from '../reactive/index';
|
|
7
|
+
import { getRouteConstraintRegex } from './constraints';
|
|
8
|
+
import { isParamChar, isParamStart, readConstraint } from './path-pattern';
|
|
9
|
+
import { getActiveRouter, routeSignal } from './state';
|
|
10
|
+
import type { RouteDefinition } from './types';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Utilities
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Flattens nested routes into a single array with full paths.
|
|
18
|
+
* Does NOT include the router base - base is only for browser history.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export const flattenRoutes = (routes: RouteDefinition[], parentPath = ''): RouteDefinition[] => {
|
|
22
|
+
const result: RouteDefinition[] = [];
|
|
23
|
+
|
|
24
|
+
for (const route of routes) {
|
|
25
|
+
const fullPath = route.path === '*' ? '*' : `${parentPath}${route.path}`.replace(/\/+/g, '/');
|
|
26
|
+
|
|
27
|
+
result.push({
|
|
28
|
+
...route,
|
|
29
|
+
path: fullPath,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (route.children) {
|
|
33
|
+
result.push(...flattenRoutes(route.children, fullPath));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolves a route by name and params.
|
|
42
|
+
*
|
|
43
|
+
* @param name - The route name
|
|
44
|
+
* @param params - Route params to interpolate
|
|
45
|
+
* @returns The resolved path
|
|
46
|
+
* @throws {Error} If no router is initialized, the route name is unknown,
|
|
47
|
+
* a required path param is missing from `params`, a param value does not satisfy
|
|
48
|
+
* its route regex constraint, or a route param constraint has invalid syntax
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { resolve } from 'bquery/router';
|
|
53
|
+
*
|
|
54
|
+
* const path = resolve('user', { id: '42' });
|
|
55
|
+
* // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const resolve = (name: string, params: Record<string, string> = {}): string => {
|
|
59
|
+
const activeRouter = getActiveRouter();
|
|
60
|
+
if (!activeRouter) {
|
|
61
|
+
throw new Error('bQuery router: No router initialized.');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const route = activeRouter.routes.find((r) => r.name === name);
|
|
65
|
+
if (!route) {
|
|
66
|
+
throw new Error(`bQuery router: Route "${name}" not found.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let path = '';
|
|
70
|
+
for (let i = 0; i < route.path.length; ) {
|
|
71
|
+
if (route.path[i] === ':' && isParamStart(route.path[i + 1])) {
|
|
72
|
+
let nameEnd = i + 2;
|
|
73
|
+
while (nameEnd < route.path.length && isParamChar(route.path[nameEnd])) {
|
|
74
|
+
nameEnd++;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let nextIndex = nameEnd;
|
|
78
|
+
let constraint: string | null = null;
|
|
79
|
+
if (route.path[nameEnd] === '(') {
|
|
80
|
+
const parsedConstraint = readConstraint(route.path, nameEnd);
|
|
81
|
+
if (!parsedConstraint) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`bQuery router: Invalid constraint syntax in path "${route.path}" for route "${name}".`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
constraint = parsedConstraint.constraint;
|
|
87
|
+
nextIndex = parsedConstraint.endIndex;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const key = route.path.slice(i + 1, nameEnd);
|
|
91
|
+
const value = params[key];
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
throw new Error(`bQuery router: Missing required param "${key}" for route "${name}".`);
|
|
94
|
+
}
|
|
95
|
+
if (constraint && !getRouteConstraintRegex(constraint).test(value)) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`bQuery router: Param "${key}" with value "${value}" does not satisfy the route constraint "${constraint}" for route "${name}".`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
path += encodeURIComponent(value);
|
|
102
|
+
i = nextIndex;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
path += route.path[i];
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return path;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Checks if a path matches the current route.
|
|
115
|
+
*
|
|
116
|
+
* @param path - Path to check
|
|
117
|
+
* @param exact - Whether to match exactly (default: false)
|
|
118
|
+
* @returns True if the path matches
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* import { isActive } from 'bquery/router';
|
|
123
|
+
*
|
|
124
|
+
* if (isActive('/dashboard')) {
|
|
125
|
+
* // Highlight nav item
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export const isActive = (path: string, exact = false): boolean => {
|
|
130
|
+
const current = routeSignal.value.path;
|
|
131
|
+
return exact ? current === path : current.startsWith(path);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Creates a computed signal that checks if a path is active.
|
|
136
|
+
*
|
|
137
|
+
* @param path - Path to check
|
|
138
|
+
* @param exact - Whether to match exactly
|
|
139
|
+
* @returns A reactive signal
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { isActiveSignal } from 'bquery/router';
|
|
144
|
+
* import { effect } from 'bquery/reactive';
|
|
145
|
+
*
|
|
146
|
+
* const dashboardActive = isActiveSignal('/dashboard');
|
|
147
|
+
* effect(() => {
|
|
148
|
+
* navItem.classList.toggle('active', dashboardActive.value);
|
|
149
|
+
* });
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {
|
|
153
|
+
return computed(() => {
|
|
154
|
+
const current = routeSignal.value.path;
|
|
155
|
+
return exact ? current === path : current.startsWith(path);
|
|
156
|
+
});
|
|
157
|
+
};
|