diff --git a/packages/admin/src/components/ThemeProvider.tsx b/packages/admin/src/components/ThemeProvider.tsx index 22aeeb6..3e6a1a3 100644 --- a/packages/admin/src/components/ThemeProvider.tsx +++ b/packages/admin/src/components/ThemeProvider.tsx @@ -44,29 +44,16 @@ export function ThemeProvider({ children, defaultTheme = "system" }: ThemeProvid return theme; }); - // 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. - // 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"). + // Resolve the effective theme whenever the user preference changes 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") { - root.removeAttribute("data-mode"); setResolvedTheme(getSystemTheme()); } else { - root.setAttribute("data-mode", theme); setResolvedTheme(theme); } }, [theme]); - // Listen for system theme changes when in system mode + // Listen for OS preference changes when in system mode React.useEffect(() => { if (theme !== "system") return; @@ -79,6 +66,17 @@ export function ThemeProvider({ children, defaultTheme = "system" }: ThemeProvid return () => mediaQuery.removeEventListener("change", handler); }, [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) => { setThemeState(newTheme); localStorage.setItem(STORAGE_KEY, newTheme); diff --git a/packages/admin/src/styles.css b/packages/admin/src/styles.css index f365908..7dd5391 100644 --- a/packages/admin/src/styles.css +++ b/packages/admin/src/styles.css @@ -19,13 +19,10 @@ @custom-variant dark (&:where([data-mode="dark"], [data-mode="dark"] *)); /* - * When no data-mode is set (system preference mode), follow the OS preference. - * Kumo's base layer sets color-scheme: light on :root — override to light dark - * so the browser respects prefers-color-scheme until the user explicitly picks. + * ThemeProvider always sets data-mode to the resolved preference ("light" or "dark"), + * so Tailwind dark: utilities (mapped to [data-mode="dark"]) activate correctly + * for both explicit and system-preference themes. */ -:root:not([data-mode]) { - color-scheme: light dark; -} /** * Classic theme token overrides