Last active
December 11, 2022 18:15
-
-
Save rosskevin/0e484f45fa95e5c7f20acfccb21f6d60 to your computer and use it in GitHub Desktop.
material-ui `next` responsive layout/grid using JSS (originally based on flexboxgrid.com)
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
// @flow | |
export function capitalizeFirstLetter (string: string) { | |
return string.charAt(0).toUpperCase() + string.slice(1) | |
} |
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
// @flow | |
import React, {Component, Element, PropTypes} from 'react' | |
import classNames from 'classnames' | |
import pure from 'recompose/pure' | |
import merge from 'lodash/merge' | |
import {createStyleSheet} from 'jss-theme-reactor' | |
import Logger from '../../util/Logger' | |
import {capitalizeFirstLetter} from '../../util/strings' | |
type DefaultProps = { | |
component: string | |
} | |
type Props = { | |
children: Element<any>, | |
component: string, | |
className: ?string, | |
// | |
xs: ?(number | boolean), | |
sm: ?(number | boolean), | |
md: ?(number | boolean), | |
lg: ?(number | boolean), | |
xsOffset: ?number, | |
smOffset: ?number, | |
mdOffset: ?number, | |
lgOffset: ?number, | |
reverse: ?boolean, | |
first: ?Breakpoints, | |
last: ?Breakpoints | |
} | |
function generateClasses (breakpoint) { | |
const bp = capitalizeFirstLetter(breakpoint) | |
return { | |
col: { | |
// flex: '0 0 auto' | |
// paddingRight: 'var(--half-gutter-width, 0.5rem)', | |
// paddingLeft: 'var(--half-gutter-width, 0.5rem)' | |
}, | |
[`col${bp}`]: { | |
extend: 'col', | |
flexGrow: '1', | |
flexBasis: '0', | |
maxWidth: '100%' | |
}, | |
[`col${bp}1`]: { | |
extend: 'col', | |
flexBasis: '8.33333333%', | |
maxWidth: '8.33333333%' | |
}, | |
[`col${bp}2`]: { | |
extend: 'col', | |
flexBasis: '16.66666667%', | |
maxWidth: '16.66666667%' | |
}, | |
[`col${bp}3`]: { | |
extend: 'col', | |
flexBasis: '25%', | |
maxWidth: '25%' | |
}, | |
[`col${bp}4`]: { | |
extend: 'col', | |
flexBasis: '33.33333333%', | |
maxWidth: '33.33333333%' | |
}, | |
[`col${bp}5`]: { | |
extend: 'col', | |
flexBasis: '41.66666667%', | |
maxWidth: '41.66666667%' | |
}, | |
[`col${bp}6`]: { | |
extend: 'col', | |
flexBasis: '50%', | |
maxWidth: '50%' | |
}, | |
[`col${bp}7`]: { | |
extend: 'col', | |
flexBasis: '58.33333333%', | |
maxWidth: '58.33333333%' | |
}, | |
[`col${bp}8`]: { | |
extend: 'col', | |
flexBasis: '66.66666667%', | |
maxWidth: '66.66666667%' | |
}, | |
[`col${bp}9`]: { | |
extend: 'col', | |
flexBasis: '75%', | |
maxWidth: '75%' | |
}, | |
[`col${bp}10`]: { | |
extend: 'col', | |
flexBasis: '83.33333333%', | |
maxWidth: '83.33333333%' | |
}, | |
[`col${bp}11`]: { | |
extend: 'col', | |
flexBasis: '91.66666667%', | |
maxWidth: '91.66666667%' | |
}, | |
[`col${bp}12`]: { | |
extend: 'col', | |
flexBasis: '100%', | |
maxWidth: '100%' | |
}, | |
[`col${bp}Offset0`]: { | |
marginLeft: '0' | |
}, | |
[`col${bp}Offset1`]: { | |
marginLeft: '8.33333333%' | |
}, | |
[`col${bp}Offset2`]: { | |
marginLeft: '16.66666667%' | |
}, | |
[`col${bp}Offset3`]: { | |
marginLeft: '25%' | |
}, | |
[`col${bp}Offset4`]: { | |
marginLeft: '33.33333333%' | |
}, | |
[`col${bp}Offset5`]: { | |
marginLeft: '41.66666667%' | |
}, | |
[`col${bp}Offset6`]: { | |
marginLeft: '50%' | |
}, | |
[`col${bp}Offset7`]: { | |
marginLeft: '58.33333333%' | |
}, | |
[`col${bp}Offset8`]: { | |
marginLeft: '66.66666667%' | |
}, | |
[`col${bp}Offset9`]: { | |
marginLeft: '75%' | |
}, | |
[`col${bp}Offset10`]: { | |
marginLeft: '83.33333333%' | |
}, | |
[`col${bp}Offset11`]: { | |
marginLeft: '91.66666667%' | |
}, | |
[`col${bp}First`]: { | |
order: '-1' | |
}, | |
[`col${bp}Last`]: { | |
order: '1' | |
} | |
} | |
} | |
export const styleSheet = createStyleSheet('AfCol', (theme) => { | |
const { breakpoints } = theme | |
const classes = { | |
col: { | |
boxSizing: 'border-box' | |
// flex: '0 0 auto' | |
}, | |
reverse: { | |
flexDirection: 'column-reverse' | |
} | |
} | |
const generated = generateClasses('xs') | |
generated[ breakpoints.up('sm') ] = generateClasses('sm') | |
generated[ breakpoints.up('md') ] = generateClasses('md') | |
generated[ breakpoints.up('lg') ] = generateClasses('lg') | |
return merge(generated, classes) | |
}) | |
const MODIFIERS = [ 'xs', 'sm', 'md', 'lg', 'xsOffset', 'smOffset', 'mdOffset', 'lgOffset', 'first', 'last' ] | |
class Col extends Component<DefaultProps, Props, void> { | |
static contextTypes = { | |
styleManager: PropTypes.object.isRequired | |
} | |
static defaultProps: DefaultProps = { | |
component: 'div' | |
} | |
props: Props | |
render (): Element<any> { | |
const classes = this.context.styleManager.render(styleSheet) | |
const { | |
children, component, className: classNameProp, reverse, | |
xs, sm, md, lg, xsOffset, smOffset, mdOffset, lgOffset, first, last, // eslint-disable-line no-unused-vars | |
...rest | |
} = this.props | |
// accumulate all modifier classes | |
const modifierClasses = [] | |
for (const key of MODIFIERS) { | |
const value = this.props[ key ] | |
if (value) { | |
let name | |
if (Number.isInteger(value)) { | |
// number case e.g. xs={3} colXs3 | |
name = `col${capitalizeFirstLetter(key)}${String(value)}` | |
} else if (typeof value === 'string') { | |
// string case e.g. start='xs' colXsStart | |
name = `col${capitalizeFirstLetter(value)}${capitalizeFirstLetter(key)}` | |
} else if (typeof value === 'boolean') { | |
// boolean case e.g. xs @see auto width example | |
name = `col${capitalizeFirstLetter(key)}` | |
} else { | |
throw new Error(`Unknown handling of key[${key}] and value[${value}]`) | |
} | |
// log.debug(`${key}=${value}: [${name}]`, Number.isInteger(value), typeof value === 'string', typeof value === 'boolean') | |
modifierClasses.push(classes[ name ]) | |
} | |
} | |
// log.debug(modifierClasses) | |
const className = classNames(...modifierClasses, { | |
[classes.reverse]: reverse | |
}, classNameProp) | |
return React.createElement(component, { className, ...rest }, children) | |
} | |
} | |
const log = Logger.get(Col) // eslint-disable-line | |
export default pure(Col) |
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
// @flow | |
import React, {Component, Element, PropTypes} from 'react' | |
import classNames from 'classnames' | |
import pure from 'recompose/pure' | |
import {createStyleSheet} from 'jss-theme-reactor' | |
type DefaultProps = { | |
component: string | |
} | |
type Props = { | |
children: Element<any>, | |
component: string, | |
className: ?string, | |
// | |
fixed: boolean, | |
} | |
/* | |
':root': { | |
'--gutter-width': '1rem', | |
'--outer-margin': '2rem', | |
'--gutter-compensation': 'calc((var(--gutter-width) * 0.5) * -1)', | |
'--half-gutter-width': 'calc((var(--gutter-width) * 0.5))', | |
'--xs-min': '30', | |
'--sm-min': '48', | |
'--md-min': '64', | |
'--lg-min': '75', | |
'--screen-xs-min': 'var(--xs-min)em', | |
'--screen-sm-min': 'var(--sm-min)em', | |
'--screen-md-min': 'var(--md-min)em', | |
'--screen-lg-min': 'var(--lg-min)em', | |
'--container-sm': 'calc(var(--sm-min) + var(--gutter-width))', | |
'--container-md': 'calc(var(--md-min) + var(--gutter-width))', | |
'--container-lg': 'calc(var(--lg-min) + var(--gutter-width))' | |
}, | |
*/ | |
export const styleSheet = createStyleSheet('AfContainer', (theme) => { | |
const { breakpoints } = theme | |
return { | |
// NOTE: we currently use ZERO padding/gutters so that developer is in control of those. | |
container: { | |
marginRight: 'auto', | |
marginLeft: 'auto' | |
}, | |
containerFixed: { | |
// paddingRight: '2rem)', | |
// paddingLeft: '2rem)' | |
}, | |
[breakpoints.up('sm')]: { | |
// containerFixed: { | |
// width: 'var(--container-sm, 46rem)' | |
// } | |
}, | |
[breakpoints.up('md')]: { | |
// containerFixed: { | |
// width: 'var(--container-md, 61rem)' | |
// } | |
}, | |
[breakpoints.up('lg')]: { | |
// containerFixed: { | |
// width: 'var(--container-lg, 71rem)' | |
// } | |
} | |
} | |
}) | |
/** | |
* This component is not necessary to be used with Row/Col. It is ported from the original code. | |
*/ | |
class Container extends Component<DefaultProps, Props, void> { | |
static contextTypes = { | |
styleManager: PropTypes.object.isRequired | |
} | |
static defaultProps: DefaultProps = { | |
component: 'div', | |
fixed: false | |
} | |
props: Props | |
render (): Element<any> { | |
const classes = this.context.styleManager.render(styleSheet) | |
const { children, component, className: classNameProp, fixed, ...rest } = this.props | |
const className = classNames(classes.container, { [classes.containerFluid]: fixed }, classNameProp) | |
return React.createElement(component, { className, ...rest }, children) | |
} | |
} | |
export default pure(Container) |
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
// @flow | |
import Container from './Container' | |
import Row from './Row' | |
import Col from './Col' | |
export {Container, Row, Col} // https://github.com/facebook/flow/issues/940 |
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
// @flow | |
import React, {Component, Element, PropTypes} from 'react' | |
import classNames from 'classnames' | |
import pure from 'recompose/pure' | |
import {createStyleSheet} from 'jss-theme-reactor' | |
import {capitalizeFirstLetter} from '../../util/strings' | |
import merge from 'lodash/merge' | |
import Logger from '../../util/Logger' | |
type DefaultProps = { | |
component: string | |
} | |
type Props = { | |
children: Element<any>, | |
component: string, | |
className: ?string, | |
// | |
reverse: ?boolean, | |
start: ?Breakpoints, | |
center: ?Breakpoints, | |
end: ?Breakpoints, | |
top: ?Breakpoints, | |
middle: ?Breakpoints, | |
bottom: ?Breakpoints, | |
around: ?Breakpoints, | |
between: ?Breakpoints, | |
first: ?Breakpoints, | |
last: ?Breakpoints | |
} | |
function generateClasses (breakpoint) { | |
const bp = capitalizeFirstLetter(breakpoint) | |
return { | |
[`row${bp}Start`]: { | |
justifyContent: 'flex-start', | |
textAlign: 'start' | |
}, | |
[`row${bp}Center`]: { | |
justifyContent: 'center', | |
textAlign: 'center' | |
}, | |
[`row${bp}End`]: { | |
justifyContent: 'flex-end', | |
textAlign: 'end' | |
}, | |
[`row${bp}Top`]: { | |
alignItems: 'flex-start' | |
}, | |
[`row${bp}Middle`]: { | |
alignItems: 'center' | |
}, | |
[`row${bp}Bottom`]: { | |
alignItems: 'flex-end' | |
}, | |
[`row${bp}Around`]: { | |
justifyContent: 'space-around' | |
}, | |
[`row${bp}Between`]: { | |
justifyContent: 'space-between' | |
}, | |
[`row${bp}First`]: { | |
order: '-1' | |
}, | |
[`row${bp}Last`]: { | |
order: '1' | |
} | |
} | |
} | |
export const styleSheet = createStyleSheet('AfRow', (theme) => { | |
const { breakpoints } = theme | |
const classes = { | |
row: { | |
boxSizing: 'border-box', | |
display: 'flex', | |
flex: '0 1 auto', | |
flexDirection: 'row', | |
flexWrap: 'wrap' | |
// marginRight: 'var(--gutter-compensation, -0.5rem)', | |
// marginLeft: 'var(--gutter-compensation, -0.5rem)' | |
}, | |
reverse: { | |
flexDirection: 'row-reverse' | |
} | |
} | |
const generated = generateClasses('xs') | |
generated[ breakpoints.up('sm') ] = generateClasses('xs') | |
generated[ breakpoints.up('md') ] = generateClasses('md') | |
generated[ breakpoints.up('lg') ] = generateClasses('lg') | |
return merge(generated, classes) | |
}) | |
const MODIFIERS = [ 'start', 'center', 'end', 'top', 'middle', 'bottom', 'around', 'between', 'first', 'last' ] | |
class Row extends Component<DefaultProps, Props, void> { | |
static contextTypes = { | |
styleManager: PropTypes.object.isRequired | |
} | |
static defaultProps: DefaultProps = { | |
component: 'div' | |
} | |
props: Props | |
render (): Element<any> { | |
const classes = this.context.styleManager.render(styleSheet) | |
const { | |
children, component, className: classNameProp, reverse, | |
start, center, end, top, middle, bottom, around, between, first, last, // eslint-disable-line no-unused-vars | |
...rest | |
} = this.props | |
// accumulate all modifier classes | |
const modifierClasses = [] | |
for (const key of MODIFIERS) { | |
const value = this.props[ key ] | |
let name | |
if (typeof value === 'boolean') { | |
// allow <Row center>, don't require <Row center='xs'> | |
name = `rowXs${capitalizeFirstLetter(key)}` | |
} else if (value) { | |
name = `row${capitalizeFirstLetter(value)}${capitalizeFirstLetter(key)}` | |
} | |
// log.debug('value needs defaulted?', !value, value, name) | |
// e.g. rowXsEnd | |
modifierClasses.push(classes[ name ]) | |
} | |
const className = classNames(classes.row, ...modifierClasses, { | |
[classes.reverse]: reverse | |
}, classNameProp) | |
return React.createElement(component, { className, ...rest }, children) | |
} | |
} | |
const log = Logger.get(Row) // eslint-disable-line | |
export default pure(Row) |
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
/* eslint-disable */ | |
// make flow Breakpoints available by adding this to the .flowconfig i.e. | |
// [libs] | |
// ./src/flow | |
type Breakpoints = 'xs' | 'sm' | 'md' | 'lg' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment