|
1 | 1 | import { useEffect, useState } from 'react';
|
2 | 2 | import useMemoizedFn from '../useMemoizedFn';
|
3 | 3 |
|
| 4 | +export enum ThemeMode { |
| 5 | + LIGHT = 'light', |
| 6 | + DARK = 'dark', |
| 7 | + SYSTEM = 'system', |
| 8 | +} |
| 9 | + |
| 10 | +export type ThemeModeType = `${ThemeMode}`; |
| 11 | + |
4 | 12 | const matchMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
5 | 13 |
|
6 | 14 | function useCurrentTheme() {
|
7 | 15 | const [theme, setTheme] = useState<'light' | 'dark'>(() => {
|
8 |
| - return matchMedia.matches ? 'dark' : 'light'; |
| 16 | + return matchMedia.matches ? ThemeMode.DARK : ThemeMode.LIGHT; |
9 | 17 | });
|
10 | 18 |
|
11 | 19 | useEffect(() => {
|
12 |
| - // 监听系统颜色切换 |
13 |
| - const listener: MediaQueryList['onchange'] = (event) => { |
| 20 | + const onThemeChange: MediaQueryList['onchange'] = (event) => { |
14 | 21 | if (event.matches) {
|
15 |
| - setTheme('dark'); |
| 22 | + setTheme(ThemeMode.DARK); |
16 | 23 | } else {
|
17 |
| - setTheme('light'); |
| 24 | + setTheme(ThemeMode.LIGHT); |
18 | 25 | }
|
19 | 26 | };
|
20 | 27 |
|
21 |
| - matchMedia.addEventListener('change', listener); |
| 28 | + matchMedia.addEventListener('change', onThemeChange); |
22 | 29 |
|
23 | 30 | return () => {
|
24 |
| - matchMedia.removeEventListener('change', listener); |
| 31 | + matchMedia.removeEventListener('change', onThemeChange); |
25 | 32 | };
|
26 | 33 | }, []);
|
| 34 | + |
27 | 35 | return theme;
|
28 | 36 | }
|
29 | 37 |
|
30 |
| -export type ThemeModeType = 'light' | 'dark' | 'system'; |
31 |
| - |
32 |
| -type PropsType = { |
| 38 | +type Options = { |
33 | 39 | localStorageKey?: string;
|
34 | 40 | };
|
35 | 41 |
|
36 |
| -export function useTheme(props: PropsType = {}) { |
37 |
| - const { localStorageKey } = props; |
| 42 | +export default function useTheme(options: Options = {}) { |
| 43 | + const { localStorageKey } = options; |
| 44 | + |
38 | 45 | const [themeMode, setThemeMode] = useState<ThemeModeType>(() => {
|
39 | 46 | const preferredThemeMode =
|
40 | 47 | localStorageKey?.length && (localStorage.getItem(localStorageKey) as ThemeModeType | null);
|
41 |
| - return preferredThemeMode ? preferredThemeMode : 'system'; |
| 48 | + |
| 49 | + return preferredThemeMode ? preferredThemeMode : ThemeMode.SYSTEM; |
42 | 50 | });
|
43 | 51 |
|
44 | 52 | const setThemeModeWithLocalStorage = (mode: ThemeModeType) => {
|
45 | 53 | setThemeMode(mode);
|
46 |
| - localStorageKey?.length && localStorage.setItem(localStorageKey, mode); |
| 54 | + |
| 55 | + if (localStorageKey?.length) { |
| 56 | + localStorage.setItem(localStorageKey, mode); |
| 57 | + } |
47 | 58 | };
|
48 | 59 |
|
49 | 60 | const currentTheme = useCurrentTheme();
|
50 |
| - |
51 |
| - const theme = themeMode === 'system' ? currentTheme : themeMode; |
| 61 | + const theme = themeMode === ThemeMode.SYSTEM ? currentTheme : themeMode; |
52 | 62 |
|
53 | 63 | return {
|
54 | 64 | theme,
|
|
0 commit comments