import type { Theme, ThemeProviderProps, ThemeProviderState } from "$/types/Theme"; import { createContext, useContext, useEffect, useMemo, useState } from "react"; const themeInitialState: ThemeProviderState = { theme: "system", setTheme: () => null } const ThemeProviderContext = createContext(themeInitialState); export default function ThemeProvider(props: ThemeProviderProps){ const { children, defaultTheme = "system", storageKey = "mattrixwv-ui-theme" } = props; const [ theme, setTheme ] = useState((localStorage.getItem(storageKey) as Theme) || defaultTheme); useEffect(() => { const root = window.document.documentElement; root.classList.remove("light", "dark"); if(theme === "system"){ const systemTheme = window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"; root.classList.add(systemTheme); } else{ root.classList.add(theme); } }, [ theme ]); const value: ThemeProviderState = useMemo(() => ({ theme, setTheme: (theme: Theme) => { localStorage.setItem(storageKey, theme); setTheme(theme); } }), [storageKey, theme]); return ( {children} ); } // eslint-disable-next-line react-refresh/only-export-components export function useTheme(){ const context = useContext(ThemeProviderContext); if(!context){ throw new Error("useTheme must be used within a ThemeProvider"); } return context; }