-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathThemeProvider.tsx
90 lines (73 loc) · 2.81 KB
/
ThemeProvider.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import './style.css';
import { ReactNode, useEffect, useMemo, useState } from 'react';
import { App, ConfigProvider } from 'antd';
import type { ConfigProviderProps } from 'antd/es/config-provider';
import antdLocalePtBR from 'antd/locale/pt_BR';
import { AppBinder } from '.';
import createTheme, { BrandColor } from './createTheme';
import CssVariables from './CssVariables';
const mediaDark =
typeof window !== 'undefined' && window?.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
export interface ThemeProviderProps extends Omit<ConfigProviderProps, 'theme' | 'children' | 'componentSize'> {
brandColor: BrandColor | `#${string}`;
brandColorDark?: BrandColor | `#${string}`;
mode?: 'dark' | 'light' | 'system';
children: ReactNode;
enableAnimation?: boolean;
}
const ThemeProvider = ({
brandColor,
brandColorDark,
mode: modeProp = 'light',
enableAnimation,
children,
...configProps
}: ThemeProviderProps) => {
const [mode, setMode] = useState<'light' | 'dark'>(() => {
if (modeProp !== 'system') {
return modeProp;
}
return mediaDark?.matches ? 'dark' : 'light';
});
const theme = useMemo(() => {
document.body.classList.remove('eduzz-ui-disable-animation', 'eduzz-ui-light-theme', 'eduzz-ui-dark-theme');
document.body.classList.add(`eduzz-ui-${mode}-theme`);
!enableAnimation && document.body.classList.add('eduzz-ui-disable-animation');
return createTheme(
mode === 'light' ? brandColor : brandColorDark ?? '#eab208',
mode ?? 'light',
enableAnimation ?? false
);
}, [mode, brandColor, enableAnimation]);
useEffect(() => {
if (modeProp !== 'system') return setMode(modeProp ?? 'light');
if (!mediaDark) return setMode('light');
const listener = (event: MediaQueryListEvent) => setMode(() => (event.matches ? 'dark' : 'light'));
mediaDark.addEventListener('change', listener);
return () => mediaDark.removeEventListener('change', listener);
}, [modeProp]);
useEffect(() => {
const themeChangeObserver = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.attributeName !== 'data-eduzz-theme') {
return;
}
const attributes = (mutation.target as HTMLElement).attributes;
const currentTheme = attributes.getNamedItem('data-eduzz-theme')?.value as 'light' | 'dark';
setMode(currentTheme ?? 'light');
});
});
themeChangeObserver.observe(document.body, { attributes: true });
return () => themeChangeObserver.disconnect();
}, []);
return (
<ConfigProvider theme={theme} componentSize='large' locale={antdLocalePtBR} {...configProps}>
<App>
<AppBinder />
<CssVariables brandColor={brandColor} />
{children}
</App>
</ConfigProvider>
);
};
export default ThemeProvider;