highstyle
TypeScript icon, indicating that this package has built-in type declarations

0.2.6 • Public • Published

HighStyle

A toolkit for fast and flexible manipulation of inline styles using composable transformations.

npm install --save highstyle

Overview

HighStyle is a collection of utility functions for working with 'CSS in JS' style objects as simply as any other JS objects.

Specifically, these utilities smooth over the difficulties of working with CSS shorthand properties, as well as numeric properties provided as strings, which together cause numerous problems when working with style objects.

// given the provided style object:
// style = { margin: 20, fontSize: '16px' }
 
// returns undefined, not 20
style.marginTop;
 
// returns NaN, not 24
style.fontSize * 1.5

Inspired by higher-order components, all HighStyle utilities are (parameterised) transforms - pure functions which take one style object and return another. This allows them to be easily composed together, as well as memoized for efficiency.

transform(...args) = (style => style)

TOC

Manipulating specific CSS properties

highstyle.filter(...properties: string[]): (style => style)

Filter and return specific style properties.

highstyle.filter('width', 'marginTop')({ width: 100, height: 50, margin: 20 });
 
// returns { width: 100, marginTop: 20 }

highstyle.expandFor(...properties: string[]): (style => style)

Expand relevant shorthands to access the given properties.

highstyle.expandFor('marginTop')({ width: 100, margin: 20 });
 
// returns { width: 100, marginTop: 20, marginRight: 20, marginBottom: 20, marginLeft: 20 }

highstyle.numeric(...properties: string[]): (style => style)

Ensure the given properties are in numeric form (or 0 if undefined).

highstyle.numeric('width', 'marginTop')({ margin: '20px' });
 
// returns { width: 0, marginTop: 20, marginRight: '20px', marginBottom: '20px', marginLeft: '20px' }

Merging together style objects

highstyle.merge(...styles: Object[]): (style => style)

Merge in the given list of styles from left-to-right.

highstyle.merge({ margin: 20 }, { width: 100, marginRight: 30 })({ marginTop: 10 });
 
// returns { width: 100, marginTop: 20, marginRight: 30, marginBottom: 20, marginLeft: 20 }

highstyle.defaults(...styles: Object[]): (style => style)

Use the given defaults for undefined styles, merged in left-to-right.

highstyle.defaults({ width: 100, margin: 10 })({ marginTop: 20 });
 
// returns { width: 100, marginTop: 20, marginRight: 10, marginBottom: 10, marginLeft: 10 }

Working with nested styles

Roughly equivalent to CSS pseudo-classes, HighStyle can work with nested styles.

const style = {
  fontSize: 16,
  focus: {
    fontWeight: 'bold',
  },
  hover: {
    color: 'red',
    focus: {
      fontWeight: '900',
    },
  },
}

highstyle.mergeKeys(...keys: string[] | [{ [key]: boolean }]): (style => style)

Merge in the modifiers for the given keys, with deeper nested modifiers taking higher priority.

If the keys are provided as an object, those with truthy values will be used.

highstyle.mergeKeys('focus', 'hover')(style);
 
// returns { fontSize: 16, fontWeight: '900', color: 'yellow' }
highstyle.mergeKeys({ focus: true, hover: false })(style);
 
// returns { fontSize: 16, fontWeight: 'bold', hover: { color: 'red', fontWeight: '900' } }

highstyle.filterKeys(...keys: string[]): (style => style)

Filter and return only the nested styles for the given keys.

highstyle.filterKeys('hover')(style);
 
// returns { fontSize: 16, hover: { color: 'red' } }

mapStyle() - React higher-order component helper

HighStyle also comes with a higher-order component mapStyle to simplify using the above utilities to build complex React components which manipulate their provided inline styles.

This HOC allows for using the standard React style prop to hold individual or multiple styles, which are transformed according to the provided transforms.

// single
props.style = {
  fontSize: 16,
  margin: '10px 20px',
  ...
}
 
// multi
props.style = {
  text: {
    fontSize: 16,
  },
  panel: {
    background: '#ddd',
  },
  ...
}

The HOC accepts a single parameter mapPropsToTransforms, which has one of three forms depending on the shape of the style prop. For the second and third forms, the new styles are combined with the existing ones, overwriting only when the keys are the same.

// basic (maps single => single)
mapStyle(
  mapPropsToTransforms: (props) => (style => style)[]
): HigherOrderComponent
 
// split (maps single => multi)
mapStyle(
  mapPropsToTransforms: (props) => { [newKey]: (style => style)[] }
): HigherOrderComponent
 
// multi (maps multi => multi)
mapStyle(
  mapPropsToTransforms: (props) => { [baseKey]: { [newKey]: (style => style)[] } }
): HigherOrderComponent

Example 1

Here we use the basic mapStyle api to create a component ShortText which forces its contents to be red whenever they exceed 20 characters, along with a default fontFamily of Verdana.

import highstyle, { mapStyle } from 'highstyle';
 
const ShortText = mapStyle(
  ({ children }) => [
    highstyle.defaults({ fontFamily: 'Verdana' }),
    highstyle.merge({ color: children.length > 20 ? 'red' }),
  ],
)('p');
 
// This will be blue
<ShortText style={{ color: 'blue' }} >Hello World!</ShortText>
 
// This will be red
<ShortText style={{ color: 'blue' }} >Hello World! Hello World!</ShortText>

Example 2

Here we combine HighStyle with Recompose to create a HOC addHover which applies the nested hover style when the wrapped component is hovered.

import highstyle, { mapStyle } from 'highstyle';
import { compose, withState } from 'recompose';
 
const addHover = compose(
  withState('hovered', 'setHovered', false),
  withHandlers({
    onMouseMove: ({ setHovered }) => () => setHovered(true),
    onMouseLeave: ({ setHovered }) => () => setHovered(false),
  }),
  mapStyle(({ hovered }) => [
    highstyle.mergeKeys('hover'),
  ]),
);
 
const Link = addHover('a');
 
// This will be red when hovered over
<Link href="#" style={{ hover: { color: 'red' } }}>Click me!</Link>

Readme

Keywords

none

Package Sidebar

Install

npm i highstyle

Weekly Downloads

2

Version

0.2.6

License

MIT

Last publish

Collaborators

  • jsiwhitehead