import { useEffect, useRef, useState } from 'react' import { create } from 'zustand' export interface UseMediaQueryOptions { getInitialValueInEffect: boolean } type MediaQueryCallback = (event: { matches: boolean; media: string }) => void // Zustand store for small screen state type SmallScreenState = { isSmallScreen: boolean setIsSmallScreen: (isSmall: boolean) => void } export const useSmallScreenStore = create((set) => ({ isSmallScreen: false, setIsSmallScreen: (isSmall) => set({ isSmallScreen: isSmall }), })) /** * Older versions of Safari (shipped withCatalina and before) do not support addEventListener on matchMedia * https://stackoverflow.com/questions/56466261/matchmedia-addlistener-marked-as-deprecated-addeventlistener-equivalent * */ function attachMediaListener( query: MediaQueryList, callback: MediaQueryCallback ) { try { query.addEventListener('change', callback) return () => query.removeEventListener('change', callback) } catch (e) { console.warn(e) // eslint-disable @typescript-eslint/no-deprecated query.addListener(callback) return () => query.removeListener(callback) // eslint-enable @typescript-eslint/no-deprecated } } function getInitialValue(query: string, initialValue?: boolean) { if (typeof initialValue === 'boolean') { return initialValue } if (typeof window !== 'undefined' && 'matchMedia' in window) { return window.matchMedia(query).matches } return false } export function useMediaQuery( query: string, initialValue?: boolean, { getInitialValueInEffect }: UseMediaQueryOptions = { getInitialValueInEffect: true, } ): boolean { const [matches, setMatches] = useState( getInitialValueInEffect ? initialValue : getInitialValue(query) ) const queryRef = useRef(null) useEffect(() => { if ('matchMedia' in window) { queryRef.current = window.matchMedia(query) setMatches(queryRef.current.matches) return attachMediaListener(queryRef.current, (event) => setMatches(event.matches) ) } return undefined }, [query]) return matches || false } // Specific hook for small screen detection with state management export const useSmallScreen = (): boolean => { const { isSmallScreen, setIsSmallScreen } = useSmallScreenStore() const mediaQuery = useMediaQuery('(max-width: 768px)') useEffect(() => { setIsSmallScreen(mediaQuery) }, [mediaQuery, setIsSmallScreen]) return isSmallScreen }