Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Responsive flex component #108

Merged
merged 10 commits into from
Jul 20, 2018
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