{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "theme-toggle",
  "title": "Theme Toggle",
  "description": "A round, glossy push button that latches down and flips the theme instantly.",
  "dependencies": [
    "class-variance-authority",
    "next-themes"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/clover-ui/theme-toggle.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { useTheme } from \"next-themes\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst themeToggleVariants = cva(\n  [\n    \"relative inline-flex size-[2.8em] shrink-0 cursor-pointer rounded-full outline-none select-none [-webkit-tap-highlight-color:transparent]\",\n    \"shadow-[0_0.2em_0.5em_rgb(0_0_0/0.3),0_0.05em_0.1em_rgb(0_0_0/0.35)]\",\n    \"focus-visible:ring-ring focus-visible:ring-offset-background focus-visible:ring-2 focus-visible:ring-offset-2\",\n    \"disabled:cursor-not-allowed disabled:opacity-50\",\n  ],\n  {\n    variants: {\n      size: {\n        sm: \"text-[12px]\",\n        default: \"text-[16px]\",\n        lg: \"text-[20px]\",\n      },\n    },\n    defaultVariants: { size: \"default\" },\n  },\n);\n\nexport type ThemeToggleSize = NonNullable<VariantProps<typeof themeToggleVariants>[\"size\"]>;\nexport type ThemeToggleTheme = \"light\" | \"dark\";\n\nexport interface ThemeToggleProps\n  extends\n    Omit<React.ComponentProps<\"button\">, \"onClick\" | \"children\">,\n    VariantProps<typeof themeToggleVariants> {\n  theme?: ThemeToggleTheme;\n  onThemeChange?: (theme: ThemeToggleTheme) => void;\n  sunColor?: string;\n  moonColor?: string;\n}\n\nconst subscribe = () => () => {};\n\nconst LIFT = {\n  up: 0.24,\n  latched: 0.1,\n  pressed: 0.02,\n};\n\nconst SKINS = {\n  dark: {\n    rim: \"linear-gradient(180deg, #343434, #050505)\",\n    well: \"linear-gradient(180deg, #000000, #101010)\",\n    wall: \"linear-gradient(180deg, #262626, #0a0a0a)\",\n    face: \"radial-gradient(circle at 38% 30%, #474747 0%, #1b1b1b 45%, #070707 80%)\",\n    shine: \"inset 0 0.07em 0.06em rgb(255 255 255 / 0.18), inset 0 -0.1em 0.2em rgb(0 0 0 / 0.6)\",\n  },\n  light: {\n    rim: \"linear-gradient(180deg, #ffffff, #c9c9cf)\",\n    well: \"linear-gradient(180deg, #a9a9b3, #c4c4cc)\",\n    wall: \"linear-gradient(180deg, #d4d4da, #a2a2ad)\",\n    face: \"radial-gradient(circle at 38% 30%, #ffffff 0%, #f1f1f4 45%, #d6d6dc 85%)\",\n    shine: \"inset 0 0.07em 0.06em rgb(255 255 255 / 0.9), inset 0 -0.1em 0.2em rgb(0 0 0 / 0.12)\",\n  },\n};\n\nfunction Sun() {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth={2.4}\n      strokeLinecap=\"round\"\n      className=\"size-full\"\n    >\n      <circle cx=\"12\" cy=\"12\" r=\"4.2\" fill=\"currentColor\" stroke=\"none\" />\n      <path d=\"M12 2.5v2.2M12 19.3v2.2M2.5 12h2.2M19.3 12h2.2M5.3 5.3l1.55 1.55M17.15 17.15l1.55 1.55M5.3 18.7l1.55-1.55M17.15 6.85l1.55-1.55\" />\n    </svg>\n  );\n}\n\nfunction Moon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" className=\"size-full\" fill=\"currentColor\">\n      <path d=\"M20.2 14.6A8.6 8.6 0 0 1 9.4 3.8a.6.6 0 0 0-.8-.7A9.4 9.4 0 1 0 20.9 15.4a.6.6 0 0 0-.7-.8Z\" />\n    </svg>\n  );\n}\n\nfunction ThemeToggle({\n  theme,\n  onThemeChange,\n  sunColor = \"#f5b81c\",\n  moonColor = \"#3b3d4a\",\n  size = \"default\",\n  className,\n  style,\n  disabled,\n  onPointerDown,\n  onPointerUp,\n  onPointerLeave,\n  onPointerCancel,\n  onKeyDown,\n  onKeyUp,\n  onBlur,\n  ...props\n}: ThemeToggleProps) {\n  const [pressing, setPressing] = React.useState(false);\n  const { resolvedTheme, setTheme } = useTheme();\n  const mounted = React.useSyncExternalStore(\n    subscribe,\n    () => true,\n    () => false,\n  );\n  const current = theme ?? (mounted ? resolvedTheme : undefined);\n  const dark = current === \"dark\";\n  const ready = mounted && current !== undefined;\n\n  const lift = pressing ? LIFT.pressed : dark ? LIFT.latched : LIFT.up;\n\n  const skin = (name: keyof typeof SKINS) => {\n    if (!ready) return name === \"dark\" ? \"dark:hidden\" : \"hidden dark:block\";\n    return (name === \"dark\") === dark ? \"hidden\" : \"\";\n  };\n\n  return (\n    <button\n      type=\"button\"\n      aria-label={dark ? \"Switch to light mode\" : \"Switch to dark mode\"}\n      disabled={disabled}\n      className={cn(\n        themeToggleVariants({ size }),\n        !ready && \"[--lift:0.24em] dark:[--lift:0.1em]\",\n        className,\n      )}\n      style={\n        {\n          ...(ready ? { \"--lift\": `${lift}em` } : null),\n          ...style,\n        } as React.CSSProperties\n      }\n      onPointerLeave={(event) => {\n        onPointerLeave?.(event);\n        setPressing(false);\n      }}\n      onPointerDown={(event) => {\n        onPointerDown?.(event);\n        if (event.button === 0) setPressing(true);\n      }}\n      onPointerUp={(event) => {\n        onPointerUp?.(event);\n        setPressing(false);\n      }}\n      onPointerCancel={(event) => {\n        onPointerCancel?.(event);\n        setPressing(false);\n      }}\n      onKeyDown={(event) => {\n        onKeyDown?.(event);\n        if (event.key === \" \" || event.key === \"Enter\") setPressing(true);\n      }}\n      onKeyUp={(event) => {\n        onKeyUp?.(event);\n        setPressing(false);\n      }}\n      onBlur={(event) => {\n        onBlur?.(event);\n        setPressing(false);\n      }}\n      onClick={() => {\n        const next: ThemeToggleTheme = dark ? \"light\" : \"dark\";\n        if (theme === undefined) setTheme(next);\n        onThemeChange?.(next);\n      }}\n      {...props}\n    >\n      {([\"dark\", \"light\"] as const).map((name) => (\n        <span\n          key={name}\n          aria-hidden\n          className={cn(\"pointer-events-none absolute inset-0 rounded-full p-[0.2em]\", skin(name))}\n          style={{ background: SKINS[name].rim }}\n        >\n          <span\n            className=\"block size-full rounded-full shadow-[inset_0_0.1em_0.2em_rgb(0_0_0/0.45)]\"\n            style={{ background: SKINS[name].well }}\n          />\n        </span>\n      ))}\n\n      <span aria-hidden className=\"pointer-events-none absolute inset-[0.3em]\">\n        {([\"dark\", \"light\"] as const).map((name) => (\n          <span\n            key={name}\n            className={cn(\n              \"absolute inset-x-0 bottom-0 h-[calc(100%+var(--lift))] rounded-full shadow-[0_calc(0.03em+var(--lift)*0.3)_calc(0.06em+var(--lift)*0.6)_rgb(0_0_0/0.4)]\",\n              skin(name),\n            )}\n            style={{ background: SKINS[name].wall }}\n          />\n        ))}\n\n        <span className=\"absolute inset-0 -translate-y-(--lift) overflow-hidden rounded-full\">\n          {([\"dark\", \"light\"] as const).map((name) => (\n            <span\n              key={name}\n              className={cn(\"absolute inset-0 rounded-full\", skin(name))}\n              style={{ background: SKINS[name].face, boxShadow: SKINS[name].shine }}\n            />\n          ))}\n\n          <span className=\"absolute inset-0 grid place-items-center\">\n            <span\n              className={cn(\"col-start-1 row-start-1 size-[1.1em]\", skin(\"dark\"))}\n              style={{ color: sunColor }}\n            >\n              <Sun />\n            </span>\n            <span\n              className={cn(\"col-start-1 row-start-1 size-[1.1em]\", skin(\"light\"))}\n              style={{ color: moonColor }}\n            >\n              <Moon />\n            </span>\n          </span>\n        </span>\n      </span>\n    </button>\n  );\n}\n\nexport { ThemeToggle, themeToggleVariants };\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}