{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "theme-provider",
  "title": "Theme Provider",
  "description": "Puts the page in light, dark, or system mode and selects a palette, persisting the choice and exposing it through `useTheme`.",
  "registryDependencies": [
    "https://guillermo-rebolledo.github.io/materialcn/r/materialcn-theme.json",
    "https://guillermo-rebolledo.github.io/materialcn/r/palettes.json",
    "https://guillermo-rebolledo.github.io/materialcn/r/theme-context.json"
  ],
  "files": [
    {
      "path": "src/components/theme-provider.tsx",
      "content": "import { useCallback, useEffect, useMemo, useState } from \"react\"\n\nimport { PALETTES, type Palette } from \"@/lib/palettes\"\nimport { ThemeContext, type Theme } from \"./theme-context\"\n\nconst PALETTE_IDS: string[] = PALETTES.map((entry) => entry.id)\n\nfunction isPalette(value: string | null): value is Palette {\n  return value === \"baseline\" || (value !== null && PALETTE_IDS.includes(value))\n}\n\nfunction systemTheme(): \"light\" | \"dark\" {\n  if (typeof window === \"undefined\") return \"light\"\n  return window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n    ? \"dark\"\n    : \"light\"\n}\n\nexport function ThemeProvider({\n  children,\n  defaultTheme = \"system\",\n  defaultPalette = \"baseline\",\n  storageKey = \"materialcn-theme\",\n  paletteStorageKey = \"materialcn-palette\",\n  element,\n}: {\n  children: React.ReactNode\n  defaultTheme?: Theme\n  defaultPalette?: Palette\n  /** Set to null to opt out of persistence. */\n  storageKey?: string | null\n  /** Set to null to opt out of persistence. */\n  paletteStorageKey?: string | null\n  /** Where the `light`/`dark` class and `data-palette` go. Defaults to <html>. */\n  element?: HTMLElement | null\n}) {\n  const [theme, setThemeState] = useState<Theme>(() => {\n    if (typeof window === \"undefined\" || !storageKey) return defaultTheme\n    const stored = window.localStorage.getItem(storageKey)\n    return stored === \"light\" || stored === \"dark\" || stored === \"system\"\n      ? stored\n      : defaultTheme\n  })\n\n  const [palette, setPaletteState] = useState<Palette>(() => {\n    if (typeof window === \"undefined\" || !paletteStorageKey) return defaultPalette\n    const stored = window.localStorage.getItem(paletteStorageKey)\n    return isPalette(stored) ? stored : defaultPalette\n  })\n\n  const [system, setSystem] = useState<\"light\" | \"dark\">(systemTheme)\n\n  // Track the OS preference so `resolvedTheme` stays correct while on \"system\".\n  useEffect(() => {\n    const query = window.matchMedia(\"(prefers-color-scheme: dark)\")\n    const onChange = () => setSystem(query.matches ? \"dark\" : \"light\")\n    query.addEventListener(\"change\", onChange)\n    return () => query.removeEventListener(\"change\", onChange)\n  }, [])\n\n  const resolvedTheme = theme === \"system\" ? system : theme\n\n  useEffect(() => {\n    const target = element ?? document.documentElement\n    target.classList.remove(\"light\", \"dark\")\n\n    // On \"system\" we deliberately add no class: tokens/color.css already falls\n    // back to `prefers-color-scheme`, so leaving both classes off is what lets\n    // an unstyled server render match the client.\n    if (theme !== \"system\") target.classList.add(theme)\n\n    return () => target.classList.remove(\"light\", \"dark\")\n  }, [theme, element])\n\n  useEffect(() => {\n    const target = element ?? document.documentElement\n\n    // The baseline carries no attribute, for the same reason \"system\" carries\n    // no class: it is what the stylesheet already does, and an attribute that\n    // changes nothing is one more thing a server render has to match.\n    if (palette === \"baseline\") target.removeAttribute(\"data-palette\")\n    else target.setAttribute(\"data-palette\", palette)\n\n    return () => target.removeAttribute(\"data-palette\")\n  }, [palette, element])\n\n  const setTheme = useCallback(\n    (next: Theme) => {\n      setThemeState(next)\n      if (storageKey) window.localStorage.setItem(storageKey, next)\n    },\n    [storageKey],\n  )\n\n  const setPalette = useCallback(\n    (next: Palette) => {\n      setPaletteState(next)\n      if (paletteStorageKey) {\n        window.localStorage.setItem(paletteStorageKey, next)\n      }\n    },\n    [paletteStorageKey],\n  )\n\n  const value = useMemo(\n    () => ({ theme, resolvedTheme, setTheme, palette, setPalette }),\n    [theme, resolvedTheme, setTheme, palette, setPalette],\n  )\n\n  return <ThemeContext value={value}>{children}</ThemeContext>\n}\n\nexport { useTheme, type Theme } from \"./theme-context\"\nexport { PALETTES, type Palette } from \"@/lib/palettes\"\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "theme"
  ],
  "type": "registry:component"
}