Spaces:
Runtime error
Runtime error
| import { useState, useEffect } from "react"; | |
| /** | |
| * Shared singleton observer for data-theme + --primary-color. | |
| * Only one MutationObserver runs regardless of how many components subscribe. | |
| */ | |
| type ThemeListener = (isDark: boolean, primaryColor: string) => void; | |
| const listeners = new Set<ThemeListener>(); | |
| let observer: MutationObserver | null = null; | |
| let cachedDark = document.documentElement.getAttribute("data-theme") === "dark"; | |
| let cachedColor = | |
| getComputedStyle(document.documentElement) | |
| .getPropertyValue("--primary-color") | |
| .trim() || "#4e79a7"; | |
| function notify() { | |
| const dark = document.documentElement.getAttribute("data-theme") === "dark"; | |
| const color = | |
| getComputedStyle(document.documentElement) | |
| .getPropertyValue("--primary-color") | |
| .trim() || "#4e79a7"; | |
| const changed = dark !== cachedDark || color !== cachedColor; | |
| cachedDark = dark; | |
| cachedColor = color; | |
| if (changed) { | |
| for (const fn of listeners) fn(dark, color); | |
| } | |
| } | |
| function subscribe(fn: ThemeListener): () => void { | |
| listeners.add(fn); | |
| if (!observer) { | |
| observer = new MutationObserver(notify); | |
| observer.observe(document.documentElement, { | |
| attributes: true, | |
| attributeFilter: ["data-theme", "style"], | |
| }); | |
| } | |
| return () => { | |
| listeners.delete(fn); | |
| if (listeners.size === 0 && observer) { | |
| observer.disconnect(); | |
| observer = null; | |
| } | |
| }; | |
| } | |
| export function useTheme(): { isDark: boolean; primaryColor: string } { | |
| const [isDark, setIsDark] = useState(cachedDark); | |
| const [primaryColor, setPrimaryColor] = useState(cachedColor); | |
| useEffect(() => { | |
| return subscribe((dark, color) => { | |
| setIsDark(dark); | |
| setPrimaryColor(color); | |
| }); | |
| }, []); | |
| return { isDark, primaryColor }; | |
| } | |
| export function useIsDark(): boolean { | |
| const { isDark } = useTheme(); | |
| return isDark; | |
| } | |