[UI Framework] Add support for wrap prop to FlexGroup (#15009) (#15128)

* Migrate KuiFlexItem numeric grow prop from EUI.
* Loop through FlexGroup gutter size modifiers.
* Add wrap prop to FlexGroup.
This commit is contained in:
CJ Cenizal 2017-11-22 12:27:39 -08:00 committed by GitHub
parent 1f6af2e792
commit 4e2832d061
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 314 additions and 86 deletions

View file

@ -1171,48 +1171,72 @@ input[type="button"] {
-webkit-flex-basis: 0;
-ms-flex-preferred-size: 0;
flex-basis: 0; }
.kuiFlexGroup.kuiFlexGroup--gutterSmall > .kuiFlexItem + .kuiFlexItem {
margin-left: 8px; }
.kuiFlexGroup.kuiFlexGroup--gutterMedium > .kuiFlexItem + .kuiFlexItem {
margin-left: 16px; }
.kuiFlexGroup.kuiFlexGroup--gutterLarge > .kuiFlexItem + .kuiFlexItem {
margin-left: 24px; }
.kuiFlexGroup.kuiFlexGroup--gutterExtraLarge > .kuiFlexItem + .kuiFlexItem {
margin-left: 40px; }
.kuiFlexGroup.kuiFlexGroup--justifyContentSpaceBetween {
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between; }
.kuiFlexGroup.kuiFlexGroup--justifyContentSpaceAround {
-webkit-justify-content: space-around;
-ms-flex-pack: distribute;
justify-content: space-around; }
.kuiFlexGroup.kuiFlexGroup--justifyContentCenter {
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center; }
.kuiFlexGroup.kuiFlexGroup--justifyContentFlexEnd {
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end; }
.kuiFlexGroup.kuiFlexGroup--alignItemsStart {
-webkit-box-align: start;
-webkit-align-items: flex-start;
-ms-flex-align: start;
align-items: flex-start; }
.kuiFlexGroup.kuiFlexGroup--alignItemsCenter {
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center; }
.kuiFlexGroup.kuiFlexGroup--alignItemsEnd {
-webkit-box-align: end;
-webkit-align-items: flex-end;
-ms-flex-align: end;
align-items: flex-end; }
.kuiFlexGroup--gutterSmall {
margin: -4px; }
.kuiFlexGroup--gutterSmall > .kuiFlexItem {
margin: 4px; }
.kuiFlexGroup--gutterMedium {
margin: -8px; }
.kuiFlexGroup--gutterMedium > .kuiFlexItem {
margin: 8px; }
.kuiFlexGroup--gutterLarge {
margin: -12px; }
.kuiFlexGroup--gutterLarge > .kuiFlexItem {
margin: 12px; }
.kuiFlexGroup--gutterExtraLarge {
margin: -20px; }
.kuiFlexGroup--gutterExtraLarge > .kuiFlexItem {
margin: 20px; }
.kuiFlexGroup--justifyContentSpaceBetween {
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between; }
.kuiFlexGroup--justifyContentSpaceAround {
-webkit-justify-content: space-around;
-ms-flex-pack: distribute;
justify-content: space-around; }
.kuiFlexGroup--justifyContentCenter {
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center; }
.kuiFlexGroup--justifyContentFlexEnd {
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end; }
.kuiFlexGroup--alignItemsStart {
-webkit-box-align: start;
-webkit-align-items: flex-start;
-ms-flex-align: start;
align-items: flex-start; }
.kuiFlexGroup--alignItemsCenter {
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center; }
.kuiFlexGroup--alignItemsEnd {
-webkit-box-align: end;
-webkit-align-items: flex-end;
-ms-flex-align: end;
align-items: flex-end; }
.kuiFlexGroup--wrap {
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap; }
@media only screen and (max-width: 768px) {
.kuiFlexGroup {
@ -1433,6 +1457,56 @@ input[type="button"] {
-ms-flex-preferred-size: auto;
flex-basis: auto;
/* 2 */ }
.kuiFlexItem.kuiFlexItem--flexGrow1 {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
-ms-flex-positive: 1;
flex-grow: 1; }
.kuiFlexItem.kuiFlexItem--flexGrow2 {
-webkit-box-flex: 2;
-webkit-flex-grow: 2;
-ms-flex-positive: 2;
flex-grow: 2; }
.kuiFlexItem.kuiFlexItem--flexGrow3 {
-webkit-box-flex: 3;
-webkit-flex-grow: 3;
-ms-flex-positive: 3;
flex-grow: 3; }
.kuiFlexItem.kuiFlexItem--flexGrow4 {
-webkit-box-flex: 4;
-webkit-flex-grow: 4;
-ms-flex-positive: 4;
flex-grow: 4; }
.kuiFlexItem.kuiFlexItem--flexGrow5 {
-webkit-box-flex: 5;
-webkit-flex-grow: 5;
-ms-flex-positive: 5;
flex-grow: 5; }
.kuiFlexItem.kuiFlexItem--flexGrow6 {
-webkit-box-flex: 6;
-webkit-flex-grow: 6;
-ms-flex-positive: 6;
flex-grow: 6; }
.kuiFlexItem.kuiFlexItem--flexGrow7 {
-webkit-box-flex: 7;
-webkit-flex-grow: 7;
-ms-flex-positive: 7;
flex-grow: 7; }
.kuiFlexItem.kuiFlexItem--flexGrow8 {
-webkit-box-flex: 8;
-webkit-flex-grow: 8;
-ms-flex-positive: 8;
flex-grow: 8; }
.kuiFlexItem.kuiFlexItem--flexGrow9 {
-webkit-box-flex: 9;
-webkit-flex-grow: 9;
-ms-flex-positive: 9;
flex-grow: 9; }
.kuiFlexItem.kuiFlexItem--flexGrow10 {
-webkit-box-flex: 10;
-webkit-flex-grow: 10;
-ms-flex-positive: 10;
flex-grow: 10; }
@media only screen and (max-width: 768px) {
.kuiFlexItem {

View file

@ -15,6 +15,10 @@ import FlexGroup from './flex_group';
const flexGroupSource = require('!!raw-loader!./flex_group');
const flexGroupHtml = renderToHtml(FlexGroup);
import FlexGroupWrap from './flex_group_wrap';
const flexGroupWrapSource = require('!!raw-loader!./flex_group_wrap');
const flexGroupWrapHtml = renderToHtml(FlexGroupWrap);
import FlexItems from './flex_items';
const flexItemsSource = require('!!raw-loader!./flex_items');
const flexItemsHtml = renderToHtml(FlexItems);
@ -23,9 +27,13 @@ import FlexGutter from './flex_gutter';
const flexGutterSource = require('!!raw-loader!./flex_gutter');
const flexGutterHtml = renderToHtml(FlexGutter);
import FlexGrow from './flex_grow';
const flexGrowSource = require('!!raw-loader!./flex_grow');
const flexGrowHtml = renderToHtml(FlexGrow);
import FlexGrowZero from './flex_grow_zero';
const flexGrowZeroSource = require('!!raw-loader!./flex_grow_zero');
const flexGrowZeroHtml = renderToHtml(FlexGrowZero);
import FlexGrowNumeric from './flex_grow_numeric';
const flexGrowNumericSource = require('!!raw-loader!./flex_grow_numeric');
const flexGrowNumericHtml = renderToHtml(FlexGrowNumeric);
import FlexJustify from './flex_justify';
const flexJustifySource = require('!!raw-loader!./flex_justify');
@ -64,6 +72,25 @@ export default props => (
<GuideDemo className="guideDemo__highlightGrid"><FlexGroup /></GuideDemo>
</GuideSection>
<GuideSection
title="FlexGroup can wrap its items"
source={[{
type: GuideSectionTypes.JS,
code: flexGroupWrapSource,
}, {
type: GuideSectionTypes.HTML,
code: flexGroupWrapHtml,
}]}
>
<GuideText>
You can set <GuideCode>wrap</GuideCode> on <GuideCode>FlexGroup</GuideCode> if it
contains <GuideCode>FlexItem</GuideCode>s with minimum widths, which you want to wrap as
the container becomes narrower.
</GuideText>
<GuideDemo className="guideDemo__highlightGrid"><FlexGroupWrap /></GuideDemo>
</GuideSection>
<GuideSection
title="FlexGroup accepts infinite items"
source={[{
@ -86,10 +113,10 @@ export default props => (
title="FlexItem can individually turn off stretching"
source={[{
type: GuideSectionTypes.JS,
code: flexGrowSource,
code: flexGrowZeroSource,
}, {
type: GuideSectionTypes.HTML,
code: flexGrowHtml,
code: flexGrowZeroHtml,
}]}
>
<GuideText>
@ -97,7 +124,25 @@ export default props => (
can be turned off on each item individually.
</GuideText>
<GuideDemo className="guideDemo__highlightGrid"><FlexGrow /></GuideDemo>
<GuideDemo className="guideDemo__highlightGrid"><FlexGrowZero /></GuideDemo>
</GuideSection>
<GuideSection
title="FlexItem can specify a proportional width"
source={[{
type: GuideSectionTypes.JS,
code: flexGrowNumericSource,
}, {
type: GuideSectionTypes.HTML,
code: flexGrowNumericHtml,
}]}
>
<GuideText>
You can specify a number between 1 and 10 for a <GuideCode>FlexItem</GuideCode> to
try to take up a proportional part of the flex box it is in.
</GuideText>
<GuideDemo className="guideDemo__highlightGrid"><FlexGrowNumeric /></GuideDemo>
</GuideSection>
<GuideSection

View file

@ -0,0 +1,22 @@
import React from 'react';
import {
KuiFlexGroup,
KuiFlexItem,
} from '../../../../components';
export default () => (
<KuiFlexGroup wrap>
<KuiFlexItem style={{ minWidth: 300 }}>
Min-width 300px
</KuiFlexItem>
<KuiFlexItem style={{ minWidth: 300 }}>
Min-width 300px
</KuiFlexItem>
<KuiFlexItem style={{ minWidth: 300 }}>
Min-width 300px
</KuiFlexItem>
</KuiFlexGroup>
);

View file

@ -0,0 +1,27 @@
import React from 'react';
import {
KuiFlexGroup,
KuiFlexItem,
} from '../../../../components';
export default () => (
<div>
<KuiFlexGroup>
<KuiFlexItem grow={1}>1</KuiFlexItem>
<KuiFlexItem grow={2}>2<br />wraps content if necessary</KuiFlexItem>
<KuiFlexItem grow={3}>3<br />expands_to_fit_if_content_cannot_wrap</KuiFlexItem>
<KuiFlexItem grow={4}>4</KuiFlexItem>
</KuiFlexGroup>
<br /><br />
<KuiFlexGroup>
<KuiFlexItem grow={6}>6</KuiFlexItem>
<KuiFlexItem grow={3}>3</KuiFlexItem>
<KuiFlexItem grow={1}>1</KuiFlexItem>
<KuiFlexItem grow={3}>3</KuiFlexItem>
<KuiFlexItem grow={6}>6</KuiFlexItem>
</KuiFlexGroup>
</div>
);

View file

@ -6,53 +6,60 @@
flex-grow: 1;
flex-basis: 0;
}
}
// Gutter Sizes
&.kuiFlexGroup--gutterSmall > .kuiFlexItem + .kuiFlexItem {
margin-left: $kuiSizeS;
}
$gutterTypes: (
gutterSmall: $kuiSizeS,
gutterMedium: $kuiSize,
gutterLarge: $kuiSizeL,
gutterExtraLarge: $kuiSizeXXL,
);
&.kuiFlexGroup--gutterMedium > .kuiFlexItem + .kuiFlexItem {
margin-left: $kuiSize;
}
// Gutter Sizes
@each $gutterName, $gutterSize in $gutterTypes {
$halfGutterSize: $gutterSize * 0.5;
&.kuiFlexGroup--gutterLarge > .kuiFlexItem + .kuiFlexItem {
margin-left: $kuiSizeL;
}
&.kuiFlexGroup--#{$gutterName} {
margin: -$halfGutterSize;
&.kuiFlexGroup--gutterExtraLarge > .kuiFlexItem + .kuiFlexItem {
margin-left: $kuiSizeXXL;
& > .kuiFlexItem {
margin: $halfGutterSize;
}
}
}
// Justify the grid
&.kuiFlexGroup--justifyContentSpaceBetween {
justify-content: space-between;
}
// Justify the grid
.kuiFlexGroup--justifyContentSpaceBetween {
justify-content: space-between;
}
&.kuiFlexGroup--justifyContentSpaceAround {
justify-content: space-around;
}
.kuiFlexGroup--justifyContentSpaceAround {
justify-content: space-around;
}
&.kuiFlexGroup--justifyContentCenter {
justify-content: center;
}
.kuiFlexGroup--justifyContentCenter {
justify-content: center;
}
&.kuiFlexGroup--justifyContentFlexEnd {
justify-content: flex-end;
}
.kuiFlexGroup--justifyContentFlexEnd {
justify-content: flex-end;
}
// Align Items
&.kuiFlexGroup--alignItemsStart {
align-items: flex-start;
}
// Align Items
.kuiFlexGroup--alignItemsStart {
align-items: flex-start;
}
&.kuiFlexGroup--alignItemsCenter {
align-items: center;
}
.kuiFlexGroup--alignItemsCenter {
align-items: center;
}
&.kuiFlexGroup--alignItemsEnd {
align-items: flex-end;
}
.kuiFlexGroup--alignItemsEnd {
align-items: flex-end;
}
.kuiFlexGroup--wrap {
flex-wrap: wrap;
}
@include screenXSmall {

View file

@ -13,6 +13,12 @@
flex-grow: 0; /* 2 */
flex-basis: auto; /* 2 */
}
@for $i from 1 through 10 {
&.kuiFlexItem--flexGrow#{$i} {
flex-grow: $i
}
}
}
// On mobile we force them to stack and act the same.

View file

@ -31,13 +31,24 @@ const justifyContentToClassNameMap = {
export const JUSTIFY_CONTENTS = Object.keys(justifyContentToClassNameMap);
export const KuiFlexGroup = ({ children, className, gutterSize, alignItems, justifyContent, ...rest }) => {
export const KuiFlexGroup = ({
children,
className,
gutterSize,
alignItems,
justifyContent,
wrap,
...rest
}) => {
const classes = classNames(
'kuiFlexGroup',
gutterSizeToClassNameMap[gutterSize],
alignItemsToClassNameMap[alignItems],
justifyContentToClassNameMap[justifyContent],
className
className,
{
'kuiFlexGroup--wrap': wrap,
},
);
return (
@ -56,10 +67,12 @@ KuiFlexGroup.propTypes = {
gutterSize: PropTypes.oneOf(GUTTER_SIZES),
alignItems: PropTypes.oneOf(ALIGN_ITEMS),
justifyContent: PropTypes.oneOf(JUSTIFY_CONTENTS),
wrap: PropTypes.bool,
};
KuiFlexGroup.defaultProps = {
gutterSize: 'large',
alignItems: 'stretch',
justifyContent: 'flexStart',
wrap: false,
};

View file

@ -2,11 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
const validGrowNumbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
export const KuiFlexItem = ({ children, className, grow, ...rest }) => {
const classes = classNames(
'kuiFlexItem',
{
'kuiFlexItem--flexGrowZero': !grow,
[`kuiFlexItem--flexGrow${grow}`]: validGrowNumbers.indexOf(grow) >= 0,
},
className
);
@ -23,9 +26,25 @@ export const KuiFlexItem = ({ children, className, grow, ...rest }) => {
KuiFlexItem.propTypes = {
children: PropTypes.node,
grow: PropTypes.bool,
grow: growPropType,
};
function growPropType(props, propName, componentName) {
const value = props[propName];
const validValues = [
null, undefined,
true, false,
...validGrowNumbers
];
if (validValues.indexOf(value) === -1) {
return new Error(
`Prop \`${propName}\` supplied to \`${componentName}\` must be a boolean or an integer between 1 and 10.`
);
}
}
KuiFlexItem.defaultProps = {
grow: true,
};

View file

@ -13,4 +13,19 @@ describe('KuiFlexItem', () => {
expect(component)
.toMatchSnapshot();
});
test('tests the grow prop correctly', () => {
const propType = KuiFlexItem.propTypes.grow;
const validValues = [undefined, null, true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const invalidValues = ['true', 'false', '1', 0];
validValues.forEach(value =>
expect(propType({ grow: value }, `grow`)).toBe(undefined)
);
invalidValues.forEach(value =>
expect(propType({ grow: value }, `grow`) instanceof Error).toBe(true)
);
});
});