import { CSSObject , UseThemeFunction } from '@theme-ui/css' ; import { Platform } from 'react-native' ; import { defaultBreakpoints } from './breakpoints' ; import { SUPPORT_FRESNEL_SSR } from '../utils/deprecated-ssr' ; import { DripsyFinalTheme } from '../declarations' ; import type { SxProp } from './types' ; import { get } from './get' ; import { Aliases , aliases , scales , Scales } from './scales' ; type SxProps = SxProp ; type Theme = DripsyFinalTheme ; type CssPropsArgument = ( { theme ? : Theme ; } | Theme ) & { /**
     * We use this for a custom font family.
     */ fontFamily ? : string ; themeKey ? : keyof DripsyFinalTheme ; } ; const defaultTheme = { space : [ 0 , 4 , 8 , 16 , 32 , 64 , 128 , 256 , 512 ] , fontSizes : [ 12 , 14 , 16 , 20 , 24 , 32 , 48 , 64 , 72 ] } ; export type ResponsiveSSRStyles = Exclude < NonNullable < SxProps > , UseThemeFunction > [ ] ; const responsive = ( styles , { breakpoint } = { } ) => ( theme ? ) => { const next = { } ; for ( const key in styles ) { const value = typeof styles [ key ] === 'function' ? styles [ key ] ( theme ) : styles [ key ] ; if ( value == null ) continue ; if ( ! Array . isArray ( value ) ) { next [ key ] = value ; continue ; } if ( key === 'transform' ) { next [ key ] = value ; continue ; } if ( Platform . OS === 'web' && SUPPORT_FRESNEL_SSR ) { next . responsiveSSRStyles = next . responsiveSSRStyles || [ ] ; const mediaQueries = [ 0 , ... defaultBreakpoints ] ; for ( let i = 0 ; i < mediaQueries . length ; i ++ ) { next . responsiveSSRStyles [ i ] = next . responsiveSSRStyles [ i ] || { } ; let styleAtThisMediaQuery = value [ i ] ; if ( styleAtThisMediaQuery == null ) { if ( i === 0 ) { continue ; } const nearestBreakpoint = ( breakpointIndex ) : number => { if ( breakpointIndex <= 0 || typeof breakpointIndex !== 'number' ) return 0 ; if ( value [ breakpointIndex ] == null ) { return nearestBreakpoint ( breakpointIndex - 1 ) ; } return breakpointIndex ; } ; const previousBreakpoint = nearestBreakpoint ( i ) ; const styleAtPreviousMediaQuery = value [ previousBreakpoint ] ; if ( styleAtPreviousMediaQuery ) { styleAtThisMediaQuery = styleAtPreviousMediaQuery ; } } next . responsiveSSRStyles [ i ] [ key ] = styleAtThisMediaQuery ; } } else { const nearestBreakpoint = ( breakpointIndex ) : number => { if ( breakpointIndex <= 0 || typeof breakpointIndex !== 'number' ) return 0 ; if ( value [ breakpointIndex ] == null ) { return nearestBreakpoint ( breakpointIndex - 1 ) ; } return breakpointIndex ; } ; const breakpointIndex = nearestBreakpoint ( breakpoint as number ) ; next [ key ] = value [ breakpointIndex ] ; } } return next ; } ; const positiveOrNegative = ( scale , value ) => { if ( typeof value !== 'number' || value >= 0 ) { if ( typeof value === 'string' && value . startsWith ( '-' ) ) { const valueWithoutMinus = value . substring ( 1 ) ; const n = get ( scale , valueWithoutMinus , valueWithoutMinus ) ; return `-${ n }` ; } return get ( scale , value , value ) ; } const absolute = Math . abs ( value ) ; const n = get ( scale , absolute , absolute ) ; if ( typeof n === 'string' ) return '-' + n ; return Number ( n ) * - 1 ; } ; const transforms = [ 'margin' , 'marginTop' , 'marginRight' , 'marginBottom' , 'marginLeft' , 'marginX' , 'marginY' , 'marginBlock' , 'marginBlockEnd' , 'marginBlockStart' , 'marginInline' , 'marginInlineEnd' , 'marginInlineStart' , 'top' , 'bottom' , 'left' , 'right' , ] . reduce ( ( acc , curr ) => ( { ... acc , [ curr ] : positiveOrNegative } ) , { } ) ; /**
 * Here we remove web style keys from components to prevent annoying errors on native
 */ const filterWebStyleKeys = ( styleProp = { } ) : Exclude < SxProps , UseThemeFunction > => { if ( Platform . OS == 'web' ) { return styleProp ; } const finalStyles = { ... styleProp } ; const webOnlyKeys = [ 'animationKeyframes' , 'animationFillMode' , 'transitionProperty' , 'whiteSpace' , 'userSelect' , 'transitionDuration' , 'transitionTimingFunction' , 'cursor' , 'animationDuration' , 'animationDelay' , 'transitionDelay' , 'animationDirection' , 'animationIterationCount' , 'outlineColor' , ] ; webOnlyKeys . forEach ( ( key ) => { if ( finalStyles ?. [ key as keyof typeof styleProp ] ) { delete finalStyles ?. [ key as keyof typeof styleProp ] ; } } ) ; return finalStyles ; } ; export const css = ( args = { } , breakpoint ? ) => ( { themeKey , fontFamily : fontFamilyFromProps , ... props } = { } ) : CSSObject => { const theme = { ... defaultTheme , ... ( 'theme' in props ? props . theme : props ) } as DripsyFinalTheme ; let result = { } ; const obj = typeof args === 'function' ? args ( theme ) : args ; const filteredOutWebKeys = filterWebStyleKeys ( obj ) ; const styles = responsive ( filteredOutWebKeys , { breakpoint } ) ( theme ) ; for ( const key in styles ) { const x = styles [ key ] ; const val = typeof x == 'function' ? x ( theme ) : x ; if ( key == 'variant' ) { const variant = css ( get ( theme , themeKey + '.' + val , get ( theme , val ) ) , breakpoint ) ( { theme } ) ; result = { ... result , ... variant } ; continue ; } if ( key == 'transform' ) { result [ key ] = val ; continue ; } if ( key == 'textShadow' && val && theme . textShadows ?. [ val ] ) { const styledTextShadow = css ( theme . textShadows [ val ] , breakpoint ) ( theme ) ; result = { ... result , ... styledTextShadow } ; continue ; } if ( key == 'boxShadow' && val && theme . shadows ?. [ val ] ) { const styledBoxShadow = css ( theme . shadows [ val ] , breakpoint ) ( theme ) ; result = { ... result , ... styledBoxShadow } ; continue ; } if ( val === '' ) { console . error ( `[dripsy] Invalid style. You passed an empty string ('') for ${ key }. Please fix this.` ) ; continue ; } if ( val && typeof val == 'object' ) { result [ key ] = css ( val , breakpoint ) ( theme ) ; continue ; } if ( typeof val == 'boolean' ) { continue ; } const prop = key in aliases ? aliases [ key as keyof Aliases ] : key ; const scaleName = prop in scales ? scales [ prop as keyof Scales ] : undefined ; const scale = get ( theme , scaleName , get ( theme , prop , { } ) ) ; const transform = get ( transforms , prop , get ) ; const value = transform ( scale , val , val ) ; if ( key === 'fontFamily' ) { if ( result ?. fontFamily ) { continue ; } if ( value === 'root' ) { if ( ! theme ?. fonts ?. root ) { continue ; } } } if ( key == 'fontWeight' && styles ?. fontWeight ) { const fontFamilyKeyFromStyles = ( styles ?. fontFamily as string ) ?? fontFamilyFromProps ; const rootFontFamilyFromTheme = theme ?. fonts ?. root ; if ( fontFamilyKeyFromStyles || rootFontFamilyFromTheme ) { const fontWeight = value ; let fontFamily ; if ( fontFamilyKeyFromStyles ) { fontFamily = theme ?. fonts ?. [ fontFamilyKeyFromStyles ] ?? fontFamilyKeyFromStyles ; } else if ( rootFontFamilyFromTheme ) { fontFamily = rootFontFamilyFromTheme ; } if ( fontFamily ) { if ( typeof fontFamily != 'string' ) { console . error ( `[dripsy] error. Passed font family name that was not a string. This value should either be a string which corresponds to a key of your theme.fonts, or, it should be a string that corresponds to a raw font name. Your font will not be applied, please resolve this.` ) ; continue ; } const customFontFamilyForWeight = theme ?. customFonts ?. [ fontFamily ] ?. [ fontWeight ] ; if ( customFontFamilyForWeight ) { result . fontFamily = customFontFamilyForWeight ; continue ; } } } } if ( key == 'size' ) { result . width = value ; result . height = value ; } else { result [ prop ] = value ; } } return result ; } ; export class Styles { static create < T extends { [ key ] : NonNullable < SxProps > ; } > ( styles ) { return styles ; } }