@vizejs/composable 0.426.3 → 0.428.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/dist/abort-signal.d.mts +1 -1
- package/dist/active-element.d.mts +37 -0
- package/dist/active-element.mjs +56 -0
- package/dist/animate.d.mts +114 -0
- package/dist/animate.mjs +157 -0
- package/dist/battery.d.mts +61 -0
- package/dist/battery.mjs +90 -0
- package/dist/breakpoints.d.mts +82 -0
- package/dist/breakpoints.mjs +91 -0
- package/dist/catalog-BeTXFKxF.d.mts +4188 -0
- package/dist/catalog-r4Z5nptX.mjs +5144 -0
- package/dist/catalog.d.mts +1 -1
- package/dist/catalog.mjs +1 -1
- package/dist/color-mode.d.mts +131 -0
- package/dist/color-mode.mjs +133 -0
- package/dist/computed-async.d.mts +63 -0
- package/dist/computed-async.mjs +43 -0
- package/dist/computed-with-control.d.mts +44 -0
- package/dist/computed-with-control.mjs +54 -0
- package/dist/create-event-hook.d.mts +77 -0
- package/dist/create-event-hook.mjs +66 -0
- package/dist/create-global-state.d.mts +24 -0
- package/dist/create-global-state.mjs +34 -0
- package/dist/create-injection-state.d.mts +51 -0
- package/dist/create-injection-state.mjs +19 -0
- package/dist/create-shared-composable.d.mts +38 -0
- package/dist/create-shared-composable.mjs +54 -0
- package/dist/device-motion.d.mts +71 -0
- package/dist/device-motion.mjs +75 -0
- package/dist/device-orientation.d.mts +82 -0
- package/dist/device-orientation.mjs +86 -0
- package/dist/device-pixel-ratio.d.mts +45 -0
- package/dist/device-pixel-ratio.mjs +50 -0
- package/dist/document-visibility.mjs +6 -2
- package/dist/draggable.d.mts +121 -0
- package/dist/draggable.mjs +153 -0
- package/dist/element-bounding.d.mts +87 -0
- package/dist/element-bounding.mjs +95 -0
- package/dist/element-by-point.d.mts +70 -0
- package/dist/element-by-point.mjs +69 -0
- package/dist/element-hover.d.mts +42 -0
- package/dist/element-hover.mjs +70 -0
- package/dist/element-ref.d.mts +34 -0
- package/dist/element-ref.mjs +23 -0
- package/dist/element-target-Crpxl4D9.d.mts +60 -0
- package/dist/element-target.d.mts +2 -0
- package/dist/element-target.mjs +58 -0
- package/dist/event-listener.mjs +7 -3
- package/dist/focus.d.mts +69 -0
- package/dist/focus.mjs +124 -0
- package/dist/fps.d.mts +59 -0
- package/dist/fps.mjs +64 -0
- package/dist/geolocation.d.mts +98 -0
- package/dist/geolocation.mjs +86 -0
- package/dist/i18n.d.mts +237 -0
- package/dist/i18n.mjs +215 -0
- package/dist/icu-message.d.mts +235 -0
- package/dist/icu-message.mjs +343 -0
- package/dist/idle.d.mts +79 -0
- package/dist/idle.mjs +90 -0
- package/dist/index.d.mts +172 -6
- package/dist/index.mjs +173 -7
- package/dist/infinite-scroll.d.mts +56 -0
- package/dist/infinite-scroll.mjs +72 -0
- package/dist/intersection-observer.d.mts +122 -0
- package/dist/intersection-observer.mjs +117 -0
- package/dist/magic-keys.d.mts +121 -0
- package/dist/magic-keys.mjs +163 -0
- package/dist/math.d.mts +96 -0
- package/dist/math.mjs +84 -0
- package/dist/media-query.d.mts +3 -1
- package/dist/media-query.mjs +5 -3
- package/dist/mouse-in-element.d.mts +49 -0
- package/dist/mouse-in-element.mjs +66 -0
- package/dist/mouse.d.mts +77 -0
- package/dist/mouse.mjs +100 -0
- package/dist/mutation-observer.d.mts +98 -0
- package/dist/mutation-observer.mjs +69 -0
- package/dist/network.d.mts +96 -0
- package/dist/network.mjs +117 -0
- package/dist/on-click-outside.d.mts +69 -0
- package/dist/on-click-outside.mjs +115 -0
- package/dist/on-key-stroke.d.mts +71 -0
- package/dist/on-key-stroke.mjs +79 -0
- package/dist/on-long-press.d.mts +82 -0
- package/dist/on-long-press.mjs +105 -0
- package/dist/on-start-typing.d.mts +44 -0
- package/dist/on-start-typing.mjs +61 -0
- package/dist/page-leave.d.mts +26 -0
- package/dist/page-leave.mjs +40 -0
- package/dist/parent-element.d.mts +16 -0
- package/dist/parent-element.mjs +27 -0
- package/dist/pinch.d.mts +73 -0
- package/dist/pinch.mjs +138 -0
- package/dist/pointer-lock.d.mts +79 -0
- package/dist/pointer-lock.mjs +126 -0
- package/dist/pointer.d.mts +78 -0
- package/dist/pointer.mjs +95 -0
- package/dist/preferences.d.mts +55 -0
- package/dist/preferences.mjs +63 -0
- package/dist/preferred-languages.d.mts +43 -0
- package/dist/preferred-languages.mjs +44 -0
- package/dist/reactify.d.mts +28 -0
- package/dist/reactify.mjs +7 -0
- package/dist/ref-auto-reset.d.mts +47 -0
- package/dist/ref-auto-reset.mjs +70 -0
- package/dist/ref-debounced.d.mts +29 -0
- package/dist/ref-debounced.mjs +29 -0
- package/dist/ref-default.d.mts +27 -0
- package/dist/ref-default.mjs +33 -0
- package/dist/resize-observer.d.mts +96 -0
- package/dist/resize-observer.mjs +111 -0
- package/dist/resolver.d.mts +124 -0
- package/dist/resolver.mjs +138 -0
- package/dist/retry-async.d.mts +2 -2
- package/dist/retry-delay-DYsdq4SE.d.mts +73 -0
- package/dist/retry-delay.d.mts +1 -72
- package/dist/screen-orientation.d.mts +77 -0
- package/dist/screen-orientation.mjs +74 -0
- package/dist/scroll-lock.d.mts +37 -0
- package/dist/scroll-lock.mjs +50 -0
- package/dist/scroll.d.mts +158 -0
- package/dist/scroll.mjs +172 -0
- package/dist/standard-schema-DmNgFVK5.d.mts +107 -0
- package/dist/standard-schema.d.mts +2 -0
- package/dist/standard-schema.mjs +60 -0
- package/dist/swipe.d.mts +125 -0
- package/dist/swipe.mjs +225 -0
- package/dist/sync-ref.d.mts +80 -0
- package/dist/sync-ref.mjs +43 -0
- package/dist/text-selection.d.mts +46 -0
- package/dist/text-selection.mjs +62 -0
- package/dist/textarea-autosize.d.mts +58 -0
- package/dist/textarea-autosize.mjs +54 -0
- package/dist/timeout-scheduler-CI8RVLZs.d.mts +18 -0
- package/dist/timeout-scheduler.d.mts +1 -17
- package/dist/to-reactive.d.mts +26 -0
- package/dist/to-reactive.mjs +46 -0
- package/dist/transition.d.mts +125 -0
- package/dist/transition.mjs +266 -0
- package/dist/until.d.mts +177 -0
- package/dist/until.mjs +111 -0
- package/dist/use-array.d.mts +112 -0
- package/dist/use-array.mjs +90 -0
- package/dist/use-async-queue.d.mts +109 -0
- package/dist/use-async-queue.mjs +96 -0
- package/dist/use-async-state.d.mts +86 -0
- package/dist/use-async-state.mjs +41 -0
- package/dist/use-barcode-detector.d.mts +159 -0
- package/dist/use-barcode-detector.mjs +143 -0
- package/dist/use-bluetooth.d.mts +164 -0
- package/dist/use-bluetooth.mjs +183 -0
- package/dist/use-broadcast-channel.d.mts +115 -0
- package/dist/use-broadcast-channel.mjs +121 -0
- package/dist/use-builtin-ai.d.mts +342 -0
- package/dist/use-builtin-ai.mjs +261 -0
- package/dist/use-clipboard.d.mts +169 -0
- package/dist/use-clipboard.mjs +226 -0
- package/dist/use-compression-stream.d.mts +173 -0
- package/dist/use-compression-stream.mjs +166 -0
- package/dist/use-confirm-dialog.d.mts +70 -0
- package/dist/use-confirm-dialog.mjs +57 -0
- package/dist/use-contact-picker.d.mts +117 -0
- package/dist/use-contact-picker.mjs +103 -0
- package/dist/use-cookie.d.mts +196 -0
- package/dist/use-cookie.mjs +259 -0
- package/dist/use-countdown.d.mts +85 -0
- package/dist/use-countdown.mjs +74 -0
- package/dist/use-css-var.d.mts +96 -0
- package/dist/use-css-var.mjs +104 -0
- package/dist/use-cycle-list.d.mts +76 -0
- package/dist/use-cycle-list.mjs +39 -0
- package/dist/use-date-format.d.mts +103 -0
- package/dist/use-date-format.mjs +147 -0
- package/dist/use-date-time-format.d.mts +75 -0
- package/dist/use-date-time-format.mjs +53 -0
- package/dist/use-debounced.d.mts +1 -1
- package/dist/use-display-media.d.mts +62 -0
- package/dist/use-display-media.mjs +46 -0
- package/dist/use-display-names.d.mts +75 -0
- package/dist/use-display-names.mjs +52 -0
- package/dist/use-document-title.d.mts +88 -0
- package/dist/use-document-title.mjs +100 -0
- package/dist/use-drop-zone.d.mts +128 -0
- package/dist/use-drop-zone.mjs +154 -0
- package/dist/use-event-source.d.mts +184 -0
- package/dist/use-event-source.mjs +226 -0
- package/dist/use-eye-dropper.d.mts +79 -0
- package/dist/use-eye-dropper.mjs +68 -0
- package/dist/use-favicon.d.mts +78 -0
- package/dist/use-favicon.mjs +68 -0
- package/dist/use-fetch.d.mts +230 -0
- package/dist/use-fetch.mjs +263 -0
- package/dist/use-field.d.mts +107 -0
- package/dist/use-field.mjs +117 -0
- package/dist/use-file-dialog.d.mts +139 -0
- package/dist/use-file-dialog.mjs +101 -0
- package/dist/use-file-system-access.d.mts +184 -0
- package/dist/use-file-system-access.mjs +151 -0
- package/dist/use-form-field-props.d.mts +235 -0
- package/dist/use-form-field-props.mjs +164 -0
- package/dist/use-form.d.mts +324 -0
- package/dist/use-form.mjs +482 -0
- package/dist/use-fullscreen.d.mts +104 -0
- package/dist/use-fullscreen.mjs +95 -0
- package/dist/use-gamepad.d.mts +242 -0
- package/dist/use-gamepad.mjs +218 -0
- package/dist/use-hid.d.mts +160 -0
- package/dist/use-hid.mjs +156 -0
- package/dist/use-id-generator.d.mts +44 -0
- package/dist/use-id-generator.mjs +38 -0
- package/dist/use-image.d.mts +125 -0
- package/dist/use-image.mjs +109 -0
- package/dist/use-indexed-db.d.mts +207 -0
- package/dist/use-indexed-db.mjs +251 -0
- package/dist/use-interval-BA55gTHT.d.mts +140 -0
- package/dist/use-interval.d.mts +2 -0
- package/dist/use-interval.mjs +100 -0
- package/dist/use-list-format.d.mts +60 -0
- package/dist/use-list-format.mjs +40 -0
- package/dist/use-machine.d.mts +90 -0
- package/dist/use-machine.mjs +78 -0
- package/dist/use-map.d.mts +90 -0
- package/dist/use-map.mjs +70 -0
- package/dist/use-media-controls.d.mts +198 -0
- package/dist/use-media-controls.mjs +264 -0
- package/dist/use-memoize.d.mts +73 -0
- package/dist/use-memoize.mjs +28 -0
- package/dist/use-mounted.d.mts +24 -0
- package/dist/use-mounted.mjs +29 -0
- package/dist/use-navigation-api.d.mts +360 -0
- package/dist/use-navigation-api.mjs +231 -0
- package/dist/use-notification.d.mts +139 -0
- package/dist/use-notification.mjs +131 -0
- package/dist/use-now.d.mts +137 -0
- package/dist/use-now.mjs +44 -0
- package/dist/use-number-format.d.mts +73 -0
- package/dist/use-number-format.mjs +58 -0
- package/dist/use-object-url.d.mts +47 -0
- package/dist/use-object-url.mjs +54 -0
- package/dist/use-offset-pagination.d.mts +91 -0
- package/dist/use-offset-pagination.mjs +80 -0
- package/dist/use-payment-request.d.mts +239 -0
- package/dist/use-payment-request.mjs +206 -0
- package/dist/use-performance-observer.d.mts +285 -0
- package/dist/use-performance-observer.mjs +132 -0
- package/dist/use-permission.d.mts +99 -0
- package/dist/use-permission.mjs +92 -0
- package/dist/use-plural-rules.d.mts +79 -0
- package/dist/use-plural-rules.mjs +59 -0
- package/dist/use-push-subscription.d.mts +154 -0
- package/dist/use-push-subscription.mjs +146 -0
- package/dist/use-queue.d.mts +89 -0
- package/dist/use-queue.mjs +116 -0
- package/dist/use-raf-fn.d.mts +87 -0
- package/dist/use-raf-fn.mjs +99 -0
- package/dist/use-relative-time-format.d.mts +111 -0
- package/dist/use-relative-time-format.mjs +119 -0
- package/dist/use-request-idle-callback.d.mts +122 -0
- package/dist/use-request-idle-callback.mjs +147 -0
- package/dist/use-route-query.d.mts +149 -0
- package/dist/use-route-query.mjs +86 -0
- package/dist/use-scheduler-post-task.d.mts +156 -0
- package/dist/use-scheduler-post-task.mjs +182 -0
- package/dist/use-screen-details.d.mts +205 -0
- package/dist/use-screen-details.mjs +188 -0
- package/dist/use-script-tag.d.mts +162 -0
- package/dist/use-script-tag.mjs +171 -0
- package/dist/use-segmenter.d.mts +78 -0
- package/dist/use-segmenter.mjs +66 -0
- package/dist/use-selection.d.mts +125 -0
- package/dist/use-selection.mjs +77 -0
- package/dist/use-serial.d.mts +165 -0
- package/dist/use-serial.mjs +205 -0
- package/dist/use-service-worker.d.mts +177 -0
- package/dist/use-service-worker.mjs +178 -0
- package/dist/use-set.d.mts +96 -0
- package/dist/use-set.mjs +74 -0
- package/dist/use-share.d.mts +92 -0
- package/dist/use-share.mjs +99 -0
- package/dist/use-sorted-locale.d.mts +62 -0
- package/dist/use-sorted-locale.mjs +52 -0
- package/dist/use-sorted.d.mts +29 -0
- package/dist/use-sorted.mjs +14 -0
- package/dist/use-speech-recognition.d.mts +150 -0
- package/dist/use-speech-recognition.mjs +168 -0
- package/dist/use-speech-synthesis.d.mts +148 -0
- package/dist/use-speech-synthesis.mjs +152 -0
- package/dist/use-stack.d.mts +83 -0
- package/dist/use-stack.mjs +93 -0
- package/dist/use-stepper.d.mts +79 -0
- package/dist/use-stepper.mjs +52 -0
- package/dist/use-storage-estimate.d.mts +151 -0
- package/dist/use-storage-estimate.mjs +170 -0
- package/dist/use-storage.d.mts +214 -0
- package/dist/use-storage.mjs +415 -0
- package/dist/use-style-tag.d.mts +102 -0
- package/dist/use-style-tag.mjs +91 -0
- package/dist/use-supported.d.mts +23 -0
- package/dist/use-supported.mjs +26 -0
- package/dist/use-throttled.d.mts +1 -1
- package/dist/use-time-ago.d.mts +163 -0
- package/dist/use-time-ago.mjs +95 -0
- package/dist/use-timeout.d.mts +122 -0
- package/dist/use-timeout.mjs +65 -0
- package/dist/use-url-hash.d.mts +88 -0
- package/dist/use-url-hash.mjs +145 -0
- package/dist/use-url-search-params.d.mts +223 -0
- package/dist/use-url-search-params.mjs +295 -0
- package/dist/use-usb.d.mts +212 -0
- package/dist/use-usb.mjs +137 -0
- package/dist/use-user-activation.d.mts +83 -0
- package/dist/use-user-activation.mjs +113 -0
- package/dist/use-user-media.d.mts +194 -0
- package/dist/use-user-media.mjs +214 -0
- package/dist/use-v-model.d.mts +113 -0
- package/dist/use-v-model.mjs +40 -0
- package/dist/use-vibrate.d.mts +81 -0
- package/dist/use-vibrate.mjs +90 -0
- package/dist/use-view-transition.d.mts +106 -0
- package/dist/use-view-transition.mjs +101 -0
- package/dist/use-visual-viewport.d.mts +105 -0
- package/dist/use-visual-viewport.mjs +104 -0
- package/dist/use-wake-lock.d.mts +96 -0
- package/dist/use-wake-lock.mjs +106 -0
- package/dist/use-web-authn.d.mts +404 -0
- package/dist/use-web-authn.mjs +323 -0
- package/dist/use-web-locks.d.mts +180 -0
- package/dist/use-web-locks.mjs +136 -0
- package/dist/use-web-midi.d.mts +148 -0
- package/dist/use-web-midi.mjs +140 -0
- package/dist/use-web-vitals.d.mts +142 -0
- package/dist/use-web-vitals.mjs +248 -0
- package/dist/use-websocket.d.mts +218 -0
- package/dist/use-websocket.mjs +257 -0
- package/dist/use-worker-fn.d.mts +119 -0
- package/dist/use-worker-fn.mjs +162 -0
- package/dist/virtual-list.d.mts +105 -0
- package/dist/virtual-list.mjs +128 -0
- package/dist/watch-debounced.d.mts +84 -0
- package/dist/watch-debounced.mjs +84 -0
- package/dist/watch-ignorable.d.mts +47 -0
- package/dist/watch-ignorable.mjs +61 -0
- package/dist/watch-once.d.mts +29 -0
- package/dist/watch-once.mjs +10 -0
- package/dist/watch-pausable.d.mts +51 -0
- package/dist/watch-pausable.mjs +23 -0
- package/dist/watch-source.d.mts +29 -0
- package/dist/watch-source.mjs +1 -0
- package/dist/watch-throttled.d.mts +70 -0
- package/dist/watch-throttled.mjs +94 -0
- package/dist/whenever.d.mts +39 -0
- package/dist/whenever.mjs +41 -0
- package/dist/window-size.d.mts +87 -0
- package/dist/window-size.mjs +65 -0
- package/package.json +846 -5
- package/registry/files/abort-signal.ts +292 -0
- package/registry/files/active-element.ts +93 -0
- package/registry/files/animate.ts +322 -0
- package/registry/files/async-resource.ts +190 -0
- package/registry/files/battery.ts +166 -0
- package/registry/files/breakpoints.ts +166 -0
- package/registry/files/capability.ts +171 -0
- package/registry/files/color-mode.ts +274 -0
- package/registry/files/computed-async.ts +123 -0
- package/registry/files/computed-with-control.ts +80 -0
- package/registry/files/create-event-hook.ts +139 -0
- package/registry/files/create-global-state.ts +34 -0
- package/registry/files/create-injection-state.ts +75 -0
- package/registry/files/create-shared-composable.ts +74 -0
- package/registry/files/device-motion.ts +152 -0
- package/registry/files/device-orientation.ts +168 -0
- package/registry/files/device-pixel-ratio.ts +100 -0
- package/registry/files/disposal-scope.ts +201 -0
- package/registry/files/document-visibility.ts +152 -0
- package/registry/files/draggable.ts +273 -0
- package/registry/files/element-bounding.ts +175 -0
- package/registry/files/element-by-point.ts +149 -0
- package/registry/files/element-hover.ts +104 -0
- package/registry/files/element-ref.ts +58 -0
- package/registry/files/element-target.ts +99 -0
- package/registry/files/event-listener.ts +188 -0
- package/registry/files/focus.ts +181 -0
- package/registry/files/fps.ts +133 -0
- package/registry/files/geolocation.ts +214 -0
- package/registry/files/i18n.ts +524 -0
- package/registry/files/icu-message.ts +701 -0
- package/registry/files/idle.ts +176 -0
- package/registry/files/infinite-scroll.ts +135 -0
- package/registry/files/intersection-observer.ts +261 -0
- package/registry/files/locale.ts +148 -0
- package/registry/files/magic-keys.ts +298 -0
- package/registry/files/math.ts +175 -0
- package/registry/files/media-query.ts +102 -0
- package/registry/files/mouse-in-element.ts +107 -0
- package/registry/files/mouse.ts +167 -0
- package/registry/files/mutation-observer.ts +183 -0
- package/registry/files/network.ts +229 -0
- package/registry/files/on-click-outside.ts +178 -0
- package/registry/files/on-key-stroke.ts +135 -0
- package/registry/files/on-long-press.ts +188 -0
- package/registry/files/on-start-typing.ts +88 -0
- package/registry/files/page-leave.ts +57 -0
- package/registry/files/parent-element.ts +29 -0
- package/registry/files/pinch.ts +187 -0
- package/registry/files/pointer-lock.ts +232 -0
- package/registry/files/pointer.ts +153 -0
- package/registry/files/preferences.ts +98 -0
- package/registry/files/preferred-languages.ts +88 -0
- package/registry/files/reactify.ts +39 -0
- package/registry/files/ref-auto-reset.ts +102 -0
- package/registry/files/ref-debounced.ts +34 -0
- package/registry/files/ref-default.ts +35 -0
- package/registry/files/resize-observer.ts +220 -0
- package/registry/files/retry-async.ts +261 -0
- package/registry/files/retry-delay.ts +132 -0
- package/registry/files/scope.ts +21 -0
- package/registry/files/screen-orientation.ts +165 -0
- package/registry/files/scroll-lock.ts +80 -0
- package/registry/files/scroll.ts +338 -0
- package/registry/files/standard-schema.ts +163 -0
- package/registry/files/swipe.ts +321 -0
- package/registry/files/sync-ref.ts +166 -0
- package/registry/files/temporal.ts +182 -0
- package/registry/files/text-selection.ts +110 -0
- package/registry/files/textarea-autosize.ts +114 -0
- package/registry/files/timeout-scheduler.ts +16 -0
- package/registry/files/to-reactive.ts +44 -0
- package/registry/files/transition.ts +271 -0
- package/registry/files/until.ts +352 -0
- package/registry/files/use-array.ts +201 -0
- package/registry/files/use-async-queue.ts +278 -0
- package/registry/files/use-async-state.ts +139 -0
- package/registry/files/use-barcode-detector.ts +321 -0
- package/registry/files/use-bluetooth.ts +409 -0
- package/registry/files/use-broadcast-channel.ts +250 -0
- package/registry/files/use-builtin-ai.ts +674 -0
- package/registry/files/use-clipboard.ts +425 -0
- package/registry/files/use-compression-stream.ts +364 -0
- package/registry/files/use-confirm-dialog.ts +137 -0
- package/registry/files/use-contact-picker.ts +246 -0
- package/registry/files/use-cookie.ts +500 -0
- package/registry/files/use-countdown.ts +161 -0
- package/registry/files/use-counter.ts +147 -0
- package/registry/files/use-css-var.ts +191 -0
- package/registry/files/use-cycle-list.ts +136 -0
- package/registry/files/use-date-format.ts +281 -0
- package/registry/files/use-date-time-format.ts +113 -0
- package/registry/files/use-debounced.ts +163 -0
- package/registry/files/use-display-media.ts +89 -0
- package/registry/files/use-display-names.ts +122 -0
- package/registry/files/use-document-title.ts +196 -0
- package/registry/files/use-drop-zone.ts +287 -0
- package/registry/files/use-event-source.ts +470 -0
- package/registry/files/use-eye-dropper.ts +134 -0
- package/registry/files/use-favicon.ts +140 -0
- package/registry/files/use-fetch.ts +578 -0
- package/registry/files/use-field.ts +247 -0
- package/registry/files/use-file-dialog.ts +257 -0
- package/registry/files/use-file-system-access.ts +383 -0
- package/registry/files/use-form-field-props.ts +381 -0
- package/registry/files/use-form.ts +980 -0
- package/registry/files/use-fullscreen.ts +214 -0
- package/registry/files/use-gamepad.ts +463 -0
- package/registry/files/use-hid.ts +359 -0
- package/registry/files/use-history.ts +231 -0
- package/registry/files/use-id-generator.ts +61 -0
- package/registry/files/use-image.ts +253 -0
- package/registry/files/use-indexed-db.ts +508 -0
- package/registry/files/use-interval.ts +253 -0
- package/registry/files/use-list-format.ts +85 -0
- package/registry/files/use-machine.ts +171 -0
- package/registry/files/use-map.ts +145 -0
- package/registry/files/use-media-controls.ts +545 -0
- package/registry/files/use-memoize.ts +118 -0
- package/registry/files/use-mounted.ts +30 -0
- package/registry/files/use-navigation-api.ts +641 -0
- package/registry/files/use-notification.ts +285 -0
- package/registry/files/use-now.ts +194 -0
- package/registry/files/use-number-format.ts +120 -0
- package/registry/files/use-object-url.ts +87 -0
- package/registry/files/use-offset-pagination.ts +168 -0
- package/registry/files/use-payment-request.ts +465 -0
- package/registry/files/use-performance-observer.ts +469 -0
- package/registry/files/use-permission.ts +220 -0
- package/registry/files/use-plural-rules.ts +134 -0
- package/registry/files/use-previous.ts +62 -0
- package/registry/files/use-push-subscription.ts +352 -0
- package/registry/files/use-queue.ts +197 -0
- package/registry/files/use-raf-fn.ts +176 -0
- package/registry/files/use-relative-time-format.ts +201 -0
- package/registry/files/use-request-idle-callback.ts +278 -0
- package/registry/files/use-route-query.ts +300 -0
- package/registry/files/use-scheduler-post-task.ts +397 -0
- package/registry/files/use-screen-details.ts +393 -0
- package/registry/files/use-script-tag.ts +341 -0
- package/registry/files/use-segmenter.ts +147 -0
- package/registry/files/use-selection.ts +233 -0
- package/registry/files/use-serial.ts +404 -0
- package/registry/files/use-service-worker.ts +413 -0
- package/registry/files/use-set.ts +154 -0
- package/registry/files/use-share.ts +168 -0
- package/registry/files/use-sorted-locale.ts +130 -0
- package/registry/files/use-sorted.ts +49 -0
- package/registry/files/use-speech-recognition.ts +357 -0
- package/registry/files/use-speech-synthesis.ts +333 -0
- package/registry/files/use-stack.ts +164 -0
- package/registry/files/use-stepper.ts +166 -0
- package/registry/files/use-storage-estimate.ts +352 -0
- package/registry/files/use-storage.ts +635 -0
- package/registry/files/use-style-tag.ts +200 -0
- package/registry/files/use-supported.ts +26 -0
- package/registry/files/use-throttled.ts +215 -0
- package/registry/files/use-time-ago.ts +276 -0
- package/registry/files/use-timeout.ts +218 -0
- package/registry/files/use-toggle.ts +54 -0
- package/registry/files/use-url-hash.ts +280 -0
- package/registry/files/use-url-search-params.ts +497 -0
- package/registry/files/use-usb.ts +395 -0
- package/registry/files/use-user-activation.ts +215 -0
- package/registry/files/use-user-media.ts +422 -0
- package/registry/files/use-v-model.ts +210 -0
- package/registry/files/use-vibrate.ts +174 -0
- package/registry/files/use-view-transition.ts +229 -0
- package/registry/files/use-visual-viewport.ts +228 -0
- package/registry/files/use-wake-lock.ts +206 -0
- package/registry/files/use-web-authn.ts +793 -0
- package/registry/files/use-web-locks.ts +363 -0
- package/registry/files/use-web-midi.ts +306 -0
- package/registry/files/use-web-vitals.ts +409 -0
- package/registry/files/use-websocket.ts +553 -0
- package/registry/files/use-worker-fn.ts +306 -0
- package/registry/files/virtual-list.ts +230 -0
- package/registry/files/watch-debounced.ts +206 -0
- package/registry/files/watch-ignorable.ts +128 -0
- package/registry/files/watch-once.ts +46 -0
- package/registry/files/watch-pausable.ts +93 -0
- package/registry/files/watch-source.ts +51 -0
- package/registry/files/watch-throttled.ts +201 -0
- package/registry/files/whenever.ts +70 -0
- package/registry/files/window-size.ts +151 -0
- package/registry/registry.json +5792 -0
- package/dist/catalog-D2AL3xYl.d.mts +0 -523
- package/dist/catalog-D5SYCsgW.mjs +0 -549
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computed,
|
|
3
|
+
hasInjectionContext,
|
|
4
|
+
readonly,
|
|
5
|
+
ref,
|
|
6
|
+
shallowReadonly,
|
|
7
|
+
shallowRef,
|
|
8
|
+
toValue,
|
|
9
|
+
watch,
|
|
10
|
+
watchPostEffect,
|
|
11
|
+
} from "vue";
|
|
12
|
+
import type { ComputedRef, MaybeRefOrGetter, Ref, ShallowRef } from "vue";
|
|
13
|
+
|
|
14
|
+
import { tryOnScopeDispose } from "./scope.ts";
|
|
15
|
+
|
|
16
|
+
/** GATT service or characteristic UUID: a full UUID string, an alias name, or a 16/32-bit number. */
|
|
17
|
+
export type BluetoothUUIDLike = string | number;
|
|
18
|
+
|
|
19
|
+
/** Scan filter for `requestDevice`. */
|
|
20
|
+
export interface BluetoothDeviceFilter {
|
|
21
|
+
/** Services the device must advertise. */
|
|
22
|
+
readonly services?: readonly BluetoothUUIDLike[];
|
|
23
|
+
/** Exact device name. */
|
|
24
|
+
readonly name?: string;
|
|
25
|
+
/** Device name prefix. */
|
|
26
|
+
readonly namePrefix?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Options for `requestDevice`: explicit filters or every nearby device. */
|
|
30
|
+
export type BluetoothRequestOptions =
|
|
31
|
+
| {
|
|
32
|
+
/** Accepted device filters. */
|
|
33
|
+
readonly filters: readonly BluetoothDeviceFilter[];
|
|
34
|
+
/** Extra services the page may access. */
|
|
35
|
+
readonly optionalServices?: readonly BluetoothUUIDLike[];
|
|
36
|
+
}
|
|
37
|
+
| {
|
|
38
|
+
/** Offer every nearby device. */
|
|
39
|
+
readonly acceptAllDevices: true;
|
|
40
|
+
/** Extra services the page may access. */
|
|
41
|
+
readonly optionalServices?: readonly BluetoothUUIDLike[];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** Minimal `BluetoothRemoteGATTCharacteristic` used by {@link useBluetooth}. */
|
|
45
|
+
export interface BluetoothCharacteristicLike extends EventTarget {
|
|
46
|
+
/** Last read or notified value. */
|
|
47
|
+
readonly value?: DataView | null | undefined;
|
|
48
|
+
/** Read the value. */
|
|
49
|
+
readValue(): Promise<DataView>;
|
|
50
|
+
/** Write and wait for the device's acknowledgement. */
|
|
51
|
+
writeValueWithResponse(value: BufferSource): Promise<void>;
|
|
52
|
+
/** Write without acknowledgement. */
|
|
53
|
+
writeValueWithoutResponse(value: BufferSource): Promise<void>;
|
|
54
|
+
/** Start `characteristicvaluechanged` notifications. */
|
|
55
|
+
startNotifications(): Promise<unknown>;
|
|
56
|
+
/** Stop notifications. */
|
|
57
|
+
stopNotifications(): Promise<unknown>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Minimal `BluetoothRemoteGATTService`. */
|
|
61
|
+
export interface BluetoothServiceLike {
|
|
62
|
+
/** Look up a characteristic. */
|
|
63
|
+
getCharacteristic(characteristic: BluetoothUUIDLike): Promise<BluetoothCharacteristicLike>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Minimal `BluetoothRemoteGATTServer`. */
|
|
67
|
+
export interface BluetoothGATTServerLike {
|
|
68
|
+
/** Whether the server is connected. */
|
|
69
|
+
readonly connected: boolean;
|
|
70
|
+
/** Connect to the server. */
|
|
71
|
+
connect(): Promise<unknown>;
|
|
72
|
+
/** Disconnect from the server. */
|
|
73
|
+
disconnect(): void;
|
|
74
|
+
/** Look up a primary service. */
|
|
75
|
+
getPrimaryService(service: BluetoothUUIDLike): Promise<BluetoothServiceLike>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Minimal `BluetoothDevice` used by {@link useBluetooth}. */
|
|
79
|
+
export interface BluetoothDeviceLike extends EventTarget {
|
|
80
|
+
/** Opaque device identifier. */
|
|
81
|
+
readonly id: string;
|
|
82
|
+
/** Advertised name. */
|
|
83
|
+
readonly name?: string | undefined;
|
|
84
|
+
/** GATT server, when the device supports GATT. */
|
|
85
|
+
readonly gatt?: BluetoothGATTServerLike | undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** `navigator.bluetooth`-like capability used by {@link useBluetooth}. */
|
|
89
|
+
export interface BluetoothHost extends EventTarget {
|
|
90
|
+
/** Whether a Bluetooth adapter is available. */
|
|
91
|
+
getAvailability(): Promise<boolean>;
|
|
92
|
+
/** Prompt the user for a device. */
|
|
93
|
+
requestDevice(options: BluetoothRequestOptions): Promise<BluetoothDeviceLike>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Options for {@link useBluetooth}. */
|
|
97
|
+
export interface UseBluetoothOptions {
|
|
98
|
+
/**
|
|
99
|
+
* `navigator.bluetooth`-like capability.
|
|
100
|
+
*
|
|
101
|
+
* @default window.navigator.bluetooth when it exists
|
|
102
|
+
*/
|
|
103
|
+
readonly host?: MaybeRefOrGetter<BluetoothHost | null | undefined>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Default options for `requestDevice()`.
|
|
107
|
+
*
|
|
108
|
+
* @default { acceptAllDevices: true }
|
|
109
|
+
*/
|
|
110
|
+
readonly requestOptions?: BluetoothRequestOptions;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Stops a notification subscription created by {@link BluetoothControls.notify}. */
|
|
114
|
+
export type BluetoothNotificationStop = () => Promise<void>;
|
|
115
|
+
|
|
116
|
+
/** Reactive state and actions returned by {@link useBluetooth}. */
|
|
117
|
+
export interface BluetoothControls {
|
|
118
|
+
/** Whether Web Bluetooth is available. */
|
|
119
|
+
readonly supported: ComputedRef<boolean>;
|
|
120
|
+
/** Whether an adapter is available, following `availabilitychanged`. */
|
|
121
|
+
readonly available: Readonly<Ref<boolean>>;
|
|
122
|
+
/** Most recently chosen device. */
|
|
123
|
+
readonly device: Readonly<ShallowRef<BluetoothDeviceLike | undefined>>;
|
|
124
|
+
/** Whether the device's GATT server is connected. */
|
|
125
|
+
readonly connected: Readonly<Ref<boolean>>;
|
|
126
|
+
/** Most recent failure. */
|
|
127
|
+
readonly error: Readonly<ShallowRef<unknown>>;
|
|
128
|
+
/**
|
|
129
|
+
* Prompt the user for a device (requires user activation). Disconnects
|
|
130
|
+
* the previous device.
|
|
131
|
+
*
|
|
132
|
+
* @returns The chosen device, or `undefined` when cancelled or failed.
|
|
133
|
+
*/
|
|
134
|
+
readonly requestDevice: (
|
|
135
|
+
options?: BluetoothRequestOptions,
|
|
136
|
+
) => Promise<BluetoothDeviceLike | undefined>;
|
|
137
|
+
/**
|
|
138
|
+
* Connect to the device's GATT server.
|
|
139
|
+
*
|
|
140
|
+
* @returns Whether the server is connected.
|
|
141
|
+
*/
|
|
142
|
+
readonly connect: () => Promise<boolean>;
|
|
143
|
+
/** Stop notifications and disconnect the GATT server. Idempotent. */
|
|
144
|
+
readonly disconnect: () => void;
|
|
145
|
+
/**
|
|
146
|
+
* Read a characteristic.
|
|
147
|
+
*
|
|
148
|
+
* @returns The value, or `undefined` on failure.
|
|
149
|
+
*/
|
|
150
|
+
readonly read: (
|
|
151
|
+
service: BluetoothUUIDLike,
|
|
152
|
+
characteristic: BluetoothUUIDLike,
|
|
153
|
+
) => Promise<DataView | undefined>;
|
|
154
|
+
/**
|
|
155
|
+
* Write a characteristic, with a response unless `withoutResponse`.
|
|
156
|
+
*
|
|
157
|
+
* @returns Whether the write succeeded.
|
|
158
|
+
*/
|
|
159
|
+
readonly write: (
|
|
160
|
+
service: BluetoothUUIDLike,
|
|
161
|
+
characteristic: BluetoothUUIDLike,
|
|
162
|
+
value: BufferSource,
|
|
163
|
+
options?: { readonly withoutResponse?: boolean },
|
|
164
|
+
) => Promise<boolean>;
|
|
165
|
+
/**
|
|
166
|
+
* Subscribe to characteristic notifications.
|
|
167
|
+
*
|
|
168
|
+
* @returns A stop function, or `undefined` on failure.
|
|
169
|
+
*/
|
|
170
|
+
readonly notify: (
|
|
171
|
+
service: BluetoothUUIDLike,
|
|
172
|
+
characteristic: BluetoothUUIDLike,
|
|
173
|
+
listener: (value: DataView) => void,
|
|
174
|
+
) => Promise<BluetoothNotificationStop | undefined>;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function browserBluetoothHost(): BluetoothHost | undefined {
|
|
178
|
+
if (typeof window === "undefined") return undefined;
|
|
179
|
+
const { navigator } = window;
|
|
180
|
+
// Web Bluetooth is not part of the DOM lib; read it through a structural guard.
|
|
181
|
+
const bluetooth: unknown = "bluetooth" in navigator ? navigator.bluetooth : undefined;
|
|
182
|
+
return isBluetoothHost(bluetooth) ? bluetooth : undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function isBluetoothHost(value: unknown): value is BluetoothHost {
|
|
186
|
+
return typeof value === "object" && value !== null && "requestDevice" in value;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function availabilityOf(event: Event): boolean | undefined {
|
|
190
|
+
return "value" in event && typeof event.value === "boolean" ? event.value : undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Connect to Bluetooth Low Energy devices with the Web Bluetooth API.
|
|
195
|
+
*
|
|
196
|
+
* `requestDevice()` prompts for a device, `connect()` connects its GATT
|
|
197
|
+
* server, and `read` / `write` / `notify` address characteristics by service
|
|
198
|
+
* and characteristic UUID. `connected` follows `gattserverdisconnected` and
|
|
199
|
+
* `available` follows `availabilitychanged`. Failures land in `error`.
|
|
200
|
+
* Notifications are stopped and the server disconnected when the owning
|
|
201
|
+
* reactive scope stops; outside a scope call `disconnect()`.
|
|
202
|
+
*
|
|
203
|
+
* Server rendering: `supported`, `available` and `connected` are false and
|
|
204
|
+
* nothing is queried.
|
|
205
|
+
* Inside a component the host is resolved after mounting, so hydration
|
|
206
|
+
* renders this server state first.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* const ble = useBluetooth({ requestOptions: { filters: [{ services: ["heart_rate"] }] } });
|
|
211
|
+
* await ble.requestDevice();
|
|
212
|
+
* await ble.connect();
|
|
213
|
+
* await ble.notify("heart_rate", "heart_rate_measurement", (value) => show(value.getUint8(1)));
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @param options Host and default request options.
|
|
217
|
+
* @default options {}
|
|
218
|
+
* @returns Bluetooth state and actions.
|
|
219
|
+
*/
|
|
220
|
+
export function useBluetooth(options: UseBluetoothOptions = {}): BluetoothControls {
|
|
221
|
+
const available = ref(false);
|
|
222
|
+
const device = shallowRef<BluetoothDeviceLike | undefined>(undefined);
|
|
223
|
+
const connected = ref(false);
|
|
224
|
+
const error = shallowRef<unknown>(undefined);
|
|
225
|
+
const notifications = new Set<BluetoothNotificationStop>();
|
|
226
|
+
|
|
227
|
+
// Inside a component the host is resolved only after mounting, so a
|
|
228
|
+
// hydrating client renders the server's unsupported state first. Outside
|
|
229
|
+
// components it resolves synchronously.
|
|
230
|
+
const hydrated = shallowRef(!hasInjectionContext());
|
|
231
|
+
if (!hydrated.value) {
|
|
232
|
+
watchPostEffect(() => {
|
|
233
|
+
hydrated.value = true;
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const resolveHost = (): BluetoothHost | undefined => {
|
|
238
|
+
if (!hydrated.value) return undefined;
|
|
239
|
+
return options.host === undefined
|
|
240
|
+
? browserBluetoothHost()
|
|
241
|
+
: (toValue(options.host) ?? undefined);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const onDisconnected = (): void => {
|
|
245
|
+
connected.value = false;
|
|
246
|
+
for (const stop of notifications) void stop();
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const disconnect = (): void => {
|
|
250
|
+
for (const stop of notifications) void stop();
|
|
251
|
+
notifications.clear();
|
|
252
|
+
device.value?.gatt?.disconnect();
|
|
253
|
+
connected.value = false;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const requestDevice = async (
|
|
257
|
+
requestOptions: BluetoothRequestOptions = options.requestOptions ?? { acceptAllDevices: true },
|
|
258
|
+
): Promise<BluetoothDeviceLike | undefined> => {
|
|
259
|
+
const host = resolveHost();
|
|
260
|
+
if (!host) return undefined;
|
|
261
|
+
try {
|
|
262
|
+
const chosen = await host.requestDevice(requestOptions);
|
|
263
|
+
disconnect();
|
|
264
|
+
device.value?.removeEventListener("gattserverdisconnected", onDisconnected);
|
|
265
|
+
chosen.addEventListener("gattserverdisconnected", onDisconnected);
|
|
266
|
+
device.value = chosen;
|
|
267
|
+
connected.value = chosen.gatt?.connected ?? false;
|
|
268
|
+
error.value = undefined;
|
|
269
|
+
return chosen;
|
|
270
|
+
} catch (cause) {
|
|
271
|
+
error.value = cause;
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const connect = async (): Promise<boolean> => {
|
|
277
|
+
const server = device.value?.gatt;
|
|
278
|
+
if (!server) return false;
|
|
279
|
+
try {
|
|
280
|
+
await server.connect();
|
|
281
|
+
connected.value = server.connected;
|
|
282
|
+
error.value = undefined;
|
|
283
|
+
} catch (cause) {
|
|
284
|
+
error.value = cause;
|
|
285
|
+
connected.value = false;
|
|
286
|
+
}
|
|
287
|
+
return connected.value;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const characteristicOf = async (
|
|
291
|
+
service: BluetoothUUIDLike,
|
|
292
|
+
characteristic: BluetoothUUIDLike,
|
|
293
|
+
): Promise<BluetoothCharacteristicLike> => {
|
|
294
|
+
const server = device.value?.gatt;
|
|
295
|
+
if (!server?.connected) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
"[VIZE_COMPOSE_BLUETOOTH_NOT_CONNECTED] connect() to a device before accessing characteristics",
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
return (await server.getPrimaryService(service)).getCharacteristic(characteristic);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const attempt = async <Value>(action: () => Promise<Value>): Promise<Value | undefined> => {
|
|
304
|
+
try {
|
|
305
|
+
const value = await action();
|
|
306
|
+
error.value = undefined;
|
|
307
|
+
return value;
|
|
308
|
+
} catch (cause) {
|
|
309
|
+
error.value = cause;
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const read = (
|
|
315
|
+
service: BluetoothUUIDLike,
|
|
316
|
+
characteristic: BluetoothUUIDLike,
|
|
317
|
+
): Promise<DataView | undefined> =>
|
|
318
|
+
attempt(async () => (await characteristicOf(service, characteristic)).readValue());
|
|
319
|
+
|
|
320
|
+
const write = async (
|
|
321
|
+
service: BluetoothUUIDLike,
|
|
322
|
+
characteristic: BluetoothUUIDLike,
|
|
323
|
+
value: BufferSource,
|
|
324
|
+
writeOptions: { readonly withoutResponse?: boolean } = {},
|
|
325
|
+
): Promise<boolean> =>
|
|
326
|
+
(await attempt(async () => {
|
|
327
|
+
const target = await characteristicOf(service, characteristic);
|
|
328
|
+
await ((writeOptions.withoutResponse ?? false)
|
|
329
|
+
? target.writeValueWithoutResponse(value)
|
|
330
|
+
: target.writeValueWithResponse(value));
|
|
331
|
+
return true;
|
|
332
|
+
})) === true;
|
|
333
|
+
|
|
334
|
+
const notify = (
|
|
335
|
+
service: BluetoothUUIDLike,
|
|
336
|
+
characteristic: BluetoothUUIDLike,
|
|
337
|
+
listener: (value: DataView) => void,
|
|
338
|
+
): Promise<BluetoothNotificationStop | undefined> =>
|
|
339
|
+
attempt(async () => {
|
|
340
|
+
const target = await characteristicOf(service, characteristic);
|
|
341
|
+
const onChange = (): void => {
|
|
342
|
+
if (target.value) listener(target.value);
|
|
343
|
+
};
|
|
344
|
+
target.addEventListener("characteristicvaluechanged", onChange);
|
|
345
|
+
try {
|
|
346
|
+
await target.startNotifications();
|
|
347
|
+
} catch (cause) {
|
|
348
|
+
target.removeEventListener("characteristicvaluechanged", onChange);
|
|
349
|
+
throw cause;
|
|
350
|
+
}
|
|
351
|
+
const stop: BluetoothNotificationStop = async () => {
|
|
352
|
+
if (!notifications.delete(stop)) return;
|
|
353
|
+
target.removeEventListener("characteristicvaluechanged", onChange);
|
|
354
|
+
try {
|
|
355
|
+
await target.stopNotifications();
|
|
356
|
+
} catch (cause) {
|
|
357
|
+
error.value = cause;
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
notifications.add(stop);
|
|
361
|
+
return stop;
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
watch(
|
|
365
|
+
resolveHost,
|
|
366
|
+
(host, _previous, onCleanup) => {
|
|
367
|
+
available.value = false;
|
|
368
|
+
if (!host) return;
|
|
369
|
+
let active = true;
|
|
370
|
+
const onAvailability = (event: Event): void => {
|
|
371
|
+
const value = availabilityOf(event);
|
|
372
|
+
if (value !== undefined) available.value = value;
|
|
373
|
+
};
|
|
374
|
+
host.addEventListener("availabilitychanged", onAvailability);
|
|
375
|
+
onCleanup(() => {
|
|
376
|
+
active = false;
|
|
377
|
+
host.removeEventListener("availabilitychanged", onAvailability);
|
|
378
|
+
});
|
|
379
|
+
host.getAvailability().then(
|
|
380
|
+
(value) => {
|
|
381
|
+
if (active) available.value = value;
|
|
382
|
+
},
|
|
383
|
+
(cause: unknown) => {
|
|
384
|
+
if (active) error.value = cause;
|
|
385
|
+
},
|
|
386
|
+
);
|
|
387
|
+
},
|
|
388
|
+
{ immediate: true, flush: "sync" },
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
tryOnScopeDispose(() => {
|
|
392
|
+
disconnect();
|
|
393
|
+
device.value?.removeEventListener("gattserverdisconnected", onDisconnected);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
supported: computed(() => resolveHost() !== undefined),
|
|
398
|
+
available: readonly(available),
|
|
399
|
+
device: shallowReadonly(device),
|
|
400
|
+
connected: readonly(connected),
|
|
401
|
+
error: readonly(error),
|
|
402
|
+
requestDevice,
|
|
403
|
+
connect,
|
|
404
|
+
disconnect,
|
|
405
|
+
read,
|
|
406
|
+
write,
|
|
407
|
+
notify,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasInjectionContext,
|
|
3
|
+
readonly,
|
|
4
|
+
ref,
|
|
5
|
+
shallowRef,
|
|
6
|
+
toValue,
|
|
7
|
+
watch,
|
|
8
|
+
watchPostEffect,
|
|
9
|
+
} from "vue";
|
|
10
|
+
import type { MaybeRefOrGetter, Ref, ShallowRef } from "vue";
|
|
11
|
+
|
|
12
|
+
import { tryOnScopeDispose } from "./scope.ts";
|
|
13
|
+
|
|
14
|
+
/** Minimal structural view of a `BroadcastChannel` instance. */
|
|
15
|
+
export interface BroadcastChannelLike extends EventTarget {
|
|
16
|
+
/** Post a structured-cloneable message to every other channel with the same name. */
|
|
17
|
+
readonly postMessage: (message: unknown) => void;
|
|
18
|
+
|
|
19
|
+
/** Close the channel; no further messages are delivered. */
|
|
20
|
+
readonly close: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Constructor creating channels, compatible with `window.BroadcastChannel`. */
|
|
24
|
+
export type BroadcastChannelConstructor = new (name: string) => BroadcastChannelLike;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Capability host exposing a channel constructor; `window` satisfies it.
|
|
28
|
+
*
|
|
29
|
+
* The constructor is wrapped in an object because a bare class would be
|
|
30
|
+
* mistaken for a getter by `MaybeRefOrGetter` resolution.
|
|
31
|
+
*/
|
|
32
|
+
export interface BroadcastChannelHost {
|
|
33
|
+
/** Channel constructor. */
|
|
34
|
+
readonly BroadcastChannel: BroadcastChannelConstructor;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Stable failure codes reported by {@link useBroadcastChannel}. */
|
|
38
|
+
export type BroadcastChannelErrorCode =
|
|
39
|
+
| "open-failed"
|
|
40
|
+
| "post-failed"
|
|
41
|
+
| "message-error"
|
|
42
|
+
| "invalid-message";
|
|
43
|
+
|
|
44
|
+
/** Failure observed while using a broadcast channel. */
|
|
45
|
+
export interface BroadcastChannelFailure {
|
|
46
|
+
/** Which step failed. */
|
|
47
|
+
readonly code: BroadcastChannelErrorCode;
|
|
48
|
+
|
|
49
|
+
/** Channel name involved in the failure. */
|
|
50
|
+
readonly name: string;
|
|
51
|
+
|
|
52
|
+
/** Exact thrown value, event, or rejected payload. */
|
|
53
|
+
readonly cause: unknown;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Options for {@link useBroadcastChannel}. */
|
|
57
|
+
export interface UseBroadcastChannelOptions<Message> {
|
|
58
|
+
/**
|
|
59
|
+
* Host exposing the channel constructor. `null`/`undefined` keeps the
|
|
60
|
+
* composable closed, which is also what happens during server rendering.
|
|
61
|
+
*
|
|
62
|
+
* @default window when it exposes `BroadcastChannel`
|
|
63
|
+
*/
|
|
64
|
+
readonly host?: MaybeRefOrGetter<BroadcastChannelHost | null | undefined>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Validate incoming payloads. Rejected payloads leave `data` untouched and
|
|
68
|
+
* report an `"invalid-message"` failure.
|
|
69
|
+
*
|
|
70
|
+
* @default every payload is accepted
|
|
71
|
+
*/
|
|
72
|
+
readonly validate?: (data: unknown) => data is Message;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Observe every accepted message.
|
|
76
|
+
*
|
|
77
|
+
* @default undefined
|
|
78
|
+
*/
|
|
79
|
+
readonly onMessage?: (message: Message) => void;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Observe failures. Failures never throw out of the composable.
|
|
83
|
+
*
|
|
84
|
+
* @default undefined
|
|
85
|
+
*/
|
|
86
|
+
readonly onError?: (failure: BroadcastChannelFailure) => void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Reactive state and controls returned by {@link useBroadcastChannel}. */
|
|
90
|
+
export interface BroadcastChannelControls<Message> {
|
|
91
|
+
/** Most recent accepted message received from another context. */
|
|
92
|
+
readonly data: Readonly<ShallowRef<Message | undefined>>;
|
|
93
|
+
|
|
94
|
+
/** Whether a channel constructor is available. */
|
|
95
|
+
readonly supported: Readonly<Ref<boolean>>;
|
|
96
|
+
|
|
97
|
+
/** Whether no channel is currently open. */
|
|
98
|
+
readonly closed: Readonly<Ref<boolean>>;
|
|
99
|
+
|
|
100
|
+
/** Most recent failure, cleared by the next successful post or message. */
|
|
101
|
+
readonly error: Readonly<ShallowRef<BroadcastChannelFailure | undefined>>;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Post a typed message.
|
|
105
|
+
*
|
|
106
|
+
* @param message Structured-cloneable payload.
|
|
107
|
+
* @returns Whether the message was handed to an open channel.
|
|
108
|
+
*/
|
|
109
|
+
readonly post: (message: Message) => boolean;
|
|
110
|
+
|
|
111
|
+
/** Close the channel and stop following the reactive name. Idempotent. */
|
|
112
|
+
readonly close: () => void;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function browserBroadcastChannelHost(): BroadcastChannelHost | undefined {
|
|
116
|
+
return typeof window !== "undefined" && typeof window.BroadcastChannel === "function"
|
|
117
|
+
? window
|
|
118
|
+
: undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Exchange typed messages with other tabs, windows, and workers of the same
|
|
123
|
+
* origin through the Broadcast Channel API.
|
|
124
|
+
*
|
|
125
|
+
* The channel follows the reactive `name`: changing it closes the old channel
|
|
126
|
+
* and opens a new one. The channel closes when the owning reactive scope
|
|
127
|
+
* stops or when `close()` is called; outside a scope the caller owns
|
|
128
|
+
* `close()`. Incoming payloads pass the `validate` type guard before they
|
|
129
|
+
* reach `data`, so foreign messages cannot widen the declared type.
|
|
130
|
+
*
|
|
131
|
+
* Server rendering: without a browser `window` no channel is opened (Node's
|
|
132
|
+
* global `BroadcastChannel` is ignored), `supported` is `false`, and `post`
|
|
133
|
+
* returns `false`.
|
|
134
|
+
*
|
|
135
|
+
* Inside a component the host is read after mounting, so hydration renders
|
|
136
|
+
* the server fallback first and never mismatches.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* type Sync = { readonly type: "logout" };
|
|
141
|
+
* const { data, post } = useBroadcastChannel<Sync>("auth");
|
|
142
|
+
* post({ type: "logout" });
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* @typeParam Message Payload type exchanged over the channel.
|
|
146
|
+
* @param name Reactive channel name.
|
|
147
|
+
* @param options Host, validation, and observation hooks.
|
|
148
|
+
* @default options {}
|
|
149
|
+
* @returns Reactive channel state and controls.
|
|
150
|
+
*/
|
|
151
|
+
export function useBroadcastChannel<Message>(
|
|
152
|
+
name: MaybeRefOrGetter<string>,
|
|
153
|
+
options: UseBroadcastChannelOptions<Message> = {},
|
|
154
|
+
): BroadcastChannelControls<Message> {
|
|
155
|
+
const data = shallowRef<Message | undefined>(undefined);
|
|
156
|
+
const error = shallowRef<BroadcastChannelFailure | undefined>(undefined);
|
|
157
|
+
const supported = ref(false);
|
|
158
|
+
const closed = ref(true);
|
|
159
|
+
let channel: BroadcastChannelLike | undefined;
|
|
160
|
+
let stopped = false;
|
|
161
|
+
// Inside a component the host is attached by a post-flush job (after the
|
|
162
|
+
// component mounted), so a hydrating client first renders the same server
|
|
163
|
+
// fallback. Outside components it is attached synchronously.
|
|
164
|
+
const hydrated = shallowRef(!hasInjectionContext());
|
|
165
|
+
if (!hydrated.value) {
|
|
166
|
+
watchPostEffect(() => {
|
|
167
|
+
hydrated.value = true;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const fail = (code: BroadcastChannelErrorCode, cause: unknown): void => {
|
|
172
|
+
const failure: BroadcastChannelFailure = { code, name: toValue(name), cause };
|
|
173
|
+
error.value = failure;
|
|
174
|
+
options.onError?.(failure);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const resolveHost = (): BroadcastChannelConstructor | undefined =>
|
|
178
|
+
(options.host === undefined ? browserBroadcastChannelHost() : toValue(options.host))
|
|
179
|
+
?.BroadcastChannel;
|
|
180
|
+
|
|
181
|
+
const onMessage = (event: Event): void => {
|
|
182
|
+
const payload: unknown = event instanceof MessageEvent ? event.data : undefined;
|
|
183
|
+
if (options.validate !== undefined && !options.validate(payload)) {
|
|
184
|
+
fail("invalid-message", payload);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// Without a validator the declared message type is trusted, as for
|
|
188
|
+
// `postMessage` peers of the same application.
|
|
189
|
+
const message = payload as Message;
|
|
190
|
+
error.value = undefined;
|
|
191
|
+
data.value = message;
|
|
192
|
+
options.onMessage?.(message);
|
|
193
|
+
};
|
|
194
|
+
const onMessageError = (event: Event): void => fail("message-error", event);
|
|
195
|
+
|
|
196
|
+
const stopWatch = watch(
|
|
197
|
+
[() => toValue(name), () => (hydrated.value ? resolveHost() : undefined)],
|
|
198
|
+
([channelName, Host], _previous, onCleanup) => {
|
|
199
|
+
supported.value = Host !== undefined;
|
|
200
|
+
if (Host === undefined || stopped) return;
|
|
201
|
+
let opened: BroadcastChannelLike;
|
|
202
|
+
try {
|
|
203
|
+
opened = new Host(channelName);
|
|
204
|
+
} catch (cause) {
|
|
205
|
+
fail("open-failed", cause);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
channel = opened;
|
|
209
|
+
closed.value = false;
|
|
210
|
+
opened.addEventListener("message", onMessage);
|
|
211
|
+
opened.addEventListener("messageerror", onMessageError);
|
|
212
|
+
onCleanup(() => {
|
|
213
|
+
opened.removeEventListener("message", onMessage);
|
|
214
|
+
opened.removeEventListener("messageerror", onMessageError);
|
|
215
|
+
opened.close();
|
|
216
|
+
if (channel === opened) channel = undefined;
|
|
217
|
+
closed.value = true;
|
|
218
|
+
});
|
|
219
|
+
},
|
|
220
|
+
{ immediate: true, flush: "sync" },
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const post = (message: Message): boolean => {
|
|
224
|
+
if (channel === undefined) return false;
|
|
225
|
+
try {
|
|
226
|
+
channel.postMessage(message);
|
|
227
|
+
} catch (cause) {
|
|
228
|
+
fail("post-failed", cause);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
error.value = undefined;
|
|
232
|
+
return true;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const close = (): void => {
|
|
236
|
+
stopped = true;
|
|
237
|
+
stopWatch();
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
tryOnScopeDispose(close);
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
data,
|
|
244
|
+
supported: readonly(supported),
|
|
245
|
+
closed: readonly(closed),
|
|
246
|
+
error,
|
|
247
|
+
post,
|
|
248
|
+
close,
|
|
249
|
+
};
|
|
250
|
+
}
|