import { fromPairs , memoize , partition } from 'lodash-es' ; import { ImageStyle , StyleProp , StyleSheet , TextStyle , ViewStyle } from 'react-native' ; template T param { boolean | undefined } condition param { T } style param { T } elseStyle returns { T | { } } example export const conditionalStyle = < T extends object > ( condition , style , elseStyle ? ) : T | { } => ( condition ? style : elseStyle ?? { } ) ; /**
 * A host style is a style that depends on it's parent, ie flex.
 * Styles like this HAVE to remain directly under their parent and
 * cannot be wrapped in another element without changing the behavior
 */ const HOST_STYLES = [ /flex$/ , /flexShrink/ , /flexGrow/ , /Self/ , /margin/ , /position/ , /top/ , /left/ , /right/ , /bottom/ , /height/ , /maxHeight/ , /width/ , /maxWidth/ ] ; param { StyleProp < T > } style returns { [ Partial < T > , Partial < T > ] } example export const extractHostStyles = < T extends ViewStyle | ImageStyle | TextStyle > ( style ? ) => { if ( ! style ) { return [ { } , { } ] as [ Partial < T > , Partial < T > ] ; } const styleSheet = StyleSheet . flatten ( style ) ; if ( Object . keys ( styleSheet ) . length === 0 ) { return [ { } , { } ] as [ Partial < T > , Partial < T > ] ; } const [ hostStylePairs , nonHostStylePairs ] = partition ( Object . entries ( styleSheet ) , ( [ style ] ) => HOST_STYLES . some ( hostStyle => hostStyle . test ( style ) ) ) ; const hostStyles = fromPairs ( hostStylePairs ) as T ; const nonHostStyles = { ... fromPairs ( nonHostStylePairs ) , ... conditionalStyle ( 'height' in hostStyles , { height : '100%' } ) , ... conditionalStyle ( 'width' in hostStyles , { width : '100%' } ) } ; return [ hostStyles as Partial < T > , nonHostStyles as Partial < T > ] as const ; } ; /**
 * A nested style is one that affects it's direct children, ie justify content
 * A style like this cannot have it's children wrapped in another element without
 * changing the behavior.
 */ const CONTAINER_STYLES = [ /display/ , /Content/ , /Items/ , /flex(?!$)/ ] ; param { StyleProp < T > } style returns { [ Partial < T > , Partial < T > ] } example export const extractContainerStyles = < T extends ViewStyle | ImageStyle | TextStyle > ( style ? ) => { if ( ! style ) { return [ { } , { } ] as [ Partial < T > , Partial < T > ] ; } const styleSheet = StyleSheet . flatten ( style ) ; if ( Object . keys ( styleSheet ) . length === 0 ) { return [ { } , { } ] as [ Partial < T > , Partial < T > ] ; } const [ nestedStyles , nonNestedStyles ] = partition ( Object . entries ( styleSheet ) , ( [ style ] ) => CONTAINER_STYLES . some ( nestedStyle => nestedStyle . test ( style ) ) ) ; return [ fromPairs ( nestedStyles ) , fromPairs ( nonNestedStyles ) ] as [ Partial < T > , Partial < T > ] ; } ; export const extractSandwichedStyles = < T extends ViewStyle | ImageStyle | TextStyle > ( style ? ) => { const [ host , updatedStyle ] = extractHostStyles ( style ) ; const [ container , self ] = extractContainerStyles ( updatedStyle ) ; return [ host , self , container ] as [ Partial < T > , Partial < T > , Partial < T > ] ; } ; export const extractFont = memoize ( ( textStyles ) : string | undefined => { const styles = StyleSheet . flatten ( textStyles ) ; return `${ styles ?. fontWeight ?? '400' } ${ ( styles ?. fontSize ?? 16 ) + ( styles ?. letterSpacing ?? 0 ) * 4 + 'px' }/${ ( styles ?. lineHeight ?? 1.2 * ( styles ?. fontSize ?? 16 ) ) + 'px' } ${ styles ?. fontFamily ?? '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif' }` ; } ) ;