createStyleFunction
Create custom style functions
import { createStyleFunction } from 'jynx'
The createStyleFunction
utility provides the ability to create custom style functions;
useful if you need regular access to properties that aren't accessible through any of the
current style functions.
Usage
The utility itself is a simple function that accepts a single argument in the form of a
config
object and returns a subsequent function that's then used to generate
style objects.
To use it, include it within the style argument of your component and pass it a
config
object.
export const Component = styled.div<Props>`
${createStyleFunction<Props>(config)}
`
Config
The config
object provides the parser with specific information regarding the CSS
properties being parsed, their correlating theme scales and if/how the values are
transformed before being added to the style object.
interface StyleFunctionConfig {
[key: string]: {
property: keyof CSSProperties
scale?: keyof DefaultTheme
transformer?: TransformFunction<any>
}
}
It's made up of a series of 'CSS property keys' each defining:
property
: the name of the CSS property used in the style objectscale
: an optional string reference to the key within the theme object of the property's corresponding scaletransformer
: an optional function used to transform the values before they're added to the style object
The example below demonstrates how a style function can be made for outline
styles:
/* Create a config object, defining CSS properties plus any theme */
/* scales and transformer functions */
const config: StyleFunctionConfig = {
outline: {
property: 'outline',
},
outlineColor: {
property: 'outlineColor',
scale: 'colors'
},
outlineWidth: {
property: 'outlineWidth',
},
outlineStyle: {
property: 'outlineStyle'
},
outlineOffset: {
property: 'outlineOffset',
scale: 'space'
}
}
/* When using typescript, a props type should be defined to add typings*/
/* to the return function*/
/* See the types section for more details */
interface OutlineProps {
outline?: StyleProp<CSS.Property.Outline>
outlineColor?: StyleProp<CSS.Property.OutlineColor | ThemeValue<'colors'>>
outlineWidth?: StyleProp<CSS.Property.OutlineWidth>
outlineStyle?: StyleProp<CSS.Property.Outline>
outlineOffset?: StyleProp<CSS.Property.OutlineOffset | ThemeValue<'space'>>
}
/* Then create an `outline` variable that calls `createStyleFunction` */
/* and passes it the config object */
const outline = createStyleFunction<OutlineProps>(config)
/* Include `outline` within the style argument of any styled component... */
export const ButtonContainer = styled.button<OutlineProps>`
${outline}
`
/* ...and style from within your tsx/jsx, the same as with any */
/* other style function */
const Button: React.FC = ({ children }) => {
return (
<ButtonContainer
outlineColor='primary[2]'
outlineStyle='solid'
outlineWidth={[1, 1.25, null, 2]}
>
{children}
</ButtonContainer>
)
}
Transformers
Transformer functions can be used to transform the values passed to the style function
before they're inserted into the style object. They are allocated within the config
object and applied individually to each value provided to their corresponding CSS prop.
Consider the following scenario:
We want to build a length
style function that styles only width
and height
CSS
properties. It will have access to the themes space
scale and will allow decimals
between 0
and 1
to act as percentage values.
To create this kind of functionality, we're going to need to first create a transformer function to handle the conversion of the decimals:
import { get } from 'lodash'
const lengthTransformer: TransformFunction<CSS.Property.Width> = (value, scale) => {
/* Create a boolean variable to determine whether `value` is a */
/* decimal between 0 and 1 */
const isPercentageDecimal = typeof value === 'number' && value < 1 && value > 0
/* Create a `fallback` variable that resolves to either a decimal or */
/* the original value based on `isPercentageDecimal` */
const fallback = isPercentageDecimal ? `${value * 100}%` : value
/* Use `lodash.get` to check if the original value returns anything */
/* from the provided scale and if not, return our fallback value */
return get(scale, value, fallback)
}
We can then set up the rest of the style function as normal, making sure when we define
the config object to pass the our lengthTransformer
to the relevant props.
/* Create a config object */
const config: StyleFunctionConfig = {
width: {
property: 'width',
scale: 'space',
/* Define the transformers for the relevant props */
transformer: lengthTransformer
}
height: {
property: 'height',
scale: 'space',
transformer: lengthTransformer
}
}
/* Define types for the props passed to `length` */
interface LengthProps {
width?: StyleProp<CSS.Property.Width | ThemeValue<'space'>>
height?: StyleProp<CSS.Property.Height | ThemeValue<'space'>>
}
/* Create a `length` variable that calls `createStyleFunction` */
/* and passes the config object */
const length = createStyleFunction<LengthProps>(config)
/* Include `length` within the style argument of any styled component */
export const Container = styled.div<LengthProps>`
${width}
`
/* Then style from within any jsx/tsx */
export const Layout: React.FC = ({children}) => {
return (
<Container width={['100vw', 0.75, 0.5 ]}>
{children}
</Container>
)
}
Types
The createStyleFunction
utility is defined as a function that takes a single argument of
a config
object and returns a style function.
A generic parameter T
is used to define typings for the props that can be passed to the
returned style function.
const createStyleFunction: <T>(config: StyleFunctionConfig): StyleFunction<T>