@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/reactive/computed.ts
CHANGED
|
@@ -1,92 +1,130 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Computed reactive values.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
clearDependencies,
|
|
7
|
-
getCurrentObserver,
|
|
8
|
-
registerDependency,
|
|
9
|
-
scheduleObserver,
|
|
10
|
-
track,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
private
|
|
26
|
-
private
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
this.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Computed reactive values.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
clearDependencies,
|
|
7
|
+
getCurrentObserver,
|
|
8
|
+
registerDependency,
|
|
9
|
+
scheduleObserver,
|
|
10
|
+
track,
|
|
11
|
+
withoutCurrentObserver,
|
|
12
|
+
type ReactiveSource,
|
|
13
|
+
} from './internals';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A computed value that derives from other reactive sources.
|
|
17
|
+
*
|
|
18
|
+
* Computed values are lazily evaluated and cached. They only
|
|
19
|
+
* recompute when their dependencies change.
|
|
20
|
+
*
|
|
21
|
+
* @template T - The type of the computed value
|
|
22
|
+
*/
|
|
23
|
+
export class Computed<T> implements ReactiveSource {
|
|
24
|
+
private cachedValue!: T;
|
|
25
|
+
private hasCachedValue = false;
|
|
26
|
+
private dirty = true;
|
|
27
|
+
private disposed = false;
|
|
28
|
+
private subscribers = new Set<() => void>();
|
|
29
|
+
private readonly markDirty = () => {
|
|
30
|
+
if (this.disposed) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.dirty = true;
|
|
34
|
+
// Create snapshot to avoid issues with subscribers modifying the set during iteration
|
|
35
|
+
const subscribersSnapshot = Array.from(this.subscribers);
|
|
36
|
+
for (const subscriber of subscribersSnapshot) {
|
|
37
|
+
scheduleObserver(subscriber);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new computed value.
|
|
43
|
+
* @param compute - Function that computes the value
|
|
44
|
+
*/
|
|
45
|
+
constructor(private readonly compute: () => T) {}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Gets the computed value, recomputing if dependencies changed.
|
|
49
|
+
* During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.
|
|
50
|
+
*/
|
|
51
|
+
get value(): T {
|
|
52
|
+
if (this.disposed) {
|
|
53
|
+
if (!this.hasCachedValue) {
|
|
54
|
+
this.cachedValue = withoutCurrentObserver(() => this.compute());
|
|
55
|
+
this.hasCachedValue = true;
|
|
56
|
+
}
|
|
57
|
+
return this.cachedValue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const current = getCurrentObserver();
|
|
61
|
+
if (current) {
|
|
62
|
+
this.subscribers.add(current);
|
|
63
|
+
registerDependency(current, this);
|
|
64
|
+
}
|
|
65
|
+
if (this.dirty) {
|
|
66
|
+
this.dirty = false;
|
|
67
|
+
// Clear old dependencies before recomputing
|
|
68
|
+
clearDependencies(this.markDirty);
|
|
69
|
+
this.cachedValue = track(this.markDirty, this.compute);
|
|
70
|
+
this.hasCachedValue = true;
|
|
71
|
+
}
|
|
72
|
+
return this.cachedValue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Reads the current computed value without tracking.
|
|
77
|
+
* Useful when you need the value but don't want to create a dependency.
|
|
78
|
+
*
|
|
79
|
+
* @returns The current cached value (recomputes if dirty)
|
|
80
|
+
*/
|
|
81
|
+
peek(): T {
|
|
82
|
+
if (this.disposed) {
|
|
83
|
+
if (!this.hasCachedValue) {
|
|
84
|
+
this.cachedValue = withoutCurrentObserver(() => this.compute());
|
|
85
|
+
this.hasCachedValue = true;
|
|
86
|
+
}
|
|
87
|
+
return this.cachedValue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (this.dirty) {
|
|
91
|
+
this.dirty = false;
|
|
92
|
+
// Clear old dependencies before recomputing
|
|
93
|
+
clearDependencies(this.markDirty);
|
|
94
|
+
this.cachedValue = track(this.markDirty, this.compute);
|
|
95
|
+
this.hasCachedValue = true;
|
|
96
|
+
}
|
|
97
|
+
return this.cachedValue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Removes an observer from this computed's subscriber set.
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
unsubscribe(observer: () => void): void {
|
|
105
|
+
this.subscribers.delete(observer);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Disposes the computed value by unsubscribing its internal observer
|
|
110
|
+
* from all upstream dependencies and clearing subscribers.
|
|
111
|
+
*/
|
|
112
|
+
dispose(): void {
|
|
113
|
+
this.disposed = true;
|
|
114
|
+
if (this.dirty) {
|
|
115
|
+
this.hasCachedValue = false;
|
|
116
|
+
}
|
|
117
|
+
this.dirty = false;
|
|
118
|
+
clearDependencies(this.markDirty);
|
|
119
|
+
this.subscribers.clear();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Creates a new computed value.
|
|
125
|
+
*
|
|
126
|
+
* @template T - The type of the computed value
|
|
127
|
+
* @param fn - Function that computes the value from reactive sources
|
|
128
|
+
* @returns A new Computed instance
|
|
129
|
+
*/
|
|
130
|
+
export const computed = <T>(fn: () => T): Computed<T> => new Computed(fn);
|
package/src/reactive/index.ts
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reactive module providing fine-grained reactivity primitives.
|
|
3
|
-
*
|
|
4
|
-
* @module bquery/reactive
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
Computed,
|
|
9
|
-
Signal,
|
|
10
|
-
batch,
|
|
11
|
-
computed,
|
|
12
|
-
createUseFetch,
|
|
13
|
-
effect,
|
|
14
|
-
isComputed,
|
|
15
|
-
isSignal,
|
|
16
|
-
linkedSignal,
|
|
17
|
-
persistedSignal,
|
|
18
|
-
readonly,
|
|
19
|
-
signal,
|
|
20
|
-
useAsyncData,
|
|
21
|
-
useFetch,
|
|
22
|
-
untrack,
|
|
23
|
-
watch,
|
|
24
|
-
} from './signal';
|
|
25
|
-
|
|
26
|
-
export type {
|
|
27
|
-
AsyncDataState,
|
|
28
|
-
AsyncDataStatus,
|
|
29
|
-
AsyncWatchSource,
|
|
30
|
-
CleanupFn,
|
|
31
|
-
FetchInput,
|
|
32
|
-
LinkedSignal,
|
|
33
|
-
Observer,
|
|
34
|
-
ReadonlySignal,
|
|
35
|
-
UseAsyncDataOptions,
|
|
36
|
-
UseFetchOptions,
|
|
37
|
-
} from './signal';
|
|
1
|
+
/**
|
|
2
|
+
* Reactive module providing fine-grained reactivity primitives.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/reactive
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
Computed,
|
|
9
|
+
Signal,
|
|
10
|
+
batch,
|
|
11
|
+
computed,
|
|
12
|
+
createUseFetch,
|
|
13
|
+
effect,
|
|
14
|
+
isComputed,
|
|
15
|
+
isSignal,
|
|
16
|
+
linkedSignal,
|
|
17
|
+
persistedSignal,
|
|
18
|
+
readonly,
|
|
19
|
+
signal,
|
|
20
|
+
useAsyncData,
|
|
21
|
+
useFetch,
|
|
22
|
+
untrack,
|
|
23
|
+
watch,
|
|
24
|
+
} from './signal';
|
|
25
|
+
|
|
26
|
+
export type {
|
|
27
|
+
AsyncDataState,
|
|
28
|
+
AsyncDataStatus,
|
|
29
|
+
AsyncWatchSource,
|
|
30
|
+
CleanupFn,
|
|
31
|
+
FetchInput,
|
|
32
|
+
LinkedSignal,
|
|
33
|
+
Observer,
|
|
34
|
+
ReadonlySignal,
|
|
35
|
+
UseAsyncDataOptions,
|
|
36
|
+
UseFetchOptions,
|
|
37
|
+
} from './signal';
|
package/src/reactive/signal.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reactive primitives inspired by fine-grained reactivity.
|
|
3
|
-
*
|
|
4
|
-
* @module bquery/reactive
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export { batch } from './batch';
|
|
8
|
-
export { createUseFetch, useAsyncData, useFetch } from './async-data';
|
|
9
|
-
export { Computed, computed } from './computed';
|
|
10
|
-
export { Signal, signal } from './core';
|
|
11
|
-
export { effect } from './effect';
|
|
12
|
-
export { linkedSignal } from './linked';
|
|
13
|
-
export { persistedSignal } from './persisted';
|
|
14
|
-
export { readonly } from './readonly';
|
|
15
|
-
export { isComputed, isSignal } from './type-guards';
|
|
16
|
-
export { untrack } from './untrack';
|
|
17
|
-
export { watch } from './watch';
|
|
18
|
-
|
|
19
|
-
export type { CleanupFn, Observer } from './internals';
|
|
20
|
-
export type {
|
|
21
|
-
AsyncDataState,
|
|
22
|
-
AsyncDataStatus,
|
|
23
|
-
AsyncWatchSource,
|
|
24
|
-
FetchInput,
|
|
25
|
-
UseAsyncDataOptions,
|
|
26
|
-
UseFetchOptions,
|
|
27
|
-
} from './async-data';
|
|
28
|
-
export type { LinkedSignal } from './linked';
|
|
29
|
-
export type { ReadonlySignal } from './readonly';
|
|
1
|
+
/**
|
|
2
|
+
* Reactive primitives inspired by fine-grained reactivity.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/reactive
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { batch } from './batch';
|
|
8
|
+
export { createUseFetch, useAsyncData, useFetch } from './async-data';
|
|
9
|
+
export { Computed, computed } from './computed';
|
|
10
|
+
export { Signal, signal } from './core';
|
|
11
|
+
export { effect } from './effect';
|
|
12
|
+
export { linkedSignal } from './linked';
|
|
13
|
+
export { persistedSignal } from './persisted';
|
|
14
|
+
export { readonly } from './readonly';
|
|
15
|
+
export { isComputed, isSignal } from './type-guards';
|
|
16
|
+
export { untrack } from './untrack';
|
|
17
|
+
export { watch } from './watch';
|
|
18
|
+
|
|
19
|
+
export type { CleanupFn, Observer } from './internals';
|
|
20
|
+
export type {
|
|
21
|
+
AsyncDataState,
|
|
22
|
+
AsyncDataStatus,
|
|
23
|
+
AsyncWatchSource,
|
|
24
|
+
FetchInput,
|
|
25
|
+
UseAsyncDataOptions,
|
|
26
|
+
UseFetchOptions,
|
|
27
|
+
} from './async-data';
|
|
28
|
+
export type { LinkedSignal } from './linked';
|
|
29
|
+
export type { ReadonlySignal } from './readonly';
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<bq-link>` custom element for declarative SPA navigation.
|
|
3
|
+
*
|
|
4
|
+
* Exposes an accessible custom element that behaves like a link for
|
|
5
|
+
* client-side routing. Automatically toggles an active class when the
|
|
6
|
+
* target path matches the current route.
|
|
7
|
+
*
|
|
8
|
+
* @module bquery/router
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```html
|
|
12
|
+
* <bq-link to="/">Home</bq-link>
|
|
13
|
+
* <bq-link to="/about" active-class="selected">About</bq-link>
|
|
14
|
+
* <bq-link to="/settings" replace exact>Settings</bq-link>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { effect, type CleanupFn } from '../reactive/index';
|
|
19
|
+
import { navigate } from './navigation';
|
|
20
|
+
import { getActiveRouter, routeSignal } from './state';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default CSS class applied when the link's target path is active.
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_ACTIVE_CLASS = 'active';
|
|
27
|
+
|
|
28
|
+
/** @internal */
|
|
29
|
+
const tokenizeClassNames = (value: string): string[] => {
|
|
30
|
+
return value
|
|
31
|
+
.split(/\s+/)
|
|
32
|
+
.map((token) => token.trim())
|
|
33
|
+
.filter((token) => token.length > 0);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** @internal SSR-safe base class for environments without HTMLElement. */
|
|
37
|
+
const BQ_LINK_BASE =
|
|
38
|
+
typeof HTMLElement !== 'undefined' ? HTMLElement : (class {} as unknown as typeof HTMLElement);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* `<bq-link>` — A navigation custom element for bQuery routers.
|
|
42
|
+
*
|
|
43
|
+
* Attributes:
|
|
44
|
+
* - `to` — Target path (required). Example: `to="/dashboard"`.
|
|
45
|
+
* - `replace` — If present, replaces the current history entry instead of pushing.
|
|
46
|
+
* - `exact` — If present, the active class is only applied on an exact path match.
|
|
47
|
+
* - `active-class` — CSS class added when the route is active (default: `'active'`).
|
|
48
|
+
*
|
|
49
|
+
* The custom element itself acts as the interactive link target using
|
|
50
|
+
* `role="link"` and keyboard handling. It does not render a native `<a>`,
|
|
51
|
+
* so browser-native link affordances like context-menu "open in new tab"
|
|
52
|
+
* are not provided automatically.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { registerBqLink } from '@bquery/bquery/router';
|
|
57
|
+
*
|
|
58
|
+
* // Register the <bq-link> element (idempotent)
|
|
59
|
+
* registerBqLink();
|
|
60
|
+
*
|
|
61
|
+
* // Then use in HTML:
|
|
62
|
+
* // <bq-link to="/about">About</bq-link>
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export class BqLinkElement extends BQ_LINK_BASE {
|
|
66
|
+
/** @internal */
|
|
67
|
+
private _cleanup: CleanupFn | null = null;
|
|
68
|
+
|
|
69
|
+
/** @internal */
|
|
70
|
+
private _trackedActiveClasses = new Map<string, boolean>();
|
|
71
|
+
|
|
72
|
+
static get observedAttributes(): string[] {
|
|
73
|
+
return ['to', 'replace', 'exact', 'active-class'];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** The target path for navigation. */
|
|
77
|
+
get to(): string {
|
|
78
|
+
const to = this.getAttribute('to');
|
|
79
|
+
return to == null || to.trim() === '' ? '/' : to;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
set to(value: string) {
|
|
83
|
+
this.setAttribute('to', value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Whether to replace the current history entry. */
|
|
87
|
+
get replace(): boolean {
|
|
88
|
+
return this.hasAttribute('replace');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
set replace(value: boolean) {
|
|
92
|
+
if (value) {
|
|
93
|
+
this.setAttribute('replace', '');
|
|
94
|
+
} else {
|
|
95
|
+
this.removeAttribute('replace');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Whether to match the path exactly for active class. */
|
|
100
|
+
get exact(): boolean {
|
|
101
|
+
return this.hasAttribute('exact');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
set exact(value: boolean) {
|
|
105
|
+
if (value) {
|
|
106
|
+
this.setAttribute('exact', '');
|
|
107
|
+
} else {
|
|
108
|
+
this.removeAttribute('exact');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** CSS class applied when the route is active. */
|
|
113
|
+
get activeClass(): string {
|
|
114
|
+
return this.getAttribute('active-class') ?? DEFAULT_ACTIVE_CLASS;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
set activeClass(value: string) {
|
|
118
|
+
this.setAttribute('active-class', value);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @internal */
|
|
122
|
+
connectedCallback(): void {
|
|
123
|
+
// Set role for accessibility if not an <a> already
|
|
124
|
+
if (!this.getAttribute('role')) {
|
|
125
|
+
this.setAttribute('role', 'link');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Make focusable if not already
|
|
129
|
+
if (!this.hasAttribute('tabindex')) {
|
|
130
|
+
this.setAttribute('tabindex', '0');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Attach click handler
|
|
134
|
+
this.addEventListener('click', this._handleClick);
|
|
135
|
+
this.addEventListener('keydown', this._handleKeydown);
|
|
136
|
+
|
|
137
|
+
// Set up reactive active-class tracking
|
|
138
|
+
this._setupActiveTracking();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** @internal */
|
|
142
|
+
disconnectedCallback(): void {
|
|
143
|
+
this.removeEventListener('click', this._handleClick);
|
|
144
|
+
this.removeEventListener('keydown', this._handleKeydown);
|
|
145
|
+
|
|
146
|
+
if (this._cleanup) {
|
|
147
|
+
this._cleanup();
|
|
148
|
+
this._cleanup = null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this._clearTrackedActiveClasses();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** @internal */
|
|
155
|
+
attributeChangedCallback(name: string, _oldValue: string | null, _newValue: string | null): void {
|
|
156
|
+
// Re-setup active tracking when relevant attributes change
|
|
157
|
+
if (name === 'to' || name === 'exact' || name === 'active-class') {
|
|
158
|
+
if (this.isConnected) {
|
|
159
|
+
this._setupActiveTracking();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Sets up the reactive effect that toggles the active CSS class
|
|
166
|
+
* based on the current route.
|
|
167
|
+
* @internal
|
|
168
|
+
*/
|
|
169
|
+
private _setupActiveTracking(): void {
|
|
170
|
+
// Clean up previous effect
|
|
171
|
+
if (this._cleanup) {
|
|
172
|
+
this._cleanup();
|
|
173
|
+
this._cleanup = null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this._clearTrackedActiveClasses();
|
|
177
|
+
|
|
178
|
+
const targetPath = this.to;
|
|
179
|
+
const exactMatch = this.exact;
|
|
180
|
+
const cssClasses = tokenizeClassNames(this.activeClass);
|
|
181
|
+
this._trackedActiveClasses = new Map(
|
|
182
|
+
cssClasses.map((cssClass) => [cssClass, this.classList.contains(cssClass)])
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
this._cleanup = effect(() => {
|
|
186
|
+
const current = routeSignal.value.path;
|
|
187
|
+
const isMatch = exactMatch
|
|
188
|
+
? current === targetPath
|
|
189
|
+
: targetPath === '/'
|
|
190
|
+
? current === '/'
|
|
191
|
+
: current === targetPath ||
|
|
192
|
+
current.startsWith(targetPath.endsWith('/') ? targetPath : targetPath + '/');
|
|
193
|
+
|
|
194
|
+
for (const cssClass of cssClasses) {
|
|
195
|
+
const wasPresentInitially = this._trackedActiveClasses.get(cssClass) ?? false;
|
|
196
|
+
this.classList.toggle(cssClass, isMatch || wasPresentInitially);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Update aria-current for accessibility
|
|
200
|
+
if (isMatch) {
|
|
201
|
+
this.setAttribute('aria-current', 'page');
|
|
202
|
+
} else {
|
|
203
|
+
this.removeAttribute('aria-current');
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** @internal */
|
|
209
|
+
private _clearTrackedActiveClasses(): void {
|
|
210
|
+
for (const [cssClass, wasPresentInitially] of this._trackedActiveClasses) {
|
|
211
|
+
this.classList.toggle(cssClass, wasPresentInitially);
|
|
212
|
+
}
|
|
213
|
+
this._trackedActiveClasses.clear();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Handles click events for SPA navigation.
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
private _handleClick = (e: Event): void => {
|
|
221
|
+
if (!(e instanceof MouseEvent)) return;
|
|
222
|
+
if (e.defaultPrevented) return;
|
|
223
|
+
if (e.button !== 0) return; // Only left clicks
|
|
224
|
+
if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
|
|
225
|
+
|
|
226
|
+
e.preventDefault();
|
|
227
|
+
this._navigate();
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Handles keyboard activation (Enter).
|
|
232
|
+
* @internal
|
|
233
|
+
*/
|
|
234
|
+
private _handleKeydown = (e: Event): void => {
|
|
235
|
+
if (e instanceof KeyboardEvent && e.key === 'Enter') {
|
|
236
|
+
e.preventDefault();
|
|
237
|
+
this._navigate();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Performs the actual navigation.
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
private _navigate(): void {
|
|
246
|
+
const targetPath = this.to;
|
|
247
|
+
if (!targetPath) return;
|
|
248
|
+
if (!getActiveRouter()) return;
|
|
249
|
+
|
|
250
|
+
void navigate(targetPath, { replace: this.replace }).catch((err) => {
|
|
251
|
+
console.error('bq-link: Navigation failed:', err);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Registers the `<bq-link>` custom element.
|
|
258
|
+
*
|
|
259
|
+
* This function is idempotent — calling it multiple times is safe.
|
|
260
|
+
* The element is registered under the tag name `bq-link`.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```ts
|
|
264
|
+
* import { registerBqLink } from '@bquery/bquery/router';
|
|
265
|
+
*
|
|
266
|
+
* registerBqLink();
|
|
267
|
+
*
|
|
268
|
+
* // Now use <bq-link to="/about">About</bq-link> in HTML
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
export const registerBqLink = (): void => {
|
|
272
|
+
if (
|
|
273
|
+
typeof HTMLElement !== 'undefined' &&
|
|
274
|
+
typeof customElements !== 'undefined' &&
|
|
275
|
+
!customElements.get('bq-link')
|
|
276
|
+
) {
|
|
277
|
+
customElements.define('bq-link', BqLinkElement);
|
|
278
|
+
}
|
|
279
|
+
};
|