Repository: mui/material-ui (TypeScript)
Date: 2019-08-14 22:07:38+00:00
Task type: Feature

Issue:
[Grid] Replace px to rem in spacing prop
Now
```jsx
<Grid spacing={8/padding: 4px|16/padding: 8px|32/padding: 16px|40/padding: 32px}>
```
Need
```jsx
<Grid spacing={8/padding:0.25rem|16/padding:0.5rem|32/padding:0.75rem|40/padding:1rem}>
```

or add another prop spacingRem


Issue discussion:
@udanpe The Grid component aims to be as simple as possible. You don't have to use the spacing property, you can keep it to 0 and use rem on your side.
I changed the spacing function to output a `rem` string as per the 'bootstrap strategy' example(https://material-ui.com/customization/spacing/). However, this breaks the `spacing` value on `Grid` completely as it is trying to divide a string. Maybe it's wise to warn any users that changing the theme spacing function might "break" things?
@Und3Rdo9 Oh, that's a bug! We could imagine the following change:
```diff
diff --git a/packages/material-ui/src/Grid/Grid.js b/packages/material-ui/src/Grid/Grid.js
index 9fa4d375f..c59765def 100644
--- a/packages/material-ui/src/Grid/Grid.js
+++ b/packages/material-ui/src/Grid/Grid.js
@@ -74,11 +74,16 @@ function generateGutter(theme, breakpoint) {
       return;
     }

+    const half =
+      typeof themeSpacing === 'number'
+        ? themeSpacing / 2
+        : themeSpacing.replace(/(\d+\.\d+)/, (str, p1) => p1 / 2);
+
     styles[`spacing-${breakpoint}-${spacing}`] = {
-      margin: -themeSpacing / 2,
+      margin: -half,
       width: `calc(100% + ${themeSpacing}px)`,
       '& > $item': {
-        padding: themeSpacing / 2,
+        padding: half,
       },
     };
   });
```
Yeah, something like that looks like it would do the trick. I didn't realise that you'd consider this a bug as you said you wanted the Grid to be as simple as possible in your previous comment 😅 Should this be reopened?
@Und3Rdo9 It looks like that I have changed my mind a bit since last year :) 

Solution patch:
diff --git a/packages/material-ui/src/Grid/Grid.js b/packages/material-ui/src/Grid/Grid.js
--- a/packages/material-ui/src/Grid/Grid.js
+++ b/packages/material-ui/src/Grid/Grid.js
@@ -64,6 +64,11 @@ function generateGrid(globalStyles, theme, breakpoint) {
   }
 }
 
+function getOffset(val, div = 1) {
+  const parse = parseFloat(val);
+  return `${parse / div}${String(val).replace(String(parse), '') || 'px'}`;
+}
+
 function generateGutter(theme, breakpoint) {
   const styles = {};
 
@@ -75,10 +80,10 @@ function generateGutter(theme, breakpoint) {
     }
 
     styles[`spacing-${breakpoint}-${spacing}`] = {
-      margin: -themeSpacing / 2,
-      width: `calc(100% + ${themeSpacing}px)`,
+      margin: `-${getOffset(themeSpacing, 2)}`,
+      width: `calc(100% + ${getOffset(themeSpacing)})`,
       '& > $item': {
-        padding: themeSpacing / 2,
+        padding: getOffset(themeSpacing, 2),
       },
     };
   });


Test patch:
diff --git a/packages/material-ui/src/Grid/Grid.test.js b/packages/material-ui/src/Grid/Grid.test.js
--- a/packages/material-ui/src/Grid/Grid.test.js
+++ b/packages/material-ui/src/Grid/Grid.test.js
@@ -1,8 +1,9 @@
 import React from 'react';
-import { assert } from 'chai';
+import { assert, expect } from 'chai';
 import { createMount, createShallow, getClasses } from '@material-ui/core/test-utils';
+import { createMuiTheme } from '@material-ui/core/styles';
 import describeConformance from '../test-utils/describeConformance';
-import Grid from './Grid';
+import Grid, { styles } from './Grid';
 
 describe('<Grid />', () => {
   let mount;
@@ -93,4 +94,24 @@ describe('<Grid />', () => {
       assert.strictEqual(wrapper.props().onClick, handleClick);
     });
   });
+
+  describe('gutter', () => {
+    it('should generate the right values', () => {
+      const defaultTheme = createMuiTheme();
+      const remTheme = createMuiTheme({
+        spacing: factor => `${0.25 * factor}rem`,
+      });
+
+      expect(styles(remTheme)['spacing-xs-2']).to.deep.equal({
+        margin: '-0.25rem',
+        width: 'calc(100% + 0.5rem)',
+        '& > $item': { padding: '0.25rem' },
+      });
+      expect(styles(defaultTheme)['spacing-xs-2']).to.deep.equal({
+        margin: '-8px',
+        width: 'calc(100% + 16px)',
+        '& > $item': { padding: '8px' },
+      });
+    });
+  });
 });