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
|
import { useCallback, useContext, useEffect } from 'react';
import { themeValidator as isValidTheme } from '../../helpers';
import { PrismThemeContext } from '../../providers/prism-theme-provider';
export const usePrismTheme = () => {
const { attribute, resolvedTheme, setTheme, theme } =
useContext(PrismThemeContext);
const currentTheme = theme === 'system' ? resolvedTheme : theme;
const handleMutations: MutationCallback = useCallback(
(mutations) => {
for (const mutation of mutations) {
if (mutation.target.nodeName.toLowerCase() !== 'pre') return;
const newTheme = (mutation.target as HTMLPreElement).getAttribute(
attribute
);
if (isValidTheme(newTheme) && newTheme !== theme) setTheme(newTheme);
}
},
[attribute, setTheme, theme]
);
useEffect(() => {
if (typeof window === 'undefined') return undefined;
const preElements = document.getElementsByTagName('pre');
const observer = new MutationObserver(handleMutations);
for (const preEl of Array.from(preElements)) {
if (preEl.className.includes('language-')) {
preEl.setAttribute(attribute, theme);
observer.observe(preEl, {
attributes: true,
attributeFilter: [attribute],
});
}
}
return () => {
observer.disconnect();
};
}, [attribute, handleMutations, theme]);
const toggleTheme = useCallback(() => {
setTheme(() => {
if (currentTheme === 'dark') return 'light';
return 'dark';
});
}, [currentTheme, setTheme]);
return { currentTheme, resolvedTheme, setTheme, theme, toggleTheme };
};
|