From 3b97b21f4635cd28741f8a1e5a080930d298c171 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 9 Aug 2022 22:46:23 +0700 Subject: [PATCH 1/7] fix useCurrentColorScheme --- .../src/cssVars/useCurrentColorScheme.ts | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index 581ceca1476c9f..fa0a5b1c8072d6 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -130,11 +130,26 @@ export default function useCurrentColorScheme { const initialMode = resolveValue(modeStorageKey, defaultMode); + const systemMode = getSystemMode(initialMode); + const lightColorScheme = + resolveValue(`${colorSchemeStorageKey}-light`) || defaultLightColorScheme; + const darkColorScheme = resolveValue(`${colorSchemeStorageKey}-dark`) || defaultDarkColorScheme; + if (typeof window !== 'undefined') { + if (initialMode) { + localStorage.setItem(modeStorageKey, initialMode); + } + if (lightColorScheme) { + localStorage.setItem(`${colorSchemeStorageKey}-light`, lightColorScheme); + } + if (darkColorScheme) { + localStorage.setItem(`${colorSchemeStorageKey}-dark`, darkColorScheme); + } + } return { mode: initialMode, - systemMode: getSystemMode(initialMode), - lightColorScheme: resolveValue(`${colorSchemeStorageKey}-light`) || defaultLightColorScheme, - darkColorScheme: resolveValue(`${colorSchemeStorageKey}-dark`) || defaultDarkColorScheme, + systemMode, + lightColorScheme, + darkColorScheme, } as State; }); @@ -243,21 +258,6 @@ export default function useCurrentColorScheme media.removeListener(handler); }, []); - // Save mode, lightColorScheme & darkColorScheme to localStorage - React.useEffect(() => { - if (state.mode) { - localStorage.setItem(modeStorageKey, state.mode); - } - processState(state, (mode) => { - if (mode === 'light') { - localStorage.setItem(`${colorSchemeStorageKey}-light`, state.lightColorScheme); - } - if (mode === 'dark') { - localStorage.setItem(`${colorSchemeStorageKey}-dark`, state.darkColorScheme); - } - }); - }, [state, colorSchemeStorageKey, modeStorageKey]); - // Handle when localStorage has changed React.useEffect(() => { const handleStorage = (event: StorageEvent) => { From 8472f9bf2e49fecccc9c49bced2e83ca758aa603 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 15 Aug 2022 14:13:31 +0700 Subject: [PATCH 2/7] simplify --- .../src/cssVars/useCurrentColorScheme.ts | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index fa0a5b1c8072d6..ce177a2449fb4a 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -90,13 +90,17 @@ export function getColorScheme( }); } -function resolveValue(key: string, defaultValue?: string) { +function initializeValue(key: string, defaultValue: string) { if (typeof window === 'undefined') { return undefined; } let value; try { - value = localStorage.getItem(key) || undefined; + value = localStorage.getItem(key); + if (!value) { + // the first time that user enters the site. + localStorage.setItem(key, defaultValue); + } } catch (e) { // Unsupported } @@ -129,27 +133,12 @@ export default function useCurrentColorScheme { - const initialMode = resolveValue(modeStorageKey, defaultMode); - const systemMode = getSystemMode(initialMode); - const lightColorScheme = - resolveValue(`${colorSchemeStorageKey}-light`) || defaultLightColorScheme; - const darkColorScheme = resolveValue(`${colorSchemeStorageKey}-dark`) || defaultDarkColorScheme; - if (typeof window !== 'undefined') { - if (initialMode) { - localStorage.setItem(modeStorageKey, initialMode); - } - if (lightColorScheme) { - localStorage.setItem(`${colorSchemeStorageKey}-light`, lightColorScheme); - } - if (darkColorScheme) { - localStorage.setItem(`${colorSchemeStorageKey}-dark`, darkColorScheme); - } - } + const initialMode = initializeValue(modeStorageKey, defaultMode); return { mode: initialMode, - systemMode, - lightColorScheme, - darkColorScheme, + systemMode: getSystemMode(initialMode), + lightColorScheme: initializeValue(`${colorSchemeStorageKey}-light`, defaultLightColorScheme), + darkColorScheme: initializeValue(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme), } as State; }); From b23256b08bcc56100b2125a39df292a387e55c7f Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 15 Aug 2022 15:29:46 +0700 Subject: [PATCH 3/7] remove unnecessary test --- packages/mui-system/src/cssVars/createCssVarsProvider.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js index ceb7ae8abc104c..8002df94e874fe 100644 --- a/packages/mui-system/src/cssVars/createCssVarsProvider.test.js +++ b/packages/mui-system/src/cssVars/createCssVarsProvider.test.js @@ -611,7 +611,6 @@ describe('createCssVarsProvider', () => { ); expect(screen.getByTestId('current-mode').textContent).to.equal('dark'); - expect(global.localStorage.setItem.calledWith(customModeStorageKey, 'dark')).to.equal(true); }); it('support custom storage window', () => { From 117f3db2e726ec9713d32932612187f3c07427b0 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 15 Aug 2022 17:36:59 +0700 Subject: [PATCH 4/7] update --- .../src/cssVars/useCurrentColorScheme.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index ce177a2449fb4a..bc924c62fd4ace 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -96,7 +96,7 @@ function initializeValue(key: string, defaultValue: string) { } let value; try { - value = localStorage.getItem(key); + value = localStorage.getItem(key) || undefined; if (!value) { // the first time that user enters the site. localStorage.setItem(key, defaultValue); @@ -134,11 +134,19 @@ export default function useCurrentColorScheme { const initialMode = initializeValue(modeStorageKey, defaultMode); + const lightColorScheme = initializeValue( + `${colorSchemeStorageKey}-light`, + defaultLightColorScheme, + ); + const darkColorScheme = initializeValue( + `${colorSchemeStorageKey}-dark`, + defaultDarkColorScheme, + ); return { mode: initialMode, systemMode: getSystemMode(initialMode), - lightColorScheme: initializeValue(`${colorSchemeStorageKey}-light`, defaultLightColorScheme), - darkColorScheme: initializeValue(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme), + lightColorScheme, + darkColorScheme, } as State; }); From 54e8f12ecb2575d5513fc243078260136c9fba2b Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 15 Aug 2022 17:37:18 +0700 Subject: [PATCH 5/7] clear storage before each test --- .../fixtures/CssVarsProvider/ColorSchemeSelector.js | 4 ++-- .../fixtures/CssVarsProvider/DarkModeSpecificity.js | 2 +- .../fixtures/CssVarsProvider/ForceColorSchemes.js | 4 ++-- test/regressions/index.test.js | 6 ++++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js b/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js index 91e4dc99599298..f4b427bbce4990 100644 --- a/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js +++ b/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js @@ -18,9 +18,9 @@ const { CssVarsProvider } = createCssVarsProvider({ }, }); -export default function DarkModeSpecificity() { +export default function ColorSchemeSelector() { return ( - + ({ p: 2, diff --git a/test/regressions/fixtures/CssVarsProvider/DarkModeSpecificity.js b/test/regressions/fixtures/CssVarsProvider/DarkModeSpecificity.js index 2a17dfd282edc9..007c0d5725969d 100644 --- a/test/regressions/fixtures/CssVarsProvider/DarkModeSpecificity.js +++ b/test/regressions/fixtures/CssVarsProvider/DarkModeSpecificity.js @@ -33,7 +33,7 @@ const DarkMode = () => { export default function DarkModeSpecificity() { return ( - +
Background should be #000. diff --git a/test/regressions/fixtures/CssVarsProvider/ForceColorSchemes.js b/test/regressions/fixtures/CssVarsProvider/ForceColorSchemes.js index ac4d32aa14618b..ada5f9efcd66c0 100644 --- a/test/regressions/fixtures/CssVarsProvider/ForceColorSchemes.js +++ b/test/regressions/fixtures/CssVarsProvider/ForceColorSchemes.js @@ -22,9 +22,9 @@ const { CssVarsProvider } = createCssVarsProvider({ }, }); -export default function DarkModeSpecificity() { +export default function ForceColorSchemes() { return ( - +
{ + beforeEach(async () => { + await page.evaluate(() => { + localStorage.clear(); + }); + }); + after(async () => { await browser.close(); }); From a33c8ed63647d3c7e522a49ece2dfa8a9ae72338 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Mon, 15 Aug 2022 17:41:23 +0700 Subject: [PATCH 6/7] fix missing dark --- test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js b/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js index f4b427bbce4990..37d0ede51be18e 100644 --- a/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js +++ b/test/regressions/fixtures/CssVarsProvider/ColorSchemeSelector.js @@ -15,6 +15,7 @@ const { CssVarsProvider } = createCssVarsProvider({ }, defaultColorScheme: { light: 'light', + dark: 'dark', }, }); From 8847f8f4773b3a11e2682bc6ca807c6677c85c9b Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 24 Aug 2022 13:38:42 +0700 Subject: [PATCH 7/7] add more tests --- .../src/cssVars/useCurrentColorScheme.test.js | 134 +++++++++++++++++- .../src/cssVars/useCurrentColorScheme.ts | 72 ++++++---- 2 files changed, 175 insertions(+), 31 deletions(-) diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js index 1f944463c821ae..80fbcfe8adee89 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.test.js @@ -324,6 +324,73 @@ describe('useCurrentColorScheme', () => { }); }); + it('change only the mode specified as key', () => { + const Data = () => { + const { setColorScheme, ...data } = useCurrentColorScheme({ + defaultMode: 'light', + defaultLightColorScheme: 'light', + defaultDarkColorScheme: 'dark', + supportedColorSchemes: ['light', 'paper', 'dark', 'dim'], + }); + return ( +
+
{JSON.stringify(data)}
+ + +
+ ); + }; + const { getByText, getByTestId } = render(); + + fireEvent.click(getByText('first')); + + expect(JSON.parse(getByTestId('data').textContent)).to.deep.equal({ + mode: 'light', + lightColorScheme: 'paper', + darkColorScheme: 'dark', + colorScheme: 'paper', + }); + + fireEvent.click(getByText('second')); + + expect(JSON.parse(getByTestId('data').textContent)).to.deep.equal({ + mode: 'light', + lightColorScheme: 'paper', + darkColorScheme: 'dim', + colorScheme: 'paper', + }); + }); + + it('able to setMode and setColorScheme in the same event', () => { + const Data = () => { + const { setColorScheme, setMode, ...data } = useCurrentColorScheme({ + defaultLightColorScheme: 'light', + defaultDarkColorScheme: 'dark', + supportedColorSchemes: ['light', 'paper', 'dark', 'dim'], + }); + return ( + + ); + }; + const { container } = render(); + + fireEvent.click(container.firstChild); + + expect(JSON.parse(container.firstChild.textContent)).to.deep.equal({ + mode: 'dark', + lightColorScheme: 'paper', + darkColorScheme: 'dim', + colorScheme: 'dim', + }); + }); + it('reset colorScheme', () => { const Data = () => { const { setColorScheme, ...data } = useCurrentColorScheme({ @@ -411,9 +478,9 @@ describe('useCurrentColorScheme', () => { fireEvent.click(container.firstChild); - expect(global.localStorage.setItem.calledWith(DEFAULT_MODE_STORAGE_KEY, 'dark')).to.equal( - true, - ); + expect( + global.localStorage.setItem.lastCall.calledWith(DEFAULT_MODE_STORAGE_KEY, 'dark'), + ).to.equal(true); }); it('save system mode', () => { @@ -624,5 +691,66 @@ describe('useCurrentColorScheme', () => { colorScheme: 'dark-dim', }); }); + + it('reset mode in storage', () => { + const Data = () => { + const { setMode } = useCurrentColorScheme({ + defaultMode: 'system', + defaultLightColorScheme: 'light', + defaultDarkColorScheme: 'dark', + supportedColorSchemes: ['light', 'dark'], + }); + return ( +
+
+ ); + }; + render(); + + fireEvent.click(screen.getByTestId('dark')); + + fireEvent.click(screen.getByTestId('reset')); + + expect( + global.localStorage.setItem.lastCall.calledWith(DEFAULT_MODE_STORAGE_KEY, 'system'), + ).to.equal(true); + }); + + it('reset color scheme in storage', () => { + const Data = () => { + const { setColorScheme } = useCurrentColorScheme({ + defaultMode: 'system', + defaultLightColorScheme: 'light', + defaultDarkColorScheme: 'dark', + supportedColorSchemes: ['light', 'dark'], + }); + return ( +
+
+ ); + }; + render(); + + fireEvent.click(screen.getByTestId('dark')); + + global.localStorage.setItem.resetHistory(); + expect(global.localStorage.setItem.callCount).to.equal(0); // reset the calls to neglect inital setItem in the assertion below + + fireEvent.click(screen.getByTestId('reset')); + + expect( + global.localStorage.setItem.calledWith( + `${DEFAULT_COLOR_SCHEME_STORAGE_KEY}-light`, + 'light', + ), + ).to.equal(true); + expect( + global.localStorage.setItem.calledWith(`${DEFAULT_COLOR_SCHEME_STORAGE_KEY}-dark`, 'dark'), + ).to.equal(true); + }); }); }); diff --git a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts index bf21a9e7afa8b9..69f8c543b7d421 100644 --- a/packages/mui-system/src/cssVars/useCurrentColorScheme.ts +++ b/packages/mui-system/src/cssVars/useCurrentColorScheme.ts @@ -155,10 +155,11 @@ export default function useCurrentColorScheme['setMode'] = React.useCallback( (mode) => { setState((currentState) => { - const newMode = !mode ? defaultMode : mode; if (mode === currentState.mode) { + // do nothing if mode does not change return currentState; } + const newMode = !mode ? defaultMode : mode; try { localStorage.setItem(modeStorageKey, newMode); } catch (e) { @@ -176,18 +177,26 @@ export default function useCurrentColorScheme['setColorScheme'] = React.useCallback( (value) => { - if (!value || typeof value === 'string') { + if (!value) { + setState((currentState) => { + try { + localStorage.setItem(`${colorSchemeStorageKey}-light`, defaultLightColorScheme); + localStorage.setItem(`${colorSchemeStorageKey}-dark`, defaultDarkColorScheme); + } catch (e) { + // Unsupported + } + return { + ...currentState, + lightColorScheme: defaultLightColorScheme, + darkColorScheme: defaultDarkColorScheme, + }; + }); + } else if (typeof value === 'string') { if (value && !joinedColorSchemes.includes(value)) { console.error(`\`${value}\` does not exist in \`theme.colorSchemes\`.`); } else { setState((currentState) => { const newState = { ...currentState }; - if (!value) { - // reset to default color scheme - newState.lightColorScheme = defaultLightColorScheme; - newState.darkColorScheme = defaultDarkColorScheme; - return newState; - } processState(currentState, (mode) => { try { localStorage.setItem(`${colorSchemeStorageKey}-${mode}`, value); @@ -204,33 +213,40 @@ export default function useCurrentColorScheme { const newState = { ...currentState }; - if (value.light || value.light === null) { - newState.lightColorScheme = - value.light === null ? defaultLightColorScheme : value.light; + const newLightColorScheme = value.light === null ? defaultLightColorScheme : value.light; + const newDarkColorScheme = value.dark === null ? defaultDarkColorScheme : value.dark; + + if (newLightColorScheme) { + if (!joinedColorSchemes.includes(newLightColorScheme)) { + console.error(`\`${newLightColorScheme}\` does not exist in \`theme.colorSchemes\`.`); + } else { + newState.lightColorScheme = newLightColorScheme; + try { + localStorage.setItem(`${colorSchemeStorageKey}-light`, newLightColorScheme); + } catch (error) { + // Unsupported + } + } } - if (value.dark || value.dark === null) { - newState.darkColorScheme = value.dark === null ? defaultDarkColorScheme : value.dark; + + if (newDarkColorScheme) { + if (!joinedColorSchemes.includes(newDarkColorScheme)) { + console.error(`\`${newDarkColorScheme}\` does not exist in \`theme.colorSchemes\`.`); + } else { + newState.darkColorScheme = newDarkColorScheme; + try { + localStorage.setItem(`${colorSchemeStorageKey}-dark`, newDarkColorScheme); + } catch (error) { + // Unsupported + } + } } + return newState; }); - try { - if (value.light) { - localStorage.setItem(`${colorSchemeStorageKey}-light`, value.light); - } - if (value.dark) { - localStorage.setItem(`${colorSchemeStorageKey}-dark`, value.dark); - } - } catch (e) { - // Unsupported - } } }, [joinedColorSchemes, colorSchemeStorageKey, defaultLightColorScheme, defaultDarkColorScheme],