lucid-ui
Version:
A UI component library from AppNexus.
101 lines (100 loc) • 4.39 kB
JavaScript
import _ from 'lodash';
import React from 'react';
import PropTypes from 'react-peek/prop-types';
import { lucidClassNames } from '../../util/style-helpers';
import { findTypes, omitProps, } from '../../util/component-types';
import Resizer from '../Resizer/Resizer';
const cx = lucidClassNames.bind('&-ResponsiveGrid');
const { string, number, arrayOf } = PropTypes;
const Cell = (_props) => null;
Cell.displayName = 'ResponsiveGrid.Cell';
Cell.peek = {
description: `
Renders a \`<article>\` as the grid cell
`,
};
const defaultProps = {
breakPoints: [960, 1430],
};
export class ResponsiveGrid extends React.Component {
constructor() {
super(...arguments);
this.getColumnLayout = (numberOfColumns) => {
const cellProps = _.map(findTypes(this.props, ResponsiveGridWrapper.Cell), 'props');
const columns = _.reduce(_.map(cellProps, (props, key) => (React.createElement("article", { key: key, className: cx('&-Cell') }, props.children))), (columns, cell, idx) => {
columns[idx % numberOfColumns].push(cell);
return columns;
}, _.times(numberOfColumns, () => []));
return (React.createElement("div", { className: cx('&', {
'&-one-column': numberOfColumns === 1,
}) }, _.map(columns, (col, index) => {
return (React.createElement("div", { key: index, className: cx('&-Column') }, col));
})));
};
}
shouldComponentUpdate(nextProps) {
const { width, breakPoints } = this.props;
const { width: nextWidth } = nextProps;
const [breakOne, breakTwo] = breakPoints;
if (nextWidth < width) {
return ((nextWidth < breakOne && width >= breakOne) ||
(nextWidth < breakTwo && width >= breakTwo));
}
else if (nextWidth > width) {
return ((nextWidth > breakOne && width <= breakOne) ||
(nextWidth > breakTwo && width <= breakTwo));
}
return false;
}
render() {
const { width, breakPoints } = this.props;
const [breakOne, breakTwo] = breakPoints;
if (width < breakTwo) {
if (width < breakOne) {
return this.getColumnLayout(1);
}
return this.getColumnLayout(2);
}
return this.getColumnLayout(3);
}
}
ResponsiveGrid.displayName = 'ResponsiveGrid';
ResponsiveGrid.propTypes = {
width: number `Width of the grid. Note: this does not set the width of the grid, and should be
provided by calculating the width of the parent element.`,
breakPoints: arrayOf(number) `
Break points for the grid to switch column layouts. Break points should be provided
in ascending order. Currently only two break points are used. Example: [960, 1430]`,
className: string `
Appended to the component-specific class names set on the root elements.
`,
};
const ResponsiveGridWrapper = (props) => {
const { breakPoints, children, className, ...passThroughs } = props;
return (React.createElement(Resizer, Object.assign({ className: cx('&', className) }, omitProps(passThroughs, undefined, _.keys(ResponsiveGridWrapper.propTypes), false)), width => {
return (React.createElement(ResponsiveGrid, { width: width, breakPoints: breakPoints }, children));
}));
};
ResponsiveGridWrapper.Cell = Cell;
ResponsiveGridWrapper.defaultProps = defaultProps;
ResponsiveGridWrapper.displayName = ResponsiveGrid.displayName;
ResponsiveGridWrapper.propTypes = {
breakPoints: arrayOf(number) `
Break points for the grid to switch column layouts. Break points should be provided
in ascending order. Currently only two break points are used. Example: [960, 1430]
`,
className: string `
Appended to the component-specific class names set on the root elements.
`,
};
ResponsiveGridWrapper.peek = {
description: `
A grid container that changes the number of grid columns in response to width changes. By default,
the grid cells are displayed in a single column for widths less than 960px, two columns for widths greater
than 960px and less than 1430px, and three columns for widths greater than 1430px. Custom break points can
be provided through the \`breakPoints\` prop.
`,
categories: ['utility'],
madeFrom: ['Resizer'],
};
export default ResponsiveGridWrapper;