import { useContext, useMemo } from "react"; import { useColorScheme, StyleSheet } from "react-native"; import theme from "mazlo-theme"; import { DimensionsContext } from "../components/DimensionsProvider"; type BaseStyleKeys = keyof typeof theme.breakpoints | "base" | "light" | "dark"; type BaseStyles = { [P in K]?: StyleSheet.NamedStyles; }; type ExtraKeys = Record; function mergeStyles< A extends StyleSheet.NamedStyles, B extends StyleSheet.NamedStyles >(style1: A, style2: B) { const mergedStyles = { ...style1 }; Object.keys(style2).forEach((key) => { mergedStyles[key as keyof A] = { ...mergedStyles[key as keyof A], ...style2[key as keyof B], }; }); return mergedStyles; } export default function useDynamicStyles< T extends BaseStyles, K extends ExtraKeys >(baseStyles: T, extraKeys?: K) { const { width } = useContext(DimensionsContext); const colorScheme = useColorScheme(); const sortedBreakpoints = useMemo( () => (Object.keys( theme.breakpoints ) as (keyof typeof theme.breakpoints)[]).sort( (a, b) => theme.breakpoints[a] - theme.breakpoints[b] ), [] ); const composedStyles = useMemo(() => { let styles = baseStyles.base; // breakpoints sortedBreakpoints.forEach((breakpoint) => { if (width >= theme.breakpoints[breakpoint] && baseStyles[breakpoint]) { styles = mergeStyles(styles, baseStyles[breakpoint]); } }); // appearance if (colorScheme && baseStyles[colorScheme]) { styles = mergeStyles(styles, baseStyles[colorScheme]); } // extras if (extraKeys) { Object.keys(extraKeys).forEach((extraKey) => { if (extraKeys[extraKey] && baseStyles[extraKey]) { styles = mergeStyles(styles, baseStyles[extraKey]); } }); } return styles; }, [baseStyles, extraKeys, width, colorScheme]); return composedStyles as Readonly; }