import React, { useContext } from 'react'; import { ThemeContext } from '@emotion/core'; import { useEffect } from 'react'; import { Dimensions, ScaledSize, Platform } from 'react-native'; import { useCallback } from 'react'; import { Theme, ReactNativeStyle, AnyStyle } from './types/StyleSheet'; import { StyleSheet, findBreakpoints } from './StyleSheet'; import memoize from 'lodash.memoize'; import { useMemo } from 'react'; import { useState } from 'react'; type AnyProps = { style: AnyStyle; [key: string]: any; } & any; function withResponsive>( Component: T ): React.ForwardRefExoticComponent< React.ComponentPropsWithoutRef & { ref?: React.Ref>; } & AnyProps >; function withResponsive

}>( Component: React.ForwardRefExoticComponent

): React.ForwardRefExoticComponent

; function withResponsive

( Component: React.FunctionComponent

): React.ForwardRefExoticComponent

; function withResponsive

( Component: React.ComponentType

) { // I don't know how to implement this without breaking out of the types. // The overloads are ensuring correct usage, so we should be good? const Responsive = React.forwardRef( ({ style, children, ...props }, ref) => { const theme = useContext(ThemeContext) as Theme; const getStylesheet = memoize( (styles: any, _breakpoint: number | undefined) => { return StyleSheet.create({ styles, }).styles as any; }, (_styles: any, _breakpoint: number | undefined) => breakpoint ); const styles = useMemo(() => { if (!style) return {}; // Adds support for `screen` media queries to support Styled System // @see https://github.com/styled-system/styled-system/pull/1133 // @see https://github.com/vitalets/react-native-extended-stylesheet/pull/132 const _styles = Object.keys(style).reduce( (acc: AnyStyle, key) => { acc[key.replace('screen', Platform.OS)] = style[key]; return acc; }, {} ); return _styles; }, [style]); const remValue = useMemo(() => { try { return Number(StyleSheet.value('$rem')); } catch { return Number(theme?.rem || 16); } }, [theme]); const breakpoints = useMemo(() => { return findBreakpoints(styles, remValue); }, [styles, remValue]); const getBreakpoint = useCallback( (width: number): number | undefined => { return (breakpoints || []).find((item: number) => width < item); }, [breakpoints] ); const [breakpoint, setBreakpoint] = useState( getBreakpoint(Dimensions.get('window').width) ); const onDimesionsChange = useCallback( ({ window }: { window: ScaledSize; screen: ScaledSize }) => { StyleSheet.build({ $theme: getBreakpoint(window.width), }); setBreakpoint(getBreakpoint(window.width)); }, [getBreakpoint] ); useEffect(() => { if (style && breakpoints.length) { Dimensions.addEventListener('change', onDimesionsChange); return () => Dimensions.removeEventListener('change', onDimesionsChange); } else { return () => null; } }, [breakpoints]); const stylesheet = getStylesheet(styles, breakpoint); return ( {children} ); } ); return Responsive; } export { withResponsive };