/* * Copyright (c) 2018-present, Revolut LTD. * * This source code is licensed under the Apache 2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { Interpolation, InterpolationFunction, ThemedCssFunction, } from 'styled-components' import { NonFunctionKeys } from 'utility-types' import { space as ssSpace, style as ssStyle, fontSize as ssFontSize } from 'styled-system' import { theme as themeFn } from 'styled-tools' import * as _ from 'lodash' import { ThemeFields } from './themeFields' import { theme as defaultTheme, DefaultTheme } from './theme.main' type BooleanFunction
= (props: P) => boolean type CallbackOrPropKey
= NonFunctionKeys
| BooleanFunction
type CallbackOrValue
= Interpolation
| ThemedCssFunction
/**
* Same as style from `styled-system` but wrapped with decorator, for custom things
*/
export function style(options) {
return withTheme(ssStyle(options))
}
export function themeGet (prop: keyof P, defaultValue?: string | number) => (
props: P,
) => {
const value = props[prop] as any
return value === 0 || value ? value : defaultValue
}
const px = (it: any) => {
return it.toString().endsWith('px') ? it : it + 'px'
}
/**
* Gets prop value from props object by prop name and convert it to css units
*/
export const getUnitProp = (prop, defaultValue = '') =>
_.flow(
propGet (prop, defaultValue),
px,
)
/**
* Adds support for css prop to inject css interpolation extending the styles in this way.
*/
export const cssMixin = (cssProp = 'css') =>
// @ts-ignore
withTheme (props => props[cssProp])
export const colorGet = getter({
key: ThemeFields.Colors,
})
export const fontFamilyGet = getter({
key: ThemeFields.FontFaces,
})
export const fontSizeGet = getter({
key: ThemeFields.FontSizes,
})
export const shadowGet = getter({
key: ThemeFields.Shadows,
})
export const paddingGet = getter({
key: ThemeFields.Padding,
})
/**
* Mandatory to use for all theme related interpolations.
*
* Wraps styled-component interpolation function injecting default theme if styled-component has no ThemeProvider above
* him. Enables all dependent on theme interpolations/components to be ThemeProvider agnostic so you can use components
* without it.
*/
export function withTheme (
callback: InterpolationFunction ,
): InterpolationFunction {
return ({ theme, ...rest }: P & { theme: Theme }) => {
if (theme !== null && theme !== undefined && Object.keys(theme).length !== 0) {
return callback({ theme, ...rest } as P & { theme: Theme })
}
return callback({ theme: defaultTheme, ...rest } as P & { theme: Theme })
}
}
/**
* Helper function to generate interpolation function for getting variants out of variant function.
* Variant function should get theme and return object with keys of 'danger', 'info' etc. and styles for them
*/
export function variantsGet(getVariantFn) {
return withTheme<{ variant?: string }>(
props => getVariantFn(props.theme)[props.variant] || {},
)
}
function guardArgument(arg) {
switch (typeof arg) {
case 'function':
return props => arg(props)
default:
return () => arg
}
}
const ifPropCurried = _.curry((propKeyOrCondFn, ifValue, elseValue) => props => {
const conditionGuard =
typeof propKeyOrCondFn === 'function'
? () => propKeyOrCondFn(props)
: () => props[propKeyOrCondFn]
const ifGuard = guardArgument(ifValue)
const elseGuard = guardArgument(elseValue)
return conditionGuard() ? ifGuard(props) : elseGuard(props)
})
// curry(A, B, C)
export function ifProp (
propKeyOrCondFn: CallbackOrPropKey ,
ifValue: CallbackOrValue ,
elseValue: CallbackOrValue ,
): InterpolationFunction
// curry(A)(B, C)
export function ifProp (
propKeyOrCondFn: CallbackOrPropKey ,
): (
propKeyOrCondFn: CallbackOrPropKey ,
ifValue?: CallbackOrValue ,
elseValue?: CallbackOrValue ,
) {
if (propKeyOrCondFn !== undefined && ifValue === undefined) {
return ifPropCurried(propKeyOrCondFn) as
}