import { useRef , useState , useEffect , useMemo } from 'react' ; import { ExtendedResizeObserverEntry } from '@envato/react-resize-observer-hook' ; import { Breakpoints } from './Breakpoints' ; import { useResizeObserverEntry } from './useResizeObserverEntry' ; import { findBreakpoint } from './findBreakpoint' ; interface BaseOptions { box ? : ResizeObserverBoxOptions ; fragment ? : number ; } interface HeightsOptions extends BaseOptions { widths ? : Breakpoints ; heights : Breakpoints ; } interface WidthsOptions extends BaseOptions { widths : Breakpoints ; heights ? : Breakpoints ; } export type UseBreakpointsOptions = HeightsOptions | WidthsOptions ; type Matches = { widthMatch : any ; heightMatch : any ; } ; export type UseBreakpointsResult = [ any , any ] & Matches ; const boxOptions = { BORDER_BOX : 'border-box' , CONTENT_BOX : 'content-box' , DEVICE_PIXEL_CONTENT_BOX : 'device-pixel-content-box' } ; /**
 * See API Docs: {@linkcode https://github.com/envato/react-breakpoints/blob/master/docs/api.md#usebreakpoints|useBreakpoints}
 *
 * Pass in an options object with at least one of the following properties:
 * - `widths`: objects with width breakpoints as keys and anything as their values;
 * - `heights`: objects with height breakpoints as keys and anything as their values.
 *
 * You may also pass the following additional optional properties:
 * - `box`: the box to measure on the observed element, one of `'border-box' | 'content-box' | 'device-pixel-content-box'`;
 * - `fragment`: index of  https of the observed element to measure (default `0`).
 *
 * Optionally pass in a `ResizeObserverEntry` as the second argument to override fetching one from context.
 *
 *  example export const useBreakpoints = ( { widths = { } , heights = { } , box = undefined , fragment = 0 } = { widths : { } , heights : { } } , injectResizeObserverEntry ? ) => { const isMounted = useRef < Boolean > ( true ) ; const matches = useRef < Matches > ( { widthMatch : undefined , heightMatch : undefined } ) ; const [ changedMatches , changeMatches ] = useState < Matches > ( { widthMatch : undefined , heightMatch : undefined } ) ; useEffect ( ( ) => { return ( ) => { isMounted . current = false ; } ; } , [ ] ) ; const result = useMemo ( ( ) => { const result = [ changedMatches . widthMatch , changedMatches . heightMatch ] as UseBreakpointsResult ; result . widthMatch = changedMatches . widthMatch ; result . heightMatch = changedMatches . heightMatch ; return result ; } , [ changedMatches . widthMatch , changedMatches . heightMatch ] ) ; const resizeObserverEntry = useResizeObserverEntry ( injectResizeObserverEntry ) ; if ( ! resizeObserverEntry ) return result ; let observedBoxSize ; switch ( box ) { case boxOptions . BORDER_BOX : observedBoxSize = resizeObserverEntry . borderBoxSize [ fragment ] ; break ; case boxOptions . CONTENT_BOX : observedBoxSize = resizeObserverEntry . contentBoxSize [ fragment ] ; break ; case boxOptions . DEVICE_PIXEL_CONTENT_BOX : if ( typeof resizeObserverEntry . devicePixelContentBoxSize !== 'undefined' ) { observedBoxSize = resizeObserverEntry . devicePixelContentBoxSize [ fragment ] ; } else { throw Error ( 'resizeObserverEntry does not contain devicePixelContentBoxSize.' ) ; } break ; default : observedBoxSize = { inlineSize : resizeObserverEntry . contentRect . width , blockSize : resizeObserverEntry . contentRect . height } ; } const widthMatch = findBreakpoint ( widths , observedBoxSize . inlineSize ) ; const heightMatch = findBreakpoint ( heights , observedBoxSize . blockSize ) ; if ( widthMatch !== matches . current . widthMatch || heightMatch !== matches . current . heightMatch ) { matches . current = { widthMatch , heightMatch } ; if ( isMounted . current ) { changeMatches ( { widthMatch , heightMatch } ) ; } } return result ; } ;