-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy paththeme.tsx
More file actions
120 lines (107 loc) · 4.19 KB
/
theme.tsx
File metadata and controls
120 lines (107 loc) · 4.19 KB
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import {
useState,
useEffect,
createContext,
useContext,
useCallback,
useMemo,
} from 'react';
import { currentTheme, refreshTheme } from 'devextreme/viz/themes';
import {
storageKey,
baseThemeMarker,
additionalThemeMarker,
swatchColors,
} from '../utils/theme-constants';
import type { ThemeContextType, ThemeData, ThemeSwatchAccent } from '../types';
function getThemeData(): ThemeData[] {
return [
{ text: 'Orange Light', value: 'orange.light', ImageSrc: '/icons/Component1.svg' },
{ text: 'Blue Light', value: 'blue.light', ImageSrc: '/icons/Component2.svg' },
{ text: 'Purple Light', value: 'purple.light', ImageSrc: '/icons/Component3.svg' },
{ text: 'Purple Dark', value: 'purple.dark', ImageSrc: '/icons/Component4.svg' },
];
}
const ThemeContext = createContext<ThemeContextType>({} as ThemeContextType);
function useTheme(): ThemeContextType {
return useContext<ThemeContextType>(ThemeContext);
}
function ThemeProvider({ theme, ...props }: React.PropsWithChildren<{ theme?: string }>): JSX.Element {
const [themeState, setTheme] = useState(theme);
const getTheme = useCallback(
() => themeState ?? window.localStorage[storageKey] as string ?? 'orange.light',
[themeState],
);
const applyBaseTheme = useCallback((themeName: string, themeMarker: string) => {
for (const styleSheet of document.styleSheets) {
const href = styleSheet.href;
if (href) {
const themeMarkerPosition: number = href.indexOf(themeMarker);
if (themeMarkerPosition >= 0) {
const startPosition = themeMarkerPosition + themeMarker.length;
const endPosition = href.indexOf('.css');
const fileNamePart = href.substring(startPosition, endPosition);
if (fileNamePart === themeName) {
for (let i = 0; i < styleSheet.cssRules.length; i++) {
const cssRule = styleSheet.cssRules.item(i) as CSSStyleRule;
if (cssRule?.selectorText === '.dx-theme-accent-as-text-color') {
document.documentElement.style.setProperty('--base-accent', cssRule.style.color);
}
if (cssRule?.selectorText === '.dx-theme-text-color') {
document.documentElement.style.setProperty('--base-text-color', cssRule.style.color);
}
}
}
styleSheet.disabled = fileNamePart != themeName;
}
}
}
}, []);
const applySwatchVariables = useCallback((accent: ThemeSwatchAccent) => {
document.documentElement.style.setProperty('--base-border-color', swatchColors[accent].borderColor);
document.documentElement.style.setProperty('--base-bg', swatchColors[accent].bg);
document.documentElement.style.setProperty('--icon-color', swatchColors[accent].iconColor);
}, []);
const applySwatchTheme = useCallback((accent: ThemeSwatchAccent, themeMarker: string) => {
for (const styleSheet of document.styleSheets) {
const href = styleSheet.href;
if (href) {
const themeMarkerPosition: number = href.indexOf(themeMarker);
if (themeMarkerPosition >= 0) {
const startPosition = themeMarkerPosition + themeMarker.length;
const endPosition = href.indexOf('.css');
const fileNamePart = href.substring(startPosition, endPosition);
styleSheet.disabled = !(accent === fileNamePart.substring((fileNamePart.indexOf('.') as number) + 1));
}
}
}
}, []);
const applyTheme = useCallback(() => {
const appliedTheme = getTheme();
applyBaseTheme(appliedTheme, baseThemeMarker);
const accent = appliedTheme?.substring(appliedTheme.indexOf('.') + 1) as ThemeSwatchAccent;
applySwatchVariables(accent);
applySwatchTheme(accent, additionalThemeMarker);
window.localStorage[storageKey] = appliedTheme;
currentTheme(`'material.'${appliedTheme}`);
refreshTheme();
}, [getTheme]);
useEffect(() => {
applyTheme();
}, [themeState, applyTheme]);
const themeContextValue = useMemo<ThemeContextType>(() => ({
getThemeData,
getTheme,
setTheme,
}), [getThemeData, getTheme, setTheme]);
return (
<ThemeContext.Provider
value={themeContextValue}
{...props}
/>
);
}
export {
ThemeProvider,
useTheme,
};