import { theme as _theme } from 'styled-tools' ; import tinycolor from 'tinycolor2' ; import { Palette , ThemeConfig } from '../types' ; import { css } from '../styled' ; import { useColorMode } from '../ColorMode/ColorModeContext' ; import { getColorFromCSSVariable } from '../ColorMode/utils' ; import { isRGBOrHSLOrHex } from './colors' ; import { isFunction } from './isFunction' ; import { get } from './get' ; import { getCSSFromStyleObject } from './getCSSFromStyleObject' ; import { useTheme } from './useTheme' ; type ScaleType = 'major' | 'minor' ; export function theme ( themeKey , path ? , defaultValue ? ) { return ( props ) => { const { colorMode , variant } = props ; const selector = `${ themeKey }${ path ? `.${ path }` : '' }` ; const variantSelector = `${ themeKey }.variants.${ variant }.${ path }` ; const colorModeSelector = `${ themeKey }.modes.${ colorMode }.${ path }` ; const defaultTheme = get ( props , `theme.${ selector }` ) || defaultValue ; const variantTheme = get ( props , `theme.${ variantSelector }` ) ; const colorModeTheme = get ( props , `theme.${ colorModeSelector }` ) ; let defaultThemeOverrides ; let variantThemeOverrides ; let colorModeThemeOverrides ; if ( props . overrides ) { defaultThemeOverrides = get ( props , `overrides.${ selector }` ) ; variantThemeOverrides = get ( props , `overrides.${ variantSelector }` ) ; colorModeThemeOverrides = get ( props , `overrides.${ colorModeSelector }` ) ; } if ( path && path . includes && path . includes ( 'styles' ) ) { const defaultThemeValue = isFunction ( defaultTheme ) ? defaultTheme ( props ) : defaultTheme ; const defaultThemeOverridesValue = isFunction ( defaultThemeOverrides ) ? defaultThemeOverrides ( props ) : defaultThemeOverrides ; const variantThemeValue = isFunction ( variantTheme ) ? variantTheme ( props ) : variantTheme ; const variantThemeOverridesValue = isFunction ( variantThemeOverrides ) ? variantThemeOverrides ( props ) : variantThemeOverrides ; const colorModeThemeValue = isFunction ( colorModeTheme ) ? colorModeTheme ( props ) : colorModeTheme ; const colorModeThemeOverridesValue = isFunction ( colorModeThemeOverrides ) ? colorModeThemeOverrides ( props ) : colorModeThemeOverrides ; let styles = { ... defaultThemeValue , ... defaultThemeOverridesValue , ... variantThemeValue , ... variantThemeOverridesValue , ... colorModeThemeValue , ... colorModeThemeOverridesValue , } ; if ( ! styles . styles ) { styles = getCSSFromStyleObject ( styles , props . theme , colorMode ) ; } return styles ; } const theme = colorModeThemeOverrides || colorModeTheme || variantThemeOverrides || variantTheme || defaultThemeOverrides || defaultTheme ; return isFunction ( theme ) ? theme ( props ) : theme ; } ; } export function altitude ( selector ? , defaultValue ? ) { return ( props ) => { const altitude = theme ( 'altitudes' , selector || props . altitude , defaultValue ) ( props ) ; return altitude ; } ; } export function useAltitude ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return altitude ( selector , defaultValue ) ( { theme } ) ; } export function border ( selector ? , defaultValue ? ) { return ( props ) => { const border = theme ( 'borders' , selector || props . border , defaultValue ) ( props ) ; return border ; } ; } export function useBorder ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return border ( selector , defaultValue ) ( { theme } ) ; } export function borderRadius ( selector ? , defaultValue ? ) { return ( props ) => { const borderRadius = theme ( 'borderRadii' , selector || props . borderRadius , defaultValue ) ( props ) ; return borderRadius ; } ; } export function useBorderRadius ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return borderRadius ( selector , defaultValue ) ( { theme } ) ; } export function font ( selector ? , defaultValue ? ) { return ( props ) => { const color = theme ( 'fonts' , selector || props . font , defaultValue ) ( props ) ; return color ; } ; } export function useFont ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return font ( selector , defaultValue ) ( { theme } ) ; } export function fontMetric ( selector ? ) { return ( props ) => { const fontMetrics = theme ( 'fontMetrics' , selector || props . fontMetrics ) ( props ) ; return fontMetrics ; } ; } export function useFontMetric ( selector ? ) { const { theme } = useTheme ( ) ; return fontMetric ( selector ) ( { theme } ) ; } export function fontSize ( selector ? , defaultValue ? ) { return ( props ) => { const color = theme ( 'fontSizes' , selector || props . fontSize , defaultValue ) ( props ) ; return color ; } ; } export function useFontSize ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return fontSize ( selector , defaultValue ) ( { theme } ) ; } export function fontWeight ( selector ? , defaultValue ? ) { return ( props ) => { const color = theme ( 'fontWeights' , selector || props . fontWeight , defaultValue ) ( props ) ; return color ; } ; } export function useFontWeight ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return fontWeight ( selector , defaultValue ) ( { theme } ) ; } export function lineHeight ( selector ? , defaultValue ? ) { return ( props ) => { const lineHeights = theme ( 'lineHeights' , selector || props . lineHeight , defaultValue ) ( props ) ; return lineHeights ; } ; } export function useLineHeight ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return lineHeight ( selector , defaultValue ) ( { theme } ) ; } export function letterSpacing ( selector ? , defaultValue ? ) { return ( props ) => { const letterSpacing = theme ( 'letterSpacings' , selector || props . letterSpacing , defaultValue ) ( props ) ; return letterSpacing ; } ; } export function useLetterSpacing ( selector ? , defaultValue ? ) { const { theme } = useTheme ( ) ; return letterSpacing ( selector , defaultValue ) ( { theme } ) ; } export function palette ( _selector ? , modes ? , { useCSSVariables = true } = { } ) { return ( props ) => { const selector = modes && modes [ props . colorMode ] ? modes [ props . colorMode ] : _selector ; let fallback = tinycolor ( selector ) . toHexString ( ) ; if ( selector === 'transparent' ) { fallback = 'transparent' ; } if ( isRGBOrHSLOrHex ( selector ) ) { return selector ; } if ( props . theme ?. useCSSVariables && useCSSVariables ) { return getColorFromCSSVariable ( selector , fallback ) ; } const color = theme ( 'palette' , selector || props . palette ) ( props ) ; if ( ! color ) return fallback ; return color ; } ; } export function usePalette ( selector , modes ? ) { const { theme } = useTheme ( ) ; const { colorMode } = useColorMode ( ) ; return palette ( selector , modes ) ( { colorMode , theme } ) ; } export function space ( _scalar , _scaleType = 'minor' ) { return ( props ) => { let scalar = _scalar ; let scaleType = _scaleType ; if ( ! scalar ) return 0 ; if ( typeof scalar === 'string' ) { let isNegative = false ; if ( scalar [ 0 ] === '-' ) { scalar = scalar . replace ( '-' , '' ) ; isNegative = true ; } if ( scalar . includes ( 'minor' ) || scalar . includes ( 'major' ) ) { [ scaleType , scalar ] = scalar . split ( '-' ) ; scalar = parseFloat ( scalar ) ; scalar = isNegative ? - scalar : scalar ; if ( isNaN ( scalar ) ) return 0 ; } else { const value = theme ( 'spacing' , scalar ) ( props ) ; return isNegative ? - value : value ; } } if ( typeof scalar === 'number' ) { const unitSize = props ?. theme ?. spacing ?. [ `${ scaleType }Unit` ] as number ; const fontSize = props ?. theme ?. global ?. fontSize ; const value = scalar * ( unitSize / fontSize ) ; return value ; } } ; } export function useSpace ( scalar , scaleType ) { const { theme } = useTheme ( ) ; return space ( scalar , scaleType ) ( { theme } ) ; } export function breakpoint ( breakpoint , cssStyle , config ? ) { const { else : elseStyle = '' , show = false } = config || { } ; return ( props ) => { if ( ! breakpoint ) return css `
        ${ elseStyle };
      ` ; let key ; let elseKey ; if ( ! show && breakpoint . includes ( 'max' ) ) { key = 'max-width' ; elseKey = 'min-width' ; } else if ( ! show && breakpoint . includes ( 'min' ) ) { key = 'min-width' ; elseKey = 'max-width' ; } else if ( show && breakpoint . includes ( 'max' ) ) { key = 'min-width' ; elseKey = 'max-width' ; } else if ( show && breakpoint . includes ( 'min' ) ) { key = 'max-width' ; elseKey = 'min-width' ; } let strippedBreakpoint = breakpoint ; strippedBreakpoint = strippedBreakpoint . replace ( 'max-' , '' ) ; strippedBreakpoint = strippedBreakpoint . replace ( 'min-' , '' ) ; const minBreakpointValues = { mobile : 0 , tablet : props ?. theme ?. breakpoints ?. mobile , desktop : props ?. theme ?. breakpoints ?. tablet , widescreen : props ?. theme ?. breakpoints ?. desktop , fullHD : props ?. theme ?. breakpoints ?. widescreen , } ; let breakpointValue = props ?. theme ?. breakpoints ?. [ strippedBreakpoint ] ; if ( ! show && breakpoint . includes ( 'max' ) ) { breakpointValue = breakpointValue - 1 ; } if ( ! show && breakpoint . includes ( 'min' ) ) { breakpointValue = minBreakpointValues [ strippedBreakpoint ] ; } if ( show && breakpoint . includes ( 'min' ) ) { breakpointValue = minBreakpointValues [ strippedBreakpoint ] - 1 ; } if ( ! breakpoint . includes ( 'min-' ) && ! breakpoint . includes ( 'max-' ) ) { if ( show ) { return css `
          @media screen and (max-width: ${ minBreakpointValues [ breakpoint ] }px) {
            ${ cssStyle };
          }
          @media screen and (min-width: ${ breakpointValue + 1 }px) {
            ${ cssStyle };
          }

          @media screen and (min-width: ${ minBreakpointValues [ breakpoint ] + 1 }px) and (max-width: ${ breakpointValue }px) {
            ${ elseStyle };
          }
        ` ; } return css `
        @media screen and (min-width: ${ minBreakpointValues [ breakpoint ] }px) and (max-width: ${ breakpointValue - 1 }px) {
          ${ cssStyle };
        }

        @media screen and (max-width: ${ minBreakpointValues [ breakpoint ] - 1 }px) {
          ${ elseStyle };
        }
        @media screen and (min-width: ${ breakpointValue }px) {
          ${ elseStyle };
        }
      ` ; } return css `
      @media screen and (${ key }: ${ breakpointValue }px) {
        ${ cssStyle };
      }
      @media screen and (${ elseKey }: ${ breakpointValue + ( elseKey . includes ( 'max' ) ? - 1 : 1 ) }px) {
        ${ elseStyle };
      }
    ` ; } ; }