diff --git a/src/composeRestyleFunctions.ts b/src/composeRestyleFunctions.ts index c0b05ffe..6b3f817c 100644 --- a/src/composeRestyleFunctions.ts +++ b/src/composeRestyleFunctions.ts @@ -5,6 +5,7 @@ import { BaseTheme, Dimensions, RNStyle, + RestyleFunction, } from './types'; import {AllProps} from './restyleFunctions'; @@ -26,18 +27,19 @@ const composeRestyleFunctions = < const properties = flattenedRestyleFunctions.map(styleFunc => { return styleFunc.property; }); - const funcs = flattenedRestyleFunctions - .sort( - (styleFuncA, styleFuncB) => - Number(styleFuncB.variant) - Number(styleFuncA.variant), - ) - .map(styleFunc => { - return styleFunc.func; - }); + const propertiesMap = properties.reduce( + (acc, prop) => ({...acc, [prop]: true}), + {} as Record, + ); + + const funcsMap = flattenedRestyleFunctions.reduce( + (acc, each) => ({[each.property]: each.func, ...acc}), + {} as Record>, + ); // TInputProps is a superset of TProps since TProps are only the Restyle Props - const buildStyle = ( - props: TInputProps, + const buildStyle = ( + props: TProps, { theme, dimensions, @@ -46,15 +48,20 @@ const composeRestyleFunctions = < dimensions: Dimensions; }, ): RNStyle => { - const styles = funcs.reduce((acc, func) => { - return Object.assign(acc, func(props, {theme, dimensions})); - }, {}); + const styles = Object.keys(props).reduce( + (styleObj, propKey) => ({ + ...styleObj, + ...funcsMap[propKey as keyof TProps](props, {theme, dimensions}), + }), + {}, + ); const {stylesheet} = StyleSheet.create({stylesheet: styles}); return stylesheet; }; return { buildStyle, properties, + propertiesMap, }; }; diff --git a/src/createRestyleComponent.tsx b/src/createRestyleComponent.tsx index 5310ba1d..5f4daa1e 100644 --- a/src/createRestyleComponent.tsx +++ b/src/createRestyleComponent.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {View} from 'react-native'; +import composeRestyleFunctions from './composeRestyleFunctions'; import {BaseTheme, RestyleFunctionContainer} from './types'; import useRestyle from './hooks/useRestyle'; @@ -13,8 +14,10 @@ const createRestyleComponent = < | RestyleFunctionContainer[])[], BaseComponent: React.ComponentType = View, ) => { + const composedRestyleFunction = composeRestyleFunctions(restyleFunctions); + const RestyleComponent = React.forwardRef((props: Props, ref) => { - const passedProps = useRestyle(restyleFunctions, props); + const passedProps = useRestyle(composedRestyleFunction, props); return ; }); type RestyleComponentType = typeof RestyleComponent; diff --git a/src/hooks/useRestyle.ts b/src/hooks/useRestyle.ts index be476c38..75e5ef41 100644 --- a/src/hooks/useRestyle.ts +++ b/src/hooks/useRestyle.ts @@ -1,8 +1,7 @@ import {useMemo} from 'react'; -import {StyleProp} from 'react-native'; +import {StyleProp, ViewStyle, TextStyle, ImageStyle} from 'react-native'; -import {BaseTheme, RestyleFunctionContainer, RNStyle} from '../types'; -import composeRestyleFunctions from '../composeRestyleFunctions'; +import {BaseTheme, RNStyle, Dimensions} from '../types'; import {getKeys} from '../typeHelpers'; import useDimensions from './useDimensions'; @@ -13,24 +12,20 @@ const filterRestyleProps = < TProps extends Record & TRestyleProps >( props: TProps, - omitList: (keyof TRestyleProps)[], -): Omit => { - const omittedProp = omitList.reduce>( - (acc, prop) => { - acc[prop] = true; - return acc; - }, - {} as Record, - ); - + omitPropertiesMap: Record, +) => { return getKeys(props).reduce( - (acc, key) => { - if (!omittedProp[key as keyof TRestyleProps]) { - acc[key] = props[key]; + ({cleanProps, restyleProps}, key) => { + if (omitPropertiesMap[key as keyof TProps]) { + return {cleanProps, restyleProps: {...restyleProps, [key]: props[key]}}; + } else { + return {cleanProps: {...cleanProps, [key]: props[key]}, restyleProps}; } - return acc; }, - {} as TProps, + {cleanProps: {}, restyleProps: {}} as { + cleanProps: TProps; + restyleProps: TRestyleProps; + }, ); }; @@ -39,9 +34,20 @@ const useRestyle = < TRestyleProps extends Record, TProps extends TRestyleProps & {style?: StyleProp} >( - restyleFunctions: ( - | RestyleFunctionContainer - | RestyleFunctionContainer[])[], + composedRestyleFunction: { + buildStyle: ( + props: TInputProps, + { + theme, + dimensions, + }: { + theme: Theme; + dimensions: Dimensions; + }, + ) => ViewStyle | TextStyle | ImageStyle; + properties: (keyof TProps)[]; + propertiesMap: Record; + }, props: TProps, ) => { const theme = useTheme(); @@ -49,18 +55,18 @@ const useRestyle = < const dimensions = useDimensions(); const restyled = useMemo(() => { - const composedRestyleFunction = composeRestyleFunctions(restyleFunctions); - const style = composedRestyleFunction.buildStyle(props, { + const {cleanProps, restyleProps} = filterRestyleProps( + props, + composedRestyleFunction.propertiesMap, + ); + const style = composedRestyleFunction.buildStyle(restyleProps, { theme, dimensions, }); - const cleanProps = filterRestyleProps( - props, - composedRestyleFunction.properties, - ); - (cleanProps as TProps).style = [style, props.style].filter(Boolean); + + cleanProps.style = [style, props.style].filter(Boolean); return cleanProps; - }, [restyleFunctions, props, dimensions, theme]); + }, [composedRestyleFunction, props, dimensions, theme]); return restyled; }; diff --git a/src/test/useRestyle.test.tsx b/src/test/useRestyle.test.tsx index ee2e8d20..330fcffb 100644 --- a/src/test/useRestyle.test.tsx +++ b/src/test/useRestyle.test.tsx @@ -4,6 +4,7 @@ import {Text, TouchableOpacity} from 'react-native'; import useRestyle from '../hooks/useRestyle'; import {position, PositionProps} from '../restyleFunctions'; import createVariant, {VariantProps} from '../createVariant'; +import composeRestyleFunctions from '../composeRestyleFunctions'; const theme = { colors: {}, @@ -15,21 +16,27 @@ const theme = { phone: 0, tablet: 376, }, + zIndices: { + phone: 5, + }, }; type Theme = typeof theme; type Props = VariantProps & - PositionProps & { - title: string; - } & ComponentPropsWithoutRef; + PositionProps & + ComponentPropsWithoutRef; const restyleFunctions = [ position, - createVariant({themeKey: 'buttonVariants'}), + createVariant({themeKey: 'buttonVariants'}), ]; -function Button({title, ...rest}: Props) { - const props = useRestyle(restyleFunctions, rest); +const composedRestyleFunction = composeRestyleFunctions( + restyleFunctions, +); + +function Button({title, ...rest}: Props & {title: string}) { + const props = useRestyle(composedRestyleFunction, rest); return ( {title}