UNPKG

flex-theme

Version:

A flexible theming system for web applications

104 lines (103 loc) 2.94 kB
// src/theme.ts var currentTheme = "system"; var listeners = []; function safeMatchMedia(query) { if (typeof window === "undefined") return false; if (typeof window.matchMedia !== "function") return false; return window.matchMedia(query).matches; } function initTheme() { if (typeof window === "undefined") return; const savedTheme = localStorage.getItem("theme"); if (savedTheme && ["light", "dark", "system"].includes(savedTheme)) { currentTheme = savedTheme; } else { currentTheme = "system"; } applyTheme(); } function applyTheme() { if (typeof window === "undefined" || !document) return; let effectiveTheme = currentTheme; if (effectiveTheme === "system") { effectiveTheme = safeMatchMedia("(prefers-color-scheme: dark)") ? "dark" : "light"; } if (effectiveTheme === "dark") { document.documentElement.classList.add("dark"); document.documentElement.classList.remove("light"); } else { document.documentElement.classList.add("light"); document.documentElement.classList.remove("dark"); } if (typeof localStorage !== "undefined") { localStorage.setItem("theme", currentTheme); } } function getTheme() { return currentTheme; } function getResolvedTheme() { if (currentTheme === "system") { return safeMatchMedia("(prefers-color-scheme: dark)") ? "dark" : "light"; } return currentTheme; } function setTheme(theme) { if (!["light", "dark", "system"].includes(theme)) { console.error(`Invalid theme: ${theme}. Must be 'light', 'dark', or 'system'`); return; } currentTheme = theme; applyTheme(); listeners.forEach((listener) => listener(theme)); } function toggleTheme() { const newTheme = currentTheme === "light" ? "dark" : "light"; setTheme(newTheme); } function onThemeChange(listener) { listeners.push(listener); } function offThemeChange(listener) { const index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } } if (typeof window !== "undefined") { initTheme(); if (typeof window.matchMedia === "function") { try { const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); if (mediaQuery.addEventListener) { mediaQuery.addEventListener("change", () => { if (currentTheme === "system") { applyTheme(); listeners.forEach((listener) => listener(currentTheme)); } }); } else if (mediaQuery.addListener) { mediaQuery.addListener(() => { if (currentTheme === "system") { applyTheme(); listeners.forEach((listener) => listener(currentTheme)); } }); } } catch (e) { console.error("Error setting up media query listener:", e); } } } var ThemeProvider = ({ children }) => { return children; }; export { ThemeProvider, getResolvedTheme, getTheme, offThemeChange, onThemeChange, setTheme, toggleTheme };