@mui/system 5.0.6 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/LICENSE +21 -21
  3. package/breakpoints.js +41 -8
  4. package/createBox.d.ts +5 -1
  5. package/createBox.js +5 -3
  6. package/createTheme/createBreakpoints.js +2 -2
  7. package/cssVars/createCssVarsProvider.d.ts +88 -38
  8. package/cssVars/createCssVarsProvider.js +83 -61
  9. package/cssVars/cssVarsParser.d.ts +14 -3
  10. package/cssVars/cssVarsParser.js +41 -11
  11. package/cssVars/getInitColorSchemeScript.d.ts +7 -2
  12. package/cssVars/getInitColorSchemeScript.js +27 -5
  13. package/cssVars/useCurrentColorScheme.d.ts +50 -0
  14. package/cssVars/useCurrentColorScheme.js +235 -0
  15. package/esm/breakpoints.js +39 -8
  16. package/esm/createBox.js +5 -3
  17. package/esm/createTheme/createBreakpoints.js +2 -2
  18. package/esm/cssVars/createCssVarsProvider.js +82 -63
  19. package/esm/cssVars/cssVarsParser.js +40 -11
  20. package/esm/cssVars/getInitColorSchemeScript.js +24 -3
  21. package/esm/cssVars/useCurrentColorScheme.js +217 -0
  22. package/esm/styleFunctionSx/extendSxProp.js +20 -1
  23. package/esm/styleFunctionSx/styleFunctionSx.js +45 -35
  24. package/index.js +1 -1
  25. package/legacy/breakpoints.js +39 -8
  26. package/legacy/createBox.js +6 -3
  27. package/legacy/createTheme/createBreakpoints.js +2 -2
  28. package/legacy/cssVars/createCssVarsProvider.js +83 -70
  29. package/legacy/cssVars/cssVarsParser.js +37 -9
  30. package/legacy/cssVars/getInitColorSchemeScript.js +13 -4
  31. package/legacy/cssVars/useCurrentColorScheme.js +231 -0
  32. package/legacy/index.js +1 -1
  33. package/legacy/styleFunctionSx/extendSxProp.js +21 -1
  34. package/legacy/styleFunctionSx/styleFunctionSx.js +44 -34
  35. package/modern/breakpoints.js +39 -8
  36. package/modern/createBox.js +5 -3
  37. package/modern/createTheme/createBreakpoints.js +2 -2
  38. package/modern/cssVars/createCssVarsProvider.js +82 -63
  39. package/modern/cssVars/cssVarsParser.js +40 -11
  40. package/modern/cssVars/getInitColorSchemeScript.js +24 -3
  41. package/modern/cssVars/useCurrentColorScheme.js +217 -0
  42. package/modern/index.js +1 -1
  43. package/modern/styleFunctionSx/extendSxProp.js +20 -1
  44. package/modern/styleFunctionSx/styleFunctionSx.js +45 -35
  45. package/package.json +7 -7
  46. package/styleFunctionSx/extendSxProp.js +21 -1
  47. package/styleFunctionSx/styleFunctionSx.d.ts +2 -1
  48. package/styleFunctionSx/styleFunctionSx.js +46 -36
  49. package/styleFunctionSx/styleFunctionSx.spec.d.ts +1 -0
@@ -0,0 +1,217 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import * as React from 'react';
3
+ import { DEFAULT_MODE_STORAGE_KEY, DEFAULT_COLOR_SCHEME_STORAGE_KEY } from './getInitColorSchemeScript';
4
+ export function getSystemMode(mode) {
5
+ if (typeof window !== 'undefined' && mode === 'system') {
6
+ const mql = window.matchMedia('(prefers-color-scheme: dark)');
7
+
8
+ if (mql.matches) {
9
+ return 'dark';
10
+ }
11
+
12
+ return 'light';
13
+ }
14
+
15
+ return undefined;
16
+ }
17
+
18
+ function processState(state, callback) {
19
+ if (state.mode === 'light' || state.mode === 'system' && state.systemMode === 'light') {
20
+ return callback('light');
21
+ }
22
+
23
+ if (state.mode === 'dark' || state.mode === 'system' && state.systemMode === 'dark') {
24
+ return callback('dark');
25
+ }
26
+
27
+ return undefined;
28
+ }
29
+
30
+ export function getColorScheme(state) {
31
+ return processState(state, mode => {
32
+ if (mode === 'light') {
33
+ return state.lightColorScheme;
34
+ }
35
+
36
+ if (mode === 'dark') {
37
+ return state.darkColorScheme;
38
+ }
39
+
40
+ return undefined;
41
+ });
42
+ }
43
+
44
+ function resolveValue(key, defaultValue) {
45
+ if (typeof window === 'undefined') {
46
+ return undefined;
47
+ }
48
+
49
+ let value;
50
+
51
+ try {
52
+ value = localStorage.getItem(key) || undefined;
53
+ } catch (e) {// Unsupported
54
+ }
55
+
56
+ return value || defaultValue;
57
+ }
58
+
59
+ export default function useCurrentColorScheme(options) {
60
+ const {
61
+ defaultMode = 'light',
62
+ defaultLightColorScheme,
63
+ defaultDarkColorScheme,
64
+ supportedColorSchemes = [],
65
+ modeStorageKey = DEFAULT_MODE_STORAGE_KEY,
66
+ colorSchemeStorageKey = DEFAULT_COLOR_SCHEME_STORAGE_KEY
67
+ } = options;
68
+ const joinedColorSchemes = supportedColorSchemes.join(',');
69
+ const [state, setState] = React.useState(() => {
70
+ const initialMode = resolveValue(modeStorageKey, defaultMode);
71
+ return {
72
+ mode: initialMode,
73
+ systemMode: getSystemMode(initialMode),
74
+ lightColorScheme: resolveValue(`${colorSchemeStorageKey}-light`) || defaultLightColorScheme,
75
+ darkColorScheme: resolveValue(`${colorSchemeStorageKey}-dark`) || defaultDarkColorScheme
76
+ };
77
+ });
78
+ const colorScheme = getColorScheme(state);
79
+ const setMode = React.useCallback(mode => {
80
+ setState(currentState => {
81
+ const newMode = !mode ? defaultMode : mode;
82
+
83
+ if (typeof localStorage !== 'undefined') {
84
+ localStorage.setItem(modeStorageKey, newMode);
85
+ }
86
+
87
+ return _extends({}, currentState, {
88
+ mode: newMode,
89
+ systemMode: getSystemMode(newMode)
90
+ });
91
+ });
92
+ }, [modeStorageKey, defaultMode]);
93
+ const setColorScheme = React.useCallback(value => {
94
+ if (!value || typeof value === 'string') {
95
+ if (value && !supportedColorSchemes.includes(value)) {
96
+ console.error(`\`${value}\` does not exist in \`theme.colorSchemes\`.`);
97
+ } else {
98
+ setState(currentState => {
99
+ const newState = _extends({}, currentState);
100
+
101
+ if (!value) {
102
+ // reset to default color scheme
103
+ newState.lightColorScheme = defaultLightColorScheme;
104
+ newState.darkColorScheme = defaultDarkColorScheme;
105
+ return newState;
106
+ }
107
+
108
+ processState(currentState, mode => {
109
+ localStorage.setItem(`${colorSchemeStorageKey}-${mode}`, value);
110
+
111
+ if (mode === 'light') {
112
+ newState.lightColorScheme = value;
113
+ }
114
+
115
+ if (mode === 'dark') {
116
+ newState.darkColorScheme = value;
117
+ }
118
+ });
119
+ return newState;
120
+ });
121
+ }
122
+ } else if (value.light && !supportedColorSchemes.includes(value.light) || value.dark && !supportedColorSchemes.includes(value.dark)) {
123
+ console.error(`\`${value}\` does not exist in \`theme.colorSchemes\`.`);
124
+ } else {
125
+ setState(currentState => {
126
+ const newState = _extends({}, currentState);
127
+
128
+ if (value.light || value.light === null) {
129
+ newState.lightColorScheme = value.light === null ? defaultLightColorScheme : value.light;
130
+ }
131
+
132
+ if (value.dark || value.dark === null) {
133
+ newState.darkColorScheme = value.dark === null ? defaultDarkColorScheme : value.dark;
134
+ }
135
+
136
+ return newState;
137
+ });
138
+
139
+ if (value.light) {
140
+ localStorage.setItem(`${colorSchemeStorageKey}-light`, value.light);
141
+ }
142
+
143
+ if (value.dark) {
144
+ localStorage.setItem(`${colorSchemeStorageKey}-dark`, value.dark);
145
+ }
146
+ }
147
+ }, [colorSchemeStorageKey, supportedColorSchemes, defaultLightColorScheme, defaultDarkColorScheme]);
148
+ const handleMediaQuery = React.useCallback(e => {
149
+ if (state.mode === 'system') {
150
+ setState(currentState => _extends({}, currentState, {
151
+ systemMode: e.matches ? 'dark' : 'light'
152
+ }));
153
+ }
154
+ }, [state.mode]); // Ref hack to avoid adding handleMediaQuery as a dep
155
+
156
+ const mediaListener = React.useRef(handleMediaQuery);
157
+ mediaListener.current = handleMediaQuery;
158
+ React.useEffect(() => {
159
+ const handler = (...args) => mediaListener.current(...args); // Always listen to System preference
160
+
161
+
162
+ const media = window.matchMedia('(prefers-color-scheme: dark)'); // Intentionally use deprecated listener methods to support iOS & old browsers
163
+
164
+ media.addListener(handler);
165
+ handler(media);
166
+ return () => media.removeListener(handler);
167
+ }, []); // Save mode, lightColorScheme & darkColorScheme to localStorage
168
+
169
+ React.useEffect(() => {
170
+ if (state.mode) {
171
+ localStorage.setItem(modeStorageKey, state.mode);
172
+ }
173
+
174
+ processState(state, mode => {
175
+ if (mode === 'light') {
176
+ localStorage.setItem(`${colorSchemeStorageKey}-light`, state.lightColorScheme);
177
+ }
178
+
179
+ if (mode === 'dark') {
180
+ localStorage.setItem(`${colorSchemeStorageKey}-dark`, state.darkColorScheme);
181
+ }
182
+ });
183
+ }, [state, colorSchemeStorageKey, modeStorageKey]); // Handle when localStorage has changed
184
+
185
+ React.useEffect(() => {
186
+ const handleStorage = event => {
187
+ const value = event.newValue;
188
+
189
+ if (typeof event.key === 'string' && event.key.startsWith(colorSchemeStorageKey) && (!value || joinedColorSchemes.match(value))) {
190
+ // If the key is deleted, value will be null then reset color scheme to the default one.
191
+ if (event.key.endsWith('light')) {
192
+ setColorScheme({
193
+ light: value
194
+ });
195
+ }
196
+
197
+ if (event.key.endsWith('dark')) {
198
+ setColorScheme({
199
+ dark: value
200
+ });
201
+ }
202
+ }
203
+
204
+ if (event.key === modeStorageKey && (!value || ['light', 'dark', 'system'].includes(value))) {
205
+ setMode(value || defaultMode);
206
+ }
207
+ };
208
+
209
+ window.addEventListener('storage', handleStorage);
210
+ return () => window.removeEventListener('storage', handleStorage);
211
+ }, [setColorScheme, setMode, modeStorageKey, colorSchemeStorageKey, joinedColorSchemes, defaultMode]);
212
+ return _extends({}, state, {
213
+ colorScheme,
214
+ setMode,
215
+ setColorScheme
216
+ });
217
+ }
package/modern/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /** @license MUI v5.0.6
1
+ /** @license MUI v5.1.0
2
2
  *
3
3
  * This source code is licensed under the MIT license found in the
4
4
  * LICENSE file in the root directory of this source tree.
@@ -1,6 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
3
  const _excluded = ["sx"];
4
+ import { isPlainObject } from '@mui/utils';
4
5
  import { propToStyleFunction } from '../getThemeValue';
5
6
 
6
7
  const splitProps = props => {
@@ -28,7 +29,25 @@ export default function extendSxProp(props) {
28
29
  systemProps,
29
30
  otherProps
30
31
  } = splitProps(other);
32
+ let finalSx;
33
+
34
+ if (Array.isArray(inSx)) {
35
+ finalSx = [systemProps, ...inSx];
36
+ } else if (typeof inSx === 'function') {
37
+ finalSx = (...args) => {
38
+ const result = inSx(...args);
39
+
40
+ if (!isPlainObject(result)) {
41
+ return systemProps;
42
+ }
43
+
44
+ return _extends({}, systemProps, result);
45
+ };
46
+ } else {
47
+ finalSx = _extends({}, systemProps, inSx);
48
+ }
49
+
31
50
  return _extends({}, otherProps, {
32
- sx: _extends({}, systemProps, inSx)
51
+ sx: finalSx
33
52
  });
34
53
  }
@@ -14,53 +14,63 @@ function callIfFn(maybeFn, arg) {
14
14
 
15
15
  function styleFunctionSx(props) {
16
16
  const {
17
- sx: styles,
17
+ sx,
18
18
  theme = {}
19
19
  } = props || {};
20
20
 
21
- if (!styles) {
22
- return null;
21
+ if (!sx) {
22
+ return null; // emotion & styled-components will neglect null
23
23
  }
24
+ /*
25
+ * Receive `sxInput` as object or callback
26
+ * and then recursively check keys & values to create media query object styles.
27
+ * (the result will be used in `styled`)
28
+ */
24
29
 
25
- let stylesObject = styles;
26
30
 
27
- if (typeof styles === 'function') {
28
- stylesObject = styles(theme);
29
- } else if (typeof styles !== 'object') {
30
- // value
31
- return styles;
32
- }
31
+ function traverse(sxInput) {
32
+ let sxObject = sxInput;
33
33
 
34
- const emptyBreakpoints = createEmptyBreakpointObject(theme.breakpoints);
35
- const breakpointsKeys = Object.keys(emptyBreakpoints);
36
- let css = emptyBreakpoints;
37
- Object.keys(stylesObject).forEach(styleKey => {
38
- const value = callIfFn(stylesObject[styleKey], theme);
34
+ if (typeof sxInput === 'function') {
35
+ sxObject = sxInput(theme);
36
+ } else if (typeof sxInput !== 'object') {
37
+ // value
38
+ return sxInput;
39
+ }
39
40
 
40
- if (typeof value === 'object') {
41
- if (propToStyleFunction[styleKey]) {
42
- css = merge(css, getThemeValue(styleKey, value, theme));
43
- } else {
44
- const breakpointsValues = handleBreakpoints({
45
- theme
46
- }, value, x => ({
47
- [styleKey]: x
48
- }));
41
+ const emptyBreakpoints = createEmptyBreakpointObject(theme.breakpoints);
42
+ const breakpointsKeys = Object.keys(emptyBreakpoints);
43
+ let css = emptyBreakpoints;
44
+ Object.keys(sxObject).forEach(styleKey => {
45
+ const value = callIfFn(sxObject[styleKey], theme);
49
46
 
50
- if (objectsHaveSameKeys(breakpointsValues, value)) {
51
- css[styleKey] = styleFunctionSx({
52
- sx: value,
53
- theme
54
- });
47
+ if (typeof value === 'object') {
48
+ if (propToStyleFunction[styleKey]) {
49
+ css = merge(css, getThemeValue(styleKey, value, theme));
55
50
  } else {
56
- css = merge(css, breakpointsValues);
51
+ const breakpointsValues = handleBreakpoints({
52
+ theme
53
+ }, value, x => ({
54
+ [styleKey]: x
55
+ }));
56
+
57
+ if (objectsHaveSameKeys(breakpointsValues, value)) {
58
+ css[styleKey] = styleFunctionSx({
59
+ sx: value,
60
+ theme
61
+ });
62
+ } else {
63
+ css = merge(css, breakpointsValues);
64
+ }
57
65
  }
66
+ } else {
67
+ css = merge(css, getThemeValue(styleKey, value, theme));
58
68
  }
59
- } else {
60
- css = merge(css, getThemeValue(styleKey, value, theme));
61
- }
62
- });
63
- return removeUnusedBreakpoints(breakpointsKeys, css);
69
+ });
70
+ return removeUnusedBreakpoints(breakpointsKeys, css);
71
+ }
72
+
73
+ return Array.isArray(sx) ? sx.map(traverse) : traverse(sx);
64
74
  }
65
75
 
66
76
  styleFunctionSx.filterProps = ['sx'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/system",
3
- "version": "5.0.6",
3
+ "version": "5.1.0",
4
4
  "private": false,
5
5
  "author": "MUI Team",
6
6
  "description": "CSS utilities for rapidly laying out custom designs.",
@@ -8,7 +8,7 @@
8
8
  "keywords": [
9
9
  "react",
10
10
  "react-component",
11
- "material-ui",
11
+ "mui",
12
12
  "system"
13
13
  ],
14
14
  "repository": {
@@ -43,11 +43,11 @@
43
43
  }
44
44
  },
45
45
  "dependencies": {
46
- "@babel/runtime": "^7.15.4",
47
- "@mui/private-theming": "^5.0.1",
48
- "@mui/styled-engine": "^5.0.2",
49
- "@mui/types": "^7.0.0",
50
- "@mui/utils": "^5.0.1",
46
+ "@babel/runtime": "^7.16.0",
47
+ "@mui/private-theming": "^5.1.0",
48
+ "@mui/styled-engine": "^5.1.0",
49
+ "@mui/types": "^7.1.0",
50
+ "@mui/utils": "^5.1.0",
51
51
  "clsx": "^1.1.1",
52
52
  "csstype": "^3.0.9",
53
53
  "prop-types": "^15.7.2"
@@ -11,6 +11,8 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")
11
11
 
12
12
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
13
13
 
14
+ var _utils = require("@mui/utils");
15
+
14
16
  var _getThemeValue = require("../getThemeValue");
15
17
 
16
18
  const _excluded = ["sx"];
@@ -39,7 +41,25 @@ function extendSxProp(props) {
39
41
  systemProps,
40
42
  otherProps
41
43
  } = splitProps(other);
44
+ let finalSx;
45
+
46
+ if (Array.isArray(inSx)) {
47
+ finalSx = [systemProps, ...inSx];
48
+ } else if (typeof inSx === 'function') {
49
+ finalSx = (...args) => {
50
+ const result = inSx(...args);
51
+
52
+ if (!(0, _utils.isPlainObject)(result)) {
53
+ return systemProps;
54
+ }
55
+
56
+ return (0, _extends2.default)({}, systemProps, result);
57
+ };
58
+ } else {
59
+ finalSx = (0, _extends2.default)({}, systemProps, inSx);
60
+ }
61
+
42
62
  return (0, _extends2.default)({}, otherProps, {
43
- sx: (0, _extends2.default)({}, systemProps, inSx)
63
+ sx: finalSx
44
64
  });
45
65
  }
@@ -56,7 +56,8 @@ export type SystemStyleObject<Theme extends object = {}> =
56
56
  */
57
57
  export type SxProps<Theme extends object = {}> =
58
58
  | SystemStyleObject<Theme>
59
- | ((theme: Theme) => SystemStyleObject<Theme>);
59
+ | ((theme: Theme) => SystemStyleObject<Theme>)
60
+ | Array<SystemStyleObject<Theme> | ((theme: Theme) => SystemStyleObject<Theme>)>;
60
61
 
61
62
  // eslint-disable-next-line @typescript-eslint/naming-convention
62
63
  export default function unstable_styleFunctionSx(props: object): object;
@@ -29,53 +29,63 @@ function callIfFn(maybeFn, arg) {
29
29
 
30
30
  function styleFunctionSx(props) {
31
31
  const {
32
- sx: styles,
32
+ sx,
33
33
  theme = {}
34
34
  } = props || {};
35
35
 
36
- if (!styles) {
37
- return null;
36
+ if (!sx) {
37
+ return null; // emotion & styled-components will neglect null
38
38
  }
39
+ /*
40
+ * Receive `sxInput` as object or callback
41
+ * and then recursively check keys & values to create media query object styles.
42
+ * (the result will be used in `styled`)
43
+ */
39
44
 
40
- let stylesObject = styles;
41
45
 
42
- if (typeof styles === 'function') {
43
- stylesObject = styles(theme);
44
- } else if (typeof styles !== 'object') {
45
- // value
46
- return styles;
47
- }
46
+ function traverse(sxInput) {
47
+ let sxObject = sxInput;
48
48
 
49
- const emptyBreakpoints = (0, _breakpoints.createEmptyBreakpointObject)(theme.breakpoints);
50
- const breakpointsKeys = Object.keys(emptyBreakpoints);
51
- let css = emptyBreakpoints;
52
- Object.keys(stylesObject).forEach(styleKey => {
53
- const value = callIfFn(stylesObject[styleKey], theme);
49
+ if (typeof sxInput === 'function') {
50
+ sxObject = sxInput(theme);
51
+ } else if (typeof sxInput !== 'object') {
52
+ // value
53
+ return sxInput;
54
+ }
54
55
 
55
- if (typeof value === 'object') {
56
- if (_getThemeValue.propToStyleFunction[styleKey]) {
57
- css = (0, _merge.default)(css, (0, _getThemeValue.default)(styleKey, value, theme));
58
- } else {
59
- const breakpointsValues = (0, _breakpoints.handleBreakpoints)({
60
- theme
61
- }, value, x => ({
62
- [styleKey]: x
63
- }));
64
-
65
- if (objectsHaveSameKeys(breakpointsValues, value)) {
66
- css[styleKey] = styleFunctionSx({
67
- sx: value,
68
- theme
69
- });
56
+ const emptyBreakpoints = (0, _breakpoints.createEmptyBreakpointObject)(theme.breakpoints);
57
+ const breakpointsKeys = Object.keys(emptyBreakpoints);
58
+ let css = emptyBreakpoints;
59
+ Object.keys(sxObject).forEach(styleKey => {
60
+ const value = callIfFn(sxObject[styleKey], theme);
61
+
62
+ if (typeof value === 'object') {
63
+ if (_getThemeValue.propToStyleFunction[styleKey]) {
64
+ css = (0, _merge.default)(css, (0, _getThemeValue.default)(styleKey, value, theme));
70
65
  } else {
71
- css = (0, _merge.default)(css, breakpointsValues);
66
+ const breakpointsValues = (0, _breakpoints.handleBreakpoints)({
67
+ theme
68
+ }, value, x => ({
69
+ [styleKey]: x
70
+ }));
71
+
72
+ if (objectsHaveSameKeys(breakpointsValues, value)) {
73
+ css[styleKey] = styleFunctionSx({
74
+ sx: value,
75
+ theme
76
+ });
77
+ } else {
78
+ css = (0, _merge.default)(css, breakpointsValues);
79
+ }
72
80
  }
81
+ } else {
82
+ css = (0, _merge.default)(css, (0, _getThemeValue.default)(styleKey, value, theme));
73
83
  }
74
- } else {
75
- css = (0, _merge.default)(css, (0, _getThemeValue.default)(styleKey, value, theme));
76
- }
77
- });
78
- return (0, _breakpoints.removeUnusedBreakpoints)(breakpointsKeys, css);
84
+ });
85
+ return (0, _breakpoints.removeUnusedBreakpoints)(breakpointsKeys, css);
86
+ }
87
+
88
+ return Array.isArray(sx) ? sx.map(traverse) : traverse(sx);
79
89
  }
80
90
 
81
91
  styleFunctionSx.filterProps = ['sx'];
@@ -0,0 +1 @@
1
+ export {};