diff --git a/packages/core/index.ts b/packages/core/index.ts index 8d8cc39019d..1ea1453c108 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -100,6 +100,7 @@ export * from './useStepper' export * from './useStorage' export * from './useStorageAsync' export * from './useStyleTag' +export * from './useSupported' export * from './useSwipe' export * from './useTemplateRefsList' export * from './useTextSelection' diff --git a/packages/core/useBattery/index.ts b/packages/core/useBattery/index.ts index 0000039bd4b..0349d3cb9ec 100644 --- a/packages/core/useBattery/index.ts +++ b/packages/core/useBattery/index.ts @@ -2,6 +2,7 @@ import { ref } from 'vue-demi' import { useEventListener } from '../useEventListener' +import { useSupported } from '../useSupported' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' @@ -25,7 +26,7 @@ type NavigatorWithBattery = Navigator & { export function useBattery({ navigator = defaultNavigator }: ConfigurableNavigator = {}) { const events = ['chargingchange', 'chargingtimechange', 'dischargingtimechange', 'levelchange'] - const isSupported = navigator && 'getBattery' in navigator + const isSupported = useSupported(() => navigator && 'getBattery' in navigator) const charging = ref(false) const chargingTime = ref(0) @@ -41,7 +42,7 @@ export function useBattery({ navigator = defaultNavigator }: ConfigurableNavigat level.value = this.level } - if (isSupported) { + if (isSupported.value) { (navigator as NavigatorWithBattery) .getBattery() .then((_battery) => { diff --git a/packages/core/useBluetooth/index.ts b/packages/core/useBluetooth/index.ts index 0ff27fd5cdc..395584ec51f 100644 --- a/packages/core/useBluetooth/index.ts +++ b/packages/core/useBluetooth/index.ts @@ -3,6 +3,7 @@ import { tryOnMounted, tryOnScopeDispose } from '@vueuse/shared' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' +import { useSupported } from '../useSupported' export interface UseBluetoothRequestDeviceOptions { /** @@ -51,7 +52,7 @@ export function useBluetooth(options?: UseBluetoothOptions) { navigator = defaultNavigator, } = options || {} - const isSupported = navigator && 'bluetooth' in navigator + const isSupported = useSupported(() => navigator && 'bluetooth' in navigator) const device = ref(undefined) @@ -63,7 +64,7 @@ export function useBluetooth(options?: UseBluetoothOptions) { async function requestDevice(): Promise { // This is the function can only be called if Bluetooth API is supported: - if (!isSupported) + if (!isSupported.value) return // Reset any errors we currently have: diff --git a/packages/core/useBroadcastChannel/index.ts b/packages/core/useBroadcastChannel/index.ts index 506079ec0c8..64a5a3c1076 100644 --- a/packages/core/useBroadcastChannel/index.ts +++ b/packages/core/useBroadcastChannel/index.ts @@ -2,6 +2,7 @@ import { ref } from 'vue-demi' import { tryOnMounted, tryOnScopeDispose } from '@vueuse/shared' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' +import { useSupported } from '../useSupported' export interface UseBroadcastChannelOptions extends ConfigurableWindow { /** @@ -24,7 +25,7 @@ export const useBroadcastChannel = (options: UseBroadcastChannelOptions) => { window = defaultWindow, } = options - const isSupported = window && 'BroadcastChannel' in window + const isSupported = useSupported(() => window && 'BroadcastChannel' in window) const isClosed = ref(false) const channel = ref() @@ -42,7 +43,7 @@ export const useBroadcastChannel = (options: UseBroadcastChannelOptions) => { isClosed.value = true } - if (isSupported) { + if (isSupported.value) { tryOnMounted(() => { error.value = null channel.value = new BroadcastChannel(name) diff --git a/packages/core/useClipboard/index.ts b/packages/core/useClipboard/index.ts index 0f8ee88d728..f95c17342df 100644 --- a/packages/core/useClipboard/index.ts +++ b/packages/core/useClipboard/index.ts @@ -2,10 +2,11 @@ import type { MaybeComputedRef } from '@vueuse/shared' import { resolveUnref, useTimeoutFn } from '@vueuse/shared' -import type { ComputedRef } from 'vue-demi' +import type { ComputedRef, Ref } from 'vue-demi' import { ref } from 'vue-demi' import type { WindowEventName } from '../useEventListener' import { useEventListener } from '../useEventListener' +import { useSupported } from '../useSupported' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' @@ -31,7 +32,7 @@ export interface ClipboardOptions extends ConfigurableNavigator { } export interface ClipboardReturn { - isSupported: boolean + isSupported: Ref text: ComputedRef copied: ComputedRef copy: Optional extends true ? (text?: string) => Promise : (text: string) => Promise @@ -54,7 +55,7 @@ export function useClipboard(options: ClipboardOptions } = options const events = ['copy', 'cut'] - const isSupported = Boolean(navigator && 'clipboard' in navigator) + const isSupported = useSupported(() => navigator && 'clipboard' in navigator) const text = ref('') const copied = ref(false) @@ -66,13 +67,13 @@ export function useClipboard(options: ClipboardOptions }) } - if (isSupported && read) { + if (isSupported.value && read) { for (const event of events) useEventListener(event as WindowEventName, updateText) } async function copy(value = resolveUnref(source)) { - if (isSupported && value != null) { + if (isSupported.value && value != null) { await navigator!.clipboard.writeText(value) text.value = value copied.value = true diff --git a/packages/core/useDeviceOrientation/index.ts b/packages/core/useDeviceOrientation/index.ts index 80e7377faa2..340aa29ceb9 100644 --- a/packages/core/useDeviceOrientation/index.ts +++ b/packages/core/useDeviceOrientation/index.ts @@ -3,6 +3,7 @@ import type { Ref } from 'vue-demi' import { ref } from 'vue-demi' import { useEventListener } from '../useEventListener' +import { useSupported } from '../useSupported' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' @@ -14,14 +15,14 @@ import { defaultWindow } from '../_configurable' */ export function useDeviceOrientation(options: ConfigurableWindow = {}) { const { window = defaultWindow } = options - const isSupported = Boolean(window && 'DeviceOrientationEvent' in window) + const isSupported = useSupported(() => window && 'DeviceOrientationEvent' in window) const isAbsolute = ref(false) const alpha: Ref = ref(null) const beta: Ref = ref(null) const gamma: Ref = ref(null) - if (window && isSupported) { + if (window && isSupported.value) { useEventListener(window, 'deviceorientation', (event) => { isAbsolute.value = event.absolute alpha.value = event.alpha diff --git a/packages/core/useDevicesList/index.ts b/packages/core/useDevicesList/index.ts index 91471473422..ae3f4ccacec 100644 --- a/packages/core/useDevicesList/index.ts +++ b/packages/core/useDevicesList/index.ts @@ -4,6 +4,7 @@ import type { ComputedRef, Ref } from 'vue-demi' import { computed, ref } from 'vue-demi' import { useEventListener } from '../useEventListener' import { usePermission } from '../usePermission' +import { useSupported } from '../useSupported' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' @@ -34,7 +35,7 @@ export interface UseDevicesListReturn { audioOutputs: ComputedRef permissionGranted: Ref ensurePermissions: () => Promise - isSupported: boolean + isSupported: Ref } /** @@ -55,11 +56,11 @@ export function useDevicesList(options: UseDevicesListOptions = {}): UseDevicesL const videoInputs = computed(() => devices.value.filter(i => i.kind === 'videoinput')) const audioInputs = computed(() => devices.value.filter(i => i.kind === 'audioinput')) const audioOutputs = computed(() => devices.value.filter(i => i.kind === 'audiooutput')) - let isSupported = false + const isSupported = useSupported(() => navigator && navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) const permissionGranted = ref(false) async function update() { - if (!isSupported) + if (!isSupported.value) return devices.value = await navigator!.mediaDevices.enumerateDevices() @@ -67,7 +68,7 @@ export function useDevicesList(options: UseDevicesListOptions = {}): UseDevicesL } async function ensurePermissions() { - if (!isSupported) + if (!isSupported.value) return false if (permissionGranted.value) @@ -88,16 +89,12 @@ export function useDevicesList(options: UseDevicesListOptions = {}): UseDevicesL return permissionGranted.value } - if (navigator) { - isSupported = Boolean(navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) + if (isSupported.value) { + if (requestPermissions) + ensurePermissions() - if (isSupported) { - if (requestPermissions) - ensurePermissions() - - useEventListener(navigator.mediaDevices, 'devicechange', update) - update() - } + useEventListener(navigator!.mediaDevices, 'devicechange', update) + update() } return { diff --git a/packages/core/useDisplayMedia/index.ts b/packages/core/useDisplayMedia/index.ts index 034111d42c1..d1e2fb43b8e 100644 --- a/packages/core/useDisplayMedia/index.ts +++ b/packages/core/useDisplayMedia/index.ts @@ -1,6 +1,7 @@ import type { MaybeRef } from '@vueuse/shared' import type { Ref } from 'vue-demi' import { ref, shallowRef, watch } from 'vue-demi' +import { useSupported } from '../useSupported' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' @@ -32,14 +33,14 @@ export function useDisplayMedia(options: UseDisplayMediaOptions = {}) { const video = options.video const audio = options.audio const { navigator = defaultNavigator } = options - const isSupported = Boolean(navigator?.mediaDevices?.getDisplayMedia) + const isSupported = useSupported(() => navigator?.mediaDevices?.getDisplayMedia) const constraint: DisplayMediaStreamConstraints = { audio, video } const stream: Ref = shallowRef() async function _start() { - if (!isSupported || stream.value) + if (!isSupported.value || stream.value) return stream.value = await navigator!.mediaDevices.getDisplayMedia(constraint) return stream.value diff --git a/packages/core/useEyeDropper/demo.vue b/packages/core/useEyeDropper/demo.vue index 2dba02db7e6..54043379a47 100644 --- a/packages/core/useEyeDropper/demo.vue +++ b/packages/core/useEyeDropper/demo.vue @@ -8,13 +8,14 @@ const { isSupported, open, sRGBHex } = useEyeDropper() -
+ +
+ Not Supported by Your Browser
diff --git a/packages/core/useEyeDropper/index.ts b/packages/core/useEyeDropper/index.ts index 32509e44626..554b56fd565 100644 --- a/packages/core/useEyeDropper/index.ts +++ b/packages/core/useEyeDropper/index.ts @@ -1,4 +1,5 @@ import { ref } from 'vue-demi' +import { useSupported } from '../useSupported' export interface EyeDropperOpenOptions { /** @@ -31,11 +32,11 @@ export interface UseEyeDropperOptions { */ export function useEyeDropper(options: UseEyeDropperOptions = {}) { const { initialValue = '' } = options - const isSupported = Boolean(typeof window !== 'undefined' && 'EyeDropper' in window) + const isSupported = useSupported(() => typeof window !== 'undefined' && 'EyeDropper' in window) const sRGBHex = ref(initialValue) async function open(openOptions?: EyeDropperOpenOptions) { - if (!isSupported) + if (!isSupported.value) return const eyeDropper: EyeDropper = new (window as any).EyeDropper() const result = await eyeDropper.open(openOptions) diff --git a/packages/core/useFileDialog/index.md b/packages/core/useFileDialog/index.md index 904885ac3d4..67b1ae210c9 100644 --- a/packages/core/useFileDialog/index.md +++ b/packages/core/useFileDialog/index.md @@ -11,7 +11,7 @@ Open file dialog with ease. ```ts import { useFileDialog } from '@vueuse/core' -const { files, open, reset } = useDialog() +const { files, open, reset } = useFileDialog() ``` ```html diff --git a/packages/core/useFileSystemAccess/index.ts b/packages/core/useFileSystemAccess/index.ts index 6921dec7348..e8169b8850e 100644 --- a/packages/core/useFileSystemAccess/index.ts +++ b/packages/core/useFileSystemAccess/index.ts @@ -3,6 +3,7 @@ import { computed, ref, unref, watch } from 'vue-demi' import type { Awaitable, MaybeComputedRef } from '@vueuse/shared' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' +import { useSupported } from '../useSupported' /** * window.showOpenFilePicker parameters @@ -102,7 +103,7 @@ export function useFileSystemAccess(options: UseFileSystemAccessOptions = {}): U dataType = 'Text', } = unref(options) const window = _window as FileSystemAccessWindow - const isSupported = Boolean(window && 'showSaveFilePicker' in window && 'showOpenFilePicker' in window) + const isSupported = useSupported(() => window && 'showSaveFilePicker' in window && 'showOpenFilePicker' in window) const fileHandle = ref() const data = ref() @@ -114,7 +115,7 @@ export function useFileSystemAccess(options: UseFileSystemAccessOptions = {}): U const fileLastModified = computed(() => file.value?.lastModified ?? 0) async function open(_options: UseFileSystemAccessCommonOptions = {}) { - if (!isSupported) + if (!isSupported.value) return const [handle] = await window.showOpenFilePicker({ ...unref(options), ..._options }) fileHandle.value = handle @@ -123,7 +124,7 @@ export function useFileSystemAccess(options: UseFileSystemAccessOptions = {}): U } async function create(_options: UseFileSystemAccessShowSaveFileOptions = {}) { - if (!isSupported) + if (!isSupported.value) return fileHandle.value = await (window as FileSystemAccessWindow).showSaveFilePicker({ ...unref(options), ..._options }) data.value = undefined @@ -132,7 +133,7 @@ export function useFileSystemAccess(options: UseFileSystemAccessOptions = {}): U } async function save(_options: UseFileSystemAccessShowSaveFileOptions = {}) { - if (!isSupported) + if (!isSupported.value) return if (!fileHandle.value) @@ -148,7 +149,7 @@ export function useFileSystemAccess(options: UseFileSystemAccessOptions = {}): U } async function saveAs(_options: UseFileSystemAccessShowSaveFileOptions = {}) { - if (!isSupported) + if (!isSupported.value) return fileHandle.value = await (window as FileSystemAccessWindow).showSaveFilePicker({ ...unref(options), ..._options }) @@ -194,7 +195,7 @@ export function useFileSystemAccess(options: UseFileSystemAccessOptions = {}): U } export interface UseFileSystemAccessReturn { - isSupported: boolean + isSupported: Ref data: Ref file: Ref fileName: Ref diff --git a/packages/core/useFullscreen/index.ts b/packages/core/useFullscreen/index.ts index 1aa4f8c04c9..5b77e9f3106 100644 --- a/packages/core/useFullscreen/index.ts +++ b/packages/core/useFullscreen/index.ts @@ -7,6 +7,7 @@ import { unrefElement } from '../unrefElement' import { useEventListener } from '../useEventListener' import type { ConfigurableDocument } from '../_configurable' import { defaultDocument } from '../_configurable' +import { useSupported } from '../useSupported' type FunctionMap = [ 'requestFullscreen', @@ -86,27 +87,27 @@ export function useFullscreen( const { document = defaultDocument, autoExit = false } = options const targetRef = target || document?.querySelector('html') const isFullscreen = ref(false) - let isSupported = false - let map: FunctionMap = functionsMap[0] - if (!document) { - isSupported = false - } - else { - for (const m of functionsMap) { - if (m[1] in document) { - map = m - isSupported = true - break + const isSupported = useSupported(() => { + if (!document) { + return false + } + else { + for (const m of functionsMap) { + if (m[1] in document) { + map = m + return true + } } } - } + return false + }) const [REQUEST, EXIT, ELEMENT,, EVENT] = map async function exit() { - if (!isSupported) + if (!isSupported.value) return if (document?.[ELEMENT]) await document[EXIT]() @@ -115,7 +116,7 @@ export function useFullscreen( } async function enter() { - if (!isSupported) + if (!isSupported.value) return await exit() diff --git a/packages/core/useGamepad/index.ts b/packages/core/useGamepad/index.ts index d99298ff4c9..3ba1ca3538b 100644 --- a/packages/core/useGamepad/index.ts +++ b/packages/core/useGamepad/index.ts @@ -5,6 +5,7 @@ import { useRafFn } from '../useRafFn' import { useEventListener } from '../useEventListener' import type { ConfigurableNavigator, ConfigurableWindow } from '../_configurable' import { defaultNavigator } from '../_configurable' +import { useSupported } from '../useSupported' export interface UseGamepadOptions extends ConfigurableWindow, ConfigurableNavigator { @@ -62,7 +63,7 @@ export function useGamepad(options: UseGamepadOptions = {}) { const { navigator = defaultNavigator, } = options - const isSupported = navigator && 'getGamepads' in navigator + const isSupported = useSupported(() => navigator && 'getGamepads' in navigator) const gamepads = ref([]) const onConnectedHook = createEventHook() diff --git a/packages/core/useGeolocation/index.ts b/packages/core/useGeolocation/index.ts index 6e06b06c445..461d53d7ee6 100644 --- a/packages/core/useGeolocation/index.ts +++ b/packages/core/useGeolocation/index.ts @@ -5,6 +5,7 @@ import { ref } from 'vue-demi' import { tryOnScopeDispose } from '@vueuse/shared' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' +import { useSupported } from '../useSupported' export interface GeolocationOptions extends Partial, ConfigurableNavigator {} @@ -22,7 +23,7 @@ export function useGeolocation(options: GeolocationOptions = {}) { navigator = defaultNavigator, } = options - const isSupported = navigator && 'geolocation' in navigator + const isSupported = useSupported(() => navigator && 'geolocation' in navigator) const locatedAt: Ref = ref(null) const error = ref(null) @@ -44,7 +45,7 @@ export function useGeolocation(options: GeolocationOptions = {}) { let watcher: number - if (isSupported) { + if (isSupported.value) { watcher = navigator!.geolocation.watchPosition( updatePosition, err => error.value = err, diff --git a/packages/core/useIntersectionObserver/index.ts b/packages/core/useIntersectionObserver/index.ts index cfbbf3097f0..a1dda20c1b9 100644 --- a/packages/core/useIntersectionObserver/index.ts +++ b/packages/core/useIntersectionObserver/index.ts @@ -4,6 +4,7 @@ import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' import type { MaybeElementRef } from '../unrefElement' import { unrefElement } from '../unrefElement' +import { useSupported } from '../useSupported' export interface IntersectionObserverOptions extends ConfigurableWindow { /** @@ -42,11 +43,11 @@ export function useIntersectionObserver( window = defaultWindow, } = options - const isSupported = window && 'IntersectionObserver' in window + const isSupported = useSupported(() => window && 'IntersectionObserver' in window) let cleanup = noop - const stopWatch = isSupported + const stopWatch = isSupported.value ? watch( () => ({ el: unrefElement(target), diff --git a/packages/core/useMediaQuery/index.ts b/packages/core/useMediaQuery/index.ts index ab2cda54996..e1c92de5711 100644 --- a/packages/core/useMediaQuery/index.ts +++ b/packages/core/useMediaQuery/index.ts @@ -4,6 +4,7 @@ import { ref } from 'vue-demi' import { tryOnBeforeMount, tryOnScopeDispose } from '@vueuse/shared' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' +import { useSupported } from '../useSupported' /** * Reactive Media Query. @@ -14,13 +15,13 @@ import { defaultWindow } from '../_configurable' */ export function useMediaQuery(query: string, options: ConfigurableWindow = {}) { const { window = defaultWindow } = options - const isSupported = Boolean(window && 'matchMedia' in window && typeof window!.matchMedia === 'function') + const isSupported = useSupported(() => window && 'matchMedia' in window && typeof window!.matchMedia === 'function') let mediaQuery: MediaQueryList | undefined const matches = ref(false) const update = () => { - if (!isSupported) + if (!isSupported.value) return if (!mediaQuery) mediaQuery = window!.matchMedia(query) diff --git a/packages/core/useMemory/index.ts b/packages/core/useMemory/index.ts index bbc5c15263b..508febecef5 100644 --- a/packages/core/useMemory/index.ts +++ b/packages/core/useMemory/index.ts @@ -1,6 +1,7 @@ import { ref } from 'vue-demi' import type { IntervalFnOptions } from '@vueuse/shared' import { useIntervalFn } from '@vueuse/shared' +import { useSupported } from '../useSupported' /** * Performance.memory @@ -40,9 +41,9 @@ type PerformanceMemory = Performance & { */ export function useMemory(options: UseMemoryOptions = {}) { const memory = ref() - const isSupported = typeof performance !== 'undefined' && 'memory' in performance + const isSupported = useSupported(() => typeof performance !== 'undefined' && 'memory' in performance) - if (isSupported) { + if (isSupported.value) { const { interval = 1000 } = options useIntervalFn(() => { memory.value = (performance as PerformanceMemory).memory diff --git a/packages/core/useMutationObserver/index.ts b/packages/core/useMutationObserver/index.ts index 202faf1a1eb..199c2322023 100644 --- a/packages/core/useMutationObserver/index.ts +++ b/packages/core/useMutationObserver/index.ts @@ -2,6 +2,7 @@ import { tryOnScopeDispose } from '@vueuse/shared' import { watch } from 'vue-demi' import type { MaybeElementRef } from '../unrefElement' import { unrefElement } from '../unrefElement' +import { useSupported } from '../useSupported' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' @@ -23,7 +24,7 @@ export function useMutationObserver( ) { const { window = defaultWindow, ...mutationOptions } = options let observer: MutationObserver | undefined - const isSupported = window && 'MutationObserver' in window + const isSupported = useSupported(() => window && 'MutationObserver' in window) const cleanup = () => { if (observer) { @@ -37,7 +38,7 @@ export function useMutationObserver( (el) => { cleanup() - if (isSupported && window && el) { + if (isSupported.value && window && el) { observer = new MutationObserver(callback) observer!.observe(el, mutationOptions) } diff --git a/packages/core/useNavigatorLanguage/index.ts b/packages/core/useNavigatorLanguage/index.ts index 368c1d37dff..3d659368926 100644 --- a/packages/core/useNavigatorLanguage/index.ts +++ b/packages/core/useNavigatorLanguage/index.ts @@ -2,12 +2,13 @@ import type { Ref } from 'vue-demi' import { ref } from 'vue-demi' import { useEventListener } from '../useEventListener' +import { useSupported } from '../useSupported' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' export interface NavigatorLanguageState { - isSupported: boolean + isSupported: Ref /** * * ISO 639-1 standard Language Code @@ -40,7 +41,7 @@ export const useNavigatorLanguage = (options: ConfigurableWindow = {}): Readonly const navigator = window?.navigator - const isSupported = Boolean(navigator && 'language' in navigator) + const isSupported = useSupported(() => navigator && 'language' in navigator) const language = ref(navigator?.language) diff --git a/packages/core/useNetwork/index.ts b/packages/core/useNetwork/index.ts index 6a9c32e7930..c4b0acde050 100644 --- a/packages/core/useNetwork/index.ts +++ b/packages/core/useNetwork/index.ts @@ -3,6 +3,7 @@ import type { Ref } from 'vue-demi' import { ref } from 'vue-demi' import { useEventListener } from '../useEventListener' +import { useSupported } from '../useSupported' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' @@ -11,7 +12,7 @@ export type NetworkType = 'bluetooth' | 'cellular' | 'ethernet' | 'none' | 'wifi export type NetworkEffectiveType = 'slow-2g' | '2g' | '3g' | '4g' | undefined export interface NetworkState { - isSupported: boolean + isSupported: Ref /** * If the user is currently connected. */ @@ -59,7 +60,7 @@ export interface NetworkState { export function useNetwork(options: ConfigurableWindow = {}): Readonly { const { window = defaultWindow } = options const navigator = window?.navigator - const isSupported = Boolean(navigator && 'connection' in navigator) + const isSupported = useSupported(() => navigator && 'connection' in navigator) const isOnline = ref(true) const saveData = ref(false) @@ -71,7 +72,7 @@ export function useNetwork(options: ConfigurableWindow = {}): Readonly = ref(undefined) const type: Ref = ref('unknown') - const connection = isSupported && (navigator as any).connection + const connection = isSupported.value && (navigator as any).connection function updateNetworkInformation() { if (!navigator) diff --git a/packages/core/usePermission/index.ts b/packages/core/usePermission/index.ts index 95867a61db3..277040d2681 100644 --- a/packages/core/usePermission/index.ts +++ b/packages/core/usePermission/index.ts @@ -4,6 +4,7 @@ import { createSingletonPromise } from '@vueuse/shared' import { useEventListener } from '../useEventListener' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' +import { useSupported } from '../useSupported' type DescriptorNamePolyfill = 'accelerometer' | @@ -38,7 +39,7 @@ export interface UsePermissionOptions extends Configur export type UsePermissionReturn = Readonly> export interface UsePermissionReturnWithControls { state: UsePermissionReturn - isSupported: boolean + isSupported: Ref query: () => Promise } @@ -64,7 +65,7 @@ export function usePermission( navigator = defaultNavigator, } = options - const isSupported = Boolean(navigator && 'permissions' in navigator) + const isSupported = useSupported(() => navigator && 'permissions' in navigator) let permissionStatus: PermissionStatus | undefined const desc = typeof permissionDesc === 'string' @@ -78,7 +79,7 @@ export function usePermission( } const query = createSingletonPromise(async () => { - if (!isSupported) + if (!isSupported.value) return if (!permissionStatus) { try { diff --git a/packages/core/useResizeObserver/index.ts b/packages/core/useResizeObserver/index.ts index eb07afed98b..1e12b3f025d 100644 --- a/packages/core/useResizeObserver/index.ts +++ b/packages/core/useResizeObserver/index.ts @@ -2,6 +2,7 @@ import { tryOnScopeDispose } from '@vueuse/shared' import { watch } from 'vue-demi' import type { MaybeComputedElementRef } from '../unrefElement' import { unrefElement } from '../unrefElement' +import { useSupported } from '../useSupported' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' @@ -52,7 +53,7 @@ export function useResizeObserver( ) { const { window = defaultWindow, ...observerOptions } = options let observer: ResizeObserver | undefined - const isSupported = window && 'ResizeObserver' in window + const isSupported = useSupported(() => window && 'ResizeObserver' in window) const cleanup = () => { if (observer) { @@ -66,7 +67,7 @@ export function useResizeObserver( (el) => { cleanup() - if (isSupported && window && el) { + if (isSupported.value && window && el) { observer = new ResizeObserver(callback) observer!.observe(el, observerOptions) } diff --git a/packages/core/useScreenOrientation/index.ts b/packages/core/useScreenOrientation/index.ts index 6ef91e043f8..ee0db36e2d6 100644 --- a/packages/core/useScreenOrientation/index.ts +++ b/packages/core/useScreenOrientation/index.ts @@ -1,5 +1,6 @@ import { ref } from 'vue-demi' import { useEventListener } from '../useEventListener' +import { useSupported } from '../useSupported' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' @@ -13,14 +14,14 @@ export const useScreenOrientation = (options: ConfigurableWindow = {}) => { window = defaultWindow, } = options - const isSupported = !!(window && 'screen' in window && 'orientation' in window.screen) + const isSupported = useSupported(() => window && 'screen' in window && 'orientation' in window.screen) - const screenOrientation = isSupported ? window.screen.orientation : {} as ScreenOrientation + const screenOrientation = isSupported.value ? window!.screen.orientation : {} as ScreenOrientation const orientation = ref(screenOrientation.type) const angle = ref(screenOrientation.angle || 0) - if (isSupported) { + if (isSupported.value) { useEventListener(window, 'orientationchange', () => { orientation.value = screenOrientation.type angle.value = screenOrientation.angle @@ -28,14 +29,14 @@ export const useScreenOrientation = (options: ConfigurableWindow = {}) => { } const lockOrientation = (type: OrientationLockType) => { - if (!isSupported) + if (!isSupported.value) return Promise.reject(new Error('Not supported')) return screenOrientation.lock(type) } const unlockOrientation = () => { - if (isSupported) + if (isSupported.value) screenOrientation.unlock() } diff --git a/packages/core/useShare/index.ts b/packages/core/useShare/index.ts index 38b6af17b82..275fad43079 100644 --- a/packages/core/useShare/index.ts +++ b/packages/core/useShare/index.ts @@ -1,5 +1,6 @@ import type { MaybeComputedRef } from '@vueuse/shared' import { resolveUnref } from '@vueuse/shared' +import { useSupported } from '../useSupported' import type { ConfigurableNavigator } from '../_configurable' import { defaultNavigator } from '../_configurable' @@ -26,10 +27,10 @@ export function useShare(shareOptions: MaybeComputedRef = {}, opti const { navigator = defaultNavigator } = options const _navigator = (navigator as NavigatorWithShare) - const isSupported = _navigator && 'canShare' in _navigator + const isSupported = useSupported(() => _navigator && 'canShare' in _navigator) const share = async (overrideOptions: MaybeComputedRef = {}) => { - if (isSupported) { + if (isSupported.value) { const data = { ...resolveUnref(shareOptions), ...resolveUnref(overrideOptions), diff --git a/packages/core/useSpeechRecognition/demo.vue b/packages/core/useSpeechRecognition/demo.vue index 16dc2ac2984..c8c4f224550 100644 --- a/packages/core/useSpeechRecognition/demo.vue +++ b/packages/core/useSpeechRecognition/demo.vue @@ -28,7 +28,7 @@ const speech = useSpeechRecognition({ const color = ref('transparent') -if (speech.isSupported) { +if (speech.isSupported.value) { // @ts-expect-error missing types const SpeechGrammarList = window.SpeechGrammarList || window.webkitSpeechGrammarList const speechRecognitionList = new SpeechGrammarList() diff --git a/packages/core/useSpeechRecognition/index.ts b/packages/core/useSpeechRecognition/index.ts index a7c7a55cd0b..c81dd4e3f9a 100644 --- a/packages/core/useSpeechRecognition/index.ts +++ b/packages/core/useSpeechRecognition/index.ts @@ -5,6 +5,7 @@ import type { MaybeComputedRef } from '@vueuse/shared' import { resolveRef, tryOnScopeDispose } from '@vueuse/shared' import type { Ref } from 'vue-demi' import { ref, shallowRef, unref, watch } from 'vue-demi' +import { useSupported } from '../useSupported' import type { ConfigurableWindow } from '../_configurable' import { defaultWindow } from '../_configurable' import type { SpeechRecognition, SpeechRecognitionErrorEvent } from './types' @@ -63,11 +64,11 @@ export function useSpeechRecognition(options: SpeechRecognitionOptions = {}) { } const SpeechRecognition = window && ((window as any).SpeechRecognition || (window as any).webkitSpeechRecognition) - const isSupported = Boolean(SpeechRecognition) + const isSupported = useSupported(() => SpeechRecognition) let recognition: SpeechRecognition | undefined - if (isSupported) { + if (isSupported.value) { recognition = new SpeechRecognition() as SpeechRecognition recognition.continuous = continuous diff --git a/packages/core/useSpeechSynthesis/demo.vue b/packages/core/useSpeechSynthesis/demo.vue index 9fdaa0090ba..a4a82466bad 100644 --- a/packages/core/useSpeechSynthesis/demo.vue +++ b/packages/core/useSpeechSynthesis/demo.vue @@ -13,7 +13,7 @@ let synth: SpeechSynthesis const voices = ref([]) -if (speech.isSupported) { +if (speech.isSupported.value) { // load at last setTimeout(() => { synth = window.speechSynthesis @@ -42,7 +42,7 @@ const stop = () => {