import { ReactNode , createContext , useCallback , useContext , useEffect , useState } from "react" ; import { isNil } from "../../shared" ; import { supportsMatchMedia } from "./useMediaQuery" ; import { useDebouncedCallback } from "use-debounce" ; export const Breakpoints = { xs : "(min-width: 640px)" , sm : "(min-width: 768px)" , md : "(min-width: 1024px)" , lg : "(min-width: 1280px)" , xl : "(min-width: 1536px)" } ; export type Breakpoint = keyof typeof Breakpoints ; export interface BreakpointContextType { matchedBreakpoints ? : Breakpoint [ ] ; } export const BreakpointContext = createContext < BreakpointContextType > ( { } ) ; export interface BreakpointProvider { children : ReactNode ; unsupportedMatchMediaBreakpoint ? : Breakpoint ; } const ReversedBreakpoints = Object . entries ( Breakpoints ) . reduce ( ( acc , entry ) => { acc . unshift ( entry ) ; return acc ; } , [ ] ) ; export function BreakpointProvider ( { children , unsupportedMatchMediaBreakpoint = "lg" } ) { const getBreakpointHandler = useCallback ( ( ) : Breakpoint [ ] => { if ( supportsMatchMedia ) { const matched = [ ] ; for ( const [ key , value ] of ReversedBreakpoints ) { if ( window . matchMedia ( value ) . matches ) { matched . push ( key ) ; } } return matched ; } return [ unsupportedMatchMediaBreakpoint ] ; } , [ unsupportedMatchMediaBreakpoint ] ) ; const [ matchedBreakpoints , setMatchedBreakpoints ] = useState < Breakpoint [ ] > ( getBreakpointHandler ) ; const handleResize = useDebouncedCallback ( ( ) => { setMatchedBreakpoints ( getBreakpointHandler ( ) ) ; } , 50 ) ; useEffect ( ( ) => { window . addEventListener ( "resize" , handleResize ) ; return ( ) => { window . removeEventListener ( "resize" , handleResize ) ; } ; } , [ handleResize ] ) ; return ( < BreakpointContext . Provider value = { { matchedBreakpoints } } > { children } < /BreakpointContext.Provider>); } export function useBreakpointContext ( ) { return useContext ( BreakpointContext ) ; } export function useMatchedBreakpoints ( ) { const context = useContext ( BreakpointContext ) ; return ! isNil ( context ) ? context . matchedBreakpoints : [ ] ; }