Last active
March 28, 2017 10:10
-
-
Save jgoux/fc4a8f193a20ec2af450a57682ccd2e1 to your computer and use it in GitHub Desktop.
CSS Grid Layout + React, version 2! (https://www.webpackbin.com/bins/-KgGJxladDSzvMZkxAT8)
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 styled, { injectGlobal, css } from 'styled-components' | |
import Grid from './Grid' | |
injectGlobal` | |
* { | |
box-sizing: border-box; | |
margin: 0; | |
padding: 0; | |
} | |
html, body, #app { | |
height: 100vh; | |
font-family: Arial, sans-serif; | |
} | |
` | |
const Header = (props) => <div {...props}>Header</div> | |
Header.displayName = 'Header' | |
const Aside = (props) => <div {...props}>Aside</div> | |
Aside.displayName = 'Aside' | |
const Main = (props) => <div {...props}>Main</div> | |
Main.displayName = 'Main' | |
const Footer = (props) => <div {...props}>Footer</div> | |
Footer.displayName = 'Footer' | |
const styles = css` | |
height: 100vh; | |
& > * { | |
font-size: 2em; | |
background-color: mediumturquoise; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
text-align: center; | |
} | |
` | |
// use area on children | |
const AppArea = styled(({ className }) => ( | |
<Grid | |
{...{ className }} | |
gap="10px" | |
template={` | |
150px 1fr | |
header header 50px | |
aside main 1fr | |
footer footer 100px | |
`} | |
> | |
<div area="header">Header</div> | |
<div area="aside">Aside</div> | |
<div area="main">Main</div> | |
<div area="footer">Footer</div> | |
</Grid> | |
))`${styles}` | |
// use displayName from children component | |
const AppDisplayName = styled(({ className }) => ( | |
<Grid | |
{...{ className }} | |
gap="10px" | |
template={` | |
150px 1fr | |
Header Header 50px | |
Aside Main 1fr | |
Footer Footer 100px | |
`} | |
> | |
<Header/> | |
<Aside/> | |
<Main/> | |
<Footer/> | |
</Grid> | |
))`${styles}` | |
// use both ! | |
const AppBoth = styled(({ className }) => ( | |
<Grid | |
{...{ className }} | |
gap="10px" | |
template={` | |
150px 1fr | |
Header Header 50px | |
Aside main 1fr | |
Footer Footer 50px | |
`} | |
> | |
<Header/> | |
<Aside/> | |
<main area="main">Main</main> | |
<Footer/> | |
</Grid> | |
))`${styles}` | |
// export default AppArea | |
// export default AppDisplayName | |
export default AppBoth |
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 R from 'ramda' | |
import React from 'react' | |
import styled, { css } from 'styled-components' | |
// Parse a template shorthand | |
// | |
// 150px 1fr | |
// header header 50px | |
// aside main 1fr | |
// footer footer 100px | |
// | |
// becomes | |
// | |
// { | |
// columns: '150px 1fr', | |
// rows: '50px 1fr 100px', | |
// areas: | |
// "header header" | |
// "aside main" | |
// "footer footer" | |
// } | |
const parseTemplate = R.pipe( | |
R.trim, | |
R.split('\n'), | |
R.addIndex(R.reduce)((acc, val, i) => ( | |
i === 0 | |
? { ...acc, columns: val } | |
: R.pipe( | |
R.trim, | |
R.lastIndexOf(' '), | |
R.splitAt(R.__, R.trim(val)), | |
([area, row]) => R.evolve({ | |
rows: R.concat(R.__, ` ${row}`), | |
areas: R.concat(R.__, `"${area}"`) | |
}, acc) | |
)(val) | |
), { columns: '', rows: '', areas: '' }) | |
) | |
// Apply each CSS transformation if the prop exists | |
const computeCSS = spec => R.pipe( | |
R.pick(R.keys(spec)), | |
R.evolve(R.map(R.ifElse(R.isNil, R.always('')), spec)), | |
R.values, R.join('') | |
) | |
// Child CSS transformations spec | |
const childToCSS = { | |
area: area => `grid-area: ${area};` | |
} | |
// Grid CSS transformations spec | |
const columnsToCSS = columns => `grid-template-columns: ${columns};` | |
const rowsToCSS = rows => `grid-template-rows: ${rows};` | |
const areasToCSS = areas => `grid-template-areas: ${areas};` | |
const gridToCSS = { | |
gap: gap => `grid-gap: ${gap};`, | |
columns: columnsToCSS, | |
rows: rowsToCSS, | |
areas: areasToCSS, | |
template: R.pipe( | |
parseTemplate, | |
R.evolve({ columns: columnsToCSS, rows: rowsToCSS, areas: areasToCSS }), | |
R.values, | |
R.join('') | |
), | |
children: R.pipe( | |
R.addIndex(R.map)((child, i) => { | |
// fallback to displayName if area prop isn't provided | |
const area = R.defaultTo(child.type.displayName) | |
const props = { ...child.props, area: area(child.props.area) } | |
return ` | |
& > *:nth-child(${i+1}) { | |
${computeCSS(childToCSS)(props)} | |
} | |
` | |
}), | |
R.join('') | |
) | |
} | |
const styles = css` | |
display: grid; | |
${computeCSS(gridToCSS)} | |
` | |
const cleanUpChild = R.over(R.lensProp('props'), R.omit(R.keys(childToCSS))) | |
const Grid = styled(({ children, className }) => { | |
return ( | |
<div {...{ className }}> | |
{React.Children.map(children, cleanUpChild)} | |
</div> | |
) | |
})`${styles}` | |
export default Grid |
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
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
</head> | |
<body> | |
<div id="app"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> | |
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 { render } from 'react-dom' | |
import App from './App' | |
render(<App />, document.querySelector('#app')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment