Last active
October 1, 2016 20:10
-
-
Save rszewczyk/28775ef0b8ce989bce22bcde2dd505bd to your computer and use it in GitHub Desktop.
Experimenting with css in js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { PropTypes } from 'react' | |
import CSSPropertyOperations from 'react/lib/CSSPropertyOperations' | |
import cn from 'classnames' | |
let classId = 0 | |
const domStyleNode = document.createElement('style') | |
document.head.appendChild(domStyleNode) | |
const styleCache = {} | |
function insertStyle(className, markup, psuedo = '') { | |
domStyleNode.appendChild(document.createTextNode(`.${className}${psuedo} { | |
${markup} | |
} | |
`)) | |
} | |
function stylesToCss({ styles, hoverStyles }) { | |
const markup = CSSPropertyOperations.createMarkupForStyles(styles) | |
const hoverMarkup = CSSPropertyOperations.createMarkupForStyles(hoverStyles) | |
if (!(markup || hoverMarkup)) { | |
return | |
} | |
let className = styleCache[markup + hoverMarkup] | |
if (!className) { | |
className = 'styled___' + classId++ | |
styleCache[markup + hoverMarkup] = className | |
if (markup) { | |
insertStyle(className, markup) | |
} | |
if (hoverMarkup) { | |
insertStyle(className, hoverMarkup, ':hover') | |
} | |
} | |
return className | |
} | |
const inheritableStyleProps = { | |
color: 'initial', | |
fontSize: 'initial', | |
lineHeight: 'initial', | |
fontWeight: 'initial', | |
letterSpacing: 'initial', | |
textAlign: 'initial', | |
fontFamily: 'initial', | |
cursor: 'initial' | |
} | |
const styleProps = { | |
display: true, | |
flex: true, | |
flexGrow: true, | |
flexShrink: true, | |
flexDirection: true, | |
alignItems: true, | |
justifyContent: true, | |
margin: true, | |
marginLeft: true, | |
marginRight: true, | |
marginTop: true, | |
marginBottom: true, | |
padding: true, | |
paddingLeft: true, | |
paddingRight: true, | |
paddingTop: true, | |
paddingBottom: true, | |
height: true, | |
width: true, | |
overflow: true, | |
fontSize: true, | |
color: true, | |
backgroundColor: true, | |
position: true, | |
cursor: true, | |
fontFamily: true, | |
textAlign: true, | |
lineHeight: true, | |
visibility: true, | |
letterSpacing: true | |
} | |
function resolveProps(props) { | |
const passOn = {} | |
const styles = {} | |
const hoverStyles = {} | |
for (let p of Object.keys(props)) { | |
if (p === 'className' || p === 'as') { | |
continue | |
} | |
const val = props[p] | |
if (typeof p === 'string') { | |
let baseName = p | |
const isHover = baseName.startsWith('__hover__') | |
if (isHover) { | |
baseName = baseName.slice(9) | |
} | |
if (styleProps.hasOwnProperty(baseName)) { | |
if (isHover) { | |
hoverStyles[baseName] = val | |
} else { | |
styles[baseName] = val | |
} | |
continue | |
} | |
} | |
passOn[p] = val | |
} | |
for (let p of Object.keys(inheritableStyleProps)) { | |
if (!styles.hasOwnProperty(p)) { | |
styles[p] = inheritableStyleProps[p] | |
} | |
} | |
const className = stylesToCss({ styles, hoverStyles }) | |
if (className) { | |
passOn.className = cn(props.className, className) | |
} | |
return passOn | |
} | |
export function hover(styles) { | |
return Object.keys(styles).reduce(function (acc, key) { | |
acc['__hover__' + key] = styles[key] | |
return acc | |
}, {}) | |
} | |
export default function createStyled(displayName, baseStyle) { | |
function styled(props) { | |
return React.createElement(props.as || 'div', resolveProps(Object.assign({}, baseStyle, props))) | |
} | |
styled.displayName = displayName | |
return styled | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import createStyled, { hover } from '../src/styled' | |
const Row = createStyled('Row', { | |
display: 'flex', | |
}) | |
const Column = createStyled('Column', { | |
display: 'flex', | |
flexDirection: 'column' | |
}) | |
function App() { | |
return ( | |
<div> | |
<Row backgroundColor="gray" padding="10px"> | |
<h2>One</h2><h2>Two</h2> | |
</Row> | |
<Column backgroundColor="green" {...hover({ color: 'red' })}> | |
<h2>One</h2><h2>Two</h2> | |
</Column> | |
</div> | |
) | |
} | |
ReactDOM.render( | |
<App/>, | |
document.getElementById('root') | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment