{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <edu@smoothui.dev>","css":{},"dependencies":["@base-ui/react","motion"],"description":"An animated Switch component for SmoothUI with a spring thumb toggle.","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { Switch as SwitchPrimitive } from \"@base-ui/react/switch\";\nimport { cn } from \"@/lib/utils\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport type { ComponentPropsWithRef } from \"react\";\nimport { useState } from \"react\";\nimport { SPRING_DEFAULT } from \"@/components/smoothui/lib/animation\";\n\ninterface SwitchOwnProps {\n  /** Accessible name, for switches without a visible `<label>` */\n  \"aria-label\"?: string;\n  /** ID of the element labelling the switch */\n  \"aria-labelledby\"?: string;\n  /** Whether the switch is checked (controlled) */\n  checked?: boolean;\n  /** Optional CSS class */\n  className?: string;\n  /** Whether the switch is initially checked (uncontrolled) */\n  defaultChecked?: boolean;\n  /** Whether the switch is disabled */\n  disabled?: boolean;\n  /** ID for label association */\n  id?: string;\n  /** Name attribute for form submission */\n  name?: string;\n  /** Callback when the checked state changes */\n  onCheckedChange?: (checked: boolean) => void;\n  /** Whether the switch is required */\n  required?: boolean;\n  /** Value attribute for form submission */\n  value?: string;\n}\n\n/**\n * Native `<button>` attributes forwarded to the control: `ref`, `aria-*`,\n * `data-*`, `onBlur`, `onFocus` and the rest, so form libraries and error\n * wiring (`aria-describedby`, `aria-invalid`) reach the element.\n */\ntype SwitchNativeProps = Omit<\n  ComponentPropsWithRef<\"button\">,\n  keyof SwitchOwnProps | \"children\" | \"defaultValue\" | \"onChange\" | \"type\"\n>;\n\nexport type SwitchProps = SwitchOwnProps & SwitchNativeProps;\n\nconst MotionThumb = motion.span;\n\nconst THUMB_OFF = \"translateX(0.125rem)\";\nconst THUMB_ON = \"translateX(1rem)\";\n\n/**\n * SmoothUI Switch — Base UI twin (default).\n * Same public props as the Radix twin; headless via `@base-ui/react/switch`.\n */\nexport default function Switch({\n  \"aria-label\": ariaLabel,\n  \"aria-labelledby\": ariaLabelledBy,\n  checked,\n  className,\n  defaultChecked = false,\n  disabled = false,\n  id,\n  name,\n  onCheckedChange,\n  required,\n  value,\n  ...props\n}: SwitchProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [uncontrolledChecked, setUncontrolledChecked] =\n    useState(defaultChecked);\n  const isOn = checked ?? uncontrolledChecked;\n\n  return (\n    <SwitchPrimitive.Root\n      aria-label={ariaLabel}\n      aria-labelledby={ariaLabelledBy}\n      checked={isOn}\n      className={cn(\n        \"peer state-transition focus-ring inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border border-transparent shadow-xs outline-none focus-visible:border-ring disabled:cursor-not-allowed\",\n        // Avoid root opacity — translucent tracks vanish on dark stages\n        disabled\n          ? isOn\n            ? \"bg-muted-foreground\"\n            : \"bg-foreground/35\"\n          : isOn\n            ? \"bg-brand\"\n            : \"bg-foreground/40\",\n        className\n      )}\n      data-slot=\"switch\"\n      disabled={disabled}\n      id={id}\n      name={name}\n      nativeButton\n      onCheckedChange={(next) => {\n        if (checked === undefined) {\n          setUncontrolledChecked(next);\n        }\n        onCheckedChange?.(next);\n      }}\n      // Native props go on the rendered <button>: Base UI types the root as a\n      // span, and merges the render element's props and ref into it.\n      render={<button type=\"button\" {...props} />}\n      required={required}\n      value={value}\n    >\n      <SwitchPrimitive.Thumb\n        className=\"pointer-events-none block\"\n        data-slot=\"switch-thumb\"\n        render={\n          <MotionThumb\n            animate={{\n              transform: isOn ? THUMB_ON : THUMB_OFF,\n            }}\n            className={cn(\n              \"pointer-events-none block size-4 rounded-full ring-0\",\n              disabled\n                ? \"bg-thumb shadow-sm\"\n                : isOn\n                  ? \"bg-thumb\"\n                  : \"bg-background dark:bg-foreground\"\n            )}\n            transition={shouldReduceMotion ? { duration: 0 } : SPRING_DEFAULT}\n          />\n        }\n      />\n    </SwitchPrimitive.Root>\n  );\n}\n","path":"index.tsx","target":"components/smoothui/switch/index.tsx","type":"registry:ui"}],"name":"switch","registryDependencies":["https://smoothui.dev/r/lib.json","https://smoothui.dev/r/tokens.json"],"title":"Switch","type":"registry:ui"}