Skip to content

Commit

Permalink
Merge pull request #108 from primer/responsive_flex_component
Browse files Browse the repository at this point in the history
Responsive flex component
  • Loading branch information
Emily authored Jul 20, 2018
2 parents 5341d3a + ac0bf1c commit 016bbc0
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 46 deletions.
8 changes: 4 additions & 4 deletions docs/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/components/index.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/index.html

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions examples/component-examples/Flex.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const FlexExample = {
<ExampleHeading>FlexContainer</ExampleHeading>
<PropsForm>
<FlexContainer
display="flex"
wrap="wrap"
direction="row"
justifyContent="start"
Expand Down
33 changes: 14 additions & 19 deletions src/FlexContainer.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import Block from './Block'
import {mapAllProps, oneOrMoreOf} from './props'

const FlexContainer = ({children, inline, wrap, direction, justifyContent, alignItems, alignContent, ...rest}) => {
const classes = classnames(
{
'd-flex': !inline,
'd-inline-flex': inline
},
wrap && `flex-${wrap}`,
direction && `flex-${direction}`,
justifyContent && `flex-justify-${justifyContent}`,
alignItems && `flex-items-${alignItems}`,
alignContent && `flex-content-${alignContent}`
)
const FlexContainer = props => {
const {className, children, ...rest} = mapAllProps(props)

return (
<Block {...rest} className={classes}>
<Block {...rest} className={className}>
{children}
</Block>
)
}

FlexContainer.propTypes = {
alignContent: PropTypes.oneOf(['start', 'end', 'center', 'between', 'around', 'stretch']),
alignItems: PropTypes.oneOf(['start', 'end', 'center', 'baseline', 'stretch']),
alignContent: oneOrMoreOf(PropTypes.oneOf(['start', 'end', 'center', 'between', 'around', 'stretch'])),
alignItems: oneOrMoreOf(PropTypes.oneOf(['start', 'end', 'center', 'baseline', 'stretch'])),
children: PropTypes.node,
direction: PropTypes.oneOf(['row', 'row-reverse', 'column']),
direction: oneOrMoreOf(PropTypes.oneOf(['row', 'row-reverse', 'column'])),
display: oneOrMoreOf(PropTypes.oneOf(['flex', 'inline-flex'])),
inline: PropTypes.bool,
justifyContent: PropTypes.oneOf(['start', 'end', 'center', 'between', 'around']),
wrap: PropTypes.oneOf(['wrap', 'nowrap'])
justifyContent: oneOrMoreOf(PropTypes.oneOf(['start', 'end', 'center', 'between', 'around'])),
wrap: oneOrMoreOf(PropTypes.oneOf(['wrap', 'nowrap']))
}

FlexContainer.defaultProps = {
display: 'flex'
}

export default FlexContainer
40 changes: 21 additions & 19 deletions src/__tests__/FlexContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@ import React from 'react'
import FlexContainer from '../FlexContainer'
import {renderClasses} from '../utils/testing'

describe('FlexContainer', () => {
it('FlexContainer renders wrap classes', () => {
expect(renderClasses(<FlexContainer wrap="nowrap" />)).toEqual(['d-flex', 'flex-nowrap'])
})
it('FlexContainer renders wrap classes', () => {
expect(renderClasses(<FlexContainer wrap="nowrap" />)).toEqual(['flex-nowrap', 'd-flex'])
})

it('FlexContainer renders direction classes', () => {
expect(renderClasses(<FlexContainer direction="row" />)).toEqual(['d-flex', 'flex-row'])
})
it('FlexContainer renders direction classes', () => {
expect(renderClasses(<FlexContainer direction="row" />)).toEqual(['flex-row', 'd-flex'])
})

it('FlexContainer renders justifyContent classes', () => {
expect(renderClasses(<FlexContainer justifyContent="start" />)).toEqual(['d-flex', 'flex-justify-start'])
})
it('FlexContainer renders justifyContent classes', () => {
expect(renderClasses(<FlexContainer justifyContent="start" />)).toEqual(['flex-justify-start', 'd-flex'])
})

it('FlexContainer renders alignItems classes', () => {
expect(renderClasses(<FlexContainer alignItems="start" />)).toEqual(['d-flex', 'flex-items-start'])
})
it('FlexContainer renders alignItems classes', () => {
expect(renderClasses(<FlexContainer alignItems="start" />)).toEqual(['flex-items-start', 'd-flex'])
})

it('FlexContainer renders alignContent classes', () => {
expect(renderClasses(<FlexContainer alignContent="start" />)).toEqual(['d-flex', 'flex-content-start'])
})
it('FlexContainer renders alignContent classes', () => {
expect(renderClasses(<FlexContainer alignContent="start" />)).toEqual(['flex-content-start', 'd-flex'])
})

it('FlexContainer renders display classes', () => {
expect(renderClasses(<FlexContainer display="inline-flex" />)).toEqual(['d-inline-flex'])
})

it('FlexContainer renders inline classes', () => {
expect(renderClasses(<FlexContainer inline />)).toEqual(['d-inline-flex'])
})
it('FlexContainer renders responsive display classes', () => {
expect(renderClasses(<FlexContainer display={['flex', 'inline-flex']} />)).toEqual(['d-flex', 'd-sm-inline-flex'])
})
31 changes: 29 additions & 2 deletions src/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,32 @@ export const oneOrMoreOf = type => PropTypes.oneOfType([type, PropTypes.arrayOf(

export const oneOrMoreNumbers = oneOrMoreOf(PropTypes.number)

export const createMapperWithPropTypes = props => {
const flexPropNames = {
justifyContent: 'justify',
alignItems: 'items',
alignContent: 'content'
}

const classPattern = (breakpoint, prop, value, type) => {
let result = ''
switch (type) {
case 'flex':
result = ['flex', breakpoint, flexPropNames[prop], value].join('-')
break
case 'display':
result = ['d', breakpoint, value].join('-')
break
default:
result = [prop, breakpoint, value].join('-')
}
return result.replace(/\-\-+/g, '-') //eslint-disable-line
}

export const createMapperWithPropTypes = (props, type) => {
const mapper = createMapper({
breakpoints,
props,
getter: ({breakpoint, prop, value}) => (breakpoint ? [prop, breakpoint, value].join('-') : [prop, value].join('-'))
getter: ({breakpoint, prop, value}) => classPattern(breakpoint, prop, value, type)
})
mapper.propTypes = props.reduce((propTypes, prop) => {
propTypes[prop] = oneOrMoreNumbers
Expand All @@ -22,8 +43,14 @@ export const createMapperWithPropTypes = props => {

export const marginProps = ['m', 'mt', 'mr', 'mb', 'ml', 'mx', 'my']
export const paddingProps = ['p', 'pt', 'pr', 'pb', 'pl', 'px', 'py']
export const flexProps = ['wrap', 'direction', 'justifyContent', 'alignItems', 'alignContent']

export const mapWhitespaceProps = createMapperWithPropTypes(marginProps.concat(paddingProps))
export const mapFlexProps = createMapperWithPropTypes(flexProps, 'flex')
export const mapDisplayProps = createMapperWithPropTypes(['display'], 'display')
export const mapAllProps = props => {
return mapWhitespaceProps(mapDisplayProps(mapFlexProps(props)))
}

export function stylizer(propsToPass) {
return props => {
Expand Down

0 comments on commit 016bbc0

Please sign in to comment.