3p1idvga1: Add dark and light design tokens with a persisted pre-paint theme
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useSyncExternalStore } from "react";
|
||||
import { applyTheme, currentTheme, DEFAULT_THEME, THEME_KEY, type Theme } from "./theme";
|
||||
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
function subscribe(listener: () => void): () => void {
|
||||
listeners.add(listener);
|
||||
const onStorage = (event: StorageEvent) => {
|
||||
// Another tab changed the theme: follow it.
|
||||
if (event.key !== THEME_KEY) return;
|
||||
const next = event.newValue === "light" || event.newValue === "dark" ? event.newValue : DEFAULT_THEME;
|
||||
applyTheme(next, document.documentElement, null);
|
||||
listeners.forEach((l) => l());
|
||||
};
|
||||
window.addEventListener("storage", onStorage);
|
||||
return () => {
|
||||
listeners.delete(listener);
|
||||
window.removeEventListener("storage", onStorage);
|
||||
};
|
||||
}
|
||||
|
||||
const getSnapshot = (): Theme => currentTheme(document.documentElement);
|
||||
const getServerSnapshot = (): Theme => DEFAULT_THEME;
|
||||
|
||||
function safeStorage(): Storage | null {
|
||||
try {
|
||||
return window.localStorage;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Shared theme state for every toggle: the current theme and a setter. */
|
||||
export function useTheme(): { theme: Theme; setTheme: (theme: Theme) => void; toggleTheme: () => void } {
|
||||
const theme = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
||||
const setTheme = useCallback((next: Theme) => {
|
||||
applyTheme(next, document.documentElement, safeStorage());
|
||||
listeners.forEach((l) => l());
|
||||
}, []);
|
||||
const toggleTheme = useCallback(() => setTheme(getSnapshot() === "dark" ? "light" : "dark"), [setTheme]);
|
||||
return { theme, setTheme, toggleTheme };
|
||||
}
|
||||
Reference in New Issue
Block a user