UNPKG

theme-o-rama

Version:

A TypeScript library for dynamic theme management in react + shadcn + tailwind applications

88 lines (87 loc) 3.4 kB
"use client"; import { jsx as _jsx } from "react/jsx-runtime"; import { createContext, useContext, useEffect, useRef, useState } from "react"; import colorTheme from "./color.json" with { type: "json" }; import darkTheme from "./dark.json" with { type: "json" }; import { applyTheme } from "./index.js"; import lightTheme from "./light.json" with { type: "json" }; import { ThemeLoader } from "./theme-loader.js"; // Browser detection for SSR compatibility const isBrowser = typeof window !== "undefined"; const SimpleThemeContext = createContext(undefined); export function SimpleThemeProvider({ children, imageResolver, onThemeChange, }) { const [currentTheme, setCurrentTheme] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isSettingTheme, setIsSettingTheme] = useState(false); const [error, setError] = useState(null); // Use refs for stable instances that don't need to trigger re-renders const themeLoader = useRef(new ThemeLoader()).current; const imageResolverRef = useRef(imageResolver); // Store callbacks and functions in refs to avoid re-running effects when they change const onThemeChangeRef = useRef(onThemeChange); useEffect(() => { onThemeChangeRef.current = onThemeChange; imageResolverRef.current = imageResolver; }, [onThemeChange]); const setTheme = async (theme) => { if (isSettingTheme) return; // Prevent concurrent calls setIsSettingTheme(true); try { setCurrentTheme(theme); if (isBrowser) { applyTheme(theme, document.documentElement); } // Notify app of theme change (app handles storage) if (onThemeChangeRef.current) { onThemeChangeRef.current(theme); } setError(null); // Clear any previous errors } catch (err) { console.error("Error setting theme:", err); setError("Failed to set theme"); } finally { setIsSettingTheme(false); } }; useEffect(() => { const initializeThemes = async () => { try { setIsLoading(true); setError(null); // Always load built-in themes so the can be inherited from await themeLoader.loadTheme(lightTheme); await themeLoader.loadTheme(darkTheme); await themeLoader.loadTheme(colorTheme); } catch (err) { console.error("Error loading themes:", err); setError("Failed to load themes"); setCurrentTheme(null); } finally { setIsLoading(false); } }; initializeThemes(); }, []); const initializeTheme = async (theme) => { return await themeLoader.initializeTheme(theme, imageResolverRef.current); }; return (_jsx(SimpleThemeContext.Provider, { value: { currentTheme, setTheme, isLoading, error, initializeTheme, }, children: children })); } export function useSimpleTheme() { const context = useContext(SimpleThemeContext); if (context === undefined) { throw new Error("useSimpleTheme must be used within a SimpleThemeProvider"); } return context; }