@6thquake/react-material
Version:
React components that implement Google's Material Design.
266 lines (232 loc) • 7.61 kB
JavaScript
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
import _extends from "@babel/runtime/helpers/extends";
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles';
import { keys as breakpointKeys } from '../styles/createBreakpoints';
import Hidden from '../Hidden';
const GUTTERS = [0, 8, 16, 24, 40];
const GRID_SIZES = [true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
const breakpointValues = {
xs: 0,
sm: 600,
md: 960,
lg: 1280,
xl: 1920
};
function generateGrid(globalStyles, theme, breakpoint) {
// For the auto layouting
const styles = {
[`grid-${breakpoint}`]: {
position: 'relative',
float: 'left',
width: '100%'
}
};
GRID_SIZES.forEach(size => {
if (typeof size === 'boolean') {
// Skip the first one as handle above.
return;
} // Only keep 6 significant numbers.
const width = `${Math.round(size / 12 * 10e6) / 10e4}%`;
/* eslint-disable max-len */
// Close to the bootstrap implementation:
// https://github.com/twbs/bootstrap/blob/8fccaa2439e97ec72a4b7dc42ccc1f649790adb0/scss/mixins/_grid.scss#L41
/* eslint-enable max-len */
styles[`grid-${breakpoint}-${size}`] = {
position: 'relative',
float: 'left',
minHeight: 1,
width
};
styles[`offset-${breakpoint}-${size}`] = {
marginLeft: width
};
styles[`push-${breakpoint}-${size}`] = {
left: width
};
styles[`pull-${breakpoint}-${size}`] = {
right: width
};
}); // No need for a media query for the first size.
if (breakpoint === 'xs') {
_extends(globalStyles, styles);
} else {
globalStyles[theme.breakpoints.up(breakpoint)] = styles;
}
}
function generateGutter(theme, breakpoint) {
const styles = {};
GUTTERS.forEach((spacing, index) => {
if (index === 0) {
// Skip the default style.
return;
}
styles[`spacing-${breakpoint}-${spacing}`] = {
margin: -spacing / 2,
width: `calc(100% + ${spacing}px)`,
'& > $item': {
padding: spacing / 2
}
};
});
return styles;
}
export const styles = theme => _extends({
container: {
boxSizing: 'border-box',
marginRight: 'auto',
marginLeft: 'auto',
'&:after, &:before': {
display: 'table',
content: 'close-quote',
clear: 'both'
}
},
item: {
boxSizing: 'border-box',
margin: '0' // For instance, it's useful when used with a `figure` element.
}
}, generateGutter(theme, 'xs'), breakpointKeys.reduce((accumulator, key) => {
// Use side effect over immutability for better performance.
generateGrid(accumulator, theme, key);
return accumulator;
}, {}));
function Grid(props) {
const {
classes,
className: classNameProp,
component: Component,
container,
hidden,
item,
spacing
} = props,
other = _objectWithoutPropertiesLoose(props, ["classes", "className", "component", "container", "hidden", "item", "lg", "md", "sm", "spacing", "xl", "xs", "offset", "pull", "push"]);
let sizeClassObj = {};
breakpointKeys.forEach(size => {
let sizeProps = {};
if (typeof props[size] === 'number') {
sizeProps.span = props[size];
sizeProps.offset = props.offset;
sizeProps.push = props.push;
sizeProps.pull = props.pull;
} else if (typeof props[size] === 'object') {
sizeProps = props[size] || {};
}
sizeClassObj = _extends({}, sizeClassObj, {
[classes[`grid-${size}-${sizeProps.span}`]]: item && sizeProps.span,
[classes[`offset-${size}-${sizeProps.offset}`]]: item && sizeProps.offset,
[classes[`push-${size}-${sizeProps.push}`]]: item && sizeProps.push,
[classes[`pull-${size}-${sizeProps.pull}`]]: item && sizeProps.pull
});
});
const className = classNames({
[classes.container]: container,
[classes.item]: item,
[classes[`spacing-xs-${String(spacing)}`]]: container && spacing !== 0
}, classNameProp, sizeClassObj);
const gridProps = _extends({
className
}, other);
if (hidden) {
return React.createElement(Hidden, hidden, React.createElement(Component, gridProps));
}
return React.createElement(Component, gridProps);
}
process.env.NODE_ENV !== "production" ? Grid.propTypes = {
/**
* The content of the component.
*/
children: PropTypes.node,
/**
* Override or extend the styles applied to the component.
* See [CSS API](#css-api) below for more details.
*/
classes: PropTypes.object.isRequired,
/**
* @ignore
*/
className: PropTypes.string,
/**
* The component used for the root node.
* Either a string to use a DOM element or a component.
*/
component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
/**
* If `true`, the component will have the flex *container* behavior.
* You should be wrapping *items* with a *container*.
*/
container: PropTypes.bool,
/**
* If provided, will wrap with [Hidden](/api/hidden) component and given properties.
*/
hidden: PropTypes.object,
/**
* If `true`, the component will have the flex *item* behavior.
* You should be wrapping *items* with a *container*.
*/
item: PropTypes.bool,
/**
* Defines the number of grids the component is going to use.
* It's applied for the `lg` breakpoint and wider screens if not overridden.
*/
lg: PropTypes.oneOfType([PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), PropTypes.object]),
/**
* Defines the number of grids the component is going to use.
* It's applied for the `md` breakpoint and wider screens if not overridden.
*/
md: PropTypes.oneOfType([PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), PropTypes.object]),
/**
* Defines the number of grids the component is going to use.
* It's applied for the `sm` breakpoint and wider screens if not overridden.
*/
// sm: PropTypes.oneOf([false, true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, PropTypes.object]),
offset: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Defines the space between the type `item` component.
* It can only be used on a type `container` component.
*/
pull: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Defines the number of grids the component is going to use.
* It's applied for the `xl` breakpoint and wider screens.
*/
push: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Defines the number of grids the component is going to use.
* It's applied for all the screen sizes with the lowest priority.
*/
sm: PropTypes.oneOfType([PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), PropTypes.object]),
/**
* The number of cells to offset Col from the left
*/
spacing: PropTypes.oneOf(GUTTERS),
/**
* The number of cells that raster is moved to the left
*/
span: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* The number of cells that raster is moved to the right
*/
xl: PropTypes.oneOfType([PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), PropTypes.object]),
/**
* Raster number of cells to occupy
*/
xs: PropTypes.oneOfType([PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), PropTypes.object])
} : void 0;
Grid.defaultProps = {
component: 'div',
container: false,
item: false,
lg: 0,
md: 0,
sm: 0,
spacing: 0,
xl: 0,
xs: 0
};
export default withStyles(styles, {
name: 'RMGrid'
})(Grid);