Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[System] Fix nested grid v2 #35994

Merged
merged 7 commits into from
Feb 3, 2023
Merged

Conversation

siriwatknp
Copy link
Member

@siriwatknp siriwatknp commented Jan 30, 2023

close #35959

After: https://codesandbox.io/s/sleepy-frost-me5qwc?file=/src/App.tsx

Root cause

the nested grid >= level 2 does not behave properly because it uses variables from the top-most grid instead of the closest parent.

Changes

Change the type of the NestedContext to the number and increase it for each level. In each level, create specific variables for the next level.

@siriwatknp siriwatknp added component: Grid The React component. package: system Specific to @mui/system package: material-ui Specific to @mui/material package: joy-ui Specific to @mui/joy bug 🐛 Something doesn't work labels Jan 30, 2023
@mui-bot
Copy link

mui-bot commented Jan 30, 2023

Messages
📖 Netlify deploy preview: https://deploy-preview-35994--material-ui.netlify.app/

@mui/joy: parsed: 0.00% 😍, gzip: +0.10%

Details of bundle changes

Generated by 🚫 dangerJS against 5920aaf

margin: `calc(var(--Grid-rowSpacing) / -2) calc(var(--Grid-columnSpacing) / -2)`,
padding: `calc(var(--Grid-nested2-rowSpacing) / 2) calc(var(--Grid-nested2-columnSpacing) / 2)`,
'--Grid-nested3-rowSpacing': 'var(--Grid-rowSpacing)',
'--Grid-nested3-columnSpacing': 'var(--Grid-columnSpacing)',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same suggestion as my comment above

Copy link
Member

@hbjORbj hbjORbj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few small question / suggestions, but looks ready for merge!

}),
}),
// variables for the next level grid container
[`--Grid-nested${(ownerState.nested ?? 0) + 1}-rowSpacing`]: 'var(--Grid-rowSpacing)',
Copy link
Member

@mnajdova mnajdova Feb 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be simpler to add the nested variables even if the grid is nested? That way we shouldn't need any leveling information.

I mean oversimplification, but something like this should work no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not possible because the variables have 2 purposes:

  • consumed by the element itself (margin)
  • consumed by the next level grid (padding)

If the variables are the same name, they will behave incorrectly:

// Ex. style of the nested grid container level 1
padding: var(--Grid-rowSpacing); // --Grid-rowSpacing is from the root grid
--Grid-nested-rowSpacing: 16px;
margin: calc(var(--Grid-nested-rowSpacing) * -1);


// style of the nested grid container level 2
padding: var(--Grid-nested-rowSpacing); // --Grid-nested-rowSpacing is from the nested grid container level 1
--Grid-nested-rowSpacing: 24px; // ❌ this will cause the padding to behave incorrectly
margin: calc(var(--Grid-nested-rowSpacing) * -1);

This is why the level of information is important to create scope variables for each level.

I am able to simplify the logic by removing nested variables and using only the --Grid-rowSpacing and --Grid-columnSpacing, however, the leveling information is still necessary.

If you are not use nested grid container, you will get a simple --Grid-rowSpacing and --Grid-columnSpacing as usual.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mnajdova Here is the sandbox to demonstrate the inheritance.

What I like about the latest change is that the inheritance works with just row and spacing variables. The spacing inheritance can be stopped by providing spacing prop to that specific container level which is a correct behavior.

Copy link
Member

@mnajdova mnajdova Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order for what I had in mind to work, we would need to bump the specificity, which is not great. This is what I had in mind:

index 148057c105..98201a717b 100644
--- a/packages/mui-system/src/Unstable_Grid/gridGenerator.ts
+++ b/packages/mui-system/src/Unstable_Grid/gridGenerator.ts
@@ -208,6 +208,10 @@ export const generateGridStyles = ({ ownerState }: Props): {} => {
                 ...((ownerState.disableEqualOverflow || ownerState.parentDisableEqualOverflow) && {
                   padding: `calc(var(--Grid-nested-rowSpacing)) 0px 0px calc(var(--Grid-nested-columnSpacing))`,
                 }),
+                // for nested grids, set the nested variables to the current rowSpacing and columnSpacing if they are defined
+                '& .MuiGrid2-root': {
+                  '--Grid-nested-rowSpacing': 'var(--Grid-rowSpacing, var(--Grid-nested-rowSpacing))',
+                  '--Grid-nested-columnSpacing': 'var(--Grid-columnSpacing, var(--Grid-nested-columnSpacing))',
+                }
               }
             : {
                 '--Grid-nested-rowSpacing': 'var(--Grid-rowSpacing)',

I will let to you decide what you think it's better. With this one we gain simpler CSS variables, but we are increasing the specificity. I don't expect people to actually change the CSS variable when they have a first class API - prop, so this could be viable solution too.

Copy link
Member Author

@siriwatknp siriwatknp Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mnajdova

  1. CSS variables does not work if it refers to themselves, so they should be:

    + '& .MuiGrid2-root': {
    +     '--Grid-nested-rowSpacing': 'var(--Grid-rowSpacing)',
    +     '--Grid-nested-columnSpacing': 'var(--Grid-columnSpacing)',
    +  }
  2. What you propose would not work if you specify spacing prop to the nested grid.

let's say that this is the style of a deeply nested grid (it could be any level), the padding of the nested grid should use the parent spacing variable to behave correctly:

// assume that --Grid-nested-rowSpacing is 8px;
padding: `calc(var(--Grid-nested-rowSpacing) / 2) calc(var(--Grid-nested-columnSpacing) / 2)`

Now if you add the CSS specificity together with spacing prop:

the styles become:

--Grid-nested-rowSpacing: 16px;
--Grid-nested-columnSpacing: 16px;
'& > .MuiGrid2-container': {
  '--Grid-nested-rowSpacing': 'var(--Grid-rowSpacing)', // 16px from itself
  '--Grid-nested-columnSpacing': 'var(--Grid-columnSpacing)', // 16px from itself
}

// --Grid-nested-rowSpacing resolves to 16px (itself) instead of 8px (parent) ❌ This is wrong.
padding: `calc(var(--Grid-nested-rowSpacing) / 2) calc(var(--Grid-nested-columnSpacing) / 2)`

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My latest change fixes the problem and is also better in one aspect. It does not produce nested variables if you don't have nested grids.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS variables does not work if it refers to themselves, so they should be:

Ah I didn't know this, I guess for this to work we need some kind of internal variable as described in the answer here: https://stackoverflow.com/questions/59015022/css-variables-defaults-set-if-not-already-set

I understand now what this wouldn't work, thanks for the explanation.

@@ -20,51 +21,52 @@ export default function SpacingGrid() {
`;

return (
<Grid sx={{ flexGrow: 1 }} container spacing={2}>
Copy link
Member Author

@siriwatknp siriwatknp Feb 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This demo does not need to use a nested grid. Simple box is enough.

@@ -161,7 +161,18 @@ export interface GridBaseProps extends Breakpoints {
}

export interface GridOwnerState extends GridBaseProps {
nested: boolean;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to level sounds better because it is not a boolean anymore, it is a number.

Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I learnt a lot by reviewing this PR :D

@siriwatknp
Copy link
Member Author

I learnt a lot by reviewing this PR :D

Me too 😄!

@siriwatknp siriwatknp merged commit ca8b908 into mui:master Feb 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: Grid The React component. package: joy-ui Specific to @mui/joy package: material-ui Specific to @mui/material package: system Specific to @mui/system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unstable_Grid2 cannot override spacing in Nested Grid
4 participants