FactuGES_ERP/apps/web/src/lib/hooks/use-theme/theme-provider.tsx
2026-04-12 12:06:32 +02:00

78 lines
1.8 KiB
TypeScript

import { createContext, useEffect, useMemo, useState } from "react";
import secureLocalStorageImport from "react-secure-storage";
type Theme = "dark" | "light" | "system";
type ThemeProviderProps = {
children: React.ReactNode;
defaultTheme?: Theme;
storageKey?: string;
};
type ThemeProviderState = {
theme: Theme;
setTheme: (theme: Theme) => void;
};
const secureLocalStorage = (secureLocalStorageImport as any)?.default ?? secureLocalStorageImport;
const initialState: ThemeProviderState = {
theme: "system",
setTheme: () => null,
};
export const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
export const ThemeProvider = ({
children,
defaultTheme = "system",
storageKey = "vite-ui-theme",
...props
}: ThemeProviderProps) => {
const [theme, setThemeState] = useState<Theme>(() => {
try {
const stored = secureLocalStorage?.getItem?.(storageKey);
return (stored as Theme) || defaultTheme;
} catch {
return defaultTheme;
}
});
useEffect(() => {
const root = window.document.documentElement;
root.classList.remove("light", "dark");
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
root.classList.add(systemTheme);
return;
}
root.classList.add(theme);
}, [theme]);
const value = useMemo(
() => ({
theme,
setTheme: (nextTheme: Theme) => {
try {
secureLocalStorage?.setItem?.(storageKey, nextTheme);
} catch {
// fallback silencioso
}
setThemeState(nextTheme);
},
}),
[theme, storageKey]
);
return (
<ThemeProviderContext.Provider {...props} value={value}>
{children}
</ThemeProviderContext.Provider>
);
};