ldc-laravel-base-project/resources/ts/back/providers/ThemeProvider.tsx
2026-07-09 17:32:17 +02:00

76 lines
1.6 KiB
TypeScript

import {
createContext,
type ReactNode,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import type { Theme } from "@/back/types/global";
interface ThemeProviderProps {
children: ReactNode;
defaultTheme?: Theme;
storageKey?: string;
}
interface ThemeProviderState {
theme: Theme;
setTheme: (theme: Theme) => void;
}
const initialState: ThemeProviderState = {
theme: "light",
setTheme: () => {
/* empty */
},
};
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
export function ThemeProvider({
children,
defaultTheme = "light",
storageKey = "vite-ui-theme",
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(() => {
if (typeof localStorage === "undefined") return defaultTheme;
const storedTheme = localStorage.getItem(storageKey) as Theme | null;
return storedTheme ?? defaultTheme;
});
useEffect(() => {
const root = window.document.documentElement;
root.classList.remove("light", "dark");
root.classList.add(theme);
}, [theme]);
const value = useMemo(
() => ({
theme,
setTheme: (newTheme: Theme) => {
localStorage.setItem(storageKey, newTheme);
setTheme(newTheme);
},
}),
[theme, setTheme, storageKey],
);
return (
<ThemeProviderContext.Provider value={value}>
{children}
</ThemeProviderContext.Provider>
);
}
export const useTheme = () => {
const context = useContext(ThemeProviderContext) as
ThemeProviderState | undefined;
if (context === undefined) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
};