/** * Theme Context + Provider (React integration) * ============================================= * Wraps the registry in a React context so that the entire component tree * re-renders when the active theme changes. */ import React, { createContext, useContext, useEffect, useSyncExternalStore, useCallback, useMemo, } from "react"; import type { ThemePackage, ComponentKey, LayoutKey, PageKey } from "./types"; import { subscribe, getActiveTheme, getActiveThemeId, getRegisteredThemes, activateTheme, deactivateTheme, reapplyActiveTheme, resolveComponent, resolveLayout, resolvePage, getSavedMode, saveMode, getEffectiveMode, registerTheme, unregisterTheme, type ThemeMode, } from "./registry"; // ─── context value ─────────────────────────────────────────────────────────── interface ThemeContextValue { /** Currently active theme package (null = default). */ activeTheme: ThemePackage | null; activeThemeId: string | null; /** All registered themes. */ themes: ThemePackage[]; /** Current mode preference. */ mode: ThemeMode; /** Resolved effective mode (never "system"). */ effectiveMode: "light" | "dark"; /** Switch the active theme. */ switchTheme: (id: string) => void; /** Reset to no custom theme (use defaults). */ resetTheme: () => void; /** Change mode preference. */ setMode: (mode: ThemeMode) => void; /** Register a new theme at runtime. */ register: (pkg: ThemePackage) => void; /** Unregister a theme by id. */ unregister: (id: string) => void; /** Resolve a component (returns themed override or fallback). */ component:
(key: ComponentKey, fallback: React.ComponentType
) => React.ComponentType
; /** Resolve a layout. */ layout: (key: LayoutKey, fallback: React.ComponentType<{ children: React.ReactNode }>) => React.ComponentType<{ children: React.ReactNode }>; /** Resolve a page. */ page:
(key: PageKey, fallback: React.ComponentType
) => React.ComponentType
;
}
const ThemeContext = createContext (
key: ComponentKey,
fallback: React.ComponentType ,
): React.ComponentType {
const ctx = useThemeContext();
return ctx.component(key, fallback);
}
/** Convenience: resolve a themed layout. */
export function useThemedLayout(
key: LayoutKey,
fallback: React.ComponentType<{ children: React.ReactNode }>,
): React.ComponentType<{ children: React.ReactNode }> {
const ctx = useThemeContext();
return ctx.layout(key, fallback);
}
/** Convenience: resolve a themed page. */
export function useThemedPage (
key: PageKey,
fallback: React.ComponentType ,
): React.ComponentType {
const ctx = useThemeContext();
return ctx.page(key, fallback);
}