mui / material-ui

Material UI: Ready-to-use foundational React components, free forever. It includes Material UI, which implements Google's Material Design.
https://mui.com/material-ui/
MIT License
91.86k stars 31.57k forks source link

[material-ui] CSS rule "& > *" not working for some components after the migration from v4 to v5 #42066

Open vinifmor opened 2 weeks ago

vinifmor commented 2 weeks ago

Steps to reproduce

I have to migrate an old Mui code from v4 to v5. There are some old CSS rules for direct children (& > *) that are not being applied. I'll provide some summarized codes below fore before/after the migration (v4 -> v5):

Before:

...
import { makeStyles } from '@material-ui/core/styles'
import DialogContent from '@material-ui/core/DialogContent'
import DialogTitle from '@material-ui/core/DialogTitle'
import Checkbox from '@material-ui/core/Checkbox'
import Grid from '@material-ui/core/Grid'
...

const useStyles = makeStyles((theme) => ({
    grid: {
        display: 'flex',
        justifyContent: "center",
        padding: "1em"
    },
    item: {
        marginTop: "0.2em",
    },
    buttons: {
        display: 'flex',
        justifyContent: "center",
        '& > *': {
            margin: theme.spacing(1)
        }
    }
}))

...
const FeedbacksForm = (props) => {
    ...
    const classes = useStyles()
    ...

    return (
        <Dialog
            open={openForm}
            maxWidth='md'
            fullWidth={true}>
            <DialogTitle className={classes.title}>Edit Feedback</DialogTitle>
            <DialogContent>
                <Grid container spacing={3} direction="row" justify="center" className={classes.grid}>
                    <Grid item xs={12} className={classes.buttons}>
                        <Button
                            variant="contained"
                            disabled={!buttonsEnabled}
                            onClick={handleClickCancel}
                            startIcon={<CancelIcon />}
                            >
                            Cancel
                        </Button>
                        <Button
                            variant="contained"
                            disabled={!buttonsEnabled}
                            onClick={handleClickSave}
                            startIcon={<SaveIcon />}
                            >
                            Save
                        </Button>
                    </Grid>
                </Grid>
            </DialogContent>
        </Dialog>
...

After (the the buttons' margin are not working):

...
import { makeStyles } from 'tss-react/mui'
...
const useStyles = makeStyles()(theme => {
    return {
        grid: {
            display: 'flex',
            justifyContent: "center",
            padding: "1em"
        },
        item: {
            marginTop: "0.2em"
        },
        buttons: {
            display: 'flex',
            justifyContent: "center",
            '& > *': {
                margin: theme.spacing(1)
            }
        }
    }
})

...
...
const FeedbacksForm = (props) => {
    ...
    const { classes } = useStyles()
    ...

The current workaround I've found is to provide the margin directly to the buttons through sx={{ margin: theme => theme.spacing(1) }}:

<Grid container spacing={3} direction="row" justify="center" className={classes.grid}>
    <Grid item xs={12} className={classes.buttons}>
         <Button
             sx={{ margin: theme => theme.spacing(1) }}
             variant="contained"
             ....

Is this migrated code right ?

Current behavior

Margins not applied in v5 when the parent rule CSS & > * is defined

Expected behavior

Margins should be applied

Context

Migration from v4 to v5

Your environment

 System:
    OS: Linux 6.6 Alpine Linux
  Binaries:
    Node: 20.11.1 - /usr/bin/node
    npm: 10.2.5 - /usr/bin/npm
    pnpm: Not Found
  Browsers:
    Chrome: Not Found
  npmPackages:
    @emotion/react: ~11.11.4 => 11.11.4 
    @emotion/styled: ~11.11.5 => 11.11.5 
    @mui/base:  5.0.0-beta.40 
    @mui/core-downloads-tracker:  5.15.15 
    @mui/icons-material: ~5.15.15 => 5.15.15 
    @mui/lab: ~5.0.0-alpha.170 => 5.0.0-alpha.170 
    @mui/material: ~5.15.15 => 5.15.15 
    @mui/private-theming:  5.15.14 
    @mui/styled-engine:  5.15.14 
    @mui/styles: ~5.15.15 => 5.15.15 
    @mui/system:  5.15.15 
    @mui/types:  7.2.14 
    @mui/utils: ~5.15.14 => 5.15.14 
    @types/react:  18.3.0 
    react: ~17.0.2 => 17.0.2 
    react-dom: ~17.0.2 => 17.0.2 
    typescript:  5.4.5

Search keywords: migration

danilo-leal commented 1 week ago

Hey, thanks for opening the issue! Could you provide a minimal reproduction? It helps us troubleshoot. A live example would be perfect. This StackBlitz sandbox template may be a good starting point.

vinifmor commented 1 week ago

I've found out the cause... this example I've shared is a simplified version of the real production code. What changes is that those buttons are actually custom buttons defined with withStyles. e.g:

import { withStyles } from 'tss-react/mui'

export const PrimaryButton = withStyles(Button, theme => ({
    root: {
        color: white,
        backgroundColor: purple,
        '&:hover': {
            backgroundColor: darken(purple, 0.10)
        }
    }
}))

The margin defined by the <Grid> container for its direct children (those custom buttons) works in v4, but doesn't work in v5. If I replace a custom button by a default <Button>, the margin works in v5. I am missing any new property or configuration that should also be added when calling withStyles ?