Skip to content

Commit

Permalink
feat(component): add responsive breakpoints for Flex props (#113)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Flex component flexDirection prop now defaults to responsive object. Flex component props renamed to be more contextual.

If you had direction="row" this will now set your all breakpoints to flex-direction: row instead of column for mobile/row for desktop.

Flex:
direction -> flexDirection
wrap -> flexWrap

Flex.Item:
basis -> flexBasis
grow -> flexGrow
order -> flexOrder
shrink -> flexShrink

* feat(component): add responsive breakpoints for Flex props

* refactor(component): change flex prop names

* refactor: change variable name to be more descriptive

* refactor: move flexed item props into same file

* refactor: moved locations of new flex changes

* refactor: rename variables

* feat: resolve PR comments

* fix: remove unused imports

* fix: remove unused argument
  • Loading branch information
chanceaclark committed Aug 1, 2019
1 parent a93b1b0 commit 335c640
Show file tree
Hide file tree
Showing 21 changed files with 293 additions and 147 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1084,27 +1084,24 @@ exports[`render loading button 1`] = `
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
-webkit-align-content: stretch;
-ms-flex-line-pack: stretch;
align-content: stretch;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.c0 {
Expand Down Expand Up @@ -1200,6 +1197,14 @@ exports[`render loading button 1`] = `
position: absolute;
}
@media (min-width:0px) {
.c2 {
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
}
@media (min-width:720px) {
.c2 {
-webkit-flex-direction: row;
Expand Down Expand Up @@ -1228,8 +1233,6 @@ exports[`render loading button 1`] = `
>
<div
class="c1 c2 c3"
direction="row"
wrap="nowrap"
>
<svg
class="c4"
Expand Down
20 changes: 2 additions & 18 deletions packages/big-design/src/components/Flex/Flex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,10 @@ import React from 'react';
import { BoxProps } from '../Box';

import { StyledFlex } from './styled';
import { FlexedProps } from './types';
import { FlexItem } from './Item/Item';

export type FlexProps = BoxProps &
Partial<{
alignContent: 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'space-between' | 'space-around';
alignItems: 'normal' | 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'baseline';
direction: 'row' | 'column' | 'row-reverse' | 'column-reverse';
wrap: 'nowrap' | 'wrap' | 'wrap-reversed';
justifyContent:
| 'center'
| 'flex-start'
| 'flex-end'
| 'left'
| 'right'
| 'normal'
| 'space-between'
| 'space-around'
| 'space-evenly'
| 'stretch';
}>;
export type FlexProps = BoxProps & FlexedProps;

export class Flex extends React.PureComponent<FlexProps> {
static Item = FlexItem;
Expand Down
10 changes: 2 additions & 8 deletions packages/big-design/src/components/Flex/Item/Item.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import React from 'react';

import { BoxProps } from '../../Box';
import { FlexedItemProps } from '../types';

import { StyledFlexItem } from './styled';

export type FlexItemProps = BoxProps &
Partial<{
alignSelf: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch';
basis: 'auto' | 'fill' | 'min-content' | 'max-content' | 'fit-content' | 'content' | string;
grow: number;
order: number;
shrink: number;
}>;
export type FlexItemProps = BoxProps & FlexedItemProps;

export const FlexItem: React.FC<FlexItemProps> = props => <StyledFlexItem {...props} />;
15 changes: 6 additions & 9 deletions packages/big-design/src/components/Flex/Item/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,19 @@ import { theme as defaultTheme } from '@bigcommerce/big-design-theme';
import styled from 'styled-components';

import { Box } from '../../Box';
import { withFlexedItems } from '../withFlex';

import { FlexItemProps } from './Item';

export const StyledFlexItem = styled(Box)<FlexItemProps>`
align-self: ${({ alignSelf }) => alignSelf};
flex-basis: ${({ basis }) => basis};
flex-grow: ${({ grow }) => grow};
flex-shrink: ${({ shrink }) => shrink};
order: ${({ order }) => order};
${withFlexedItems()}
`;

StyledFlexItem.defaultProps = {
alignSelf: 'auto',
basis: 'auto',
grow: 0,
order: 0,
shrink: 1,
flexBasis: 'auto',
flexGrow: 0,
flexOrder: 0,
flexShrink: 1,
theme: defaultTheme,
};
27 changes: 15 additions & 12 deletions packages/big-design/src/components/Flex/__snapshots__/spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,32 @@ exports[`render flex 1`] = `
}
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
-webkit-align-content: stretch;
-ms-flex-line-pack: stretch;
align-content: stretch;
-webkit-align-items: stretch;
-webkit-box-align: stretch;
-ms-flex-align: stretch;
align-items: stretch;
-webkit-flex-wrap: nowrap;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
@media (min-width:0px) {
.c0 {
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
}
@media (min-width:720px) {
Expand All @@ -39,8 +44,6 @@ exports[`render flex 1`] = `
<div
class="c0 c1"
direction="row"
wrap="nowrap"
>
Flex
</div>
Expand Down
16 changes: 5 additions & 11 deletions packages/big-design/src/components/Flex/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,20 @@ import styled from 'styled-components';

import { Box } from '../Box';

import { withFlexedContainer } from './withFlex';
import { FlexProps } from './Flex';

export const StyledFlex = styled(Box)<FlexProps>`
display: flex;
flex-direction: column;
flex-wrap: ${({ wrap }) => wrap};
align-content: ${({ alignContent }) => alignContent};
align-items: ${({ alignItems }) => alignItems};
justify-content: ${({ justifyContent }) => justifyContent};
${withFlexedContainer()}
${({ theme }) => theme.breakpoints.tablet} {
flex-direction: ${({ direction }) => direction};
}
display: flex;
`;

StyledFlex.defaultProps = {
alignContent: 'stretch',
alignItems: 'stretch',
direction: 'row',
wrap: 'nowrap',
flexDirection: { mobile: 'column', tablet: 'row' },
flexWrap: 'nowrap',
justifyContent: 'flex-start',
theme: defaultTheme,
};
116 changes: 116 additions & 0 deletions packages/big-design/src/components/Flex/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { ThemeInterface } from '@bigcommerce/big-design-theme';
import { FlattenSimpleInterpolation } from 'styled-components';

import { Responsive } from '../../types';

type SingleAlignContent =
| 'normal'
| 'start'
| 'end'
| 'flex-start'
| 'flex-end'
| 'center'
| 'baseline'
| 'space-between'
| 'space-around'
| 'space-evenly'
| 'stretch';
type ResponsiveAlignContent = Responsive<SingleAlignContent>;
type AlignContent = SingleAlignContent | ResponsiveAlignContent;

type SingleAlignItems =
| 'normal'
| 'flex-start'
| 'flex-end'
| 'center'
| 'start'
| 'end'
| 'self-start'
| 'self-end'
| 'baseline'
| 'stretch';
type ResponsiveAlignItems = Responsive<SingleAlignItems>;
type AlignItems = SingleAlignItems | ResponsiveAlignItems;

type SingleAlignSelf =
| 'auto'
| 'normal'
| 'self-start'
| 'self-end'
| 'flex-start'
| 'flex-end'
| 'center'
| 'baseline'
| 'stretch';
type ResponsiveAlignSelf = Responsive<SingleAlignSelf>;
type AlignSelf = SingleAlignSelf | ResponsiveAlignSelf;

type SingleFlexDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse';
type ResponsiveFlexDirection = Responsive<SingleFlexDirection>;
type FlexDirection = SingleFlexDirection | ResponsiveFlexDirection;

type SingleFlexWrap = 'nowrap' | 'wrap' | 'wrap-reversed';
type ResponsiveFlexWrap = Responsive<SingleFlexWrap>;
type FlexWrap = SingleFlexWrap | ResponsiveFlexWrap;

type SingleJustifyContent =
| 'normal'
| 'start'
| 'end'
| 'flex-start'
| 'flex-end'
| 'center'
| 'left'
| 'right'
| 'baseline'
| 'space-between'
| 'space-around'
| 'space-evenly'
| 'stretch';
type ResponsiveJustifyContent = Responsive<SingleJustifyContent>;
type JustifyContent = SingleJustifyContent | ResponsiveJustifyContent;

type SingleFlexBasis = 'auto' | 'fill' | 'min-content' | 'max-content' | 'fit-content' | 'content' | string;
type ResponsiveFlexBasis = Responsive<SingleFlexBasis>;
type FlexBasis = SingleFlexBasis | ResponsiveFlexBasis;

type SingleFlexGrow = number;
type ResponsiveFlexGrow = Responsive<SingleFlexGrow>;
type FlexGrow = SingleFlexGrow | ResponsiveFlexGrow;

type SingleFlexOrder = number;
type ResponsiveFlexOrder = Responsive<SingleFlexOrder>;
type FlexOrder = SingleFlexOrder | ResponsiveFlexOrder;

type SingleFlexShrink = number;
type ResponsiveFlexShrink = Responsive<SingleFlexShrink>;
type FlexShrink = SingleFlexShrink | ResponsiveFlexShrink;

export type FlexedProps = Partial<{
alignContent: AlignContent;
alignItems: AlignItems;
flexDirection: FlexDirection;
flexWrap: FlexWrap;
justifyContent: JustifyContent;
}>;

export type FlexedItemProps = Partial<{
alignSelf: AlignSelf;
flexBasis: FlexBasis;
flexGrow: FlexGrow;
flexOrder: FlexOrder;
flexShrink: FlexShrink;
}>;

export interface FlexedOverload {
(flexedProp: AlignContent, theme: ThemeInterface, cssKey: 'align-content'): FlattenSimpleInterpolation;
(flexedProp: AlignItems, theme: ThemeInterface, cssKey: 'align-items'): FlattenSimpleInterpolation;
(flexedProp: FlexDirection, theme: ThemeInterface, cssKey: 'flex-direction'): FlattenSimpleInterpolation;
(flexedProp: FlexWrap, theme: ThemeInterface, cssKey: 'flex-wrap'): FlattenSimpleInterpolation;
(flexedProp: JustifyContent, theme: ThemeInterface, cssKey: 'justify-content'): FlattenSimpleInterpolation;
(flexedProp: AlignSelf, theme: ThemeInterface, cssKey: 'align-self'): FlattenSimpleInterpolation;
(flexedProp: FlexBasis, theme: ThemeInterface, cssKey: 'flex-basis'): FlattenSimpleInterpolation;
(flexedProp: FlexGrow, theme: ThemeInterface, cssKey: 'flex-grow'): FlattenSimpleInterpolation;
(flexedProp: FlexOrder, theme: ThemeInterface, cssKey: 'order'): FlattenSimpleInterpolation;
(flexedProp: FlexShrink, theme: ThemeInterface, cssKey: 'flex-shrink'): FlattenSimpleInterpolation;
}
61 changes: 61 additions & 0 deletions packages/big-design/src/components/Flex/withFlex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { breakpointsOrder, Breakpoints, ThemeInterface } from '@bigcommerce/big-design-theme';
import { css, FlattenSimpleInterpolation } from 'styled-components';

import { FlexedItemProps, FlexedOverload, FlexedProps } from './types';

export const withFlexedContainer = () => css<FlexedProps>`
${({ alignContent, theme }) => alignContent && getFlexedStyles(alignContent, theme, 'align-content')};
${({ alignItems, theme }) => alignItems && getFlexedStyles(alignItems, theme, 'align-items')};
${({ flexDirection, theme }) => flexDirection && getFlexedStyles(flexDirection, theme, 'flex-direction')};
${({ flexWrap, theme }) => flexWrap && getFlexedStyles(flexWrap, theme, 'flex-wrap')};
${({ justifyContent, theme }) => justifyContent && getFlexedStyles(justifyContent, theme, 'justify-content')};
`;

export const withFlexedItems = () => css<FlexedItemProps>`
${({ alignSelf, theme }) => alignSelf && getFlexedStyles(alignSelf, theme, 'align-self')};
${({ flexBasis, theme }) => flexBasis && getFlexedStyles(flexBasis, theme, 'flex-basis')};
${({ flexGrow, theme }) => flexGrow && getFlexedStyles(flexGrow, theme, 'flex-grow')};
${({ flexOrder, theme }) => flexOrder && getFlexedStyles(flexOrder, theme, 'order')};
${({ flexShrink, theme }) => flexShrink && getFlexedStyles(flexShrink, theme, 'flex-shrink')};
`;

const getFlexedStyles: FlexedOverload = (
flexedProp: any,
theme: ThemeInterface,
cssKey: any,
): FlattenSimpleInterpolation => {
if (typeof flexedProp === 'object') {
return getResponsiveFlex(flexedProp, theme, cssKey);
}

if (typeof flexedProp === 'string' || typeof flexedProp === 'number') {
return getSimpleFlex(flexedProp, cssKey);
}

return [];
};

const getSimpleFlex = (flexedProp: string | number, cssKey: string): FlattenSimpleInterpolation => css`
${cssKey}: ${flexedProp}
`;

const getResponsiveFlex: FlexedOverload = (
flexedProp: any,
theme: ThemeInterface,
cssKey: string,
): FlattenSimpleInterpolation[] => {
const breakpointKeys = Object.keys(flexedProp).sort(
(firstBreakpoint, secondBreakpoint) =>
breakpointsOrder.indexOf(firstBreakpoint as keyof Breakpoints) -
breakpointsOrder.indexOf(secondBreakpoint as keyof Breakpoints),
);

return (breakpointKeys as Array<keyof Breakpoints>).map(
breakpointKey =>
css`
${theme.breakpoints[breakpointKey]} {
${getSimpleFlex(flexedProp[breakpointKey], cssKey)}
}
`,
);
};
Loading

0 comments on commit 335c640

Please sign in to comment.