@bquery/bquery 1.7.0 → 1.8.2
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 +760 -716
- package/dist/{a11y-C5QOVvRn.js → a11y-DVBCy09c.js} +3 -3
- package/dist/a11y-DVBCy09c.js.map +1 -0
- package/dist/a11y.es.mjs +1 -1
- package/dist/component/library.d.ts.map +1 -1
- package/dist/{component-CuuTijA6.js → component-L3-JfOFz.js} +5 -5
- package/dist/component-L3-JfOFz.js.map +1 -0
- package/dist/component.es.mjs +1 -1
- package/dist/{config-BW35FKuA.js → config-DhT9auRm.js} +1 -1
- package/dist/{config-BW35FKuA.js.map → config-DhT9auRm.js.map} +1 -1
- package/dist/{constraints-3lV9yyBw.js → constraints-D5RHQLmP.js} +1 -1
- package/dist/constraints-D5RHQLmP.js.map +1 -0
- package/dist/core/collection.d.ts +86 -0
- package/dist/core/collection.d.ts.map +1 -1
- package/dist/core/element.d.ts +28 -0
- package/dist/core/element.d.ts.map +1 -1
- package/dist/core/shared.d.ts +6 -0
- package/dist/core/shared.d.ts.map +1 -1
- package/dist/core-DdtZHzsS.js +168 -0
- package/dist/core-DdtZHzsS.js.map +1 -0
- package/dist/{core-Cjl7GUu8.js → core-EMYSLzaT.js} +289 -259
- package/dist/core-EMYSLzaT.js.map +1 -0
- package/dist/core.es.mjs +48 -47
- package/dist/{custom-directives-7wAShnnd.js → custom-directives-Dr4C5lVV.js} +1 -1
- package/dist/custom-directives-Dr4C5lVV.js.map +1 -0
- package/dist/{devtools-D2fQLhDN.js → devtools-BhB2iDPT.js} +2 -2
- package/dist/devtools-BhB2iDPT.js.map +1 -0
- package/dist/devtools.es.mjs +1 -1
- package/dist/{dnd-B8EgyzaI.js → dnd-NwZBYh4l.js} +1 -1
- package/dist/dnd-NwZBYh4l.js.map +1 -0
- package/dist/dnd.es.mjs +1 -1
- package/dist/{env-NeVmr4Gf.js → env-CTdvLaH2.js} +1 -1
- package/dist/env-CTdvLaH2.js.map +1 -0
- package/dist/forms/create-form.d.ts.map +1 -1
- package/dist/forms/index.d.ts +3 -2
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/types.d.ts +46 -0
- package/dist/forms/types.d.ts.map +1 -1
- 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 +25 -0
- package/dist/forms/validators.d.ts.map +1 -1
- package/dist/forms-UcRHsYxC.js +227 -0
- package/dist/forms-UcRHsYxC.js.map +1 -0
- package/dist/forms.es.mjs +14 -12
- package/dist/full.d.ts +17 -26
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +206 -181
- package/dist/full.iife.js +33 -33
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +33 -33
- 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-BnnhTFOS.js → i18n-kuF6Ekj6.js} +3 -3
- package/dist/i18n-kuF6Ekj6.js.map +1 -0
- package/dist/i18n.es.mjs +1 -1
- package/dist/index.es.mjs +251 -228
- package/dist/media/breakpoints.d.ts.map +1 -1
- package/dist/media/types.d.ts +2 -2
- package/dist/media/types.d.ts.map +1 -1
- package/dist/{media-Di2Ta22s.js → media-i-fB5WxI.js} +3 -3
- package/dist/media-i-fB5WxI.js.map +1 -0
- package/dist/media.es.mjs +1 -1
- package/dist/{motion-qPj_TYGv.js → motion-BJsAuULb.js} +2 -2
- package/dist/motion-BJsAuULb.js.map +1 -0
- package/dist/motion.es.mjs +1 -1
- package/dist/{mount-SM07RUa6.js → mount-B4Y8bk8Z.js} +5 -5
- package/dist/mount-B4Y8bk8Z.js.map +1 -0
- package/dist/{platform-CPbCprb6.js → platform-Dw2gE3zI.js} +3 -3
- package/dist/{platform-CPbCprb6.js.map → platform-Dw2gE3zI.js.map} +1 -1
- package/dist/platform.es.mjs +2 -2
- package/dist/plugin/registry.d.ts.map +1 -1
- package/dist/{plugin-cPoOHFLY.js → plugin-C2WuC8SF.js} +20 -18
- package/dist/plugin-C2WuC8SF.js.map +1 -0
- package/dist/plugin.es.mjs +1 -1
- 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 +3 -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 -19
- package/dist/{registry-CWf368tT.js → registry-B08iilIh.js} +1 -1
- package/dist/{registry-CWf368tT.js.map → registry-B08iilIh.js.map} +1 -1
- package/dist/router/constraints.d.ts.map +1 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/router/index.d.ts.map +1 -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-CQikC9Ed.js +492 -0
- package/dist/router-CQikC9Ed.js.map +1 -0
- package/dist/router.es.mjs +9 -8
- package/dist/ssr/hydrate.d.ts.map +1 -1
- package/dist/{ssr-B2qd_WBB.js → ssr-_dAcGdzu.js} +4 -4
- package/dist/ssr-_dAcGdzu.js.map +1 -0
- package/dist/ssr.es.mjs +1 -1
- package/dist/store/persisted.d.ts.map +1 -1
- package/dist/{store-DWpyH6p5.js → store-Cb3gPRve.js} +7 -7
- package/dist/store-Cb3gPRve.js.map +1 -0
- package/dist/store.es.mjs +2 -2
- package/dist/storybook.es.mjs.map +1 -1
- package/dist/{testing-CsqjNUyy.js → testing-C5Sjfsna.js} +8 -8
- package/dist/testing-C5Sjfsna.js.map +1 -0
- package/dist/testing.es.mjs +1 -1
- package/dist/{type-guards-Do9DWgNp.js → type-guards-BMX2c0LP.js} +1 -1
- package/dist/{type-guards-Do9DWgNp.js.map → type-guards-BMX2c0LP.js.map} +1 -1
- package/dist/untrack-D0fnO5k2.js +36 -0
- package/dist/untrack-D0fnO5k2.js.map +1 -0
- package/dist/view/custom-directives.d.ts.map +1 -1
- package/dist/view.es.mjs +4 -4
- package/package.json +178 -177
- package/src/a11y/announce.ts +131 -131
- package/src/a11y/audit.ts +314 -314
- package/src/a11y/index.ts +68 -68
- package/src/a11y/media-preferences.ts +255 -255
- package/src/a11y/roving-tab-index.ts +164 -164
- package/src/a11y/skip-link.ts +255 -255
- package/src/a11y/trap-focus.ts +184 -184
- package/src/a11y/types.ts +183 -183
- package/src/component/component.ts +599 -599
- package/src/component/html.ts +153 -153
- package/src/component/index.ts +52 -52
- package/src/component/library.ts +540 -542
- package/src/component/scope.ts +212 -212
- package/src/component/types.ts +310 -310
- package/src/core/collection.ts +876 -707
- package/src/core/element.ts +1015 -981
- package/src/core/env.ts +60 -60
- package/src/core/index.ts +49 -49
- package/src/core/shared.ts +77 -62
- package/src/core/utils/index.ts +148 -148
- package/src/devtools/devtools.ts +410 -410
- package/src/devtools/index.ts +48 -48
- package/src/devtools/types.ts +104 -104
- package/src/dnd/draggable.ts +296 -296
- package/src/dnd/droppable.ts +228 -228
- package/src/dnd/index.ts +62 -62
- package/src/dnd/sortable.ts +307 -307
- package/src/dnd/types.ts +293 -293
- package/src/forms/create-form.ts +320 -278
- package/src/forms/index.ts +70 -65
- package/src/forms/types.ts +203 -154
- package/src/forms/use-field.ts +231 -0
- package/src/forms/validators.ts +294 -265
- package/src/full.ts +554 -480
- package/src/i18n/formatting.ts +67 -67
- package/src/i18n/i18n.ts +200 -200
- package/src/i18n/index.ts +67 -67
- package/src/i18n/translate.ts +182 -182
- package/src/i18n/types.ts +171 -171
- package/src/index.ts +108 -108
- package/src/media/battery.ts +116 -116
- package/src/media/breakpoints.ts +129 -131
- package/src/media/clipboard.ts +80 -80
- package/src/media/device-sensors.ts +158 -158
- package/src/media/geolocation.ts +119 -119
- package/src/media/index.ts +76 -76
- package/src/media/media-query.ts +92 -92
- package/src/media/network.ts +115 -115
- package/src/media/types.ts +177 -177
- package/src/media/viewport.ts +84 -84
- package/src/motion/index.ts +57 -57
- package/src/motion/morph.ts +151 -151
- package/src/motion/parallax.ts +120 -120
- package/src/motion/reduced-motion.ts +66 -66
- package/src/motion/types.ts +271 -271
- package/src/motion/typewriter.ts +164 -164
- package/src/plugin/index.ts +37 -37
- package/src/plugin/registry.ts +284 -269
- package/src/plugin/types.ts +137 -137
- package/src/reactive/async-data.ts +250 -29
- package/src/reactive/computed.ts +144 -130
- 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 -279
- package/src/router/constraints.ts +204 -201
- package/src/router/index.ts +49 -49
- package/src/router/match.ts +312 -312
- package/src/router/path-pattern.ts +52 -52
- package/src/router/query.ts +38 -38
- package/src/router/router.ts +421 -402
- package/src/router/state.ts +51 -3
- package/src/router/types.ts +139 -139
- package/src/router/use-route.ts +68 -68
- package/src/router/utils.ts +157 -157
- package/src/security/index.ts +12 -12
- package/src/ssr/hydrate.ts +84 -82
- package/src/ssr/index.ts +70 -70
- package/src/ssr/render.ts +508 -508
- package/src/ssr/serialize.ts +296 -296
- package/src/ssr/types.ts +81 -81
- package/src/store/create-store.ts +467 -467
- package/src/store/index.ts +27 -27
- package/src/store/persisted.ts +245 -249
- package/src/store/types.ts +247 -247
- package/src/store/utils.ts +135 -135
- package/src/storybook/index.ts +480 -480
- package/src/testing/index.ts +42 -42
- package/src/testing/testing.ts +593 -593
- package/src/testing/types.ts +170 -170
- package/src/view/custom-directives.ts +28 -30
- package/src/view/evaluate.ts +292 -292
- package/src/view/process.ts +108 -108
- package/dist/a11y-C5QOVvRn.js.map +0 -1
- package/dist/component-CuuTijA6.js.map +0 -1
- package/dist/constraints-3lV9yyBw.js.map +0 -1
- package/dist/core-Cjl7GUu8.js.map +0 -1
- package/dist/core-DnlyjbF2.js +0 -112
- package/dist/core-DnlyjbF2.js.map +0 -1
- package/dist/custom-directives-7wAShnnd.js.map +0 -1
- package/dist/devtools-D2fQLhDN.js.map +0 -1
- package/dist/dnd-B8EgyzaI.js.map +0 -1
- package/dist/env-NeVmr4Gf.js.map +0 -1
- package/dist/forms-C3yovgH9.js +0 -141
- package/dist/forms-C3yovgH9.js.map +0 -1
- package/dist/i18n-BnnhTFOS.js.map +0 -1
- package/dist/media-Di2Ta22s.js.map +0 -1
- package/dist/motion-qPj_TYGv.js.map +0 -1
- package/dist/mount-SM07RUa6.js.map +0 -1
- package/dist/plugin-cPoOHFLY.js.map +0 -1
- package/dist/reactive-Cfv0RK6x.js +0 -233
- package/dist/reactive-Cfv0RK6x.js.map +0 -1
- package/dist/router-BrthaP_z.js +0 -473
- package/dist/router-BrthaP_z.js.map +0 -1
- package/dist/ssr-B2qd_WBB.js.map +0 -1
- package/dist/store-DWpyH6p5.js.map +0 -1
- package/dist/testing-CsqjNUyy.js.map +0 -1
- package/dist/untrack-DJVQQ2WM.js +0 -33
- package/dist/untrack-DJVQQ2WM.js.map +0 -1
package/src/media/index.ts
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* bQuery Media module — reactive browser and device API signals.
|
|
3
|
-
*
|
|
4
|
-
* Provides reactive wrappers around browser media queries, viewport,
|
|
5
|
-
* network status, battery, geolocation, device sensors, and clipboard.
|
|
6
|
-
*
|
|
7
|
-
* @module bquery/media
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { mediaQuery, breakpoints, useViewport, useNetworkStatus, clipboard } from '@bquery/bquery/media';
|
|
12
|
-
* import { effect } from '@bquery/bquery/reactive';
|
|
13
|
-
*
|
|
14
|
-
* // Reactive media query
|
|
15
|
-
* const isDark = mediaQuery('(prefers-color-scheme: dark)');
|
|
16
|
-
*
|
|
17
|
-
* // Named breakpoints
|
|
18
|
-
* const bp = breakpoints({ sm: 640, md: 768, lg: 1024, xl: 1280 });
|
|
19
|
-
*
|
|
20
|
-
* // Viewport tracking
|
|
21
|
-
* const viewport = useViewport();
|
|
22
|
-
* effect(() => console.log(viewport.value.width));
|
|
23
|
-
*
|
|
24
|
-
* // Network status
|
|
25
|
-
* const net = useNetworkStatus();
|
|
26
|
-
* effect(() => console.log('Online:', net.value.online));
|
|
27
|
-
*
|
|
28
|
-
* // Clipboard
|
|
29
|
-
* await clipboard.write('Hello!');
|
|
30
|
-
* const text = await clipboard.read();
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
// Media query
|
|
35
|
-
export { mediaQuery } from './media-query';
|
|
36
|
-
|
|
37
|
-
// Breakpoints
|
|
38
|
-
export { breakpoints } from './breakpoints';
|
|
39
|
-
|
|
40
|
-
// Viewport
|
|
41
|
-
export { useViewport } from './viewport';
|
|
42
|
-
|
|
43
|
-
// Network
|
|
44
|
-
export { useNetworkStatus } from './network';
|
|
45
|
-
|
|
46
|
-
// Battery
|
|
47
|
-
export { useBattery } from './battery';
|
|
48
|
-
|
|
49
|
-
// Geolocation
|
|
50
|
-
export { useGeolocation } from './geolocation';
|
|
51
|
-
|
|
52
|
-
// Device sensors
|
|
53
|
-
export { useDeviceMotion, useDeviceOrientation } from './device-sensors';
|
|
54
|
-
|
|
55
|
-
// Clipboard
|
|
56
|
-
export { clipboard } from './clipboard';
|
|
57
|
-
|
|
58
|
-
// Types
|
|
59
|
-
export type {
|
|
60
|
-
BatterySignal,
|
|
61
|
-
BatteryState,
|
|
62
|
-
BreakpointMap,
|
|
63
|
-
ClipboardAPI,
|
|
64
|
-
DeviceMotionSignal,
|
|
65
|
-
DeviceMotionState,
|
|
66
|
-
DeviceOrientationSignal,
|
|
67
|
-
DeviceOrientationState,
|
|
68
|
-
GeolocationOptions,
|
|
69
|
-
GeolocationSignal,
|
|
70
|
-
GeolocationState,
|
|
71
|
-
MediaSignalHandle,
|
|
72
|
-
NetworkSignal,
|
|
73
|
-
NetworkState,
|
|
74
|
-
ViewportSignal,
|
|
75
|
-
ViewportState,
|
|
76
|
-
} from './types';
|
|
1
|
+
/**
|
|
2
|
+
* bQuery Media module — reactive browser and device API signals.
|
|
3
|
+
*
|
|
4
|
+
* Provides reactive wrappers around browser media queries, viewport,
|
|
5
|
+
* network status, battery, geolocation, device sensors, and clipboard.
|
|
6
|
+
*
|
|
7
|
+
* @module bquery/media
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { mediaQuery, breakpoints, useViewport, useNetworkStatus, clipboard } from '@bquery/bquery/media';
|
|
12
|
+
* import { effect } from '@bquery/bquery/reactive';
|
|
13
|
+
*
|
|
14
|
+
* // Reactive media query
|
|
15
|
+
* const isDark = mediaQuery('(prefers-color-scheme: dark)');
|
|
16
|
+
*
|
|
17
|
+
* // Named breakpoints
|
|
18
|
+
* const bp = breakpoints({ sm: 640, md: 768, lg: 1024, xl: 1280 });
|
|
19
|
+
*
|
|
20
|
+
* // Viewport tracking
|
|
21
|
+
* const viewport = useViewport();
|
|
22
|
+
* effect(() => console.log(viewport.value.width));
|
|
23
|
+
*
|
|
24
|
+
* // Network status
|
|
25
|
+
* const net = useNetworkStatus();
|
|
26
|
+
* effect(() => console.log('Online:', net.value.online));
|
|
27
|
+
*
|
|
28
|
+
* // Clipboard
|
|
29
|
+
* await clipboard.write('Hello!');
|
|
30
|
+
* const text = await clipboard.read();
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
// Media query
|
|
35
|
+
export { mediaQuery } from './media-query';
|
|
36
|
+
|
|
37
|
+
// Breakpoints
|
|
38
|
+
export { breakpoints } from './breakpoints';
|
|
39
|
+
|
|
40
|
+
// Viewport
|
|
41
|
+
export { useViewport } from './viewport';
|
|
42
|
+
|
|
43
|
+
// Network
|
|
44
|
+
export { useNetworkStatus } from './network';
|
|
45
|
+
|
|
46
|
+
// Battery
|
|
47
|
+
export { useBattery } from './battery';
|
|
48
|
+
|
|
49
|
+
// Geolocation
|
|
50
|
+
export { useGeolocation } from './geolocation';
|
|
51
|
+
|
|
52
|
+
// Device sensors
|
|
53
|
+
export { useDeviceMotion, useDeviceOrientation } from './device-sensors';
|
|
54
|
+
|
|
55
|
+
// Clipboard
|
|
56
|
+
export { clipboard } from './clipboard';
|
|
57
|
+
|
|
58
|
+
// Types
|
|
59
|
+
export type {
|
|
60
|
+
BatterySignal,
|
|
61
|
+
BatteryState,
|
|
62
|
+
BreakpointMap,
|
|
63
|
+
ClipboardAPI,
|
|
64
|
+
DeviceMotionSignal,
|
|
65
|
+
DeviceMotionState,
|
|
66
|
+
DeviceOrientationSignal,
|
|
67
|
+
DeviceOrientationState,
|
|
68
|
+
GeolocationOptions,
|
|
69
|
+
GeolocationSignal,
|
|
70
|
+
GeolocationState,
|
|
71
|
+
MediaSignalHandle,
|
|
72
|
+
NetworkSignal,
|
|
73
|
+
NetworkState,
|
|
74
|
+
ViewportSignal,
|
|
75
|
+
ViewportState,
|
|
76
|
+
} from './types';
|
package/src/media/media-query.ts
CHANGED
|
@@ -1,92 +1,92 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reactive media query matching.
|
|
3
|
-
*
|
|
4
|
-
* Returns a reactive boolean signal that tracks whether a CSS media query matches.
|
|
5
|
-
*
|
|
6
|
-
* @module bquery/media
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { readonly, signal } from '../reactive/index';
|
|
10
|
-
import type { MediaSignalHandle } from './types';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Creates a reactive signal that tracks whether a CSS media query matches.
|
|
14
|
-
*
|
|
15
|
-
* Uses `window.matchMedia()` under the hood and automatically updates
|
|
16
|
-
* when the match state changes (e.g., on window resize, device orientation change).
|
|
17
|
-
*
|
|
18
|
-
* @param query - A valid CSS media query string (e.g., `'(min-width: 768px)'`)
|
|
19
|
-
* @returns A readonly reactive signal that is `true` when the query matches,
|
|
20
|
-
* plus a `destroy()` method to remove the media query listener
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* import { mediaQuery } from '@bquery/bquery/media';
|
|
25
|
-
* import { effect } from '@bquery/bquery/reactive';
|
|
26
|
-
*
|
|
27
|
-
* const isDark = mediaQuery('(prefers-color-scheme: dark)');
|
|
28
|
-
* effect(() => {
|
|
29
|
-
* document.body.classList.toggle('dark', isDark.value);
|
|
30
|
-
* });
|
|
31
|
-
*
|
|
32
|
-
* const isWide = mediaQuery('(min-width: 1024px)');
|
|
33
|
-
* effect(() => {
|
|
34
|
-
* console.log('Wide screen:', isWide.value);
|
|
35
|
-
* });
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export const mediaQuery = (query: string): MediaSignalHandle<boolean> => {
|
|
39
|
-
const s = signal(false);
|
|
40
|
-
let cleanup: (() => void) | undefined;
|
|
41
|
-
|
|
42
|
-
if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
|
|
43
|
-
try {
|
|
44
|
-
const mql = window.matchMedia(query);
|
|
45
|
-
s.value = mql.matches;
|
|
46
|
-
|
|
47
|
-
const handler = (e: MediaQueryListEvent): void => {
|
|
48
|
-
s.value = e.matches;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
if (typeof mql.addEventListener === 'function') {
|
|
52
|
-
mql.addEventListener('change', handler);
|
|
53
|
-
cleanup = () => {
|
|
54
|
-
mql.removeEventListener('change', handler);
|
|
55
|
-
};
|
|
56
|
-
} else if (
|
|
57
|
-
typeof (
|
|
58
|
-
mql as MediaQueryList & {
|
|
59
|
-
addListener?: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
60
|
-
removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
61
|
-
}
|
|
62
|
-
).addListener === 'function'
|
|
63
|
-
) {
|
|
64
|
-
const legacyMql = mql as MediaQueryList & {
|
|
65
|
-
addListener: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
66
|
-
removeListener: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
67
|
-
};
|
|
68
|
-
legacyMql.addListener(handler);
|
|
69
|
-
cleanup = () => {
|
|
70
|
-
legacyMql.removeListener(handler);
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
} catch {
|
|
74
|
-
// matchMedia may throw in non-browser environments
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const ro = readonly(s) as MediaSignalHandle<boolean>;
|
|
79
|
-
let destroyed = false;
|
|
80
|
-
Object.defineProperty(ro, 'destroy', {
|
|
81
|
-
enumerable: false,
|
|
82
|
-
configurable: true,
|
|
83
|
-
value(): void {
|
|
84
|
-
if (destroyed) return;
|
|
85
|
-
destroyed = true;
|
|
86
|
-
cleanup?.();
|
|
87
|
-
s.dispose();
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return ro;
|
|
92
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Reactive media query matching.
|
|
3
|
+
*
|
|
4
|
+
* Returns a reactive boolean signal that tracks whether a CSS media query matches.
|
|
5
|
+
*
|
|
6
|
+
* @module bquery/media
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readonly, signal } from '../reactive/index';
|
|
10
|
+
import type { MediaSignalHandle } from './types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates a reactive signal that tracks whether a CSS media query matches.
|
|
14
|
+
*
|
|
15
|
+
* Uses `window.matchMedia()` under the hood and automatically updates
|
|
16
|
+
* when the match state changes (e.g., on window resize, device orientation change).
|
|
17
|
+
*
|
|
18
|
+
* @param query - A valid CSS media query string (e.g., `'(min-width: 768px)'`)
|
|
19
|
+
* @returns A readonly reactive signal that is `true` when the query matches,
|
|
20
|
+
* plus a `destroy()` method to remove the media query listener
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { mediaQuery } from '@bquery/bquery/media';
|
|
25
|
+
* import { effect } from '@bquery/bquery/reactive';
|
|
26
|
+
*
|
|
27
|
+
* const isDark = mediaQuery('(prefers-color-scheme: dark)');
|
|
28
|
+
* effect(() => {
|
|
29
|
+
* document.body.classList.toggle('dark', isDark.value);
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const isWide = mediaQuery('(min-width: 1024px)');
|
|
33
|
+
* effect(() => {
|
|
34
|
+
* console.log('Wide screen:', isWide.value);
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export const mediaQuery = (query: string): MediaSignalHandle<boolean> => {
|
|
39
|
+
const s = signal(false);
|
|
40
|
+
let cleanup: (() => void) | undefined;
|
|
41
|
+
|
|
42
|
+
if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
|
|
43
|
+
try {
|
|
44
|
+
const mql = window.matchMedia(query);
|
|
45
|
+
s.value = mql.matches;
|
|
46
|
+
|
|
47
|
+
const handler = (e: MediaQueryListEvent): void => {
|
|
48
|
+
s.value = e.matches;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if (typeof mql.addEventListener === 'function') {
|
|
52
|
+
mql.addEventListener('change', handler);
|
|
53
|
+
cleanup = () => {
|
|
54
|
+
mql.removeEventListener('change', handler);
|
|
55
|
+
};
|
|
56
|
+
} else if (
|
|
57
|
+
typeof (
|
|
58
|
+
mql as MediaQueryList & {
|
|
59
|
+
addListener?: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
60
|
+
removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
61
|
+
}
|
|
62
|
+
).addListener === 'function'
|
|
63
|
+
) {
|
|
64
|
+
const legacyMql = mql as MediaQueryList & {
|
|
65
|
+
addListener: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
66
|
+
removeListener: (listener: (event: MediaQueryListEvent) => void) => void;
|
|
67
|
+
};
|
|
68
|
+
legacyMql.addListener(handler);
|
|
69
|
+
cleanup = () => {
|
|
70
|
+
legacyMql.removeListener(handler);
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// matchMedia may throw in non-browser environments
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const ro = readonly(s) as MediaSignalHandle<boolean>;
|
|
79
|
+
let destroyed = false;
|
|
80
|
+
Object.defineProperty(ro, 'destroy', {
|
|
81
|
+
enumerable: false,
|
|
82
|
+
configurable: true,
|
|
83
|
+
value(): void {
|
|
84
|
+
if (destroyed) return;
|
|
85
|
+
destroyed = true;
|
|
86
|
+
cleanup?.();
|
|
87
|
+
s.dispose();
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return ro;
|
|
92
|
+
};
|
package/src/media/network.ts
CHANGED
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reactive network status.
|
|
3
|
-
*
|
|
4
|
-
* Provides a reactive signal tracking the browser's network connectivity
|
|
5
|
-
* and connection quality via the Network Information API.
|
|
6
|
-
*
|
|
7
|
-
* @module bquery/media
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { readonly, signal } from '../reactive/index';
|
|
11
|
-
import type { NetworkSignal, NetworkState } from './types';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Navigator connection interface for the Network Information API.
|
|
15
|
-
* @internal
|
|
16
|
-
*/
|
|
17
|
-
interface NavigatorConnection extends EventTarget {
|
|
18
|
-
effectiveType?: string;
|
|
19
|
-
downlink?: number;
|
|
20
|
-
rtt?: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Extended Navigator with connection property.
|
|
25
|
-
* @internal
|
|
26
|
-
*/
|
|
27
|
-
interface NavigatorWithConnection extends Navigator {
|
|
28
|
-
connection?: NavigatorConnection;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Reads current network state from browser APIs.
|
|
33
|
-
* @internal
|
|
34
|
-
*/
|
|
35
|
-
const getNetworkState = (): NetworkState => {
|
|
36
|
-
const online =
|
|
37
|
-
typeof navigator !== 'undefined' && navigator.onLine !== undefined ? navigator.onLine : true;
|
|
38
|
-
|
|
39
|
-
const nav = typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;
|
|
40
|
-
const conn = nav?.connection;
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
online,
|
|
44
|
-
effectiveType: conn?.effectiveType ?? 'unknown',
|
|
45
|
-
downlink: conn?.downlink ?? 0,
|
|
46
|
-
rtt: conn?.rtt ?? 0,
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Returns a reactive signal tracking network connectivity and quality.
|
|
52
|
-
*
|
|
53
|
-
* Tracks whether the browser is online/offline and, where supported,
|
|
54
|
-
* the effective connection type, downlink speed, and round-trip time
|
|
55
|
-
* via the Network Information API.
|
|
56
|
-
*
|
|
57
|
-
* @returns A readonly reactive signal with `{ online, effectiveType, downlink, rtt }`
|
|
58
|
-
* and a `destroy()` method to remove attached listeners
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```ts
|
|
62
|
-
* import { useNetworkStatus } from '@bquery/bquery/media';
|
|
63
|
-
* import { effect } from '@bquery/bquery/reactive';
|
|
64
|
-
*
|
|
65
|
-
* const net = useNetworkStatus();
|
|
66
|
-
* effect(() => {
|
|
67
|
-
* if (!net.value.online) {
|
|
68
|
-
* console.warn('You are offline!');
|
|
69
|
-
* }
|
|
70
|
-
* console.log(`Connection: ${net.value.effectiveType}, RTT: ${net.value.rtt}ms`);
|
|
71
|
-
* });
|
|
72
|
-
* ```
|
|
73
|
-
*/
|
|
74
|
-
export const useNetworkStatus = (): NetworkSignal => {
|
|
75
|
-
const s = signal<NetworkState>(getNetworkState());
|
|
76
|
-
let cleanup: (() => void) | undefined;
|
|
77
|
-
|
|
78
|
-
if (typeof window !== 'undefined') {
|
|
79
|
-
const update = (): void => {
|
|
80
|
-
s.value = getNetworkState();
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
window.addEventListener('online', update);
|
|
84
|
-
window.addEventListener('offline', update);
|
|
85
|
-
|
|
86
|
-
const nav =
|
|
87
|
-
typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;
|
|
88
|
-
if (nav?.connection && typeof nav.connection.addEventListener === 'function') {
|
|
89
|
-
nav.connection.addEventListener('change', update);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
cleanup = () => {
|
|
93
|
-
window.removeEventListener('online', update);
|
|
94
|
-
window.removeEventListener('offline', update);
|
|
95
|
-
if (nav?.connection && typeof nav.connection.removeEventListener === 'function') {
|
|
96
|
-
nav.connection.removeEventListener('change', update);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const ro = readonly(s) as NetworkSignal;
|
|
102
|
-
let destroyed = false;
|
|
103
|
-
Object.defineProperty(ro, 'destroy', {
|
|
104
|
-
value(): void {
|
|
105
|
-
if (destroyed) return;
|
|
106
|
-
destroyed = true;
|
|
107
|
-
cleanup?.();
|
|
108
|
-
s.dispose();
|
|
109
|
-
},
|
|
110
|
-
enumerable: false,
|
|
111
|
-
configurable: true,
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
return ro;
|
|
115
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Reactive network status.
|
|
3
|
+
*
|
|
4
|
+
* Provides a reactive signal tracking the browser's network connectivity
|
|
5
|
+
* and connection quality via the Network Information API.
|
|
6
|
+
*
|
|
7
|
+
* @module bquery/media
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readonly, signal } from '../reactive/index';
|
|
11
|
+
import type { NetworkSignal, NetworkState } from './types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Navigator connection interface for the Network Information API.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
interface NavigatorConnection extends EventTarget {
|
|
18
|
+
effectiveType?: string;
|
|
19
|
+
downlink?: number;
|
|
20
|
+
rtt?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Extended Navigator with connection property.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
interface NavigatorWithConnection extends Navigator {
|
|
28
|
+
connection?: NavigatorConnection;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Reads current network state from browser APIs.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
const getNetworkState = (): NetworkState => {
|
|
36
|
+
const online =
|
|
37
|
+
typeof navigator !== 'undefined' && navigator.onLine !== undefined ? navigator.onLine : true;
|
|
38
|
+
|
|
39
|
+
const nav = typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;
|
|
40
|
+
const conn = nav?.connection;
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
online,
|
|
44
|
+
effectiveType: conn?.effectiveType ?? 'unknown',
|
|
45
|
+
downlink: conn?.downlink ?? 0,
|
|
46
|
+
rtt: conn?.rtt ?? 0,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns a reactive signal tracking network connectivity and quality.
|
|
52
|
+
*
|
|
53
|
+
* Tracks whether the browser is online/offline and, where supported,
|
|
54
|
+
* the effective connection type, downlink speed, and round-trip time
|
|
55
|
+
* via the Network Information API.
|
|
56
|
+
*
|
|
57
|
+
* @returns A readonly reactive signal with `{ online, effectiveType, downlink, rtt }`
|
|
58
|
+
* and a `destroy()` method to remove attached listeners
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { useNetworkStatus } from '@bquery/bquery/media';
|
|
63
|
+
* import { effect } from '@bquery/bquery/reactive';
|
|
64
|
+
*
|
|
65
|
+
* const net = useNetworkStatus();
|
|
66
|
+
* effect(() => {
|
|
67
|
+
* if (!net.value.online) {
|
|
68
|
+
* console.warn('You are offline!');
|
|
69
|
+
* }
|
|
70
|
+
* console.log(`Connection: ${net.value.effectiveType}, RTT: ${net.value.rtt}ms`);
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export const useNetworkStatus = (): NetworkSignal => {
|
|
75
|
+
const s = signal<NetworkState>(getNetworkState());
|
|
76
|
+
let cleanup: (() => void) | undefined;
|
|
77
|
+
|
|
78
|
+
if (typeof window !== 'undefined') {
|
|
79
|
+
const update = (): void => {
|
|
80
|
+
s.value = getNetworkState();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
window.addEventListener('online', update);
|
|
84
|
+
window.addEventListener('offline', update);
|
|
85
|
+
|
|
86
|
+
const nav =
|
|
87
|
+
typeof navigator !== 'undefined' ? (navigator as NavigatorWithConnection) : undefined;
|
|
88
|
+
if (nav?.connection && typeof nav.connection.addEventListener === 'function') {
|
|
89
|
+
nav.connection.addEventListener('change', update);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
cleanup = () => {
|
|
93
|
+
window.removeEventListener('online', update);
|
|
94
|
+
window.removeEventListener('offline', update);
|
|
95
|
+
if (nav?.connection && typeof nav.connection.removeEventListener === 'function') {
|
|
96
|
+
nav.connection.removeEventListener('change', update);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const ro = readonly(s) as NetworkSignal;
|
|
102
|
+
let destroyed = false;
|
|
103
|
+
Object.defineProperty(ro, 'destroy', {
|
|
104
|
+
value(): void {
|
|
105
|
+
if (destroyed) return;
|
|
106
|
+
destroyed = true;
|
|
107
|
+
cleanup?.();
|
|
108
|
+
s.dispose();
|
|
109
|
+
},
|
|
110
|
+
enumerable: false,
|
|
111
|
+
configurable: true,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return ro;
|
|
115
|
+
};
|