diff --git a/docs/data/material/components/grid2/SpacingGrid.js b/docs/data/material/components/grid2/SpacingGrid.js index 09eb9e9a2d2a07..97d79b33841787 100644 --- a/docs/data/material/components/grid2/SpacingGrid.js +++ b/docs/data/material/components/grid2/SpacingGrid.js @@ -1,4 +1,5 @@ import * as React from 'react'; +import Box from '@mui/material/Box'; import Grid from '@mui/material/Unstable_Grid2'; import FormLabel from '@mui/material/FormLabel'; import FormControl from '@mui/material/FormControl'; @@ -20,51 +21,52 @@ export default function SpacingGrid() { `; return ( - - - - {[0, 1, 2].map((value) => ( - - - theme.palette.mode === 'dark' ? '#1A2027' : '#fff', - }} - /> - - ))} - - - - - - - - spacing - - {[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => ( - } - label={value.toString()} - /> - ))} - - - + + + {[0, 1, 2].map((value) => ( + + + theme.palette.mode === 'dark' ? '#1A2027' : '#fff', + }} + /> - - + ))} - + + + spacing + + {[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => ( + } + label={value.toString()} + /> + ))} + + + + + ); } diff --git a/docs/data/material/components/grid2/SpacingGrid.tsx b/docs/data/material/components/grid2/SpacingGrid.tsx index 4505fd4a0727e3..a3fcce0dd0198e 100644 --- a/docs/data/material/components/grid2/SpacingGrid.tsx +++ b/docs/data/material/components/grid2/SpacingGrid.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import Box from '@mui/material/Box'; import Grid from '@mui/material/Unstable_Grid2'; import FormLabel from '@mui/material/FormLabel'; import FormControl from '@mui/material/FormControl'; @@ -20,51 +21,52 @@ export default function SpacingGrid() { `; return ( - - - - {[0, 1, 2].map((value) => ( - - - theme.palette.mode === 'dark' ? '#1A2027' : '#fff', - }} - /> - - ))} - - - - - - - - spacing - - {[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => ( - } - label={value.toString()} - /> - ))} - - - + + + {[0, 1, 2].map((value) => ( + + + theme.palette.mode === 'dark' ? '#1A2027' : '#fff', + }} + /> - - + ))} - + + + spacing + + {[0, 0.5, 1, 2, 3, 4, 8, 12].map((value) => ( + } + label={value.toString()} + /> + ))} + + + + + ); } diff --git a/packages/mui-system/src/Unstable_Grid/GridProps.ts b/packages/mui-system/src/Unstable_Grid/GridProps.ts index f4456f15edafb4..fb87411411531e 100644 --- a/packages/mui-system/src/Unstable_Grid/GridProps.ts +++ b/packages/mui-system/src/Unstable_Grid/GridProps.ts @@ -161,7 +161,18 @@ export interface GridBaseProps extends Breakpoints { } export interface GridOwnerState extends GridBaseProps { - nested: boolean; + /** + * The level of the grid starts from `0` + * and increases when the grid nests inside another grid regardless of container or item. + * + * ```js + * // level 0 + * // level 1 + * // level 2 + * // level 1 + * ``` + */ + level: number; gridSize: Partial>; gridOffset: Partial>; } diff --git a/packages/mui-system/src/Unstable_Grid/createGrid.tsx b/packages/mui-system/src/Unstable_Grid/createGrid.tsx index 6dc66f30b49234..920caf5073731a 100644 --- a/packages/mui-system/src/Unstable_Grid/createGrid.tsx +++ b/packages/mui-system/src/Unstable_Grid/createGrid.tsx @@ -58,7 +58,7 @@ export default function createGrid( componentName = 'MuiGrid', } = options; - const NestedContext = React.createContext(false); + const NestedContext = React.createContext(0); const OverflowContext = React.createContext(undefined); const useUtilityClasses = (ownerState: GridOwnerState, theme: typeof defaultTheme) => { @@ -93,7 +93,7 @@ export default function createGrid( const theme = useTheme(); const themeProps = useThemeProps(inProps); const props = extendSxProp(themeProps) as Omit; // `color` type conflicts with html color attribute. - const nested = React.useContext(NestedContext); + const level = React.useContext(NestedContext); const overflow = React.useContext(OverflowContext); const { className, @@ -110,7 +110,7 @@ export default function createGrid( } = props; // Because `disableEqualOverflow` can be set from the theme's defaultProps, the **nested** grid should look at the instance props instead. let disableEqualOverflow = themeDisableEqualOverflow; - if (nested && themeDisableEqualOverflow !== undefined) { + if (level && themeDisableEqualOverflow !== undefined) { disableEqualOverflow = inProps.disableEqualOverflow; } // collect breakpoints related props because they can be customized from the theme. @@ -128,15 +128,15 @@ export default function createGrid( } }); - const columns = inProps.columns ?? (nested ? undefined : columnsProp); - const spacing = inProps.spacing ?? (nested ? undefined : spacingProp); + const columns = inProps.columns ?? (level ? undefined : columnsProp); + const spacing = inProps.spacing ?? (level ? undefined : spacingProp); const rowSpacing = - inProps.rowSpacing ?? inProps.spacing ?? (nested ? undefined : rowSpacingProp); + inProps.rowSpacing ?? inProps.spacing ?? (level ? undefined : rowSpacingProp); const columnSpacing = - inProps.columnSpacing ?? inProps.spacing ?? (nested ? undefined : columnSpacingProp); + inProps.columnSpacing ?? inProps.spacing ?? (level ? undefined : columnSpacingProp); const ownerState = { ...props, - nested, + level, columns, container, direction, @@ -162,8 +162,8 @@ export default function createGrid( /> ); - if (!nested) { - result = {result}; + if (container) { + result = {result}; } if (disableEqualOverflow !== undefined && disableEqualOverflow !== (overflow ?? false)) { diff --git a/packages/mui-system/src/Unstable_Grid/gridGenerator.test.js b/packages/mui-system/src/Unstable_Grid/gridGenerator.test.js index 21dfe67b5ed89c..0cca34f51f1477 100644 --- a/packages/mui-system/src/Unstable_Grid/gridGenerator.test.js +++ b/packages/mui-system/src/Unstable_Grid/gridGenerator.test.js @@ -239,33 +239,39 @@ describe('grid generator', () => { describe('generateGridStyles', () => { it('root container', () => { - const result = generateGridStyles({ ownerState: { container: true, nested: false } }); + const result = generateGridStyles({ ownerState: { container: true, level: 0 } }); expect(result).to.deep.equal({ minWidth: 0, boxSizing: 'border-box', display: 'flex', flexWrap: 'wrap', margin: 'calc(var(--Grid-rowSpacing) / -2) calc(var(--Grid-columnSpacing) / -2)', - '--Grid-nested-rowSpacing': 'var(--Grid-rowSpacing)', - '--Grid-nested-columnSpacing': 'var(--Grid-columnSpacing)', }); }); - it('nested container', () => { - const result = generateGridStyles({ ownerState: { container: true, nested: true } }); + it('nested container level 1', () => { + const result = generateGridStyles({ ownerState: { container: true, level: 1 } }); sinon.assert.match(result, { - margin: `calc(var(--Grid-rowSpacing) / -2) calc(var(--Grid-columnSpacing) / -2)`, - padding: `calc(var(--Grid-nested-rowSpacing) / 2) calc(var(--Grid-nested-columnSpacing) / 2)`, + margin: `calc(var(--Grid-rowSpacing1) / -2) calc(var(--Grid-columnSpacing1) / -2)`, + padding: `calc(var(--Grid-rowSpacing) / 2) calc(var(--Grid-columnSpacing) / 2)`, + }); + }); + + it('nested container level 2', () => { + const result = generateGridStyles({ ownerState: { container: true, level: 2 } }); + sinon.assert.match(result, { + margin: `calc(var(--Grid-rowSpacing2) / -2) calc(var(--Grid-columnSpacing2) / -2)`, + padding: `calc(var(--Grid-rowSpacing1) / 2) calc(var(--Grid-columnSpacing1) / 2)`, }); }); it('root container with disableEqualOverflow', () => { const result = generateGridStyles({ - ownerState: { container: true, nested: true, disableEqualOverflow: true }, + ownerState: { container: true, level: 1, disableEqualOverflow: true }, }); sinon.assert.match(result, { - margin: `calc(var(--Grid-rowSpacing) * -1) 0px 0px calc(var(--Grid-columnSpacing) * -1)`, - padding: `calc(var(--Grid-nested-rowSpacing)) 0px 0px calc(var(--Grid-nested-columnSpacing))`, + margin: `calc(var(--Grid-rowSpacing1) * -1) 0px 0px calc(var(--Grid-columnSpacing1) * -1)`, + padding: `var(--Grid-rowSpacing) 0px 0px var(--Grid-columnSpacing)`, }); }); @@ -273,19 +279,19 @@ describe('grid generator', () => { const result = generateGridStyles({ ownerState: { container: true, - nested: true, + level: 1, disableEqualOverflow: false, parentDisableEqualOverflow: true, }, }); sinon.assert.match(result, { - margin: `calc(var(--Grid-rowSpacing) / -2) calc(var(--Grid-columnSpacing) / -2)`, - padding: `calc(var(--Grid-nested-rowSpacing)) 0px 0px calc(var(--Grid-nested-columnSpacing))`, + margin: `calc(var(--Grid-rowSpacing1) / -2) calc(var(--Grid-columnSpacing1) / -2)`, + padding: `var(--Grid-rowSpacing) 0px 0px var(--Grid-columnSpacing)`, }); }); it('item', () => { - const result = generateGridStyles({ ownerState: { container: false, nested: false } }); + const result = generateGridStyles({ ownerState: { container: false, level: 1 } }); expect(result).to.deep.equal({ minWidth: 0, boxSizing: 'border-box', @@ -298,7 +304,16 @@ describe('grid generator', () => { ownerState: { container: false, disableEqualOverflow: true }, }); sinon.assert.match(result, { - padding: `calc(var(--Grid-rowSpacing)) 0px 0px calc(var(--Grid-columnSpacing))`, + padding: `var(--Grid-rowSpacing) 0px 0px var(--Grid-columnSpacing)`, + }); + }); + + it('item level 2', () => { + const result = generateGridStyles({ + ownerState: { container: false, disableEqualOverflow: true, level: 2 }, + }); + sinon.assert.match(result, { + padding: `var(--Grid-rowSpacing1) 0px 0px var(--Grid-columnSpacing1)`, }); }); }); @@ -454,6 +469,14 @@ describe('grid generator', () => { }, }); }); + + it('nested item level 1 should have default spacing set to parent', () => { + const result = generateGridRowSpacingStyles({ + theme: { breakpoints }, + ownerState: { container: true, level: 1 }, + }); + expect(result['--Grid-rowSpacing1']).to.equal('var(--Grid-rowSpacing)'); + }); }); describe('generateGridColumnSpacingStyles', () => { @@ -510,6 +533,14 @@ describe('grid generator', () => { }, }); }); + + it('nested item level 1 should have default spacing set to parent', () => { + const result = generateGridColumnSpacingStyles({ + theme: { breakpoints }, + ownerState: { container: true, level: 1 }, + }); + expect(result['--Grid-columnSpacing1']).to.equal('var(--Grid-columnSpacing)'); + }); }); describe('generateGridOffsetStyles', () => { diff --git a/packages/mui-system/src/Unstable_Grid/gridGenerator.ts b/packages/mui-system/src/Unstable_Grid/gridGenerator.ts index 148057c105a734..34cc5e846dc128 100644 --- a/packages/mui-system/src/Unstable_Grid/gridGenerator.ts +++ b/packages/mui-system/src/Unstable_Grid/gridGenerator.ts @@ -12,6 +12,25 @@ interface Iterator { (appendStyle: (responsiveStyles: Record, style: object) => void, value: T): void; } +function isNestedContainer(ownerState: Props['ownerState']) { + return ownerState.level > 0 && ownerState.container; +} + +function createGetSelfSpacing(ownerState: Props['ownerState']) { + return function getSelfSpacing(axis: 'row' | 'column') { + return `var(--Grid-${axis}Spacing${ownerState.level || ''})`; + }; +} + +function createGetParentSpacing(ownerState: Props['ownerState']) { + return function getParentSpacing(axis: 'row' | 'column') { + if (ownerState.level === 0) { + return `var(--Grid-${axis}Spacing)`; + } + return `var(--Grid-${axis}Spacing${ownerState.level - 1 || ''})`; + }; +} + export const filterBreakpointKeys = (breakpointsKeys: Breakpoint[], responsiveKeys: string[]) => breakpointsKeys.filter((key: string) => responsiveKeys.includes(key)); @@ -66,6 +85,7 @@ export const traverseBreakpoints = ( }; export const generateGridSizeStyles = ({ theme, ownerState }: Props) => { + const getSelfSpacing = createGetSelfSpacing(ownerState); const styles = {}; traverseBreakpoints<'auto' | number | true>( theme.breakpoints, @@ -93,7 +113,7 @@ export const generateGridSizeStyles = ({ theme, ownerState }: Props) => { flexGrow: 0, flexBasis: 'auto', width: `calc(100% * ${value} / var(--Grid-columns)${ - ownerState.nested && ownerState.container ? ` + var(--Grid-columnSpacing)` : '' + isNestedContainer(ownerState) ? ` + ${getSelfSpacing('column')}` : '' })`, }; } @@ -141,13 +161,21 @@ export const generateGridRowSpacingStyles = ({ theme, ownerState }: Props) => { if (!ownerState.container) { return {}; } - const styles = {}; + const getParentSpacing = createGetParentSpacing(ownerState); + const styles = isNestedContainer(ownerState) + ? { + // Set the default spacing as its parent spacing. + // It will be overridden if spacing props are provided + [`--Grid-rowSpacing${ownerState.level || ''}`]: getParentSpacing('row'), + } + : {}; traverseBreakpoints( theme.breakpoints, ownerState.rowSpacing, (appendStyle, value) => { appendStyle(styles, { - '--Grid-rowSpacing': typeof value === 'string' ? value : theme.spacing?.(value), + [`--Grid-rowSpacing${ownerState.level || ''}`]: + typeof value === 'string' ? value : theme.spacing?.(value), }); }, ); @@ -158,13 +186,21 @@ export const generateGridColumnSpacingStyles = ({ theme, ownerState }: Props) => if (!ownerState.container) { return {}; } - const styles = {}; + const getParentSpacing = createGetParentSpacing(ownerState); + const styles = isNestedContainer(ownerState) + ? { + // Set the default spacing as its parent spacing. + // It will be overridden if spacing props are provided + [`--Grid-columnSpacing${ownerState.level || ''}`]: getParentSpacing('column'), + } + : {}; traverseBreakpoints( theme.breakpoints, ownerState.columnSpacing, (appendStyle, value) => { appendStyle(styles, { - '--Grid-columnSpacing': typeof value === 'string' ? value : theme.spacing?.(value), + [`--Grid-columnSpacing${ownerState.level || ''}`]: + typeof value === 'string' ? value : theme.spacing?.(value), }); }, ); @@ -187,39 +223,31 @@ export const generateGridDirectionStyles = ({ theme, ownerState }: Props) => { }; export const generateGridStyles = ({ ownerState }: Props): {} => { + const getSelfSpacing = createGetSelfSpacing(ownerState); + const getParentSpacing = createGetParentSpacing(ownerState); return { minWidth: 0, boxSizing: 'border-box', - ...(ownerState.container - ? { - display: 'flex', - flexWrap: 'wrap', - ...(ownerState.wrap && - ownerState.wrap !== 'wrap' && { - flexWrap: ownerState.wrap, - }), - margin: `calc(var(--Grid-rowSpacing) / -2) calc(var(--Grid-columnSpacing) / -2)`, - ...(ownerState.disableEqualOverflow && { - margin: `calc(var(--Grid-rowSpacing) * -1) 0px 0px calc(var(--Grid-columnSpacing) * -1)`, - }), - ...(ownerState.nested - ? { - padding: `calc(var(--Grid-nested-rowSpacing) / 2) calc(var(--Grid-nested-columnSpacing) / 2)`, - ...((ownerState.disableEqualOverflow || ownerState.parentDisableEqualOverflow) && { - padding: `calc(var(--Grid-nested-rowSpacing)) 0px 0px calc(var(--Grid-nested-columnSpacing))`, - }), - } - : { - '--Grid-nested-rowSpacing': 'var(--Grid-rowSpacing)', - '--Grid-nested-columnSpacing': 'var(--Grid-columnSpacing)', - }), - } - : { - padding: `calc(var(--Grid-rowSpacing) / 2) calc(var(--Grid-columnSpacing) / 2)`, - ...(ownerState.disableEqualOverflow && { - padding: `calc(var(--Grid-rowSpacing)) 0px 0px calc(var(--Grid-columnSpacing))`, - }), + ...(ownerState.container && { + display: 'flex', + flexWrap: 'wrap', + ...(ownerState.wrap && + ownerState.wrap !== 'wrap' && { + flexWrap: ownerState.wrap, }), + margin: `calc(${getSelfSpacing('row')} / -2) calc(${getSelfSpacing('column')} / -2)`, + ...(ownerState.disableEqualOverflow && { + margin: `calc(${getSelfSpacing('row')} * -1) 0px 0px calc(${getSelfSpacing( + 'column', + )} * -1)`, + }), + }), + ...((!ownerState.container || isNestedContainer(ownerState)) && { + padding: `calc(${getParentSpacing('row')} / 2) calc(${getParentSpacing('column')} / 2)`, + ...((ownerState.disableEqualOverflow || ownerState.parentDisableEqualOverflow) && { + padding: `${getParentSpacing('row')} 0px 0px ${getParentSpacing('column')}`, + }), + }), }; };