Wrap style objects with a fluent API for easy manipulation.
yarn add style-transform
When treated like plain JavaScript objects, 'CSS in JS' style objects don't always behave as you'd hope, due to shorthand properties, and numeric values sometimes being written as strings. For example:
const style1 = { marginLeft: 10 };
const style2 = { margin: 20 };
const style3 = { ...style1, ...style2 };
// Output: { marginLeft: 10, margin: 20 }
// Intention: { margin: 20 }
This library wraps style objects with a fluent API of utilities for manipulating them while avoiding these difficulties. These wrapped style objects can still be passed directly to React components.
import st from 'style-transform';
const style = st({
background: 'orange',
heading: {
background: 'red',
},
})
.defaults({ fontSize: '20px', color: 'black', background: 'white' })
.mergeKeys('heading')
.scale({ fontSize: 1.5 });
// {
// fontSize: 30,
// color: 'black',
// background: 'red',
// };
//
// Use in React: <p style={style}>Hello world!</p>
As in the example above, any style object (the wrapped one or one passed to a method) can optionally be nested, and the names of these nested styles are referred to as keys (i.e. the example style has a key of 'heading').
This nesting can be of any depth.
Once wrapped, the following methods will be available on the style object.
Merging takes both shorthand properties and nested styles into account, allowing styles to be easily combined together.
Merge the wrapped style with the provided styles
, with the wrapped style last.
const style = st({ margin: 20 }).defaults({ marginTop: 10, color: 'black' });
// { margin: 20, color: 'black' };
Merge the wrapped style with the provided styles
, with the wrapped style first.
const style = st({ margin: 20 }).merge({ marginTop: 10 });
// { marginTop: 10, marginRight: 20, marginBottom: 20, marginLeft: 20 };
Merge in the nested styles for the provided keys (given either as an array or a keyed object). For multiple keys, all paths covered will be merged, with more deeply nested styles overriding those below.
const style = st({
fontSize: 20,
active: {
fontSize: 30,
color: 'orange'
hover: {
color: 'red',
},
},
}).mergeKeys('active', 'hover');
// { fontSize: 30, color: 'red' };
These utilities transform specified values, and don't affect nested styles.
Expands any relevant shorthand styles to make the requested values available.
const style = st({ margin: 20 }).expandFor('marginTop');
// { marginTop: 20, marginRight: 20, marginBottom: 20, marginLeft: 20 };
Applies expandFor
to make the requested values available, then clears all other values.
const style = st({ margin: 20 }).filter('marginTop', 'marginBottom');
// { marginTop: 20, marginBottom: 20 };
Applies map
to the base styles, leaving nested styles unchanged.
const style = st({ margin: 20, hover: { color: 'red' } }).map(({ margin }) => ({
margin: margin * 2,
}));
// { margin: 40, hover: { color: 'red' } };
Applies expandFor
to make the requested values available, then converts them to numeric values if required (e.g. '16px'
becomes 16
).
const style = st({ margin: '20px' }).numeric('marginTop', 'marginBottom');
// { marginTop: 20, marginRight: '20px', marginBottom: 20, marginLeft: '20px' };
Calculates values as multiples of other values. The provided multipliers can simply be numbers, in which case the value itself is scaled, or another map of values and numbers, in which case those are calculated and added together.
const style = st({ margin: '20px' }).scale({
marginTop: 2,
marginBottom: { marginTop: 1, marginBottom: 2 },
});
// { marginTop: 40, marginRight: '20px', marginBottom: 60, marginLeft: '20px' };