import { useCallback, useSyncExternalStore } from 'react' type Theme = 'dark' | 'light' const STORAGE_KEY = 'ant-theme' function getSystemTheme(): Theme { return window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark' } function getStoredTheme(): Theme | null { const stored = localStorage.getItem(STORAGE_KEY) if (stored === 'dark' || stored === 'light') return stored return null } function applyTheme(theme: Theme) { if (theme === 'light') { document.documentElement.setAttribute('data-theme', 'light') } else { document.documentElement.removeAttribute('data-theme') } document.documentElement.style.colorScheme = theme } const listeners = new Set<() => void>() let currentTheme: Theme = getStoredTheme() ?? getSystemTheme() applyTheme(currentTheme) const mediaQuery = window.matchMedia('(prefers-color-scheme: light)') mediaQuery.addEventListener('change', () => { if (!getStoredTheme()) { currentTheme = getSystemTheme() applyTheme(currentTheme) for (const listener of listeners) listener() } }) function subscribe(listener: () => void) { listeners.add(listener) return () => { listeners.delete(listener) } } function getSnapshot(): Theme { return currentTheme } export function useTheme() { const theme = useSyncExternalStore(subscribe, getSnapshot) const toggle = useCallback(() => { const next: Theme = currentTheme === 'dark' ? 'light' : 'dark' currentTheme = next localStorage.setItem(STORAGE_KEY, next) applyTheme(next) for (const listener of listeners) listener() }, []) return { theme, toggle } as const }