@bquery/bquery 1.6.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -18
- 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-DVBCy09c.js +421 -0
- package/dist/a11y-DVBCy09c.js.map +1 -0
- package/dist/a11y.es.mjs +14 -0
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/html.d.ts.map +1 -1
- package/dist/component/index.d.ts +2 -1
- 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 +53 -1
- package/dist/component/types.d.ts.map +1 -1
- package/dist/component-L3-JfOFz.js +684 -0
- package/dist/component-L3-JfOFz.js.map +1 -0
- package/dist/component.es.mjs +9 -6
- package/dist/{config-DRmZZno3.js → config-DhT9auRm.js} +4 -4
- package/dist/{config-DRmZZno3.js.map → config-DhT9auRm.js.map} +1 -1
- package/dist/constraints-D5RHQLmP.js +100 -0
- package/dist/constraints-D5RHQLmP.js.map +1 -0
- package/dist/core/collection.d.ts +134 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +120 -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 +14 -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-DdtZHzsS.js +168 -0
- package/dist/core-DdtZHzsS.js.map +1 -0
- package/dist/{core-CCEabVHl.js → core-EMYSLzaT.js} +293 -194
- package/dist/core-EMYSLzaT.js.map +1 -0
- package/dist/core.es.mjs +48 -46
- package/dist/custom-directives-Dr4C5lVV.js +9 -0
- package/dist/custom-directives-Dr4C5lVV.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-BhB2iDPT.js +122 -0
- package/dist/devtools-BhB2iDPT.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-NwZBYh4l.js +244 -0
- package/dist/dnd-NwZBYh4l.js.map +1 -0
- package/dist/dnd.es.mjs +6 -0
- package/dist/env-CTdvLaH2.js +19 -0
- package/dist/env-CTdvLaH2.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 +40 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/types.d.ts +185 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/use-field.d.ts +34 -0
- package/dist/forms/use-field.d.ts.map +1 -0
- package/dist/forms/validators.d.ts +204 -0
- package/dist/forms/validators.d.ts.map +1 -0
- package/dist/forms-UcRHsYxC.js +227 -0
- package/dist/forms-UcRHsYxC.js.map +1 -0
- package/dist/forms.es.mjs +16 -0
- package/dist/full.d.ts +30 -11
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +209 -93
- 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/function-Cybd57JV.js +33 -0
- package/dist/function-Cybd57JV.js.map +1 -0
- 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-kuF6Ekj6.js +89 -0
- package/dist/i18n-kuF6Ekj6.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 +257 -143
- 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-i-fB5WxI.js +340 -0
- package/dist/media-i-fB5WxI.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-BJsAuULb.js +530 -0
- package/dist/motion-BJsAuULb.js.map +1 -0
- package/dist/motion.es.mjs +27 -23
- package/dist/{view-C70lA3vf.js → mount-B4Y8bk8Z.js} +166 -160
- package/dist/mount-B4Y8bk8Z.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-Dr9b6fsq.js → platform-Dw2gE3zI.js} +21 -22
- package/dist/{platform-Dr9b6fsq.js.map → platform-Dw2gE3zI.js.map} +1 -1
- 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-C2WuC8SF.js +66 -0
- package/dist/plugin-C2WuC8SF.js.map +1 -0
- package/dist/plugin.es.mjs +9 -0
- package/dist/reactive/async-data.d.ts +28 -3
- package/dist/reactive/async-data.d.ts.map +1 -1
- package/dist/reactive/computed.d.ts +10 -0
- package/dist/reactive/computed.d.ts.map +1 -1
- package/dist/reactive/effect.d.ts +3 -0
- package/dist/reactive/effect.d.ts.map +1 -1
- package/dist/reactive/http.d.ts +194 -0
- package/dist/reactive/http.d.ts.map +1 -0
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/pagination.d.ts +126 -0
- package/dist/reactive/pagination.d.ts.map +1 -0
- package/dist/reactive/polling.d.ts +55 -0
- package/dist/reactive/polling.d.ts.map +1 -0
- package/dist/reactive/readonly.d.ts +20 -1
- package/dist/reactive/readonly.d.ts.map +1 -1
- package/dist/reactive/rest.d.ts +293 -0
- package/dist/reactive/rest.d.ts.map +1 -0
- package/dist/reactive/scope.d.ts +140 -0
- package/dist/reactive/scope.d.ts.map +1 -0
- package/dist/reactive/signal.d.ts +16 -2
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive/to-value.d.ts +57 -0
- package/dist/reactive/to-value.d.ts.map +1 -0
- package/dist/reactive/websocket.d.ts +285 -0
- package/dist/reactive/websocket.d.ts.map +1 -0
- package/dist/reactive-DwkhUJfP.js +1148 -0
- package/dist/reactive-DwkhUJfP.js.map +1 -0
- package/dist/reactive.es.mjs +38 -20
- package/dist/registry-B08iilIh.js +26 -0
- package/dist/registry-B08iilIh.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 +15 -7
- 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/state.d.ts +25 -2
- package/dist/router/state.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-CQikC9Ed.js +492 -0
- package/dist/router-CQikC9Ed.js.map +1 -0
- package/dist/router.es.mjs +14 -10
- package/dist/{sanitize-Bs2dkMby.js → sanitize-B1V4JswB.js} +2 -1
- package/dist/{sanitize-Bs2dkMby.js.map → sanitize-B1V4JswB.js.map} +1 -1
- package/dist/security/index.d.ts +2 -2
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security.es.mjs +1 -1
- 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-_dAcGdzu.js +248 -0
- package/dist/ssr-_dAcGdzu.js.map +1 -0
- package/dist/ssr.es.mjs +9 -0
- package/dist/store/create-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/persisted.d.ts +38 -4
- package/dist/store/persisted.d.ts.map +1 -1
- package/dist/store/types.d.ts +138 -1
- 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-Cb3gPRve.js +338 -0
- package/dist/store-Cb3gPRve.js.map +1 -0
- package/dist/store.es.mjs +11 -10
- package/dist/storybook/index.d.ts.map +1 -1
- package/dist/storybook.es.mjs +1 -1
- package/dist/storybook.es.mjs.map +1 -1
- 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-C5Sjfsna.js +224 -0
- package/dist/testing-C5Sjfsna.js.map +1 -0
- package/dist/testing.es.mjs +9 -0
- package/dist/type-guards-BMX2c0LP.js +44 -0
- package/dist/type-guards-BMX2c0LP.js.map +1 -0
- package/dist/untrack-D0fnO5k2.js +36 -0
- package/dist/untrack-D0fnO5k2.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 +9 -9
- package/package.json +47 -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 +599 -524
- package/src/component/html.ts +153 -153
- package/src/component/index.ts +52 -50
- package/src/component/library.ts +540 -518
- package/src/component/scope.ts +212 -0
- package/src/component/types.ts +310 -256
- package/src/core/collection.ts +249 -1
- package/src/core/element.ts +252 -11
- package/src/core/env.ts +60 -0
- package/src/core/index.ts +1 -0
- package/src/core/shared.ts +64 -0
- package/src/core/utils/index.ts +66 -1
- 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 +320 -0
- package/src/forms/index.ts +70 -0
- package/src/forms/types.ts +203 -0
- package/src/forms/use-field.ts +231 -0
- package/src/forms/validators.ts +294 -0
- package/src/full.ts +554 -229
- 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 +72 -0
- package/src/media/battery.ts +116 -0
- package/src/media/breakpoints.ts +129 -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 +11 -2
- package/src/motion/morph.ts +151 -0
- package/src/motion/parallax.ts +120 -0
- package/src/motion/reduced-motion.ts +52 -3
- package/src/motion/types.ts +63 -0
- package/src/motion/typewriter.ts +164 -0
- package/src/plugin/index.ts +37 -0
- package/src/plugin/registry.ts +284 -0
- package/src/plugin/types.ts +137 -0
- package/src/reactive/async-data.ts +250 -29
- package/src/reactive/computed.ts +53 -1
- package/src/reactive/effect.ts +29 -6
- package/src/reactive/http.ts +790 -0
- package/src/reactive/index.ts +60 -0
- package/src/reactive/pagination.ts +317 -0
- package/src/reactive/polling.ts +179 -0
- package/src/reactive/readonly.ts +52 -8
- package/src/reactive/rest.ts +859 -0
- package/src/reactive/scope.ts +276 -0
- package/src/reactive/signal.ts +61 -1
- package/src/reactive/to-value.ts +71 -0
- package/src/reactive/websocket.ts +849 -0
- package/src/router/bq-link.ts +279 -0
- package/src/router/constraints.ts +204 -0
- package/src/router/index.ts +15 -7
- package/src/router/match.ts +255 -49
- package/src/router/path-pattern.ts +52 -0
- package/src/router/query.ts +3 -0
- package/src/router/router.ts +258 -48
- package/src/router/state.ts +51 -3
- package/src/router/types.ts +50 -4
- package/src/router/use-route.ts +68 -0
- package/src/router/utils.ts +44 -3
- package/src/security/index.ts +12 -17
- package/src/security/sanitize.ts +70 -70
- package/src/security/trusted-html.ts +71 -71
- package/src/ssr/hydrate.ts +84 -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 +146 -8
- package/src/store/define-store.ts +49 -49
- package/src/store/index.ts +5 -0
- package/src/store/mapping.ts +74 -74
- package/src/store/persisted.ts +245 -62
- package/src/store/types.ts +247 -92
- package/src/store/utils.ts +4 -10
- package/src/store/watch.ts +53 -53
- package/src/storybook/index.ts +480 -479
- 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 +28 -0
- package/src/view/evaluate.ts +2 -0
- package/src/view/process.ts +19 -3
- package/dist/component-BEQgt5hl.js +0 -600
- package/dist/component-BEQgt5hl.js.map +0 -1
- package/dist/core-BGQJVw0-.js +0 -35
- package/dist/core-BGQJVw0-.js.map +0 -1
- package/dist/core-CCEabVHl.js.map +0 -1
- package/dist/effect-AFRW_Plg.js +0 -84
- package/dist/effect-AFRW_Plg.js.map +0 -1
- package/dist/motion-D9TcHxOF.js +0 -415
- package/dist/motion-D9TcHxOF.js.map +0 -1
- package/dist/reactive-DSkct0dO.js +0 -254
- package/dist/reactive-DSkct0dO.js.map +0 -1
- package/dist/router-CbDhl8rS.js +0 -188
- package/dist/router-CbDhl8rS.js.map +0 -1
- package/dist/store-BwDvI45q.js +0 -263
- package/dist/store-BwDvI45q.js.map +0 -1
- package/dist/untrack-B0rVscTc.js +0 -7
- package/dist/untrack-B0rVscTc.js.map +0 -1
- package/dist/view-C70lA3vf.js.map +0 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive effect scopes for grouped disposal.
|
|
3
|
+
*
|
|
4
|
+
* An `EffectScope` collects all effects, computed values, and watches created
|
|
5
|
+
* inside its `run()` callback so they can be disposed together with a single
|
|
6
|
+
* `stop()` call. Scopes nest — an inner scope is collected by its parent.
|
|
7
|
+
*
|
|
8
|
+
* @module bquery/reactive
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { CleanupFn } from './internals';
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Types
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A scope that collects reactive resources for grouped disposal.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { effectScope, signal, effect, computed } from '@bquery/bquery/reactive';
|
|
23
|
+
*
|
|
24
|
+
* const scope = effectScope();
|
|
25
|
+
*
|
|
26
|
+
* scope.run(() => {
|
|
27
|
+
* const count = signal(0);
|
|
28
|
+
* effect(() => console.log(count.value));
|
|
29
|
+
* const doubled = computed(() => count.value * 2);
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* scope.stop(); // All effects and computed values disposed
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export interface EffectScope {
|
|
36
|
+
/** Whether the scope has not yet been stopped. */
|
|
37
|
+
readonly active: boolean;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Executes `fn` inside this scope, collecting any reactive resources
|
|
41
|
+
* (effects, computed values, watches, nested scopes) created during the call.
|
|
42
|
+
*
|
|
43
|
+
* `run()` is synchronous-only. Do not pass an async function or a function
|
|
44
|
+
* that returns a Promise — resources created after an `await` cannot be
|
|
45
|
+
* collected reliably.
|
|
46
|
+
*
|
|
47
|
+
* @template T - Return type of the provided function
|
|
48
|
+
* @param fn - Function to run inside the scope
|
|
49
|
+
* @returns The return value of `fn`
|
|
50
|
+
* @throws {Error} If the scope has already been stopped
|
|
51
|
+
*/
|
|
52
|
+
run<T>(fn: () => T): T;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Disposes all collected resources and marks the scope as inactive.
|
|
56
|
+
* Calling `stop()` on an already-stopped scope is a safe no-op.
|
|
57
|
+
*/
|
|
58
|
+
stop(): void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Internal scope stack
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
/** @internal */
|
|
66
|
+
interface ScopeInternal extends EffectScope {
|
|
67
|
+
/** @internal – Register a cleanup callback to run when the scope stops. */
|
|
68
|
+
_addDisposer(fn: CleanupFn): void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const scopeStack: ScopeInternal[] = [];
|
|
72
|
+
|
|
73
|
+
/** @internal */
|
|
74
|
+
export const hasScopeDisposer = (
|
|
75
|
+
scope: EffectScope | undefined
|
|
76
|
+
): scope is EffectScope & { _addDisposer(fn: CleanupFn): void } =>
|
|
77
|
+
typeof scope === 'object' && scope !== null && '_addDisposer' in scope;
|
|
78
|
+
|
|
79
|
+
const isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>
|
|
80
|
+
(typeof value === 'object' || typeof value === 'function') &&
|
|
81
|
+
value !== null &&
|
|
82
|
+
typeof (value as { then?: unknown }).then === 'function';
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Best-effort detection for native async functions so `run()` can reject them
|
|
86
|
+
* before invocation. Transpiled async functions may not preserve this shape, so
|
|
87
|
+
* promise-like return values are still checked after execution as a fallback.
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
const isAsyncFunction = (value: unknown): value is (...args: never[]) => Promise<unknown> => {
|
|
91
|
+
const constructorName =
|
|
92
|
+
typeof (value as { constructor?: unknown }).constructor === 'function'
|
|
93
|
+
? (value as { constructor: { name?: unknown } }).constructor.name
|
|
94
|
+
: undefined;
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
typeof value === 'function' &&
|
|
98
|
+
((Symbol.toStringTag in value &&
|
|
99
|
+
(value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag] === 'AsyncFunction') ||
|
|
100
|
+
constructorName === 'AsyncFunction')
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Returns the currently active scope, or `undefined` if none.
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
export const getActiveScope = (): EffectScope | undefined => {
|
|
109
|
+
for (let i = scopeStack.length - 1; i >= 0; i--) {
|
|
110
|
+
if (scopeStack[i].active) {
|
|
111
|
+
return scopeStack[i];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return undefined;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// EffectScope implementation
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
class EffectScopeImpl implements ScopeInternal {
|
|
123
|
+
private disposers: CleanupFn[] = [];
|
|
124
|
+
private _active = true;
|
|
125
|
+
|
|
126
|
+
get active(): boolean {
|
|
127
|
+
return this._active;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** @internal */
|
|
131
|
+
_addDisposer(fn: CleanupFn): void {
|
|
132
|
+
if (this._active) {
|
|
133
|
+
this.disposers.push(fn);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
run<T>(fn: () => T): T {
|
|
138
|
+
if (!this._active) {
|
|
139
|
+
throw new Error('bQuery reactive: Cannot run in a stopped effectScope');
|
|
140
|
+
}
|
|
141
|
+
if (isAsyncFunction(fn)) {
|
|
142
|
+
throw new Error('bQuery reactive: effectScope.run() only supports synchronous callbacks');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
scopeStack.push(this);
|
|
146
|
+
try {
|
|
147
|
+
const result = fn();
|
|
148
|
+
if (isPromiseLike(result)) {
|
|
149
|
+
this.stop();
|
|
150
|
+
throw new Error('bQuery reactive: effectScope.run() only supports synchronous callbacks');
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
} finally {
|
|
154
|
+
scopeStack.pop();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
stop(): void {
|
|
159
|
+
if (!this._active) return;
|
|
160
|
+
this._active = false;
|
|
161
|
+
|
|
162
|
+
// Dispose in reverse order (LIFO) to mirror creation order
|
|
163
|
+
for (let i = this.disposers.length - 1; i >= 0; i--) {
|
|
164
|
+
try {
|
|
165
|
+
this.disposers[i]();
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error('bQuery reactive: Error in scope cleanup', error);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
this.disposers.length = 0;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// Public API
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Creates a new effect scope for grouped disposal of reactive resources.
|
|
180
|
+
*
|
|
181
|
+
* All `effect()`, `computed()`, `watch()`, and nested `effectScope()` calls
|
|
182
|
+
* made inside `scope.run(fn)` are automatically collected. Calling
|
|
183
|
+
* `scope.stop()` disposes them all at once.
|
|
184
|
+
*
|
|
185
|
+
* `run()` is synchronous-only. Create the scope outside async flows when
|
|
186
|
+
* needed, but keep the callback itself synchronous so cleanup registration
|
|
187
|
+
* stays deterministic.
|
|
188
|
+
*
|
|
189
|
+
* @returns A new {@link EffectScope}
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* import { effectScope, signal, effect, onScopeDispose } from '@bquery/bquery/reactive';
|
|
194
|
+
*
|
|
195
|
+
* const scope = effectScope();
|
|
196
|
+
*
|
|
197
|
+
* scope.run(() => {
|
|
198
|
+
* const count = signal(0);
|
|
199
|
+
*
|
|
200
|
+
* effect(() => console.log(count.value));
|
|
201
|
+
*
|
|
202
|
+
* onScopeDispose(() => {
|
|
203
|
+
* console.log('Custom cleanup');
|
|
204
|
+
* });
|
|
205
|
+
* });
|
|
206
|
+
*
|
|
207
|
+
* scope.stop(); // logs "Custom cleanup", all effects stopped
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export const effectScope = (): EffectScope => {
|
|
211
|
+
const scope = new EffectScopeImpl();
|
|
212
|
+
|
|
213
|
+
// If created inside another scope, auto-collect as a nested scope
|
|
214
|
+
const parent = getActiveScope();
|
|
215
|
+
if (hasScopeDisposer(parent)) {
|
|
216
|
+
parent._addDisposer(() => scope.stop());
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return scope;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Returns the currently active {@link EffectScope}, or `undefined` if
|
|
224
|
+
* code is not running inside any scope's `run()` callback.
|
|
225
|
+
*
|
|
226
|
+
* @returns The active scope, or `undefined`
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```ts
|
|
230
|
+
* import { effectScope, getCurrentScope } from '@bquery/bquery/reactive';
|
|
231
|
+
*
|
|
232
|
+
* const scope = effectScope();
|
|
233
|
+
* scope.run(() => {
|
|
234
|
+
* console.log(getCurrentScope() !== undefined); // true
|
|
235
|
+
* });
|
|
236
|
+
*
|
|
237
|
+
* console.log(getCurrentScope()); // undefined
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
export const getCurrentScope = (): EffectScope | undefined => getActiveScope();
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Registers a cleanup callback on the currently active scope.
|
|
244
|
+
*
|
|
245
|
+
* The callback runs when the scope is stopped. This is useful for
|
|
246
|
+
* registering arbitrary cleanup (e.g. event listeners, timers)
|
|
247
|
+
* alongside effects and computed values.
|
|
248
|
+
*
|
|
249
|
+
* @param fn - Cleanup function to run when the scope stops
|
|
250
|
+
* @throws {Error} If called outside an active scope
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* import { effectScope, onScopeDispose } from '@bquery/bquery/reactive';
|
|
255
|
+
*
|
|
256
|
+
* const scope = effectScope();
|
|
257
|
+
*
|
|
258
|
+
* scope.run(() => {
|
|
259
|
+
* const controller = new AbortController();
|
|
260
|
+
* fetch('/api/data', { signal: controller.signal });
|
|
261
|
+
*
|
|
262
|
+
* onScopeDispose(() => controller.abort());
|
|
263
|
+
* });
|
|
264
|
+
*
|
|
265
|
+
* scope.stop(); // abort() is called
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
export const onScopeDispose = (fn: CleanupFn): void => {
|
|
269
|
+
const scope = getActiveScope();
|
|
270
|
+
if (!scope || !scope.active || !hasScopeDisposer(scope)) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
'bQuery reactive: onScopeDispose() must be called inside an active effectScope'
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
scope._addDisposer(fn);
|
|
276
|
+
};
|
package/src/reactive/signal.ts
CHANGED
|
@@ -9,12 +9,25 @@ export { createUseFetch, useAsyncData, useFetch } from './async-data';
|
|
|
9
9
|
export { Computed, computed } from './computed';
|
|
10
10
|
export { Signal, signal } from './core';
|
|
11
11
|
export { effect } from './effect';
|
|
12
|
+
export { createHttp, createRequestQueue, http, HttpError } from './http';
|
|
12
13
|
export { linkedSignal } from './linked';
|
|
14
|
+
export { useInfiniteFetch, usePaginatedFetch } from './pagination';
|
|
13
15
|
export { persistedSignal } from './persisted';
|
|
16
|
+
export { usePolling } from './polling';
|
|
14
17
|
export { readonly } from './readonly';
|
|
18
|
+
export {
|
|
19
|
+
createRestClient,
|
|
20
|
+
deduplicateRequest,
|
|
21
|
+
useResource,
|
|
22
|
+
useResourceList,
|
|
23
|
+
useSubmit,
|
|
24
|
+
} from './rest';
|
|
25
|
+
export { effectScope, getCurrentScope, onScopeDispose } from './scope';
|
|
15
26
|
export { isComputed, isSignal } from './type-guards';
|
|
27
|
+
export { toValue } from './to-value';
|
|
16
28
|
export { untrack } from './untrack';
|
|
17
29
|
export { watch } from './watch';
|
|
30
|
+
export { useEventSource, useWebSocket, useWebSocketChannel } from './websocket';
|
|
18
31
|
|
|
19
32
|
export type { CleanupFn, Observer } from './internals';
|
|
20
33
|
export type {
|
|
@@ -24,6 +37,53 @@ export type {
|
|
|
24
37
|
FetchInput,
|
|
25
38
|
UseAsyncDataOptions,
|
|
26
39
|
UseFetchOptions,
|
|
40
|
+
UseFetchRetryConfig,
|
|
27
41
|
} from './async-data';
|
|
42
|
+
export type {
|
|
43
|
+
HttpClient,
|
|
44
|
+
HttpProgressEvent,
|
|
45
|
+
HttpRequestConfig,
|
|
46
|
+
HttpResponse,
|
|
47
|
+
Interceptor,
|
|
48
|
+
InterceptorManager,
|
|
49
|
+
RequestQueue,
|
|
50
|
+
RequestQueueOptions,
|
|
51
|
+
RetryConfig,
|
|
52
|
+
} from './http';
|
|
53
|
+
export type {
|
|
54
|
+
InfiniteState,
|
|
55
|
+
PaginatedState,
|
|
56
|
+
UseInfiniteFetchOptions,
|
|
57
|
+
UsePaginatedFetchOptions,
|
|
58
|
+
} from './pagination';
|
|
59
|
+
export type { PollingState, UsePollingOptions } from './polling';
|
|
60
|
+
export type {
|
|
61
|
+
IdExtractor,
|
|
62
|
+
ResourceListActions,
|
|
63
|
+
RestClient,
|
|
64
|
+
UseResourceListOptions,
|
|
65
|
+
UseResourceListReturn,
|
|
66
|
+
UseResourceOptions,
|
|
67
|
+
UseResourceReturn,
|
|
68
|
+
UseSubmitOptions,
|
|
69
|
+
UseSubmitReturn,
|
|
70
|
+
} from './rest';
|
|
71
|
+
export type { EffectScope } from './scope';
|
|
28
72
|
export type { LinkedSignal } from './linked';
|
|
29
|
-
export type {
|
|
73
|
+
export type { MaybeSignal } from './to-value';
|
|
74
|
+
export type { ReadonlySignal, ReadonlySignalHandle } from './readonly';
|
|
75
|
+
export type {
|
|
76
|
+
ChannelMessage,
|
|
77
|
+
ChannelSubscription,
|
|
78
|
+
EventSourceStatus,
|
|
79
|
+
UseEventSourceOptions,
|
|
80
|
+
UseEventSourceReturn,
|
|
81
|
+
UseWebSocketChannelOptions,
|
|
82
|
+
UseWebSocketChannelReturn,
|
|
83
|
+
UseWebSocketOptions,
|
|
84
|
+
UseWebSocketReturn,
|
|
85
|
+
WebSocketHeartbeatConfig,
|
|
86
|
+
WebSocketReconnectConfig,
|
|
87
|
+
WebSocketSerializer,
|
|
88
|
+
WebSocketStatus,
|
|
89
|
+
} from './websocket';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility to unwrap reactive or plain values.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Computed } from './computed';
|
|
6
|
+
import { Signal } from './core';
|
|
7
|
+
import { readonly, isReadonlySignal } from './readonly';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A value that may be a raw value, a Signal, a `readonly()` wrapper, or a Computed.
|
|
11
|
+
*
|
|
12
|
+
* Useful for APIs that accept both reactive and plain inputs.
|
|
13
|
+
*
|
|
14
|
+
* Readonly wrappers are limited to the values returned by {@link readonly}. This keeps
|
|
15
|
+
* the type aligned with runtime behavior, where arbitrary structural `{ value, peek }`
|
|
16
|
+
* objects are intentionally returned unchanged.
|
|
17
|
+
*
|
|
18
|
+
* @template T - The underlying value type
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* function useTitle(title: MaybeSignal<string>) {
|
|
23
|
+
* document.title = toValue(title);
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* useTitle('Hello'); // plain string
|
|
27
|
+
* useTitle(signal('Hello')); // reactive signal
|
|
28
|
+
* useTitle(computed(() => 'Hi')); // computed value
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export type MaybeSignal<T> = T | Signal<T> | ReturnType<typeof readonly<T>> | Computed<T>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extracts the current value from a Signal, a bQuery `readonly()` wrapper, a
|
|
35
|
+
* Computed, or returns the raw value as-is. This eliminates repetitive
|
|
36
|
+
* `isSignal(x) ? x.value : x` patterns throughout user code.
|
|
37
|
+
*
|
|
38
|
+
* Reading a Signal or Computed via `toValue()` uses `.value`, so the
|
|
39
|
+
* read **does** participate in reactive tracking when called inside
|
|
40
|
+
* an effect or computed.
|
|
41
|
+
*
|
|
42
|
+
* @template T - The underlying value type
|
|
43
|
+
* @param source - A plain value, Signal, bQuery readonly wrapper, or Computed
|
|
44
|
+
* @returns The unwrapped value
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { signal, computed, toValue } from '@bquery/bquery/reactive';
|
|
49
|
+
*
|
|
50
|
+
* const count = signal(5);
|
|
51
|
+
* const doubled = computed(() => count.value * 2);
|
|
52
|
+
*
|
|
53
|
+
* toValue(42); // 42
|
|
54
|
+
* toValue(count); // 5
|
|
55
|
+
* toValue(doubled); // 10
|
|
56
|
+
* toValue(null); // null
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export const toValue = <T>(source: MaybeSignal<T>): T => {
|
|
60
|
+
if (source instanceof Signal || source instanceof Computed) {
|
|
61
|
+
return source.value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (isReadonlySignal<T>(source)) {
|
|
65
|
+
return source.value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Remaining values are plain `T` inputs. Structural readonly-like objects that are not
|
|
69
|
+
// branded bQuery wrappers intentionally fall through and are returned unchanged.
|
|
70
|
+
return source as T;
|
|
71
|
+
};
|