import { computed, onMounted, onUnmounted, ref, unref, watch, type ComputedRef, type Ref } from 'vue' export const DEFAULT_MOBILE_VIEWPORT_QUERY = '(max-width: 767px)' export type MobileSupportSource = boolean | Ref | ComputedRef export type MobileViewportQuerySource = string | Ref | ComputedRef export interface UseMobileSupportGateOptions { supported?: MobileSupportSource mediaQuery?: MobileViewportQuerySource } export interface UseMobileSupportGateReturn { isMobileViewport: Ref isSupported: ComputedRef shouldShowUnsupported: ComputedRef } export function useMobileSupportGate(options: UseMobileSupportGateOptions = {}): UseMobileSupportGateReturn { const isMobileViewport = ref(false) const mediaQuery = computed(() => { const value = unref(options.mediaQuery) return value?.trim() || DEFAULT_MOBILE_VIEWPORT_QUERY }) const isSupported = computed(() => { if (options.supported === undefined) return true return Boolean(unref(options.supported)) }) const shouldShowUnsupported = computed(() => isMobileViewport.value && !isSupported.value) let mediaQueryList: MediaQueryList | null = null let removeMediaListener: (() => void) | undefined const syncMobileState = (event?: MediaQueryListEvent | MediaQueryList) => { isMobileViewport.value = Boolean(event?.matches ?? mediaQueryList?.matches) } const unbindMediaQuery = () => { removeMediaListener?.() removeMediaListener = undefined mediaQueryList = null } const bindMediaQuery = () => { unbindMediaQuery() if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') { isMobileViewport.value = false return } const queryList = window.matchMedia(mediaQuery.value) mediaQueryList = queryList syncMobileState(queryList) const handleChange = (event: MediaQueryListEvent) => syncMobileState(event) if (typeof queryList.addEventListener === 'function') { queryList.addEventListener('change', handleChange) removeMediaListener = () => queryList.removeEventListener('change', handleChange) return } queryList.addListener(handleChange) removeMediaListener = () => queryList.removeListener(handleChange) } onMounted(bindMediaQuery) watch(mediaQuery, bindMediaQuery, { flush: 'post' }) onUnmounted(unbindMediaQuery) return { isMobileViewport, isSupported, shouldShowUnsupported, } }