mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-23 05:57:05 +02:00
* refactor color mode system to enable all possibilities * fix destructuring bug * colorMode validation + deprecation + minor name changes + doc * rename method noFlashColorMode * fix doc wording * docs wording * docs wording * re-enable theme config merging/normalization + colorMode fixes * document theme normalization * code review changes
97 lines
2.2 KiB
TypeScript
97 lines
2.2 KiB
TypeScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import {useState, useCallback, useEffect} from 'react';
|
|
|
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
|
|
|
const themes = {
|
|
light: 'light',
|
|
dark: 'dark',
|
|
};
|
|
|
|
// Ensure to always return a valid theme even if input is invalid
|
|
const coerceToTheme = (theme) => {
|
|
return theme === themes.dark ? themes.dark : themes.light;
|
|
};
|
|
|
|
const getInitialTheme = () => {
|
|
if (!ExecutionEnvironment.canUseDOM) {
|
|
return themes.light; // SSR: we don't care
|
|
}
|
|
return coerceToTheme(document.documentElement.getAttribute('data-theme'));
|
|
};
|
|
|
|
const storeTheme = (newTheme) => {
|
|
try {
|
|
localStorage.setItem('theme', coerceToTheme(newTheme));
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
};
|
|
|
|
const useTheme = (): {
|
|
isDarkTheme: boolean;
|
|
setLightTheme: () => void;
|
|
setDarkTheme: () => void;
|
|
} => {
|
|
const {
|
|
siteConfig: {
|
|
themeConfig: {colorMode: {disableSwitch = false} = {}} = {},
|
|
} = {},
|
|
} = useDocusaurusContext();
|
|
const [theme, setTheme] = useState(getInitialTheme);
|
|
|
|
const setLightTheme = useCallback(() => {
|
|
setTheme(themes.light);
|
|
storeTheme(themes.light);
|
|
}, []);
|
|
const setDarkTheme = useCallback(() => {
|
|
setTheme(themes.dark);
|
|
storeTheme(themes.dark);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
document.documentElement.setAttribute('data-theme', coerceToTheme(theme));
|
|
}, [theme]);
|
|
|
|
useEffect(() => {
|
|
if (disableSwitch) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const localStorageTheme = localStorage.getItem('theme');
|
|
if (localStorageTheme !== null) {
|
|
setTheme(coerceToTheme(localStorageTheme));
|
|
}
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
}, [setTheme]);
|
|
|
|
useEffect(() => {
|
|
if (disableSwitch) {
|
|
return;
|
|
}
|
|
|
|
window
|
|
.matchMedia('(prefers-color-scheme: dark)')
|
|
.addListener(({matches}) => {
|
|
setTheme(matches ? themes.dark : themes.light);
|
|
});
|
|
}, []);
|
|
|
|
return {
|
|
isDarkTheme: theme === themes.dark,
|
|
setLightTheme,
|
|
setDarkTheme,
|
|
};
|
|
};
|
|
|
|
export default useTheme;
|