diff --git a/docs/pages/api-docs/grid.json b/docs/pages/api-docs/grid.json index 5277e065e7fb56..862d2a25e81dcb 100644 --- a/docs/pages/api-docs/grid.json +++ b/docs/pages/api-docs/grid.json @@ -61,6 +61,7 @@ }, "default": "0" }, + "sx": { "type": { "name": "object" } }, "wrap": { "type": { "name": "enum", @@ -143,5 +144,5 @@ "filename": "/packages/material-ui/src/Grid/Grid.js", "inheritance": null, "demos": "", - "styledComponent": false + "styledComponent": true } diff --git a/docs/scripts/buildApi.ts b/docs/scripts/buildApi.ts index f7fddf81289470..1bc2d8cb1abd13 100644 --- a/docs/scripts/buildApi.ts +++ b/docs/scripts/buildApi.ts @@ -709,8 +709,15 @@ async function updateStylesDefinition(context: { if (members) { styles.descriptions = styles.descriptions || {}; members.forEach((member) => { - const className = ((member as babel.types.TSPropertySignature) + let className = ((member as babel.types.TSPropertySignature) .key as babel.types.Identifier).name; + + if (!className) { + // Necessary for classes defined as kebab case + className = ((member as babel.types.TSPropertySignature) + .key as babel.types.StringLiteral).value; + } + styles.classes.push(className); if (member.leadingComments) { styles.descriptions[className] = trimComment(member.leadingComments[0].value); diff --git a/docs/translations/api-docs/grid/grid.json b/docs/translations/api-docs/grid/grid.json index 0f11afda580efc..a4b938bb09d92b 100644 --- a/docs/translations/api-docs/grid/grid.json +++ b/docs/translations/api-docs/grid/grid.json @@ -14,6 +14,7 @@ "md": "Defines the number of grids the component is going to use. It's applied for the md breakpoint and wider screens if not overridden.", "sm": "Defines the number of grids the component is going to use. It's applied for the sm breakpoint and wider screens if not overridden.", "spacing": "Defines the space between the type item component. It can only be used on a type container component.", + "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "wrap": "Defines the flex-wrap style property. It's applied for all screen sizes.", "xl": "Defines the number of grids the component is going to use. It's applied for the xl breakpoint and wider screens.", "xs": "Defines the number of grids the component is going to use. It's applied for all the screen sizes with the lowest priority.", diff --git a/packages/material-ui/src/Button/Button.js b/packages/material-ui/src/Button/Button.js index d19e174bac541e..80a67fd2932857 100644 --- a/packages/material-ui/src/Button/Button.js +++ b/packages/material-ui/src/Button/Button.js @@ -34,7 +34,7 @@ const overridesResolver = (props, styles) => { }; const useUtilityClasses = (styleProps) => { - const { color, disableElevation, fullWidth, size, variant, classes = {} } = styleProps; + const { color, disableElevation, fullWidth, size, variant, classes } = styleProps; const slots = { root: [ diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.js b/packages/material-ui/src/ButtonBase/ButtonBase.js index d8836e07728288..f3a9de6c7cd670 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.js +++ b/packages/material-ui/src/ButtonBase/ButtonBase.js @@ -21,7 +21,7 @@ const overridesResolver = (props, styles) => { }; const useUtilityClasses = (styleProps) => { - const { disabled, focusVisible, focusVisibleClassName, classes = {} } = styleProps; + const { disabled, focusVisible, focusVisibleClassName, classes } = styleProps; const slots = { root: ['root', disabled && 'disabled', focusVisible && 'focusVisible'], diff --git a/packages/material-ui/src/Grid/Grid.d.ts b/packages/material-ui/src/Grid/Grid.d.ts index e15b97a5eedf47..50f1dc597071aa 100644 --- a/packages/material-ui/src/Grid/Grid.d.ts +++ b/packages/material-ui/src/Grid/Grid.d.ts @@ -1,4 +1,6 @@ import * as React from 'react'; +import { SxProps } from '@material-ui/system'; +import { Theme } from '../styles'; import { OverridableComponent, OverrideProps } from '../OverridableComponent'; export type GridItemsAlignment = 'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline'; @@ -170,6 +172,10 @@ export interface GridTypeMap

{ * @default 0 */ spacing?: GridSpacing; + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx?: SxProps; /** * Defines the `flex-wrap` style property. * It's applied for all screen sizes. diff --git a/packages/material-ui/src/Grid/Grid.js b/packages/material-ui/src/Grid/Grid.js index fa64775cfcb0da..ce5c22aa23a4b5 100644 --- a/packages/material-ui/src/Grid/Grid.js +++ b/packages/material-ui/src/Grid/Grid.js @@ -12,50 +12,45 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; -import withStyles from '../styles/withStyles'; +import { deepmerge } from '@material-ui/utils'; +import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled'; import requirePropFactory from '../utils/requirePropFactory'; +import experimentalStyled from '../styles/experimentalStyled'; +import useThemeProps from '../styles/useThemeProps'; +import gridClasses, { getGridUtilityClass } from './gridClasses'; -const SPACINGS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; -const GRID_SIZES = ['auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; +function generateGrid(globalStyles, theme, breakpoint, styleProps) { + const size = styleProps[breakpoint]; -function generateGrid(globalStyles, theme, breakpoint) { - const styles = {}; + if (!size) return; - GRID_SIZES.forEach((size) => { - const key = `grid-${breakpoint}-${size}`; - - if (size === true) { - // For the auto layouting - styles[key] = { - flexBasis: 0, - flexGrow: 1, - maxWidth: '100%', - }; - - return; - } - - if (size === 'auto') { - styles[key] = { - flexBasis: 'auto', - flexGrow: 0, - maxWidth: 'none', - }; - - return; - } + let styles = {}; + if (size === true) { + // For the auto layouting + styles = { + flexBasis: 0, + flexGrow: 1, + maxWidth: '100%', + }; + } else if (size === 'auto') { + styles = { + flexBasis: 'auto', + flexGrow: 0, + maxWidth: 'none', + }; + } else { // Keep 7 significant numbers. const width = `${Math.round((size / 12) * 10e7) / 10e5}%`; // Close to the bootstrap implementation: // https://github.com/twbs/bootstrap/blob/8fccaa2439e97ec72a4b7dc42ccc1f649790adb0/scss/mixins/_grid.scss#L41 - styles[key] = { + styles = { flexBasis: width, flexGrow: 0, maxWidth: width, }; - }); + } // No need for a media query for the first size. if (breakpoint === 'xs') { @@ -70,150 +65,177 @@ function getOffset(val, div = 1) { return `${parse / div}${String(val).replace(String(parse), '') || 'px'}`; } -function generateGutter(theme, breakpoint) { - const styles = {}; +function generateGutter({ theme, styleProps }) { + const { container, spacing } = styleProps; + let styles = {}; - SPACINGS.forEach((spacing) => { + if (container && spacing !== 0) { const themeSpacing = theme.spacing(spacing); - if (themeSpacing === '0px') { - return; + if (themeSpacing !== '0px') { + styles = { + margin: `-${getOffset(themeSpacing, 2)}`, + width: `calc(100% + ${getOffset(themeSpacing)})`, + [`& > .${gridClasses.item}`]: { + padding: getOffset(themeSpacing, 2), + }, + }; } - - styles[`spacing-${breakpoint}-${spacing}`] = { - margin: `-${getOffset(themeSpacing, 2)}`, - width: `calc(100% + ${getOffset(themeSpacing)})`, - '& > $item': { - padding: getOffset(themeSpacing, 2), - }, - }; - }); + } return styles; } +const overridesResolver = (props, styles) => { + const { + alignContent, + alignItems, + container, + direction, + item, + justifyContent, + lg, + md, + sm, + spacing, + wrap, + xl, + xs, + zeroMinWidth, + } = props.styleProps; + + return deepmerge(styles.root || {}, { + ...(container && styles.container), + ...(item && styles.item), + ...(zeroMinWidth && styles.zeroMinWidth), + ...(container && spacing !== 0 && styles[`spacing-xs-${String(spacing)}`]), + ...(direction !== 'row' && styles[`direction-xs-${String(direction)}`]), + ...(wrap !== 'wrap' && styles[`wrap-xs-${String(wrap)}`]), + ...(alignItems !== 'stretch' && styles[`align-items-xs-${String(alignItems)}`]), + ...(alignContent !== 'stretch' && styles[`align-content-xs-${String(alignContent)}`]), + ...(justifyContent !== 'flex-start' && styles[`justify-content-xs-${String(justifyContent)}`]), + ...(xs !== false && styles[`grid-xs-${String(xs)}`]), + ...(sm !== false && styles[`grid-sm-${String(sm)}`]), + ...(md !== false && styles[`grid-md-${String(md)}`]), + ...(lg !== false && styles[`grid-lg-${String(lg)}`]), + ...(xl !== false && styles[`grid-xl-${String(xl)}`]), + }); +}; + // Default CSS values // flex: '0 1 auto', // flexDirection: 'row', // alignItems: 'flex-start', // flexWrap: 'nowrap', // justifyContent: 'flex-start', -export const styles = (theme) => ({ - /* Styles applied to the root element. */ - root: {}, - /* Styles applied to the root element if `container={true}`. */ - container: { - boxSizing: 'border-box', - display: 'flex', - flexWrap: 'wrap', - width: '100%', - }, - /* Styles applied to the root element if `item={true}`. */ - item: { +const GridRoot = experimentalStyled( + 'div', + {}, + { name: 'MuiGrid', slot: 'Root', overridesResolver }, +)( + ({ styleProps }) => ({ boxSizing: 'border-box', - margin: 0, // For instance, it's useful when used with a `figure` element. - }, - /* Styles applied to the root element if `zeroMinWidth={true}`. */ - zeroMinWidth: { - minWidth: 0, - }, - /* Styles applied to the root element if `direction="column"`. */ - 'direction-xs-column': { - flexDirection: 'column', - '& > $item': { - maxWidth: 'none', - }, - }, - /* Styles applied to the root element if `direction="column-reverse"`. */ - 'direction-xs-column-reverse': { - flexDirection: 'column-reverse', - '& > $item': { - maxWidth: 'none', - }, - }, - /* Styles applied to the root element if `direction="row-reverse"`. */ - 'direction-xs-row-reverse': { - flexDirection: 'row-reverse', - }, - /* Styles applied to the root element if `wrap="nowrap"`. */ - 'wrap-xs-nowrap': { - flexWrap: 'nowrap', - }, - /* Styles applied to the root element if `wrap="reverse"`. */ - 'wrap-xs-wrap-reverse': { - flexWrap: 'wrap-reverse', - }, - /* Styles applied to the root element if `alignItems="center"`. */ - 'align-items-xs-center': { - alignItems: 'center', - }, - /* Styles applied to the root element if `alignItems="flex-start"`. */ - 'align-items-xs-flex-start': { - alignItems: 'flex-start', - }, - /* Styles applied to the root element if `alignItems="flex-end"`. */ - 'align-items-xs-flex-end': { - alignItems: 'flex-end', - }, - /* Styles applied to the root element if `alignItems="baseline"`. */ - 'align-items-xs-baseline': { - alignItems: 'baseline', - }, - /* Styles applied to the root element if `alignContent="center"`. */ - 'align-content-xs-center': { - alignContent: 'center', - }, - /* Styles applied to the root element if `alignContent="flex-start"`. */ - 'align-content-xs-flex-start': { - alignContent: 'flex-start', - }, - /* Styles applied to the root element if `alignContent="flex-end"`. */ - 'align-content-xs-flex-end': { - alignContent: 'flex-end', - }, - /* Styles applied to the root element if `alignContent="space-between"`. */ - 'align-content-xs-space-between': { - alignContent: 'space-between', - }, - /* Styles applied to the root element if `alignContent="space-around"`. */ - 'align-content-xs-space-around': { - alignContent: 'space-around', - }, - /* Styles applied to the root element if `justifyContent="center"`. */ - 'justify-content-xs-center': { - justifyContent: 'center', - }, - /* Styles applied to the root element if `justifyContent="flex-end"`. */ - 'justify-content-xs-flex-end': { - justifyContent: 'flex-end', - }, - /* Styles applied to the root element if `justifyContent="space-between"`. */ - 'justify-content-xs-space-between': { - justifyContent: 'space-between', - }, - /* Styles applied to the root element if `justifyContent="space-around"`. */ - 'justify-content-xs-space-around': { - justifyContent: 'space-around', - }, - /* Styles applied to the root element if `justifyContent="space-evenly"`. */ - 'justify-content-xs-space-evenly': { - justifyContent: 'space-evenly', - }, - ...generateGutter(theme, 'xs'), - ...theme.breakpoints.keys.reduce((accumulator, key) => { - // Use side effect over immutability for better performance. - generateGrid(accumulator, theme, key); - return accumulator; - }, {}), -}); + ...(styleProps.container && { + display: 'flex', + flexWrap: 'wrap', + width: '100%', + }), + ...(styleProps.item && { + margin: 0, // For instance, it's useful when used with a `figure` element. + }), + ...(styleProps.zeroMinWidth && { + minWidth: 0, + }), + ...(styleProps.direction === 'column' && { + flexDirection: 'column', + [`& > .${gridClasses.item}`]: { + maxWidth: 'none', + }, + }), + ...(styleProps.direction === 'column-reverse' && { + flexDirection: 'column-reverse', + [`& > .${gridClasses.item}`]: { + maxWidth: 'none', + }, + }), + ...(styleProps.direction === 'row-reverse' && { + flexDirection: 'row-reverse', + }), + ...(styleProps.wrap === 'nowrap' && { + flexWrap: 'nowrap', + }), + ...(styleProps.wrap === 'reverse' && { + flexWrap: 'wrap-reverse', + }), + ...(styleProps.alignItems && { + alignItems: styleProps.alignItems, + }), + ...(styleProps.alignContent && { + alignContent: styleProps.alignContent, + }), + ...(styleProps.justifyContent && { + justifyContent: styleProps.justifyContent, + }), + }), + generateGutter, + ({ theme, styleProps }) => + theme.breakpoints.keys.reduce((accumulator, key) => { + // Use side effect over immutability for better performance. + generateGrid(accumulator, theme, key, styleProps); + return accumulator; + }, {}), +); + +const useUtilityClasses = (styleProps) => { + const { + alignContent, + alignItems, + classes, + container, + direction, + item, + justifyContent, + lg, + md, + sm, + spacing, + wrap, + xl, + xs, + zeroMinWidth, + } = styleProps; + + const slots = { + root: [ + 'root', + container && 'container', + item && 'item', + zeroMinWidth && 'zeroMinWidth', + container && spacing !== 0 && `spacing-xs-${String(spacing)}`, + direction !== 'row' && `direction-xs-${String(direction)}`, + wrap !== 'wrap' && `wrap-xs-${String(wrap)}`, + alignItems !== 'stretch' && `align-items-xs-${String(alignItems)}`, + alignContent !== 'stretch' && `align-content-xs-${String(alignContent)}`, + justifyContent !== 'flex-start' && `justify-content-xs-${String(justifyContent)}`, + xs !== false && `grid-xs-${String(xs)}`, + sm !== false && `grid-sm-${String(sm)}`, + md !== false && `grid-md-${String(md)}`, + lg !== false && `grid-lg-${String(lg)}`, + xl !== false && `grid-xl-${String(xl)}`, + ], + }; + + return composeClasses({ slots, classes, getUtilityClass: getGridUtilityClass }); +}; + +const Grid = React.forwardRef(function Grid(inProps, ref) { + const props = useThemeProps({ props: inProps, name: 'MuiGrid' }); -const Grid = React.forwardRef(function Grid(props, ref) { const { alignContent = 'stretch', alignItems = 'stretch', - classes, - className: classNameProp, - component: Component = 'div', + className, + component = 'div', container = false, direction = 'row', item = false, @@ -229,28 +251,35 @@ const Grid = React.forwardRef(function Grid(props, ref) { ...other } = props; - const className = clsx( - classes.root, - { - [classes.container]: container, - [classes.item]: item, - [classes.zeroMinWidth]: zeroMinWidth, - [classes[`spacing-xs-${String(spacing)}`]]: container && spacing !== 0, - [classes[`direction-xs-${String(direction)}`]]: direction !== 'row', - [classes[`wrap-xs-${String(wrap)}`]]: wrap !== 'wrap', - [classes[`align-items-xs-${String(alignItems)}`]]: alignItems !== 'stretch', - [classes[`align-content-xs-${String(alignContent)}`]]: alignContent !== 'stretch', - [classes[`justify-content-xs-${String(justifyContent)}`]]: justifyContent !== 'flex-start', - [classes[`grid-xs-${String(xs)}`]]: xs !== false, - [classes[`grid-sm-${String(sm)}`]]: sm !== false, - [classes[`grid-md-${String(md)}`]]: md !== false, - [classes[`grid-lg-${String(lg)}`]]: lg !== false, - [classes[`grid-xl-${String(xl)}`]]: xl !== false, - }, - classNameProp, - ); + const styleProps = { + ...props, + alignContent, + alignItems, + container, + direction, + item, + justifyContent, + lg, + md, + sm, + spacing, + wrap, + xl, + xs, + zeroMinWidth, + }; + + const classes = useUtilityClasses(styleProps); - return ; + return ( + + ); }); Grid.propTypes = { @@ -358,6 +387,10 @@ Grid.propTypes = { * @default 0 */ spacing: PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.object, /** * Defines the `flex-wrap` style property. * It's applied for all screen sizes. @@ -390,12 +423,12 @@ Grid.propTypes = { zeroMinWidth: PropTypes.bool, }; -const StyledGrid = withStyles(styles, { name: 'MuiGrid' })(Grid); - if (process.env.NODE_ENV !== 'production') { const requireProp = requirePropFactory('Grid'); - StyledGrid.propTypes = { - ...StyledGrid.propTypes, + // eslint-disable-next-line no-useless-concat + Grid['propTypes' + ''] = { + // eslint-disable-next-line react/forbid-foreign-prop-types + ...Grid.propTypes, alignContent: requireProp('container'), alignItems: requireProp('container'), direction: requireProp('container'), @@ -410,4 +443,4 @@ if (process.env.NODE_ENV !== 'production') { }; } -export default StyledGrid; +export default Grid; diff --git a/packages/material-ui/src/Grid/Grid.test.js b/packages/material-ui/src/Grid/Grid.test.js index 4d64ec03a8826a..6592a9518ff9e8 100644 --- a/packages/material-ui/src/Grid/Grid.test.js +++ b/packages/material-ui/src/Grid/Grid.test.js @@ -1,24 +1,23 @@ import * as React from 'react'; import { expect } from 'chai'; -import { getClasses, createMount, describeConformance, createClientRender } from 'test/utils'; -import { createMuiTheme } from '@material-ui/core/styles'; -import Grid, { styles } from './Grid'; +import { createMount, describeConformanceV5, createClientRender, screen } from 'test/utils'; +import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import Grid from './Grid'; +import classes from './gridClasses'; describe('', () => { const mount = createMount(); const render = createClientRender(); - let classes; - before(() => { - classes = getClasses(); - }); - - describeConformance(, () => ({ + describeConformanceV5(, () => ({ classes, inheritComponent: 'div', mount, refInstanceof: window.HTMLDivElement, - testComponentPropWith: 'span', + muiName: 'MuiGrid', + testVariantProps: { container: true, spacing: 5 }, + testStateOverrides: { prop: 'container', value: true, styleKey: 'container' }, + skip: ['componentsProp'], })); describe('prop: container', () => { @@ -90,21 +89,63 @@ describe('', () => { }); describe('gutter', () => { - it('should generate the right values', () => { - const defaultTheme = createMuiTheme(); + it('should generate the right values', function test() { + if (/jsdom/.test(window.navigator.userAgent)) this.skip(); + + const parentWidth = 500; + const remValue = 16; const remTheme = createMuiTheme({ spacing: (factor) => `${0.25 * factor}rem`, }); - expect(styles(remTheme)['spacing-xs-2']).to.deep.equal({ - margin: '-0.25rem', - width: 'calc(100% + 0.5rem)', - '& > $item': { padding: '0.25rem' }, + const { rerender } = render( +

+ + + + + + +
, + ); + + expect(screen.getByTestId('grid')).toHaveComputedStyle({ + marginTop: `${-1 * remValue * 0.25}px`, // '-0.25rem' + marginBottom: `${-1 * remValue * 0.25}px`, // '-0.25rem' + marginLeft: `${-1 * remValue * 0.25}px`, // '-0.25rem' + marginRight: `${-1 * remValue * 0.25}px`, // '-0.25rem' + width: `${parentWidth + remValue * 0.5}px`, // 'calc(100% + 0.5rem)' + }); + + expect(screen.getByTestId('first-custom-theme')).toHaveComputedStyle({ + paddingTop: `${0.25 * remValue}px`, // 0.25rem + paddingBottom: `${0.25 * remValue}px`, // 0.25rem + paddingLeft: `${0.25 * remValue}px`, // 0.25rem + paddingRight: `${0.25 * remValue}px`, // 0.25rem + }); + + rerender( +
+ + + + +
, + ); + + expect(screen.getByTestId('grid')).toHaveComputedStyle({ + marginTop: '-8px', + marginBottom: '-8px', + marginLeft: '-8px', + marginRight: '-8px', + width: `${parentWidth + 16}px`, // 'calc(100% + 16px)' }); - expect(styles(defaultTheme)['spacing-xs-2']).to.deep.equal({ - margin: '-8px', - width: 'calc(100% + 16px)', - '& > $item': { padding: '8px' }, + + expect(screen.getByTestId('first-default-theme')).toHaveComputedStyle({ + paddingTop: '8px', + paddingBottom: '8px', + paddingLeft: '8px', + paddingRight: '8px', }); }); }); diff --git a/packages/material-ui/src/Grid/gridClasses.d.ts b/packages/material-ui/src/Grid/gridClasses.d.ts new file mode 100644 index 00000000000000..9492249389c70f --- /dev/null +++ b/packages/material-ui/src/Grid/gridClasses.d.ts @@ -0,0 +1,131 @@ +export interface GridClasses { + root: string; + container: string; + item: string; + zeroMinWidth: string; + + 'spacing-xs-auto': string; + 'spacing-xs-true': string; + 'spacing-xs-1': string; + 'spacing-xs-2': string; + 'spacing-xs-3': string; + 'spacing-xs-4': string; + 'spacing-xs-5': string; + 'spacing-xs-6': string; + 'spacing-xs-7': string; + 'spacing-xs-8': string; + 'spacing-xs-9': string; + 'spacing-xs-10': string; + 'spacing-xs-11': string; + 'spacing-xs-12': string; + + 'direction-xs-column-reverse': string; + 'direction-xs-column': string; + 'direction-xs-row-reverse': string; + 'direction-xs-row': string; + + 'align-content-xs-center': string; + 'align-content-xs-flex-end': string; + 'align-content-xs-flex-start': string; + 'align-content-xs-space-around': string; + 'align-content-xs-space-between': string; + 'align-content-xs-stretch': string; + + 'align-items-xs-baseline': string; + 'align-items-xs-center': string; + 'align-items-xs-flex-end': string; + 'align-items-xs-flex-start': string; + 'align-items-xs-stretch': string; + + 'wrap-xs-nowrap': string; + 'wrap-xs-wrap-reverse': string; + 'wrap-xs-wrap': string; + + 'justify-content-xs-center': string; + 'justify-content-xs-flex-end': string; + 'justify-content-xs-flex-start': string; + 'justify-content-xs-space-around': string; + 'justify-content-xs-space-between': string; + 'justify-content-xs-space-evenly': string; + + 'grid-xs-auto': string; + 'grid-xs-true': string; + 'grid-xs-1': string; + 'grid-xs-2': string; + 'grid-xs-3': string; + 'grid-xs-4': string; + 'grid-xs-5': string; + 'grid-xs-6': string; + 'grid-xs-7': string; + 'grid-xs-8': string; + 'grid-xs-9': string; + 'grid-xs-10': string; + 'grid-xs-11': string; + 'grid-xs-12': string; + + 'grid-sm-auto': string; + 'grid-sm-true': string; + 'grid-sm-1': string; + 'grid-sm-2': string; + 'grid-sm-3': string; + 'grid-sm-4': string; + 'grid-sm-5': string; + 'grid-sm-6': string; + 'grid-sm-7': string; + 'grid-sm-8': string; + 'grid-sm-9': string; + 'grid-sm-10': string; + 'grid-sm-11': string; + 'grid-sm-12': string; + + 'grid-md-auto': string; + 'grid-md-true': string; + 'grid-md-1': string; + 'grid-md-2': string; + 'grid-md-3': string; + 'grid-md-4': string; + 'grid-md-5': string; + 'grid-md-6': string; + 'grid-md-7': string; + 'grid-md-8': string; + 'grid-md-9': string; + 'grid-md-10': string; + 'grid-md-11': string; + 'grid-md-12': string; + + 'grid-lg-auto': string; + 'grid-lg-true': string; + 'grid-lg-1': string; + 'grid-lg-2': string; + 'grid-lg-3': string; + 'grid-lg-4': string; + 'grid-lg-5': string; + 'grid-lg-6': string; + 'grid-lg-7': string; + 'grid-lg-8': string; + 'grid-lg-9': string; + 'grid-lg-10': string; + 'grid-lg-11': string; + 'grid-lg-12': string; + + 'grid-xl-auto': string; + 'grid-xl-true': string; + 'grid-xl-1': string; + 'grid-xl-2': string; + 'grid-xl-3': string; + 'grid-xl-4': string; + 'grid-xl-5': string; + 'grid-xl-6': string; + 'grid-xl-7': string; + 'grid-xl-8': string; + 'grid-xl-9': string; + 'grid-xl-10': string; + 'grid-xl-11': string; + 'grid-xl-12': string; +} + +declare const gridClasses: GridClasses; + +export function getGridUtilityClass(slot: string): string; + +export default gridClasses; diff --git a/packages/material-ui/src/Grid/gridClasses.js b/packages/material-ui/src/Grid/gridClasses.js new file mode 100644 index 00000000000000..9a3225c9c52fa0 --- /dev/null +++ b/packages/material-ui/src/Grid/gridClasses.js @@ -0,0 +1,56 @@ +import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled'; + +export function getGridUtilityClass(slot) { + return generateUtilityClass('MuiGrid', slot); +} + +const SPACINGS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +const DIRECTIONS = ['column-reverse', 'column', 'row-reverse', 'row']; +const ALIGN_CONTENTS = [ + 'center', + 'flex-end', + 'flex-start', + 'space-around', + 'space-between', + 'stretch', +]; +const ALIGN_ITEMS = ['baseline', 'center', 'flex-end', 'flex-start', 'stretch']; +const JUSTIFY_CONTENTS = [ + 'center', + 'flex-end', + 'flex-start', + 'space-around', + 'space-between', + 'space-evenly', +]; +const WRAPS = ['nowrap', 'wrap-reverse', 'wrap']; +const GRID_SIZES = ['auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + +const gridClasses = generateUtilityClasses('MuiGrid', [ + 'root', + 'container', + 'item', + 'zeroMinWidth', + + // spacings + ...SPACINGS.map((spacing) => `spacing-xs-${spacing}`), + // direction values + ...DIRECTIONS.map((direction) => `direction-xs-${direction}`), + // align content values + ...ALIGN_CONTENTS.map((alignContent) => `align-content-xs-${alignContent}`), + // align items values + ...ALIGN_ITEMS.map((alignItems) => `align-items-xs-${alignItems}`), + // wrap values + ...WRAPS.map((wrap) => `wrap-xs-${wrap}`), + // justify content values + ...JUSTIFY_CONTENTS.map((justifyContent) => `justify-content-xs-${justifyContent}`), + + // grid sizes for all breakpoints + ...GRID_SIZES.map((size) => `grid-xs-${String(size)}`), + ...GRID_SIZES.map((size) => `grid-sm-${String(size)}`), + ...GRID_SIZES.map((size) => `grid-md-${String(size)}`), + ...GRID_SIZES.map((size) => `grid-lg-${String(size)}`), + ...GRID_SIZES.map((size) => `grid-xl-${String(size)}`), +]); + +export default gridClasses; diff --git a/packages/material-ui/src/Grid/index.d.ts b/packages/material-ui/src/Grid/index.d.ts index 243da15e14de82..de7826137c176c 100644 --- a/packages/material-ui/src/Grid/index.d.ts +++ b/packages/material-ui/src/Grid/index.d.ts @@ -1,2 +1,5 @@ export { default } from './Grid'; export * from './Grid'; + +export { default as gridClasses } from './gridClasses'; +export * from './gridClasses'; diff --git a/packages/material-ui/src/Grid/index.js b/packages/material-ui/src/Grid/index.js index 3d919c9acb4394..c952f0ddd87e8e 100644 --- a/packages/material-ui/src/Grid/index.js +++ b/packages/material-ui/src/Grid/index.js @@ -1 +1,3 @@ export { default } from './Grid'; +export { default as gridClasses } from './gridClasses'; +export * from './gridClasses';