@mui/system 6.4.6 → 6.4.7

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # [Versions](https://mui.com/versions/)
2
2
 
3
+ ## 6.4.7
4
+
5
+ <!-- generated comparing v6.4.6..v6.x -->
6
+
7
+ _Mar 5, 2025_
8
+
9
+ A big thanks to the 3 contributors who made this release possible.
10
+
11
+ ### `@mui/material@6.4.7`
12
+
13
+ - [ThemeProvider] Add `storageManager` prop to `ThemeProvider` (@siriwatknp) (#45437) @siriwatknp
14
+ - [Rating] Deprecate \*Props and complete slots, slotProps (#45295) (#45398) @DiegoAndai
15
+ - [Radio] Fix `inputProps` not forwarded (@siriwatknp) (#45475) @siriwatknp
16
+
17
+ ### Core
18
+
19
+ - [blog] React 19 migration for MUI X (#45440) @arminmeh
20
+
21
+ All contributors of this release in alphabetical order: @arminmeh, @DiegoAndai, @siriwatknp
22
+
3
23
  ## 6.4.6
4
24
 
5
25
  <!-- generated comparing v6.4.5..v6.x -->
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import InitColorSchemeScript from '../InitColorSchemeScript';
3
3
  import { Result } from './useCurrentColorScheme';
4
+ import type { StorageManager } from './localStorageManager';
4
5
 
5
6
  export interface ColorSchemeContextValue<SupportedColorScheme extends string>
6
7
  extends Result<SupportedColorScheme> {
@@ -70,6 +71,11 @@ export interface CreateCssVarsProviderResult<
70
71
  * @default document
71
72
  */
72
73
  colorSchemeNode?: Element | null;
74
+ /**
75
+ * The storage manager to be used for storing the mode and color scheme.
76
+ * @default using `window.localStorage`
77
+ */
78
+ storageManager?: StorageManager | null;
73
79
  /**
74
80
  * The window that attaches the 'storage' event listener
75
81
  * @default window
@@ -58,6 +58,7 @@ function createCssVarsProvider(options) {
58
58
  modeStorageKey = defaultModeStorageKey,
59
59
  colorSchemeStorageKey = defaultColorSchemeStorageKey,
60
60
  disableTransitionOnChange = designSystemTransitionOnChange,
61
+ storageManager,
61
62
  storageWindow = typeof window === 'undefined' ? undefined : window,
62
63
  documentNode = typeof document === 'undefined' ? undefined : document,
63
64
  colorSchemeNode = typeof document === 'undefined' ? undefined : document.documentElement,
@@ -105,6 +106,7 @@ function createCssVarsProvider(options) {
105
106
  modeStorageKey,
106
107
  colorSchemeStorageKey,
107
108
  defaultMode,
109
+ storageManager,
108
110
  storageWindow,
109
111
  noSsr
110
112
  });
@@ -299,6 +301,11 @@ function createCssVarsProvider(options) {
299
301
  * You should use this option in conjuction with `InitColorSchemeScript` component.
300
302
  */
301
303
  noSsr: _propTypes.default.bool,
304
+ /**
305
+ * The storage manager to be used for storing the mode and color scheme
306
+ * @default using `window.localStorage`
307
+ */
308
+ storageManager: _propTypes.default.func,
302
309
  /**
303
310
  * The window that attaches the 'storage' event listener.
304
311
  * @default window
@@ -5,3 +5,4 @@ export { default as prepareTypographyVars } from './prepareTypographyVars';
5
5
  export type { ExtractTypographyTokens } from './prepareTypographyVars';
6
6
  export { default as createCssVarsTheme } from './createCssVarsTheme';
7
7
  export { createGetColorSchemeSelector } from './getColorSchemeSelector';
8
+ export type { StorageManager } from './localStorageManager';
@@ -0,0 +1,34 @@
1
+ export interface StorageManager {
2
+ (options: {
3
+ key: string;
4
+ storageWindow?: Window | null;
5
+ }): {
6
+ /**
7
+ * Function to get the value from the storage
8
+ * @param defaultValue The default value to be returned if the key is not found
9
+ * @returns The value from the storage or the default value
10
+ */
11
+ get(defaultValue: any): any;
12
+ /**
13
+ * Function to set the value in the storage
14
+ * @param value The value to be set
15
+ * @returns void
16
+ */
17
+ set(value: any): void;
18
+ /**
19
+ * Function to subscribe to the value of the specified key triggered by external events
20
+ * @param handler The function to be called when the value changes
21
+ * @returns A function to unsubscribe the handler
22
+ * @example
23
+ * React.useEffect(() => {
24
+ * const unsubscribe = storageManager.subscribe((value) => {
25
+ * console.log(value);
26
+ * });
27
+ * return unsubscribe;
28
+ * }, []);
29
+ */
30
+ subscribe(handler: (value: any) => void): () => void;
31
+ };
32
+ }
33
+ declare const localStorageManager: StorageManager;
34
+ export default localStorageManager;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ function noop() {}
8
+ const localStorageManager = ({
9
+ key,
10
+ storageWindow
11
+ }) => {
12
+ if (!storageWindow && typeof window !== 'undefined') {
13
+ storageWindow = window;
14
+ }
15
+ return {
16
+ get(defaultValue) {
17
+ if (typeof window === 'undefined') {
18
+ return undefined;
19
+ }
20
+ if (!storageWindow) {
21
+ return defaultValue;
22
+ }
23
+ let value;
24
+ try {
25
+ value = storageWindow.localStorage.getItem(key);
26
+ } catch {
27
+ // Unsupported
28
+ }
29
+ return value || defaultValue;
30
+ },
31
+ set: value => {
32
+ if (storageWindow) {
33
+ try {
34
+ storageWindow.localStorage.setItem(key, value);
35
+ } catch {
36
+ // Unsupported
37
+ }
38
+ }
39
+ },
40
+ subscribe: handler => {
41
+ if (!storageWindow) {
42
+ return noop;
43
+ }
44
+ const listener = event => {
45
+ const value = event.newValue;
46
+ if (event.key === key) {
47
+ handler(value);
48
+ }
49
+ };
50
+ storageWindow.addEventListener('storage', listener);
51
+ return () => {
52
+ storageWindow.removeEventListener('storage', listener);
53
+ };
54
+ }
55
+ };
56
+ };
57
+ var _default = exports.default = localStorageManager;
@@ -1,3 +1,4 @@
1
+ import type { StorageManager } from './localStorageManager';
1
2
  export type Mode = 'light' | 'dark' | 'system';
2
3
  export type SystemMode = Exclude<Mode, 'system'>;
3
4
  export interface State<SupportedColorScheme extends string> {
@@ -48,6 +49,7 @@ interface UseCurrentColoSchemeOptions<SupportedColorScheme extends string> {
48
49
  modeStorageKey?: string;
49
50
  colorSchemeStorageKey?: string;
50
51
  storageWindow?: Window | null;
52
+ storageManager?: StorageManager | null;
51
53
  noSsr?: boolean;
52
54
  }
53
55
  export default function useCurrentColorScheme<SupportedColorScheme extends string>(options: UseCurrentColoSchemeOptions<SupportedColorScheme>): Result<SupportedColorScheme>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  'use client';
3
3
 
4
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
5
  var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
6
  Object.defineProperty(exports, "__esModule", {
6
7
  value: true
@@ -10,6 +11,8 @@ exports.getColorScheme = getColorScheme;
10
11
  exports.getSystemMode = getSystemMode;
11
12
  var React = _interopRequireWildcard(require("react"));
12
13
  var _InitColorSchemeScript = require("../InitColorSchemeScript/InitColorSchemeScript");
14
+ var _localStorageManager = _interopRequireDefault(require("./localStorageManager"));
15
+ function noop() {}
13
16
  function getSystemMode(mode) {
14
17
  if (typeof window !== 'undefined' && typeof window.matchMedia === 'function' && mode === 'system') {
15
18
  const mql = window.matchMedia('(prefers-color-scheme: dark)');
@@ -40,22 +43,6 @@ function getColorScheme(state) {
40
43
  return undefined;
41
44
  });
42
45
  }
43
- function initializeValue(key, defaultValue) {
44
- if (typeof window === 'undefined') {
45
- return undefined;
46
- }
47
- let value;
48
- try {
49
- value = localStorage.getItem(key) || undefined;
50
- if (!value) {
51
- // the first time that user enters the site.
52
- localStorage.setItem(key, defaultValue);
53
- }
54
- } catch {
55
- // Unsupported
56
- }
57
- return value || defaultValue;
58
- }
59
46
  function useCurrentColorScheme(options) {
60
47
  const {
61
48
  defaultMode = 'light',
@@ -65,14 +52,27 @@ function useCurrentColorScheme(options) {
65
52
  modeStorageKey = _InitColorSchemeScript.DEFAULT_MODE_STORAGE_KEY,
66
53
  colorSchemeStorageKey = _InitColorSchemeScript.DEFAULT_COLOR_SCHEME_STORAGE_KEY,
67
54
  storageWindow = typeof window === 'undefined' ? undefined : window,
55
+ storageManager = _localStorageManager.default,
68
56
  noSsr = false
69
57
  } = options;
70
58
  const joinedColorSchemes = supportedColorSchemes.join(',');
71
59
  const isMultiSchemes = supportedColorSchemes.length > 1;
60
+ const modeStorage = React.useMemo(() => storageManager?.({
61
+ key: modeStorageKey,
62
+ storageWindow
63
+ }), [storageManager, modeStorageKey, storageWindow]);
64
+ const lightStorage = React.useMemo(() => storageManager?.({
65
+ key: `${colorSchemeStorageKey}-light`,
66
+ storageWindow
67
+ }), [storageManager, colorSchemeStorageKey, storageWindow]);
68
+ const darkStorage = React.useMemo(() => storageManager?.({
69
+ key: `${colorSchemeStorageKey}-dark`,
70
+ storageWindow
71
+ }), [storageManager, colorSchemeStorageKey, storageWindow]);
72
72
  const [state, setState] = React.useState(() => {
73
- const initialMode = initializeValue(modeStorageKey, defaultMode);
74
- const lightColorScheme = initializeValue(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);
75
- const darkColorScheme = initializeValue(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);
73
+ const initialMode = modeStorage?.get(defaultMode) || defaultMode;
74
+ const lightColorScheme = lightStorage?.get(defaultLightColorScheme) || defaultLightColorScheme;
75
+ const darkColorScheme = darkStorage?.get(defaultDarkColorScheme) || defaultDarkColorScheme;
76
76
  return {
77
77
  mode: initialMode,
78
78
  systemMode: getSystemMode(initialMode),
@@ -92,27 +92,19 @@ function useCurrentColorScheme(options) {
92
92
  return currentState;
93
93
  }
94
94
  const newMode = mode ?? defaultMode;
95
- try {
96
- localStorage.setItem(modeStorageKey, newMode);
97
- } catch {
98
- // Unsupported
99
- }
95
+ modeStorage?.set(newMode);
100
96
  return {
101
97
  ...currentState,
102
98
  mode: newMode,
103
99
  systemMode: getSystemMode(newMode)
104
100
  };
105
101
  });
106
- }, [modeStorageKey, defaultMode]);
102
+ }, [modeStorage, defaultMode]);
107
103
  const setColorScheme = React.useCallback(value => {
108
104
  if (!value) {
109
105
  setState(currentState => {
110
- try {
111
- localStorage.setItem(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);
112
- localStorage.setItem(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);
113
- } catch {
114
- // Unsupported
115
- }
106
+ lightStorage?.set(defaultLightColorScheme);
107
+ darkStorage?.set(defaultDarkColorScheme);
116
108
  return {
117
109
  ...currentState,
118
110
  lightColorScheme: defaultLightColorScheme,
@@ -128,15 +120,12 @@ function useCurrentColorScheme(options) {
128
120
  ...currentState
129
121
  };
130
122
  processState(currentState, mode => {
131
- try {
132
- localStorage.setItem(`${colorSchemeStorageKey}-${mode}`, value);
133
- } catch {
134
- // Unsupported
135
- }
136
123
  if (mode === 'light') {
124
+ lightStorage?.set(value);
137
125
  newState.lightColorScheme = value;
138
126
  }
139
127
  if (mode === 'dark') {
128
+ darkStorage?.set(value);
140
129
  newState.darkColorScheme = value;
141
130
  }
142
131
  });
@@ -155,11 +144,7 @@ function useCurrentColorScheme(options) {
155
144
  console.error(`\`${newLightColorScheme}\` does not exist in \`theme.colorSchemes\`.`);
156
145
  } else {
157
146
  newState.lightColorScheme = newLightColorScheme;
158
- try {
159
- localStorage.setItem(`${colorSchemeStorageKey}-light`, newLightColorScheme);
160
- } catch (error) {
161
- // Unsupported
162
- }
147
+ lightStorage?.set(newLightColorScheme);
163
148
  }
164
149
  }
165
150
  if (newDarkColorScheme) {
@@ -167,17 +152,13 @@ function useCurrentColorScheme(options) {
167
152
  console.error(`\`${newDarkColorScheme}\` does not exist in \`theme.colorSchemes\`.`);
168
153
  } else {
169
154
  newState.darkColorScheme = newDarkColorScheme;
170
- try {
171
- localStorage.setItem(`${colorSchemeStorageKey}-dark`, newDarkColorScheme);
172
- } catch (error) {
173
- // Unsupported
174
- }
155
+ darkStorage?.set(newDarkColorScheme);
175
156
  }
176
157
  }
177
158
  return newState;
178
159
  });
179
160
  }
180
- }, [joinedColorSchemes, colorSchemeStorageKey, defaultLightColorScheme, defaultDarkColorScheme]);
161
+ }, [joinedColorSchemes, lightStorage, darkStorage, defaultLightColorScheme, defaultDarkColorScheme]);
181
162
  const handleMediaQuery = React.useCallback(event => {
182
163
  if (state.mode === 'system') {
183
164
  setState(currentState => {
@@ -217,34 +198,34 @@ function useCurrentColorScheme(options) {
217
198
 
218
199
  // Handle when localStorage has changed
219
200
  React.useEffect(() => {
220
- if (storageWindow && isMultiSchemes) {
221
- const handleStorage = event => {
222
- const value = event.newValue;
223
- if (typeof event.key === 'string' && event.key.startsWith(colorSchemeStorageKey) && (!value || joinedColorSchemes.match(value))) {
224
- // If the key is deleted, value will be null then reset color scheme to the default one.
225
- if (event.key.endsWith('light')) {
226
- setColorScheme({
227
- light: value
228
- });
229
- }
230
- if (event.key.endsWith('dark')) {
231
- setColorScheme({
232
- dark: value
233
- });
234
- }
235
- }
236
- if (event.key === modeStorageKey && (!value || ['light', 'dark', 'system'].includes(value))) {
201
+ if (isMultiSchemes) {
202
+ const unsubscribeMode = modeStorage?.subscribe(value => {
203
+ if (!value || ['light', 'dark', 'system'].includes(value)) {
237
204
  setMode(value || defaultMode);
238
205
  }
239
- };
240
- // For syncing color-scheme changes between iframes
241
- storageWindow.addEventListener('storage', handleStorage);
206
+ }) || noop;
207
+ const unsubscribeLight = lightStorage?.subscribe(value => {
208
+ if (!value || joinedColorSchemes.match(value)) {
209
+ setColorScheme({
210
+ light: value
211
+ });
212
+ }
213
+ }) || noop;
214
+ const unsubscribeDark = darkStorage?.subscribe(value => {
215
+ if (!value || joinedColorSchemes.match(value)) {
216
+ setColorScheme({
217
+ dark: value
218
+ });
219
+ }
220
+ }) || noop;
242
221
  return () => {
243
- storageWindow.removeEventListener('storage', handleStorage);
222
+ unsubscribeMode();
223
+ unsubscribeLight();
224
+ unsubscribeDark();
244
225
  };
245
226
  }
246
227
  return undefined;
247
- }, [setColorScheme, setMode, modeStorageKey, colorSchemeStorageKey, joinedColorSchemes, defaultMode, storageWindow, isMultiSchemes]);
228
+ }, [setColorScheme, setMode, joinedColorSchemes, defaultMode, storageWindow, isMultiSchemes, modeStorage, lightStorage, darkStorage]);
248
229
  return {
249
230
  ...state,
250
231
  mode: isClient ? state.mode : undefined,
@@ -50,6 +50,7 @@ export default function createCssVarsProvider(options) {
50
50
  modeStorageKey = defaultModeStorageKey,
51
51
  colorSchemeStorageKey = defaultColorSchemeStorageKey,
52
52
  disableTransitionOnChange = designSystemTransitionOnChange,
53
+ storageManager,
53
54
  storageWindow = typeof window === 'undefined' ? undefined : window,
54
55
  documentNode = typeof document === 'undefined' ? undefined : document,
55
56
  colorSchemeNode = typeof document === 'undefined' ? undefined : document.documentElement,
@@ -97,6 +98,7 @@ export default function createCssVarsProvider(options) {
97
98
  modeStorageKey,
98
99
  colorSchemeStorageKey,
99
100
  defaultMode,
101
+ storageManager,
100
102
  storageWindow,
101
103
  noSsr
102
104
  });
@@ -291,6 +293,11 @@ export default function createCssVarsProvider(options) {
291
293
  * You should use this option in conjuction with `InitColorSchemeScript` component.
292
294
  */
293
295
  noSsr: PropTypes.bool,
296
+ /**
297
+ * The storage manager to be used for storing the mode and color scheme
298
+ * @default using `window.localStorage`
299
+ */
300
+ storageManager: PropTypes.func,
294
301
  /**
295
302
  * The window that attaches the 'storage' event listener.
296
303
  * @default window
@@ -0,0 +1,51 @@
1
+ function noop() {}
2
+ const localStorageManager = ({
3
+ key,
4
+ storageWindow
5
+ }) => {
6
+ if (!storageWindow && typeof window !== 'undefined') {
7
+ storageWindow = window;
8
+ }
9
+ return {
10
+ get(defaultValue) {
11
+ if (typeof window === 'undefined') {
12
+ return undefined;
13
+ }
14
+ if (!storageWindow) {
15
+ return defaultValue;
16
+ }
17
+ let value;
18
+ try {
19
+ value = storageWindow.localStorage.getItem(key);
20
+ } catch {
21
+ // Unsupported
22
+ }
23
+ return value || defaultValue;
24
+ },
25
+ set: value => {
26
+ if (storageWindow) {
27
+ try {
28
+ storageWindow.localStorage.setItem(key, value);
29
+ } catch {
30
+ // Unsupported
31
+ }
32
+ }
33
+ },
34
+ subscribe: handler => {
35
+ if (!storageWindow) {
36
+ return noop;
37
+ }
38
+ const listener = event => {
39
+ const value = event.newValue;
40
+ if (event.key === key) {
41
+ handler(value);
42
+ }
43
+ };
44
+ storageWindow.addEventListener('storage', listener);
45
+ return () => {
46
+ storageWindow.removeEventListener('storage', listener);
47
+ };
48
+ }
49
+ };
50
+ };
51
+ export default localStorageManager;
@@ -2,6 +2,8 @@
2
2
 
3
3
  import * as React from 'react';
4
4
  import { DEFAULT_MODE_STORAGE_KEY, DEFAULT_COLOR_SCHEME_STORAGE_KEY } from "../InitColorSchemeScript/InitColorSchemeScript.js";
5
+ import localStorageManager from "./localStorageManager.js";
6
+ function noop() {}
5
7
  export function getSystemMode(mode) {
6
8
  if (typeof window !== 'undefined' && typeof window.matchMedia === 'function' && mode === 'system') {
7
9
  const mql = window.matchMedia('(prefers-color-scheme: dark)');
@@ -32,22 +34,6 @@ export function getColorScheme(state) {
32
34
  return undefined;
33
35
  });
34
36
  }
35
- function initializeValue(key, defaultValue) {
36
- if (typeof window === 'undefined') {
37
- return undefined;
38
- }
39
- let value;
40
- try {
41
- value = localStorage.getItem(key) || undefined;
42
- if (!value) {
43
- // the first time that user enters the site.
44
- localStorage.setItem(key, defaultValue);
45
- }
46
- } catch {
47
- // Unsupported
48
- }
49
- return value || defaultValue;
50
- }
51
37
  export default function useCurrentColorScheme(options) {
52
38
  const {
53
39
  defaultMode = 'light',
@@ -57,14 +43,27 @@ export default function useCurrentColorScheme(options) {
57
43
  modeStorageKey = DEFAULT_MODE_STORAGE_KEY,
58
44
  colorSchemeStorageKey = DEFAULT_COLOR_SCHEME_STORAGE_KEY,
59
45
  storageWindow = typeof window === 'undefined' ? undefined : window,
46
+ storageManager = localStorageManager,
60
47
  noSsr = false
61
48
  } = options;
62
49
  const joinedColorSchemes = supportedColorSchemes.join(',');
63
50
  const isMultiSchemes = supportedColorSchemes.length > 1;
51
+ const modeStorage = React.useMemo(() => storageManager?.({
52
+ key: modeStorageKey,
53
+ storageWindow
54
+ }), [storageManager, modeStorageKey, storageWindow]);
55
+ const lightStorage = React.useMemo(() => storageManager?.({
56
+ key: `${colorSchemeStorageKey}-light`,
57
+ storageWindow
58
+ }), [storageManager, colorSchemeStorageKey, storageWindow]);
59
+ const darkStorage = React.useMemo(() => storageManager?.({
60
+ key: `${colorSchemeStorageKey}-dark`,
61
+ storageWindow
62
+ }), [storageManager, colorSchemeStorageKey, storageWindow]);
64
63
  const [state, setState] = React.useState(() => {
65
- const initialMode = initializeValue(modeStorageKey, defaultMode);
66
- const lightColorScheme = initializeValue(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);
67
- const darkColorScheme = initializeValue(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);
64
+ const initialMode = modeStorage?.get(defaultMode) || defaultMode;
65
+ const lightColorScheme = lightStorage?.get(defaultLightColorScheme) || defaultLightColorScheme;
66
+ const darkColorScheme = darkStorage?.get(defaultDarkColorScheme) || defaultDarkColorScheme;
68
67
  return {
69
68
  mode: initialMode,
70
69
  systemMode: getSystemMode(initialMode),
@@ -84,27 +83,19 @@ export default function useCurrentColorScheme(options) {
84
83
  return currentState;
85
84
  }
86
85
  const newMode = mode ?? defaultMode;
87
- try {
88
- localStorage.setItem(modeStorageKey, newMode);
89
- } catch {
90
- // Unsupported
91
- }
86
+ modeStorage?.set(newMode);
92
87
  return {
93
88
  ...currentState,
94
89
  mode: newMode,
95
90
  systemMode: getSystemMode(newMode)
96
91
  };
97
92
  });
98
- }, [modeStorageKey, defaultMode]);
93
+ }, [modeStorage, defaultMode]);
99
94
  const setColorScheme = React.useCallback(value => {
100
95
  if (!value) {
101
96
  setState(currentState => {
102
- try {
103
- localStorage.setItem(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);
104
- localStorage.setItem(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);
105
- } catch {
106
- // Unsupported
107
- }
97
+ lightStorage?.set(defaultLightColorScheme);
98
+ darkStorage?.set(defaultDarkColorScheme);
108
99
  return {
109
100
  ...currentState,
110
101
  lightColorScheme: defaultLightColorScheme,
@@ -120,15 +111,12 @@ export default function useCurrentColorScheme(options) {
120
111
  ...currentState
121
112
  };
122
113
  processState(currentState, mode => {
123
- try {
124
- localStorage.setItem(`${colorSchemeStorageKey}-${mode}`, value);
125
- } catch {
126
- // Unsupported
127
- }
128
114
  if (mode === 'light') {
115
+ lightStorage?.set(value);
129
116
  newState.lightColorScheme = value;
130
117
  }
131
118
  if (mode === 'dark') {
119
+ darkStorage?.set(value);
132
120
  newState.darkColorScheme = value;
133
121
  }
134
122
  });
@@ -147,11 +135,7 @@ export default function useCurrentColorScheme(options) {
147
135
  console.error(`\`${newLightColorScheme}\` does not exist in \`theme.colorSchemes\`.`);
148
136
  } else {
149
137
  newState.lightColorScheme = newLightColorScheme;
150
- try {
151
- localStorage.setItem(`${colorSchemeStorageKey}-light`, newLightColorScheme);
152
- } catch (error) {
153
- // Unsupported
154
- }
138
+ lightStorage?.set(newLightColorScheme);
155
139
  }
156
140
  }
157
141
  if (newDarkColorScheme) {
@@ -159,17 +143,13 @@ export default function useCurrentColorScheme(options) {
159
143
  console.error(`\`${newDarkColorScheme}\` does not exist in \`theme.colorSchemes\`.`);
160
144
  } else {
161
145
  newState.darkColorScheme = newDarkColorScheme;
162
- try {
163
- localStorage.setItem(`${colorSchemeStorageKey}-dark`, newDarkColorScheme);
164
- } catch (error) {
165
- // Unsupported
166
- }
146
+ darkStorage?.set(newDarkColorScheme);
167
147
  }
168
148
  }
169
149
  return newState;
170
150
  });
171
151
  }
172
- }, [joinedColorSchemes, colorSchemeStorageKey, defaultLightColorScheme, defaultDarkColorScheme]);
152
+ }, [joinedColorSchemes, lightStorage, darkStorage, defaultLightColorScheme, defaultDarkColorScheme]);
173
153
  const handleMediaQuery = React.useCallback(event => {
174
154
  if (state.mode === 'system') {
175
155
  setState(currentState => {
@@ -209,34 +189,34 @@ export default function useCurrentColorScheme(options) {
209
189
 
210
190
  // Handle when localStorage has changed
211
191
  React.useEffect(() => {
212
- if (storageWindow && isMultiSchemes) {
213
- const handleStorage = event => {
214
- const value = event.newValue;
215
- if (typeof event.key === 'string' && event.key.startsWith(colorSchemeStorageKey) && (!value || joinedColorSchemes.match(value))) {
216
- // If the key is deleted, value will be null then reset color scheme to the default one.
217
- if (event.key.endsWith('light')) {
218
- setColorScheme({
219
- light: value
220
- });
221
- }
222
- if (event.key.endsWith('dark')) {
223
- setColorScheme({
224
- dark: value
225
- });
226
- }
227
- }
228
- if (event.key === modeStorageKey && (!value || ['light', 'dark', 'system'].includes(value))) {
192
+ if (isMultiSchemes) {
193
+ const unsubscribeMode = modeStorage?.subscribe(value => {
194
+ if (!value || ['light', 'dark', 'system'].includes(value)) {
229
195
  setMode(value || defaultMode);
230
196
  }
231
- };
232
- // For syncing color-scheme changes between iframes
233
- storageWindow.addEventListener('storage', handleStorage);
197
+ }) || noop;
198
+ const unsubscribeLight = lightStorage?.subscribe(value => {
199
+ if (!value || joinedColorSchemes.match(value)) {
200
+ setColorScheme({
201
+ light: value
202
+ });
203
+ }
204
+ }) || noop;
205
+ const unsubscribeDark = darkStorage?.subscribe(value => {
206
+ if (!value || joinedColorSchemes.match(value)) {
207
+ setColorScheme({
208
+ dark: value
209
+ });
210
+ }
211
+ }) || noop;
234
212
  return () => {
235
- storageWindow.removeEventListener('storage', handleStorage);
213
+ unsubscribeMode();
214
+ unsubscribeLight();
215
+ unsubscribeDark();
236
216
  };
237
217
  }
238
218
  return undefined;
239
- }, [setColorScheme, setMode, modeStorageKey, colorSchemeStorageKey, joinedColorSchemes, defaultMode, storageWindow, isMultiSchemes]);
219
+ }, [setColorScheme, setMode, joinedColorSchemes, defaultMode, storageWindow, isMultiSchemes, modeStorage, lightStorage, darkStorage]);
240
220
  return {
241
221
  ...state,
242
222
  mode: isClient ? state.mode : undefined,
@@ -1,6 +1,6 @@
1
- export const version = "6.4.6";
1
+ export const version = "6.4.7";
2
2
  export const major = Number("6");
3
3
  export const minor = Number("4");
4
- export const patch = Number("6");
4
+ export const patch = Number("7");
5
5
  export const prerelease = undefined;
6
6
  export default version;
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/system v6.4.6
2
+ * @mui/system v6.4.7
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -50,6 +50,7 @@ export default function createCssVarsProvider(options) {
50
50
  modeStorageKey = defaultModeStorageKey,
51
51
  colorSchemeStorageKey = defaultColorSchemeStorageKey,
52
52
  disableTransitionOnChange = designSystemTransitionOnChange,
53
+ storageManager,
53
54
  storageWindow = typeof window === 'undefined' ? undefined : window,
54
55
  documentNode = typeof document === 'undefined' ? undefined : document,
55
56
  colorSchemeNode = typeof document === 'undefined' ? undefined : document.documentElement,
@@ -97,6 +98,7 @@ export default function createCssVarsProvider(options) {
97
98
  modeStorageKey,
98
99
  colorSchemeStorageKey,
99
100
  defaultMode,
101
+ storageManager,
100
102
  storageWindow,
101
103
  noSsr
102
104
  });
@@ -291,6 +293,11 @@ export default function createCssVarsProvider(options) {
291
293
  * You should use this option in conjuction with `InitColorSchemeScript` component.
292
294
  */
293
295
  noSsr: PropTypes.bool,
296
+ /**
297
+ * The storage manager to be used for storing the mode and color scheme
298
+ * @default using `window.localStorage`
299
+ */
300
+ storageManager: PropTypes.func,
294
301
  /**
295
302
  * The window that attaches the 'storage' event listener.
296
303
  * @default window
@@ -0,0 +1,51 @@
1
+ function noop() {}
2
+ const localStorageManager = ({
3
+ key,
4
+ storageWindow
5
+ }) => {
6
+ if (!storageWindow && typeof window !== 'undefined') {
7
+ storageWindow = window;
8
+ }
9
+ return {
10
+ get(defaultValue) {
11
+ if (typeof window === 'undefined') {
12
+ return undefined;
13
+ }
14
+ if (!storageWindow) {
15
+ return defaultValue;
16
+ }
17
+ let value;
18
+ try {
19
+ value = storageWindow.localStorage.getItem(key);
20
+ } catch {
21
+ // Unsupported
22
+ }
23
+ return value || defaultValue;
24
+ },
25
+ set: value => {
26
+ if (storageWindow) {
27
+ try {
28
+ storageWindow.localStorage.setItem(key, value);
29
+ } catch {
30
+ // Unsupported
31
+ }
32
+ }
33
+ },
34
+ subscribe: handler => {
35
+ if (!storageWindow) {
36
+ return noop;
37
+ }
38
+ const listener = event => {
39
+ const value = event.newValue;
40
+ if (event.key === key) {
41
+ handler(value);
42
+ }
43
+ };
44
+ storageWindow.addEventListener('storage', listener);
45
+ return () => {
46
+ storageWindow.removeEventListener('storage', listener);
47
+ };
48
+ }
49
+ };
50
+ };
51
+ export default localStorageManager;
@@ -2,6 +2,8 @@
2
2
 
3
3
  import * as React from 'react';
4
4
  import { DEFAULT_MODE_STORAGE_KEY, DEFAULT_COLOR_SCHEME_STORAGE_KEY } from "../InitColorSchemeScript/InitColorSchemeScript.js";
5
+ import localStorageManager from "./localStorageManager.js";
6
+ function noop() {}
5
7
  export function getSystemMode(mode) {
6
8
  if (typeof window !== 'undefined' && typeof window.matchMedia === 'function' && mode === 'system') {
7
9
  const mql = window.matchMedia('(prefers-color-scheme: dark)');
@@ -32,22 +34,6 @@ export function getColorScheme(state) {
32
34
  return undefined;
33
35
  });
34
36
  }
35
- function initializeValue(key, defaultValue) {
36
- if (typeof window === 'undefined') {
37
- return undefined;
38
- }
39
- let value;
40
- try {
41
- value = localStorage.getItem(key) || undefined;
42
- if (!value) {
43
- // the first time that user enters the site.
44
- localStorage.setItem(key, defaultValue);
45
- }
46
- } catch {
47
- // Unsupported
48
- }
49
- return value || defaultValue;
50
- }
51
37
  export default function useCurrentColorScheme(options) {
52
38
  const {
53
39
  defaultMode = 'light',
@@ -57,14 +43,27 @@ export default function useCurrentColorScheme(options) {
57
43
  modeStorageKey = DEFAULT_MODE_STORAGE_KEY,
58
44
  colorSchemeStorageKey = DEFAULT_COLOR_SCHEME_STORAGE_KEY,
59
45
  storageWindow = typeof window === 'undefined' ? undefined : window,
46
+ storageManager = localStorageManager,
60
47
  noSsr = false
61
48
  } = options;
62
49
  const joinedColorSchemes = supportedColorSchemes.join(',');
63
50
  const isMultiSchemes = supportedColorSchemes.length > 1;
51
+ const modeStorage = React.useMemo(() => storageManager?.({
52
+ key: modeStorageKey,
53
+ storageWindow
54
+ }), [storageManager, modeStorageKey, storageWindow]);
55
+ const lightStorage = React.useMemo(() => storageManager?.({
56
+ key: `${colorSchemeStorageKey}-light`,
57
+ storageWindow
58
+ }), [storageManager, colorSchemeStorageKey, storageWindow]);
59
+ const darkStorage = React.useMemo(() => storageManager?.({
60
+ key: `${colorSchemeStorageKey}-dark`,
61
+ storageWindow
62
+ }), [storageManager, colorSchemeStorageKey, storageWindow]);
64
63
  const [state, setState] = React.useState(() => {
65
- const initialMode = initializeValue(modeStorageKey, defaultMode);
66
- const lightColorScheme = initializeValue(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);
67
- const darkColorScheme = initializeValue(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);
64
+ const initialMode = modeStorage?.get(defaultMode) || defaultMode;
65
+ const lightColorScheme = lightStorage?.get(defaultLightColorScheme) || defaultLightColorScheme;
66
+ const darkColorScheme = darkStorage?.get(defaultDarkColorScheme) || defaultDarkColorScheme;
68
67
  return {
69
68
  mode: initialMode,
70
69
  systemMode: getSystemMode(initialMode),
@@ -84,27 +83,19 @@ export default function useCurrentColorScheme(options) {
84
83
  return currentState;
85
84
  }
86
85
  const newMode = mode ?? defaultMode;
87
- try {
88
- localStorage.setItem(modeStorageKey, newMode);
89
- } catch {
90
- // Unsupported
91
- }
86
+ modeStorage?.set(newMode);
92
87
  return {
93
88
  ...currentState,
94
89
  mode: newMode,
95
90
  systemMode: getSystemMode(newMode)
96
91
  };
97
92
  });
98
- }, [modeStorageKey, defaultMode]);
93
+ }, [modeStorage, defaultMode]);
99
94
  const setColorScheme = React.useCallback(value => {
100
95
  if (!value) {
101
96
  setState(currentState => {
102
- try {
103
- localStorage.setItem(`${colorSchemeStorageKey}-light`, defaultLightColorScheme);
104
- localStorage.setItem(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme);
105
- } catch {
106
- // Unsupported
107
- }
97
+ lightStorage?.set(defaultLightColorScheme);
98
+ darkStorage?.set(defaultDarkColorScheme);
108
99
  return {
109
100
  ...currentState,
110
101
  lightColorScheme: defaultLightColorScheme,
@@ -120,15 +111,12 @@ export default function useCurrentColorScheme(options) {
120
111
  ...currentState
121
112
  };
122
113
  processState(currentState, mode => {
123
- try {
124
- localStorage.setItem(`${colorSchemeStorageKey}-${mode}`, value);
125
- } catch {
126
- // Unsupported
127
- }
128
114
  if (mode === 'light') {
115
+ lightStorage?.set(value);
129
116
  newState.lightColorScheme = value;
130
117
  }
131
118
  if (mode === 'dark') {
119
+ darkStorage?.set(value);
132
120
  newState.darkColorScheme = value;
133
121
  }
134
122
  });
@@ -147,11 +135,7 @@ export default function useCurrentColorScheme(options) {
147
135
  console.error(`\`${newLightColorScheme}\` does not exist in \`theme.colorSchemes\`.`);
148
136
  } else {
149
137
  newState.lightColorScheme = newLightColorScheme;
150
- try {
151
- localStorage.setItem(`${colorSchemeStorageKey}-light`, newLightColorScheme);
152
- } catch (error) {
153
- // Unsupported
154
- }
138
+ lightStorage?.set(newLightColorScheme);
155
139
  }
156
140
  }
157
141
  if (newDarkColorScheme) {
@@ -159,17 +143,13 @@ export default function useCurrentColorScheme(options) {
159
143
  console.error(`\`${newDarkColorScheme}\` does not exist in \`theme.colorSchemes\`.`);
160
144
  } else {
161
145
  newState.darkColorScheme = newDarkColorScheme;
162
- try {
163
- localStorage.setItem(`${colorSchemeStorageKey}-dark`, newDarkColorScheme);
164
- } catch (error) {
165
- // Unsupported
166
- }
146
+ darkStorage?.set(newDarkColorScheme);
167
147
  }
168
148
  }
169
149
  return newState;
170
150
  });
171
151
  }
172
- }, [joinedColorSchemes, colorSchemeStorageKey, defaultLightColorScheme, defaultDarkColorScheme]);
152
+ }, [joinedColorSchemes, lightStorage, darkStorage, defaultLightColorScheme, defaultDarkColorScheme]);
173
153
  const handleMediaQuery = React.useCallback(event => {
174
154
  if (state.mode === 'system') {
175
155
  setState(currentState => {
@@ -209,34 +189,34 @@ export default function useCurrentColorScheme(options) {
209
189
 
210
190
  // Handle when localStorage has changed
211
191
  React.useEffect(() => {
212
- if (storageWindow && isMultiSchemes) {
213
- const handleStorage = event => {
214
- const value = event.newValue;
215
- if (typeof event.key === 'string' && event.key.startsWith(colorSchemeStorageKey) && (!value || joinedColorSchemes.match(value))) {
216
- // If the key is deleted, value will be null then reset color scheme to the default one.
217
- if (event.key.endsWith('light')) {
218
- setColorScheme({
219
- light: value
220
- });
221
- }
222
- if (event.key.endsWith('dark')) {
223
- setColorScheme({
224
- dark: value
225
- });
226
- }
227
- }
228
- if (event.key === modeStorageKey && (!value || ['light', 'dark', 'system'].includes(value))) {
192
+ if (isMultiSchemes) {
193
+ const unsubscribeMode = modeStorage?.subscribe(value => {
194
+ if (!value || ['light', 'dark', 'system'].includes(value)) {
229
195
  setMode(value || defaultMode);
230
196
  }
231
- };
232
- // For syncing color-scheme changes between iframes
233
- storageWindow.addEventListener('storage', handleStorage);
197
+ }) || noop;
198
+ const unsubscribeLight = lightStorage?.subscribe(value => {
199
+ if (!value || joinedColorSchemes.match(value)) {
200
+ setColorScheme({
201
+ light: value
202
+ });
203
+ }
204
+ }) || noop;
205
+ const unsubscribeDark = darkStorage?.subscribe(value => {
206
+ if (!value || joinedColorSchemes.match(value)) {
207
+ setColorScheme({
208
+ dark: value
209
+ });
210
+ }
211
+ }) || noop;
234
212
  return () => {
235
- storageWindow.removeEventListener('storage', handleStorage);
213
+ unsubscribeMode();
214
+ unsubscribeLight();
215
+ unsubscribeDark();
236
216
  };
237
217
  }
238
218
  return undefined;
239
- }, [setColorScheme, setMode, modeStorageKey, colorSchemeStorageKey, joinedColorSchemes, defaultMode, storageWindow, isMultiSchemes]);
219
+ }, [setColorScheme, setMode, joinedColorSchemes, defaultMode, storageWindow, isMultiSchemes, modeStorage, lightStorage, darkStorage]);
240
220
  return {
241
221
  ...state,
242
222
  mode: isClient ? state.mode : undefined,
package/modern/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/system v6.4.6
2
+ * @mui/system v6.4.7
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -1,6 +1,6 @@
1
- export const version = "6.4.6";
1
+ export const version = "6.4.7";
2
2
  export const major = Number("6");
3
3
  export const minor = Number("4");
4
- export const patch = Number("6");
4
+ export const patch = Number("7");
5
5
  export const prerelease = undefined;
6
6
  export default version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/system",
3
- "version": "6.4.6",
3
+ "version": "6.4.7",
4
4
  "private": false,
5
5
  "author": "MUI Team",
6
6
  "description": "MUI System is a set of CSS utilities to help you build custom designs more efficiently. It makes it possible to rapidly lay out custom designs.",
@@ -31,9 +31,9 @@
31
31
  "csstype": "^3.1.3",
32
32
  "prop-types": "^15.8.1",
33
33
  "@mui/private-theming": "^6.4.6",
34
+ "@mui/utils": "^6.4.6",
34
35
  "@mui/styled-engine": "^6.4.6",
35
- "@mui/types": "^7.2.21",
36
- "@mui/utils": "^6.4.6"
36
+ "@mui/types": "^7.2.21"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@emotion/react": "^11.5.0",
package/version/index.js CHANGED
@@ -4,9 +4,9 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.version = exports.prerelease = exports.patch = exports.minor = exports.major = exports.default = void 0;
7
- const version = exports.version = "6.4.6";
7
+ const version = exports.version = "6.4.7";
8
8
  const major = exports.major = Number("6");
9
9
  const minor = exports.minor = Number("4");
10
- const patch = exports.patch = Number("6");
10
+ const patch = exports.patch = Number("7");
11
11
  const prerelease = exports.prerelease = undefined;
12
12
  var _default = exports.default = version;