Skip to content

Instantly share code, notes, and snippets.

@souporserious
Last active June 19, 2017 22:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save souporserious/a352fe9c4ae18518f1d38099201d673a to your computer and use it in GitHub Desktop.
Save souporserious/a352fe9c4ae18518f1d38099201d673a to your computer and use it in GitHub Desktop.
Compute design system styles
import deepExtend from 'deep-extend'
import colorStyles from './color-styles'
import fluidSize from './fluid-size'
import { fontBase, lineHeight, spacing, verticalRhythm } from '../design-system'
function valuesDefined(...values) {
return values.some(value => typeof value !== 'undefined')
}
function parseSides(...sides) {
return sides.reduce((acc, side) => {
if (typeof side === 'string') {
return side
}
if (side !== null && typeof side !== 'undefined') {
return side * spacing
}
return acc
})
}
function parseValues(...values) {
return values.reduce((acc, value) => {
return value !== null && typeof value !== 'undefined' ? value : acc
})
}
// TODO:
// we should be able to add to an array or something and deep merge at the end
// probably split out into smaller functions
function computeDesignSystem({
// size
width,
height,
// spacing
top,
right,
bottom,
left,
padding,
paddingHorizontal,
paddingVertical,
paddingTop,
paddingRight,
paddingBottom,
paddingLeft,
margin,
marginHorizontal,
marginVertical,
marginTop,
marginRight,
marginBottom,
marginLeft,
// border
borderWidth,
borderTopWidth,
borderRightWidth,
borderBottomWidth,
borderLeftWidth,
dividerHorizontalWidth,
dividerVerticalWidth,
// color
fill,
stroke,
borderColor,
borderTopColor,
borderRightColor,
borderBottomColor,
borderLeftColor,
dividerHorizontalColor,
dividerVerticalColor,
backgroundColor,
color,
// radius
radius,
radiusTop,
radiusRight,
radiusBottom,
radiusLeft,
// type
fontSize,
uppercase,
// misc
shadow,
opacity,
...props
}) {
/////////////////////////////////////////////////
// SPACE
/////////////////////////////////////////////////
let styles = {
paddingTop: parseSides(padding, paddingVertical, paddingTop),
paddingRight: parseSides(padding, paddingHorizontal, paddingRight),
paddingBottom: parseSides(padding, paddingVertical, paddingBottom),
paddingLeft: parseSides(padding, paddingHorizontal, paddingLeft),
marginTop: parseSides(margin, marginVertical, marginTop),
marginRight: parseSides(margin, marginHorizontal, marginRight),
marginBottom: parseSides(margin, marginVertical, marginBottom),
marginLeft: parseSides(margin, marginHorizontal, marginLeft),
}
/////////////////////////////////////////////////
// POSITION
//////////////////////////////////
if (top) {
styles.top = parseSides(top)
}
if (right) {
styles.right = parseSides(right)
}
if (bottom) {
styles.bottom = parseSides(bottom)
}
if (left) {
styles.left = parseSides(left)
}
/////////////////////////////////////////////////
// SIZE
/////////////////////////////////////////////////
if (width) {
if (width <= 1) {
styles.width = width * 100 + '%'
} else {
styles.width = typeof width === 'string' ? width : width * spacing
}
}
if (height) {
styles.height = typeof height === 'string' ? height : height * spacing
}
/////////////////////////////////////////////////
// COLOR
/////////////////////////////////////////////////
const colorProps = {
fill,
stroke,
borderColor,
borderTopColor,
borderRightColor,
borderBottomColor,
borderLeftColor,
backgroundColor,
color,
}
Object.keys(colorProps).forEach(key => {
const colorProp = colorProps[key]
if (colorProp) {
deepExtend(styles, colorStyles(colorProp, { key }))
}
})
/////////////////////////////////////////////////
// FONT SIZE
/////////////////////////////////////////////////
if (typeof fontSize !== 'undefined') {
if (isNaN(fontSize)) {
styles.fontSize = fontSize
} else {
const vr = verticalRhythm(fontSize)
styles.fontSize = vr.fontSize
styles.lineHeight = vr.lineHeight
}
}
if (uppercase) {
styles.textTransform = 'uppercase'
styles.letterSpacing = '0.025em'
}
/////////////////////////////////////////////////
// RADIUS
/////////////////////////////////////////////////
if (radius) {
if (radius === 'circle') {
styles.borderRadius = '100%'
} else {
styles.borderTopLeftRadius = radius
styles.borderTopRightRadius = radius
styles.borderBottomRightRadius = radius
styles.borderBottomLeftRadius = radius
}
}
if (radiusTop) {
styles.borderTopLeftRadius = radiusTop
styles.borderTopRightRadius = radiusTop
}
if (radiusRight) {
styles.borderTopRightRadius = radiusRight
styles.borderBottomRightRadius = radiusRight
}
if (radiusBottom) {
styles.borderBottomRightRadius = radiusBottom
styles.borderBottomLeftRadius = radiusBottom
}
if (radiusLeft) {
styles.borderTopLeftRadius = radiusLeft
styles.borderBottomLeftRadius = radiusLeft
}
/////////////////////////////////////////////////
// BORDER
/////////////////////////////////////////////////
styles.borderTopWidth = parseValues(borderWidth, borderTopWidth)
styles.borderRightWidth = parseValues(borderWidth, borderRightWidth)
styles.borderBottomWidth = parseValues(borderWidth, borderBottomWidth)
styles.borderLeftWidth = parseValues(borderWidth, borderLeftWidth)
if (dividerHorizontalColor) {
const size = dividerHorizontalWidth || 1
const color = dividerHorizontalColor
styles['& > * + *'] = {
marginLeft: `-${size}px !important`,
borderLeftStyle: 'solid !important',
borderLeftWidth: `${size}px !important`,
borderLeftColor: `${color} !important`,
}
}
if (dividerVerticalColor) {
const prevDividerStyles = styles['& > * + *'] || {}
const size = dividerVerticalWidth || 1
const color = dividerVerticalColor
styles['& > * + *'] = {
...prevDividerStyles,
marginTop: `-${size}px !important`,
borderTopStyle: 'solid !important',
borderTopWidth: `${size}px !important`,
borderTopColor: `${color} !important`,
}
}
if (shadow === true) {
styles.boxShadow = '0px 0px 4px 2px rgba(220,220,220,0.5)'
}
if (typeof opacity !== 'undefined') {
styles.opacity = opacity
}
// attempt to fix vertical rhythm
if (styles.paddingTop > 0 && styles.borderTopWidth > 0) {
styles.paddingTop -= styles.borderTopWidth
}
if (styles.paddingBottom > 0 && styles.borderBottomWidth > 0) {
styles.paddingBottom -= styles.borderBottomWidth
}
return {
styles,
props,
}
}
const styleReset = {
appearance: 'none',
font: 'inherit',
fontFamily:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"',
lineHeight: '24px',
textAlign: 'inherit',
textDecoration: 'none',
listStyle: 'none',
position: 'relative',
boxSizing: 'border-box',
minHeight: 0,
minWidth: 0,
margin: 0,
padding: 0,
outline: 0,
borderStyle: 'solid',
borderWidth: 0,
borderColor: 'transparent',
backgroundColor: 'transparent',
color: 'inherit',
// use focus-ring polyfill to provide keyboard only outlines
// https://github.com/WICG/focus-ring
'&.focus-ring:after': {
content: '""',
position: 'absolute',
top: -3,
right: -3,
bottom: -3,
left: -3,
border: '3px solid #007eff',
zIndex: 9999,
},
}
export { computeDesignSystem as default, styleReset }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment