Skip to content

Commit

Permalink
feat: introduce configurable transformers
Browse files Browse the repository at this point in the history
Transformers are now configurable in theme, this way you can decide the
unit.

A `rpxTransformers` is also exposed to use `rem` based unit everywhere.
  • Loading branch information
gregberge committed Jul 9, 2019
1 parent a7af03d commit 4958bcb
Show file tree
Hide file tree
Showing 16 changed files with 250 additions and 82 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"bundlesize": [
{
"path": "./packages/system/dist/xstyled-system.min.js",
"maxSize": "4.5 kB"
"maxSize": "4.6 kB"
},
{
"path": "./packages/styled-components/dist/xstyled-styled-components.min.js",
Expand Down
1 change: 1 addition & 0 deletions packages/system/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export * from './styles/index'
export * from './th'
export * from './variant'
export * from './breakpoints'
export * from './transformers'
export { getBreakpoints } from './media'
export { createSystemComponent } from './systemComponent'
42 changes: 26 additions & 16 deletions packages/system/src/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,39 @@ function getCacheNamespace(theme, namespace) {
}

let themeGetterId = 0
export const themeGetter = ({ transform, key, defaultVariants }) => {
export const themeGetter = ({
name,
transform: defaultTransform,
key,
defaultVariants,
compose,
}) => {
const id = themeGetterId++
return value => props => {
if (!string(value) && !num(value)) return value
const getter = value => props => {
let res = value
if (!string(value) && !num(value)) return res
const cache = getCacheNamespace(props.theme, `__themeGetter${id}`)
if (cache.has(value)) return cache.get(value)
let variants = is(key) ? getThemeValue(props, key) : null
variants = is(variants) ? variants : defaultVariants
const themeValue = is(variants)
? getThemeValue(props, value, variants)
: null
const computedValue = is(themeValue) ? themeValue : value
if (!transform) {
cache.set(value, computedValue)
return computedValue
res = is(variants) ? getThemeValue(props, value, variants) : null
res = is(res) ? res : value
const transform =
(name && props.theme && props.theme.transformers
? props.theme.transformers[name]
: null) || defaultTransform
if (transform) {
res = transform(res, {
rawValue: value,
variants,
})
}
const transformedValue = transform(computedValue, {
rawValue: value,
variants,
})
cache.set(value, transformedValue)
return transformedValue
res = compose ? compose(res)(props) : res
cache.set(value, res)
return res
}
getter.meta = { name, transform: defaultTransform }
return getter
}

function styleFromValue(cssProperties, value, props, themeGet, cache) {
Expand Down
11 changes: 11 additions & 0 deletions packages/system/src/style.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ describe('#style', () => {
expect(scope(10)({ theme })).toBe(11)
expect(scope(0)({ theme })).toBe(2)
})

it('supports transform func from theme', () => {
const scope = themeGetter({
key: 'scope',
name: 'getter',
transform: x => x + 1,
})
const theme = { scope: [1], transformers: { getter: x => x + 2 } }
expect(scope(10)({ theme })).toBe(12)
expect(scope(0)({ theme })).toBe(3)
})
})

describe('#style', () => {
Expand Down
25 changes: 19 additions & 6 deletions packages/system/src/styles/basics.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import { style, themeGetter, compose } from '../style'
import { rpxPx, percent } from '../unit'
import { px, rpx, percent } from '../unit'

export const getColor = themeGetter({ key: 'colors' })
// Getters

export const getPx = themeGetter({ transform: rpxPx })
export const getColor = themeGetter({ name: 'color', key: 'colors' })

export const getPx = themeGetter({
name: 'px',
transform: value => px(rpx(value)),
})

export const getPercent = themeGetter({
name: 'percent',
transform: percent,
compose: getPx,
})

export const getRadius = themeGetter({
name: 'radius',
key: 'radii',
transform: rpxPx,
compose: getPx,
})

export const getTransition = themeGetter({
name: 'transition',
key: 'transitions',
})

// Style

export const opacity = style({
prop: 'opacity',
})
Expand All @@ -22,8 +37,6 @@ export const overflow = style({
prop: 'overflow',
})

export const getTransition = themeGetter({ key: 'transitions' })

export const transition = style({ prop: 'transition', themeGet: getTransition })

export const basics = compose(
Expand Down
38 changes: 23 additions & 15 deletions packages/system/src/styles/borders.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import { style, themeGetter, compose } from '../style'
import { num } from '../util'
import { px, rpxPx } from '../unit'
import { getColor, getRadius } from './basics'
import { px } from '../unit'
import { getColor, getRadius, getPx } from './basics'

// Getters

export const getBorder = themeGetter({
name: 'border',
key: 'borders',
transform: n => (num(n) && n > 0 ? `${px(n)} solid` : n),
})

export const getBorderWidth = themeGetter({
name: 'borderWidth',
key: 'borderWidths',
compose: getPx,
})

export const getBorderStyle = themeGetter({
name: 'borderStyle',
key: 'borderStyles',
})

export const getShadow = themeGetter({
name: 'shadow',
key: 'shadows',
})

// Style

export const border = style({
prop: 'border',
themeGet: getBorder,
Expand Down Expand Up @@ -58,20 +79,11 @@ export const borderColor = style({
themeGet: getColor,
})

export const getBorderWidth = themeGetter({
key: 'borderWidths',
transform: rpxPx,
})

export const borderWidth = style({
prop: 'borderWidth',
themeGet: getBorderWidth,
})

export const getBorderStyle = themeGetter({
key: 'borderStyles',
})

export const borderStyle = style({
prop: 'borderStyle',
themeGet: getBorderStyle,
Expand All @@ -82,10 +94,6 @@ export const borderRadius = style({
themeGet: getRadius,
})

export const getShadow = themeGetter({
key: 'shadows',
})

export const boxShadow = style({
prop: 'boxShadow',
themeGet: getShadow,
Expand Down
9 changes: 7 additions & 2 deletions packages/system/src/styles/layout.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { style, themeGetter, compose } from '../style'
import { percent } from '../unit'
import { getPercent } from './basics'

// Getters

export const getSize = themeGetter({
transform: percent,
name: 'size',
key: 'sizes',
compose: getPercent,
})

// Styles

export const display = style({
prop: 'display',
})
Expand Down
6 changes: 4 additions & 2 deletions packages/system/src/styles/positioning.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { style, themeGetter, compose } from '../style'
import { getPx } from './basics'

export const position = style({ prop: 'position' })
// Getters
export const getZIndex = themeGetter({ name: 'zIndex', key: 'zIndices' })

export const getZIndex = themeGetter({ key: 'zIndices' })
// Styles
export const position = style({ prop: 'position' })

export const zIndex = style({
prop: 'zIndex',
Expand Down
12 changes: 9 additions & 3 deletions packages/system/src/styles/space.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { style, themeGetter, compose } from '../style'
import { is, string, negative } from '../util'
import { rpxPx } from '../unit'
import { getPx } from './basics'

function toNegative(value) {
if (string(value)) return `-${value}`
return value * -1
}

// Getters

export const getSpace = themeGetter({
name: 'space',
key: 'space',
defaultVariants: [0, 4, 8, 16, 24, 48, 96, 144, 192, 240],
compose: getPx,
transform: (_, { rawValue, variants }) => {
if (string(rawValue)) {
const neg = rawValue.startsWith('-')
const absoluteValue = neg ? rawValue.substr(1) : rawValue
const variantValue = variants[absoluteValue]
const value = is(variantValue) ? variantValue : absoluteValue
return rpxPx(neg ? toNegative(value) : value)
return neg ? toNegative(value) : value
}
const abs = Math.abs(rawValue)
const neg = negative(rawValue)
const value = is(variants[abs]) ? variants[abs] : abs
return rpxPx(neg ? toNegative(value) : value)
return neg ? toNegative(value) : value
},
})

// Styles

export const margin = style({
prop: ['margin', 'm'],
cssProperty: 'margin',
Expand Down
39 changes: 26 additions & 13 deletions packages/system/src/styles/typography.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,52 @@
import { style, compose, themeGetter } from '../style'
import { rpx, rpxPx } from '../unit'
import { getColor } from './basics'
import { rpx } from '../unit'
import { getColor, getPx } from './basics'

export const getFont = themeGetter({ key: 'fonts' })
// Getters

export const getFont = themeGetter({ name: 'font', key: 'fonts' })

export const getLineHeight = themeGetter({
name: 'lineHeight',
key: 'lineHeights',
transform: rpx,
})

export const getFontWeight = themeGetter({
name: 'fontWeight',
key: 'fontWeights',
})

export const getLetterSpacing = themeGetter({
name: 'letterSpacing',
key: 'letterSpacings',
compose: getPx,
})

// Styles

export const fontFamily = style({
prop: 'fontFamily',
themeGet: getFont,
})

export const getFontSize = themeGetter({
name: 'fontSize',
key: 'fontSizes',
defaultVariants: [0, 12, 14, 16, 20, 24, 32, 48, 64, 72],
transform: rpxPx,
compose: getPx,
})

export const fontSize = style({
prop: 'fontSize',
themeGet: getFontSize,
})

export const getLineHeight = themeGetter({ key: 'lineHeights', transform: rpx })

export const lineHeight = style({
prop: 'lineHeight',
themeGet: getLineHeight,
})

export const getFontWeight = themeGetter({ key: 'fontWeights' })

export const fontWeight = style({
prop: 'fontWeight',
themeGet: getFontWeight,
Expand All @@ -38,11 +56,6 @@ export const textAlign = style({
prop: 'textAlign',
})

export const getLetterSpacing = themeGetter({
key: 'letterSpacings',
transform: rpxPx,
})

export const letterSpacing = style({
prop: 'letterSpacing',
themeGet: getLetterSpacing,
Expand Down
39 changes: 21 additions & 18 deletions packages/system/src/th.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,24 @@ export const th = path => props => {
warn(is(value), `value "${path}" not found in theme`)
return value
}

th.color = getColor
th.px = getPx
th.percent = getPercent
th.radius = getRadius
th.border = getBorder
th.borderWidth = getBorderWidth
th.borderStyle = getBorderStyle
th.shadow = getShadow
th.size = getSize
th.zIndex = getZIndex
th.space = getSpace
th.font = getFont
th.fontSize = getFontSize
th.lineHeight = getLineHeight
th.fontWeight = getFontWeight
th.letterSpacing = getLetterSpacing
th.transition = getTransition
;[
getColor,
getPx,
getPercent,
getRadius,
getBorder,
getBorderWidth,
getBorderStyle,
getShadow,
getSize,
getZIndex,
getSpace,
getFont,
getFontSize,
getLineHeight,
getFontWeight,
getLetterSpacing,
getTransition,
].forEach(themeGetter => {
th[themeGetter.meta.name] = themeGetter
})

0 comments on commit 4958bcb

Please sign in to comment.