import React, { useEffect, useRef, useState, useMemo } from 'react' import { Dimensions, ScaledSize } from 'react-native' import { getBreakpointIndex } from '../css/get-breakpoint-index' import { useDripsyTheme } from '../use-dripsy-theme' import { BreakpointIndexContext } from './breakpoint-context' export const useBreakpoints = () => { const dripsy = useDripsyTheme() const breakpoints = dripsy?.theme?.breakpoints as | (number | string)[] | undefined if (breakpoints && typeof __DEV__ !== 'undefined' && __DEV__) { if (!Array.isArray(breakpoints)) { const arrayError = '[dripsy] theme.breakpoints must be an array. Or, you can leave it blank. However, you used \n' + JSON.stringify(breakpoints) + '\n Please turn this into an array, or remove the "breakpoints" field from your theme.' throw new Error(arrayError) } } return useMemo(() => { return (breakpoints || defaultBreakpoints).map((breakpoint) => { if (typeof breakpoint === 'string') { if (breakpoint.endsWith('px')) { return Number(breakpoint.replace('px', '')) } } if (typeof breakpoint !== 'number') { console.error( '[dripsy] Invalid breakpoints passed to theme.breakpoints. Expected an array of numbers, or strings ending with "px", but got this: \n', JSON.stringify(breakpoints), '\nPlease turn these into numbers, or remove the breakpoints array from your theme.' ) } return Number(breakpoint) }) }, [breakpoints]) } export const defaultBreakpoints = [576, 768, 992, 1200] const useCreateBreakpointIndex = () => { const breakpoints = useBreakpoints() const [index, setIndex] = useState(() => { return getBreakpointIndex({ width: Dimensions.get('window').width, breakpoints, }) }) const indexRef = useRef(index) useEffect(() => { indexRef.current = index }, [index]) useEffect(() => { const onChange = ({ window: { width }, }: { window: ScaledSize screen: ScaledSize }) => { const breakpointIndex = getBreakpointIndex({ width, breakpoints }) if (breakpointIndex !== indexRef.current) { setIndex(breakpointIndex) } } const unsubscribe: | { remove: () => void } | undefined = Dimensions.addEventListener('change', onChange) as | undefined | { remove: () => void } onChange({ window: Dimensions.get('window'), screen: Dimensions.get('screen'), }) return () => { if (!unsubscribe?.remove) { Dimensions.removeEventListener('change', onChange) } else { unsubscribe.remove() } } }, [breakpoints]) return index } export function BreakpointIndexProvider({ children, }: { children: React.ReactNode }) { const breakpointIndex = useCreateBreakpointIndex() return ( {children} ) }