systemthing
v1.74.0
Published
Responsive, theme-based style props for building design systems
Downloads
9
Maintainers
Readme
A System Thing
Responsive, theme-based style props for building design systems in ~~React~~ JavaScript
npm i systemthing
This repository is a fork of the styled-system.
As with styled-system, this fork presents a collection of css-style yielding functions that support the development of responsive and theme-based design systems in JavaScript.
Unlike styled-system, this implementation is geared to also work with virtual dom libraries other than React.
Features
This fork provides the same core functionality found in the orignal styled-system libary,
plus:
- Works with any virtual DOM view layer (e. g. Mithril)
- Works great in tandem with bss and stylething.
minus:
- Social proof, i. e. not used in Rebass et al.
Table of Contents
Notable differences
While this implementation tries to stay as close as possible to styled-system's original API, the following changes were made:
non-contextual theming
Style yielding functions can be called with a custom theme by passing a theme-object as a second argument.
import { space, fontSize, color } from 'systemthing'
const theme = {
breakpoints: [ '32em', '48em', '64em' ],
space: [ 0, 6, 12, 18, 24 ],
fontSizes: [ 12, 16, 18, 24, 36, 72 ],
radii: [ 2, 4 ],
colors: {
blue: '#07c',
green: '#1c0',
gray: ['#ccc', '#555']
}
}
// aliases
theme.space.big = 64
theme.fontSizes.big = 128
const blue = color({ color: 'blue' }, theme) // yields { color: '07c' }
const big = fontSize({ fontSize: 'big' }, theme) // yields { fontSize: '128px' }
const butAlso = space({ padding: 'big', theme }) // yields { padding: '64px' }
Passing a theme as 2nd argument bypasses React context
and allows this implementation to work in concert with any virtual DOM based view layer.
It is still possible however to also use theme
as a prop on the first argument. Prop based themes take precedence. styled-system's original theming mechanism remains intact.
No prop abbreviations
Mapping of popular style prop abbreviations to corresponding css properties (e. g. mt
to marginTop
) is delegated downstream. The only exceptions are mx
, my
, px
and py
within the space
function. For there are no css equivalents to these props.
Default values
It is possible to directly instrument style yielding functions with default values as a fallback in case no corresponding style props are present at call time.
import { space } from 'systemthing'
const spaceWithDefaults = space.withDefaults({ padding: '1em' })
const spaced = spaceWithDefaults({ foo: 'bar' }) // { padding: '1em' }
Responsive default styles may be useful for defining components that do not require expensive style re-computations down the line.
Prop bundling
To minimize the number of downstream function calls, style props are bundled into a single function where possible.
import { flexbox } from 'systemthing'
const flexing = flexbox({
display: 'flex',
justifyContent: 'center',
flexDirection: 'row-reverse'
})
The following prop bundles are available:
1. backgrounds
bundled props:
background
,
backgroundImage
,
backgroundPosition
,
backgroundRepeat
,
backgroundSize
2. borders
bundled props:
border
,
borderTop
,
borderRight
,
borderBottom
,
borderLeft
3. color
bundled props:
color
,
backgroundColor
4. direction
bundled props:
top
,
right
,
bottom
,
left
5. flexbox
bundled props:
display
,
alignContent
,
alignSelf
,
justifyContent
,
justifyItems
,
justifySelf
,
flex
,
flexBasis
,
flexDirection
,
flexWrap
,
order
6. gridLayout
bundled props:
gridArea
,
gridAutoColumns
,
gridAutoFlo
',
gridAutoRows
,
gridRow
,
gridRowGap
,
gridTemplateAreas
,
gridTemplateColumns
,
gridTemplateRows
7. gridGaps
bundled props:
gridColumnGap
,
gridGap
,
gridRow
,
gridRowGap
,
8. space
bundled props:
margin
,
marginTop
,
marginRight
,
marginBottom
,
marginLeft
,
mx
,
my
,
padding
,
paddingTop
,
paddingRight
,
paddingBottom
,
paddingLeft
,
px
,
py
No PropTypes
Facebook's prop-types
has been removed. Instead type declaration is delegated downstream. Users of this fork have to be prepared to properly type out components themselves, if necessary. This fork ships without external dependencies.
Width fit & fill
The width
style yielding function accepts two additional prop values:
{ width: 'fit' }
- Make an element shrink wrap its content withflex-basis
.{ width: 'fill' }
- Make an element fill the remaining space. Distribute space evenly on multiple elements.
low level changes
get
The get
utility function accepts excactly two arguments obj :: Object
and path :: Array
. get
's path
argument is not being destructured.
Hence, instead of writing:
// wrong
let bingo = get({ path: { in: { obj: 'Bingo' } } }, 'path', 'in', 'obj')
you'd have to write:
// correct
let bingo = get({ path: { in: { obj: 'Bingo' } } }, [ 'path', 'in', 'obj' ])
Secondly, dot notation in path
strings is not supported out of the box. The following statement will fail to produce the desired result:
// wont work
let bingo = get({ path: { in: { obj: 'Bingo' } } }, [ 'path.in.obj' ])
Note: Refactoring the get
function apparently resulted in significant performance improvements for some style functions.
num
The num
utility is renamed to isNum
.
px
The px
transformation utility is renamed to addPx
.
cloneFunc
The cloneFunc
utility has been removed together with the prop-types
dependency.
merge
The merge
utility is renamed to mergeStyles
.
compose
The compose
utility is renamed to composeStyleFns
. (may be removed entirely, as it is only used in a benchmarking script right now)
style
The style
utility function is renamed to createStyleFn
.
The original function was refactored to also process arrays when passed as prop
and cssProptery
arguments. This enables the prop bundling functionality described above.
import { util } from 'systemthing'
const custom = util.createStyleFn({
prop: [ 'display', 'overflow', 'opacity' ]
})
const result = custom({ display: 'none', overflow: 'hidden' })
mixed
The mixed
utility has been removed entirely.
Usage
This implementation maintains most of styled-system's original API.
Here is an idiomatic usage example:
// Usage in tandem with compatible css-in-js lib is recommended
// Example uses bss, but systemthing works with most other css-in-js libraries as well
import b from 'bss'
import { color, fontSize, util } from 'systemthing'
// custom theme
const theme = {
breakpoints: [ '32em', '48em', '64em' ],
space: [ 0, 6, 12, 18, 24 ],
fontSizes: [ 12, 16, 18, 24, 36, 72 ],
colors: {
blue: '#07c',
green: '#1c0',
grays: [ '#ccc', '#555', '#ddd' ]
}
}
// define style props
const props = {
// responsive background-color (theme.colors)
backgroundColor: [ 'blue', 'green', 'grays.1', 'grays.2' ],
// responsive font-size of 24px, 36px or 72px (theme.fontSizes)
fontSize: [ 3, 4, 5 ],
// theme passed as prop
theme
}
// pass style props into the style functions and merge their return values
const result = util.mergeStyles(color(props), fontSize(props))
// result is a responsively themed css style object that
// can then be processed downstream by many css-in-js libraries
const classy = b(result).class
document.body.classList.add(classy)
document.body.appendChild(
document.createTextNode(
'Responsively themed! (resize the window!)'))
A live version of this script is available on flems.
Usage within the React ecosystem
Usage in combination with React and React-focused css-in-js libraries such as styled-components or emotion should work as advertised in styled-stystem's documentation (not tested, YMMV).
// Example uses react and styled-components, but systemthing works with most other vdom and css-in-js libraries as well
import React from 'react'
import ReactDOM from 'react-dom' // virtual DOM libary
import styled from 'styled-components' // css-in-js layer / component factory
import { space, width, fontSize, color } from 'systemthing'
// custom theme
const theme = {
breakpoints: [ '32em', '48em', '64em' ],
space: [ 0, 6, 12, 18, 24 ],
fontSizes: [ 12, 16, 18, 24, 36, 72 ],
colors: {
blue: '#07c',
green: '#1c0',
grays: ['#ccc', '#555']
}
}
// Add style yielding functions to your component
const Box = styled.div`
${space}
${width}
${fontSize}
${color}`
ReactDOM.render(
<Box
// width: 50%
width={1 / 2}
// responsive font-size of 24px, 36px or 72px (theme.fontSizes)
fontSize={[ 3, 4, 5 ]}
// margin: 12px (theme.space[2])
margin={2}
// padding: 18px (theme.space[3])
padding={3}
// color: #ccc (theme.colors.grays[0])
color='grays.0'
// responsive background-color (theme.colors)
backgroundColor={[ 'blue', 'green', 'grays.0', 'grays.1' ]}
// theme passed as prop
theme={theme}>Hello React!</Box>
, document.body)
A live version of the script is available on flems..
Usage with other vdom libaries
This fork definitely also works well in concert with the more exotic bss and stylething utilities, as well as vdom libaries other than React.
// Example illustrates usage with mithril, bss and stylething
import m from 'mithril' // virtual DOM libary
import b from 'bss' // css-in-js layer
import { createStyler } from 'stylething' // component factory
import { space, width, fontSize, color } from 'systemthing'
// custom theme
const theme = {
breakpoints: [ '32em', '48em', '64em' ],
space: [ 0, 6, 12, 18, 24 ],
fontSizes: [ 12, 16, 18, 24, 36, 72 ],
colors: {
blue: '#07c',
green: '#1c0',
grays: [ '#ccc', '#555', '#ddd' ]
}
}
// instrument stylething's component factory with the vdom lib and bss css-in-js package
// note custom theme passed as a config option
const styled = createStyler(m, b, { mode: 'mithril', output: 'class', theme })
// Add a custom class name and style yielding functions to your component
const Box = styled('.Box', space, width, fontSize, color)
m.mount(document.body, {
view: () =>
m(Box, {
// widthL 50%
width: 1 / 2,
// responsive font-size of 24px, 36px or 72px (theme.fontSizes)
fontSize: [ 3, 4, 5 ],
// margin: 12px (theme.space[2])
margin: 2,
// padding: 18px (theme.space[3])
padding: 3,
// color: #ccc (theme.colors.grays[0])
color: 'grays.0',
// responsive background-color (theme.colors)
backgroundColor: [ 'blue', 'green', 'grays.1', 'grays.2' ]
}, 'Hello Mithril!')
})
A live version of this script is available on flems.
Docs
TODO