Repository: mui/material-ui (TypeScript)
Date: 2022-05-26 05:21:45+00:00
Task type: Bug Fix

Issue:
[theme] Getting `styleFromPropValue` for spacing will return undefined when using custom breakpoint named small
### Duplicates

- [X] I have searched the existing issues

### Latest version

- [X] I have tested the latest version

### Current behavior 😯

Setting theme breakpoints like  this

```js
  breakpoints: {
    values: {
      xs: false,
      sm: false,
      md: false,
      lg: false,
      xl: false,
      smallest: 0,
      small: 375,
      mobile: 600,
      tablet: 992,
      desktop: 1200,
    }
  }
```

will return `marginundefined: 32px` when using

```js
<Stack spacing={4}>
...
</Stack>
```

It seems that just the name `small` will cause that issue.

If renaming `small` into `whatever` will return correctly `marginTop: 32px`

### Expected behavior 🤔

Should return a valid margin for spacing based on direction.

### Steps to reproduce 🕹

CodeSandbox: https://codesandbox.io/s/peaceful-https-6iewi9?file=/src/Demo.tsx

Steps:

1. use custom Breakpoint `small`
2. use Stack spacing


### Context 🔦

Look at: 

https://github.com/mui/material-ui/blob/ba2fce43a735f6085e68c2d76ab746a098488862/packages/mui-material/src/Stack/Stack.js#L79-L88

https://github.com/mui/material-ui/blob/19e068343cce39c5b331fe8a9a3d647bd308aa44/packages/mui-system/src/breakpoints.js#L142



### Your environment 🌎

<details>
  <summary>`npx @mui/envinfo`</summary>

```
  Don't forget to mention which browser you used.
  Output from `npx @mui/envinfo` goes here.
```
</details>



Issue discussion:
Please provide a CodeSandbox reproducing the issue. The [issue template](https://material-ui.com/r/issue-template-latest) is a good starting point.
Since the issue is missing key information, and has been inactive for 7 days, it has been automatically closed.
If you wish to see the issue reopened, please provide the missing information.
Hi @ZeeshanTamboli 

Today I have reproduced that in a very small nextjs project for you.

All you need is:

```console
mkdir mui-small-error-test
cd mui-small-error-test
touch package.json
mkdir pages
touch index.js
```

**package.json**

```json
{
  "scripts": {
    "dev": "next dev"
  },
  "dependencies": {
    "@emotion/react": "^11.9.0",
    "@emotion/styled": "^11.8.1",
    "@mui/material": "^5.8.0",
    "next": "^12.1.6",
    "react": "^18.1.0",
    "react-dom": "^18.1.0"
  }
}
```

**pages/index.js**

```js
import { createTheme } from '@mui/material/styles';
import { ThemeProvider } from '@mui/material';
import { Stack } from '@mui/material';

const themeSettings = {
  breakpoints: {
    values: {
      mini: 375
    }
  }
};

const theme = createTheme(themeSettings);

function HomePage() {
  return (
    <ThemeProvider theme={theme}>
      <Stack spacing={4}>
        <div>Welcome to Next.js!</div>
        <div>Welcome to Next.js!</div>
      </Stack>
    </ThemeProvider>
  )
}

export default HomePage
```

```console
npm install
npm run dev
```

**open browser**

http://localhost:3000

You will get the following content in your browser, which is fine:

<img width="334" alt="grafik" src="https://user-images.githubusercontent.com/410087/169644831-172d5428-3b3e-4162-b654-42b265a00c9a.png">

## Produce the error:

Change line 8 from `mini` to `small`

```js
  small: 375
```

Reload the page on localhost

Now you see no spacing anymore between the divs

<img width="317" alt="grafik" src="https://user-images.githubusercontent.com/410087/169644890-72a88e80-7c6e-4230-9bb5-f938bf5ed8fa.png">

And if you check the HTML and search for `undefined` you get:

<img width="821" alt="grafik" src="https://user-images.githubusercontent.com/410087/169644963-3851fe68-b064-4be1-b7ec-4603081978cc.png">

This does not depend on browser, it is there in any case.

---

If you like me to add more information please let me know.

Cheers
Tom

@ZeeshanTamboli @danilo-leal - I can't reopen this issue - guess you will handle the follow-up.
Hi @ZeeshanTamboli 

I just had a look at the [issue template](https://material-ui.com/r/issue-template-latest)

You only need to replace the code for `Demo.tsx` with my above `index.js` code and things will show the issue. 
@TomFreudenberg Yes, I was able to reproduce it now. Thanks for the code snippet. [Here is the CodeSandbox](https://codesandbox.io/s/peaceful-https-6iewi9?file=/src/Demo.tsx) reproducing the issue. It looks like a bug. 
It's a regression from `v5.1.0` perhaps due to changes in #29300. It works in `v5.0.6`, see: https://codesandbox.io/s/bold-torvalds-vslvdl?file=/src/Demo.tsx. I will take a look.

Solution patch:
diff --git a/packages/mui-material/src/Stack/Stack.js b/packages/mui-material/src/Stack/Stack.js
--- a/packages/mui-material/src/Stack/Stack.js
+++ b/packages/mui-material/src/Stack/Stack.js
@@ -60,7 +60,10 @@ export const style = ({ ownerState, theme }) => {
     const transformer = createUnarySpacing(theme);
 
     const base = Object.keys(theme.breakpoints.values).reduce((acc, breakpoint) => {
-      if (ownerState.spacing[breakpoint] != null || ownerState.direction[breakpoint] != null) {
+      if (
+        (typeof ownerState.spacing === 'object' && ownerState.spacing[breakpoint] != null) ||
+        (typeof ownerState.direction === 'object' && ownerState.direction[breakpoint] != null)
+      ) {
         acc[breakpoint] = true;
       }
       return acc;
diff --git a/packages/mui-system/src/breakpoints.js b/packages/mui-system/src/breakpoints.js
--- a/packages/mui-system/src/breakpoints.js
+++ b/packages/mui-system/src/breakpoints.js
@@ -158,12 +158,14 @@ export function resolveBreakpointValues({
       acc[breakpoint] =
         breakpointValues[i] != null ? breakpointValues[i] : breakpointValues[previous];
       previous = i;
-    } else {
+    } else if (typeof breakpointValues === 'object') {
       acc[breakpoint] =
         breakpointValues[breakpoint] != null
           ? breakpointValues[breakpoint]
-          : breakpointValues[previous] || breakpointValues;
+          : breakpointValues[previous];
       previous = breakpoint;
+    } else {
+      acc[breakpoint] = breakpointValues;
     }
     return acc;
   }, {});


Test patch:
diff --git a/packages/mui-material/src/Stack/Stack.test.js b/packages/mui-material/src/Stack/Stack.test.js
--- a/packages/mui-material/src/Stack/Stack.test.js
+++ b/packages/mui-material/src/Stack/Stack.test.js
@@ -256,5 +256,69 @@ describe('<Stack />', () => {
         flexDirection: 'column',
       });
     });
+
+    it('should generate correct styles if custom breakpoints are provided in theme', () => {
+      const customTheme = createTheme({
+        breakpoints: {
+          values: {
+            smallest: 0,
+            small: 375,
+            mobile: 600,
+            tablet: 992,
+            desktop: 1200,
+          },
+        },
+      });
+
+      expect(
+        style({
+          ownerState: {
+            direction: 'column',
+            spacing: 4,
+          },
+          theme: customTheme,
+        }),
+      ).to.deep.equal({
+        '& > :not(style) + :not(style)': {
+          margin: 0,
+          marginTop: '32px',
+        },
+        display: 'flex',
+        flexDirection: 'column',
+      });
+    });
+
+    it('should generate correct responsive styles if custom responsive spacing values are provided', () => {
+      const customTheme = createTheme({
+        breakpoints: {
+          values: {
+            smallest: 0,
+            small: 375,
+            mobile: 600,
+            tablet: 992,
+            desktop: 1200,
+          },
+        },
+      });
+
+      expect(
+        style({
+          ownerState: {
+            direction: 'column',
+            spacing: { small: 4 },
+          },
+          theme: customTheme,
+        }),
+      ).to.deep.equal({
+        [`@media (min-width:${customTheme.breakpoints.values.small}px)`]: {
+          '& > :not(style) + :not(style)': {
+            margin: 0,
+            marginTop: '32px',
+          },
+        },
+        display: 'flex',
+        flexDirection: 'column',
+      });
+    });
   });
 });
diff --git a/packages/mui-system/src/breakpoints.test.js b/packages/mui-system/src/breakpoints.test.js
--- a/packages/mui-system/src/breakpoints.test.js
+++ b/packages/mui-system/src/breakpoints.test.js
@@ -192,6 +192,32 @@ describe('breakpoints', () => {
         expect(values).to.equal(3);
       });
 
+      it('return prop as it is for prop of fixed string value', () => {
+        const directionValue = 'columns';
+        const values = resolveBreakpointValues({
+          values: directionValue,
+        });
+        expect(values).to.equal('columns');
+      });
+
+      it('given custom base, resolve breakpoint values for prop of string type', () => {
+        const directionValue = 'columns';
+        const values = resolveBreakpointValues({
+          values: directionValue,
+          base: { small: true },
+        });
+        expect(values).to.deep.equal({ small: directionValue });
+      });
+
+      it('given custom base, resolve breakpoint values for prop of number type', () => {
+        const spacingValue = 3;
+        const values = resolveBreakpointValues({
+          values: spacingValue,
+          base: { small: true },
+        });
+        expect(values).to.deep.equal({ small: spacingValue });
+      });
+
       it('given custom base, resolve breakpoint values for prop of array type', () => {
         const columns = [1, 2, 3];
         const customBase = { extraSmall: true, small: true, medium: true, large: true };