fix(admin): apply data-mode attribute for system theme preference (#97)
When theme is "system", ThemeProvider removed the data-mode attribute from <html>, expecting color-scheme: light dark to handle dark mode. However, Tailwind dark: utilities are mapped to [data-mode="dark"] via @custom-variant and do not respond to color-scheme, so dark mode never activated for system preference users. Decouple DOM synchronization from the theme preference by syncing data-mode with resolvedTheme instead. This ensures data-mode is always set to "light" or "dark" regardless of whether the user chose explicitly or follows system preference. Fixes #96 Co-authored-by: Matt Kane <mkane@cloudflare.com>
This commit is contained in:
@@ -44,29 +44,16 @@ export function ThemeProvider({ children, defaultTheme = "system" }: ThemeProvid
|
|||||||
return theme;
|
return theme;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update DOM and resolved theme when theme changes.
|
// Resolve the effective theme whenever the user preference changes
|
||||||
// Uses data-mode (not data-theme) for dark mode — kumo's convention.
|
|
||||||
// data-theme is reserved for visual identity overrides.
|
|
||||||
// Update DOM and resolved theme when theme changes.
|
|
||||||
// Uses data-mode (not data-theme) for dark mode — kumo's convention.
|
|
||||||
// data-theme is reserved for visual identity overrides (e.g. "classic").
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const root = document.documentElement;
|
|
||||||
|
|
||||||
// Apply classic visual identity at the root level
|
|
||||||
// so token overrides cascade to all kumo components including portals
|
|
||||||
root.setAttribute("data-theme", "classic");
|
|
||||||
|
|
||||||
if (theme === "system") {
|
if (theme === "system") {
|
||||||
root.removeAttribute("data-mode");
|
|
||||||
setResolvedTheme(getSystemTheme());
|
setResolvedTheme(getSystemTheme());
|
||||||
} else {
|
} else {
|
||||||
root.setAttribute("data-mode", theme);
|
|
||||||
setResolvedTheme(theme);
|
setResolvedTheme(theme);
|
||||||
}
|
}
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
// Listen for system theme changes when in system mode
|
// Listen for OS preference changes when in system mode
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (theme !== "system") return;
|
if (theme !== "system") return;
|
||||||
|
|
||||||
@@ -79,6 +66,17 @@ export function ThemeProvider({ children, defaultTheme = "system" }: ThemeProvid
|
|||||||
return () => mediaQuery.removeEventListener("change", handler);
|
return () => mediaQuery.removeEventListener("change", handler);
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
|
// Sync DOM attributes with the resolved theme.
|
||||||
|
// data-mode drives Tailwind dark: utilities via @custom-variant.
|
||||||
|
// data-theme is reserved for visual identity overrides (e.g. "classic").
|
||||||
|
// Always set data-mode explicitly — relying on its absence + color-scheme
|
||||||
|
// does not activate Tailwind dark: utilities which require [data-mode="dark"].
|
||||||
|
React.useEffect(() => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
root.setAttribute("data-theme", "classic");
|
||||||
|
root.setAttribute("data-mode", resolvedTheme);
|
||||||
|
}, [resolvedTheme]);
|
||||||
|
|
||||||
const setTheme = React.useCallback((newTheme: Theme) => {
|
const setTheme = React.useCallback((newTheme: Theme) => {
|
||||||
setThemeState(newTheme);
|
setThemeState(newTheme);
|
||||||
localStorage.setItem(STORAGE_KEY, newTheme);
|
localStorage.setItem(STORAGE_KEY, newTheme);
|
||||||
|
|||||||
@@ -19,13 +19,10 @@
|
|||||||
@custom-variant dark (&:where([data-mode="dark"], [data-mode="dark"] *));
|
@custom-variant dark (&:where([data-mode="dark"], [data-mode="dark"] *));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When no data-mode is set (system preference mode), follow the OS preference.
|
* ThemeProvider always sets data-mode to the resolved preference ("light" or "dark"),
|
||||||
* Kumo's base layer sets color-scheme: light on :root — override to light dark
|
* so Tailwind dark: utilities (mapped to [data-mode="dark"]) activate correctly
|
||||||
* so the browser respects prefers-color-scheme until the user explicitly picks.
|
* for both explicit and system-preference themes.
|
||||||
*/
|
*/
|
||||||
:root:not([data-mode]) {
|
|
||||||
color-scheme: light dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classic theme token overrides
|
* Classic theme token overrides
|
||||||
|
|||||||
Reference in New Issue
Block a user