import { useState, useLayoutEffect, useCallback } from 'react'; import { useDebounce } from '@react-hooks-hub/use-debounce'; const defaultBreakpoints = { desktop: 992, tablet: 768, mobile: 0 }; type Breakpoints = { [breakpointName: string]: number; }; type UseMediaQueryOptions = { breakpoints?: T; debounceDelay?: number } type Orientation = 'portrait' | 'landscape'; type Device = keyof T | undefined; export function useMediaQuery({ breakpoints = defaultBreakpoints as unknown as T, debounceDelay = 500 }: UseMediaQueryOptions = {}) { const breakpointNames = Object.keys(breakpoints) as Array; const [device, setDevice] = useState | null>(null); const [orientation, setOrientation] = useState(); const update = useCallback(() => { const width = window.innerWidth; let newDevice: keyof T | null = null; breakpointNames.forEach((breakpointName) => { if (width >= breakpoints[breakpointName] ) { if (!newDevice || breakpoints[breakpointName] > breakpoints[newDevice]) { newDevice = breakpointName; } } }) setDevice(newDevice ); if (window.matchMedia('(orientation: portrait)').matches) { setOrientation('portrait'); } else { setOrientation('landscape'); } }, [breakpointNames, breakpoints]); const debounced = useDebounce(update, debounceDelay); useLayoutEffect(() => { update(); window.addEventListener('resize', debounced); window.addEventListener('orientationchange', debounced); return () => { window.removeEventListener('resize', debounced); window.removeEventListener('orientationchange', debounced); } }, [update, debounced]); return { device, orientation }; }