Skip to content

Commit

Permalink
[system] Improve breakpoints resolver function (#29300)
Browse files Browse the repository at this point in the history
  • Loading branch information
hbjORbj committed Oct 28, 2021
1 parent a1a2aef commit 75c7050
Show file tree
Hide file tree
Showing 8 changed files with 585 additions and 102 deletions.
44 changes: 4 additions & 40 deletions packages/mui-lab/src/Masonry/Masonry.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,6 @@ const useUtilityClasses = (ownerState) => {
return composeClasses(slots, getMasonryUtilityClass, classes);
};

// compute base for responsive values; e.g.,
// [1,2,3] => {xs: true, sm: true, md: true}
// {xs: 1, sm: 2, md: 3} => {xs: true, sm: true, md: true}
const computeBreakpointsBase = (breakpoints, prop) => {
const base = {};
if (Array.isArray(prop)) {
Object.keys(breakpoints.values).forEach((breakpoint, i, arr) => {
if (i < arr.length) {
base[breakpoint] = true;
}
});
} else {
Object.keys(breakpoints.values).forEach((breakpoint) => {
if (prop[breakpoint] != null) {
base[breakpoint] = true;
}
});
}
return base;
};

// if prop is an array, convert to object; e.g.,
// (base: {xs: true, sm: true, md: true}, prop: [1,2,3]) => {xs: 1, sm: 2, md: 3}
const validatePropValues = (base, prop) => {
const values = {};
if (Array.isArray(prop)) {
Object.keys(base).forEach((breakpoint, i) => {
values[breakpoint] = prop[i];
});
return values;
}
return prop;
};

export const getStyle = ({ ownerState, theme }) => {
let styles = {
width: '100%',
Expand Down Expand Up @@ -94,10 +60,9 @@ export const getStyle = ({ ownerState, theme }) => {
};
}

const spacingBreakpointsBase = computeBreakpointsBase(theme.breakpoints, ownerState.spacing);
const spacingValues = resolveBreakpointValues({
values: validatePropValues(spacingBreakpointsBase, ownerState.spacing),
base: spacingBreakpointsBase,
values: ownerState.spacing,
breakpoints: theme.breakpoints.values,
});

const transformer = createUnarySpacing(theme);
Expand All @@ -120,10 +85,9 @@ export const getStyle = ({ ownerState, theme }) => {
handleBreakpoints({ theme }, spacingValues, spacingStyleFromPropValue),
);

const columnBreakpointsBase = computeBreakpointsBase(theme.breakpoints, ownerState.columns);
const columnValues = resolveBreakpointValues({
values: validatePropValues(columnBreakpointsBase, ownerState.columns),
base: columnBreakpointsBase,
values: ownerState.columns,
breakpoints: theme.breakpoints.values,
});

const columnStyleFromPropValue = (propValue) => {
Expand Down
95 changes: 95 additions & 0 deletions packages/mui-lab/src/Masonry/Masonry.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,99 @@ describe('<Masonry />', () => {
});
});
});

describe('prop: columns', () => {
it('should generate correct responsive styles regardless of breakpoints order', () => {
const columns = { sm: 5, md: 7, xs: 3 };
const spacing = 1;
expect(
getStyle({
ownerState: {
columns,
spacing,
maxColumnHeight,
},
theme,
}),
).to.deep.equal({
width: '100%',
display: 'flex',
flexFlow: 'column wrap',
alignContent: 'space-between',
boxSizing: 'border-box',
'& > *': {
boxSizing: 'border-box',
margin: parseToNumber(theme.spacing(spacing)) / 2,
},
margin: -(parseToNumber(theme.spacing(spacing)) / 2),
height: maxColumnHeight + parseToNumber(theme.spacing(spacing)),
[`@media (min-width:${theme.breakpoints.values.xs}px)`]: {
'& > *': {
width: `calc(${(100 / columns.xs).toFixed(2)}% - ${theme.spacing(spacing)})`,
},
},
[`@media (min-width:${theme.breakpoints.values.sm}px)`]: {
'& > *': {
width: `calc(${(100 / columns.sm).toFixed(2)}% - ${theme.spacing(spacing)})`,
},
},
[`@media (min-width:${theme.breakpoints.values.md}px)`]: {
'& > *': {
width: `calc(${(100 / columns.md).toFixed(2)}% - ${theme.spacing(spacing)})`,
},
},
});
});
});

describe('prop: spacing', () => {
it('should generate correct responsive styles regardless of breakpoints order', () => {
const columns = 4;
const spacing = { sm: 2, md: 3, xs: 1 };
expect(
getStyle({
ownerState: {
columns,
spacing,
maxColumnHeight,
},
theme,
}),
).to.deep.equal({
width: '100%',
display: 'flex',
flexFlow: 'column wrap',
alignContent: 'space-between',
boxSizing: 'border-box',
'& > *': {
boxSizing: 'border-box',
width: `calc(${(100 / columns).toFixed(2)}% - 0px)`,
},
[`@media (min-width:${theme.breakpoints.values.xs}px)`]: {
'& > *': {
margin: parseToNumber(theme.spacing(spacing.xs)) / 2,
width: `calc(${(100 / columns).toFixed(2)}% - ${theme.spacing(spacing.xs)})`,
},
margin: -(parseToNumber(theme.spacing(spacing.xs)) / 2),
height: maxColumnHeight + parseToNumber(theme.spacing(spacing.xs)),
},
[`@media (min-width:${theme.breakpoints.values.sm}px)`]: {
'& > *': {
margin: parseToNumber(theme.spacing(spacing.sm)) / 2,
width: `calc(${(100 / columns).toFixed(2)}% - ${theme.spacing(spacing.sm)})`,
},
margin: -(parseToNumber(theme.spacing(spacing.sm)) / 2),
height: maxColumnHeight + parseToNumber(theme.spacing(spacing.sm)),
},
[`@media (min-width:${theme.breakpoints.values.md}px)`]: {
'& > *': {
margin: parseToNumber(theme.spacing(spacing.md)) / 2,
width: `calc(${(100 / columns).toFixed(2)}% - ${theme.spacing(spacing.md)})`,
},
margin: -(parseToNumber(theme.spacing(spacing.md)) / 2),
height: maxColumnHeight + parseToNumber(theme.spacing(spacing.md)),
},
});
});
});
});
32 changes: 25 additions & 7 deletions packages/mui-material/src/Grid/Grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,15 @@ function generateGrid(globalStyles, theme, breakpoint, ownerState) {
} else {
const columnsBreakpointValues = resolveBreakpointValues({
values: ownerState.columns,
base: theme.breakpoints.values,
breakpoints: theme.breakpoints.values,
});

const columnValue =
typeof columnsBreakpointValues === 'object'
? columnsBreakpointValues[breakpoint]
: columnsBreakpointValues;
// Keep 7 significant numbers.
const width = `${Math.round((size / columnsBreakpointValues[breakpoint]) * 10e7) / 10e5}%`;
const width = `${Math.round((size / columnValue) * 10e7) / 10e5}%`;
let more = {};

if (ownerState.container && ownerState.item && ownerState.columnSpacing !== 0) {
Expand Down Expand Up @@ -92,8 +96,13 @@ function generateGrid(globalStyles, theme, breakpoint, ownerState) {
}
}

function generateDirection({ theme, ownerState }) {
return handleBreakpoints({ theme }, ownerState.direction, (propValue) => {
export function generateDirection({ theme, ownerState }) {
const directionValues = resolveBreakpointValues({
values: ownerState.direction,
breakpoints: theme.breakpoints.values,
});

return handleBreakpoints({ theme }, directionValues, (propValue) => {
const output = {
flexDirection: propValue,
};
Expand All @@ -113,7 +122,12 @@ export function generateRowGap({ theme, ownerState }) {
let styles = {};

if (container && rowSpacing !== 0) {
styles = handleBreakpoints({ theme }, rowSpacing, (propValue) => {
const rowSpacingValues = resolveBreakpointValues({
values: rowSpacing,
breakpoints: theme.breakpoints.values,
});

styles = handleBreakpoints({ theme }, rowSpacingValues, (propValue) => {
const themeSpacing = theme.spacing(propValue);

if (themeSpacing !== '0px') {
Expand All @@ -137,9 +151,13 @@ export function generateColumnGap({ theme, ownerState }) {
let styles = {};

if (container && columnSpacing !== 0) {
styles = handleBreakpoints({ theme }, columnSpacing, (propValue) => {
const themeSpacing = theme.spacing(propValue);
const columnSpacingValues = resolveBreakpointValues({
values: columnSpacing,
breakpoints: theme.breakpoints.values,
});

styles = handleBreakpoints({ theme }, columnSpacingValues, (propValue) => {
const themeSpacing = theme.spacing(propValue);
if (themeSpacing !== '0px') {
return {
width: `calc(100% + ${getOffset(themeSpacing)})`,
Expand Down

0 comments on commit 75c7050

Please sign in to comment.