{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"theme-toggle","title":"Theme Toggle","description":"System, light and dark as one segmented control, plus the round light and dark button ward.so uses; it can apply and remember the choice.","dependencies":["lucide-react@1.47.0"],"registryDependencies":[],"files":[{"path":"registry/ward/ThemeToggle.tsx","content":"\"use client\";\nimport { useState } from \"react\";\nimport { Moon, Sun } from \"lucide-react\";\nimport { applyTheme, saveTheme, themes, type Theme } from \"./theme\";\nimport \"./styles/theme-toggle.css\";\n\nexport { applyTheme, saveTheme, type Theme } from \"./theme\";\n\nconst label = (theme: Theme) => theme[0].toUpperCase() + theme.slice(1);\nconst classes = (...names: (string | undefined)[]) => names.filter(Boolean).join(\" \");\n\n/** System, light and dark as one segmented control. With apply, a choice also updates <html> and is remembered. */\nexport default function ThemeToggle({ variant = \"System\", value, onChange, apply = false, storageKey = \"ward-theme\", className }: { variant?: string; value?: Theme; onChange?: (theme: Theme) => void; apply?: boolean; storageKey?: string; className?: string }) {\n  const [selected, setSelected] = useState<Theme>(themes.find(theme => theme === variant.toLowerCase()) ?? \"system\");\n  const current = value ?? selected;\n  function choose(theme: Theme) {\n    if (value === undefined) setSelected(theme);\n    if (apply) { applyTheme(theme); saveTheme(theme, storageKey); }\n    onChange?.(theme);\n  }\n  return <div className={classes(\"ward-theme-toggle\", className)} role=\"group\" aria-label=\"Appearance\">{themes.map(theme =>\n    <button key={theme} type=\"button\" aria-pressed={current === theme} onClick={() => choose(theme)}>{label(theme)}</button>)}</div>;\n}\n\n/** ward.so's rail control: one round button that flips light and dark. */\nexport function ThemeIconToggle({ className, storageKey = \"ward-theme\" }: { className?: string; storageKey?: string }) {\n  return <button type=\"button\" className={classes(\"ward-theme-icon\", className)} aria-label=\"Toggle light and dark mode\" onClick={() => {\n    const root = document.documentElement;\n    const next: Theme = root.dataset.theme === \"dark\" || root.classList.contains(\"dark\") ? \"light\" : \"dark\";\n    applyTheme(next); saveTheme(next, storageKey);\n  }}><Moon className=\"ward-theme-icon-light\" size={15} aria-hidden=\"true\" /><Sun className=\"ward-theme-icon-dark\" size={15} aria-hidden=\"true\" /></button>;\n}\n","type":"registry:component","target":"components/ward/ThemeToggle.tsx"},{"path":"registry/ward/theme.ts","content":"export type Theme = \"system\" | \"light\" | \"dark\";\nexport const themes: readonly Theme[] = [\"system\", \"light\", \"dark\"];\n\nexport function resolveTheme(theme: Theme, prefersDark: boolean): \"light\" | \"dark\" {\n  return theme === \"system\" ? (prefersDark ? \"dark\" : \"light\") : theme;\n}\n\n/** Puts a theme on <html> in both forms Ward's CSS reads: data-theme (ward.so) and the .dark class (shadcn). */\nexport function applyTheme(theme: Theme, root: HTMLElement = document.documentElement) {\n  const resolved = resolveTheme(theme, matchMedia(\"(prefers-color-scheme: dark)\").matches);\n  root.dataset.theme = resolved;\n  root.classList.toggle(\"dark\", resolved === \"dark\");\n  root.style.colorScheme = resolved;\n  return resolved;\n}\n\nexport function saveTheme(theme: Theme, storageKey = \"ward-theme\") {\n  try { localStorage.setItem(storageKey, theme); } catch { /* Private mode: the page still switches. */ }\n}\n","type":"registry:lib","target":"components/ward/theme.ts"},{"path":"registry/ward/styles/theme-toggle.css","content":".ward-theme-toggle { display: inline-flex; gap: 4px; }\n.ward-theme-toggle button { height: 28px; padding: 0 12px; border: 0; border-radius: 999px; background: var(--secondary); color: var(--muted-foreground); font: inherit; font-size: 13px; cursor: pointer; transition: background 120ms cubic-bezier(.2, 0, 0, 1), color 120ms cubic-bezier(.2, 0, 0, 1); }\n.ward-theme-toggle button:hover { color: var(--foreground); }\n.ward-theme-toggle button[aria-pressed=\"true\"] { background: var(--primary); color: var(--primary-foreground); }\n.ward-theme-icon { display: inline-grid; flex: none; width: 28px; height: 28px; place-items: center; padding: 0; border: 0; border-radius: 999px; background: var(--secondary); color: var(--foreground); cursor: pointer; transition: background 180ms cubic-bezier(.2, 0, 0, 1); }\n.ward-theme-icon:hover { background: var(--accent); }\n.ward-theme-toggle button:focus-visible, .ward-theme-icon:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }\n.ward-theme-icon-dark, :is(.dark, [data-theme=\"dark\"]) .ward-theme-icon-light { display: none; }\n:is(.dark, [data-theme=\"dark\"]) .ward-theme-icon-dark { display: block; }\n@media (prefers-reduced-motion: reduce) { .ward-theme-toggle button, .ward-theme-icon { transition: none; } }\n","type":"registry:file","target":"components/ward/styles/theme-toggle.css"}],"meta":{"variants":["System","Light","Dark"],"version":"2.0.0","source":null,"access":"free","new":true},"categories":["ui"],"type":"registry:component"}