{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "switch",
  "type": "registry:component",
  "title": "Switch",
  "description": "On or off, for a setting that takes effect the moment it changes.",
  "dependencies": [
    "@base-ui/react",
    "tailwind-variants"
  ],
  "registryDependencies": [],
  "cssVars": {
    "light": {
      "success": "oklch(0.696 0.17 162.48)",
      "info": "oklch(0.623 0.214 259.815)"
    },
    "dark": {
      "success": "oklch(0.696 0.17 162.48)",
      "info": "oklch(0.623 0.214 259.815)"
    }
  },
  "files": [
    {
      "path": "components/panelui/switch.tsx",
      "type": "registry:component",
      "target": "@components/panelui/switch.tsx",
      "content": "/**\n * Switch — on or off, for a setting that takes effect the moment it changes.\n *\n * ```tsx\n * <Switch label=\"Dark mode\" defaultChecked />\n *\n * <Label>\n *   <Label.Text>Email me a receipt</Label.Text>\n *   <Label.Action><Switch /></Label.Action>\n * </Label>\n * ```\n *\n * ## It moves like a thing with weight\n *\n * The colour does not fade in. It sweeps along the track behind the thumb,\n * so the track fills from the side the thumb left and reads as the thumb's\n * doing. While it is pressed, the thumb stretches towards where it is going,\n * so a press that has not yet let go already says which way it will flip.\n *\n * ## While a change is saved\n *\n * A setting saved to a server is not on until the server says so. `pending`\n * puts a turning ring in the thumb and stops the switch being pressed again,\n * so the switch can show the new state at once and still be honest that it\n * has not landed yet.\n */\nimport { Switch as BaseSwitch } from '@base-ui/react/switch';\nimport type { CSSProperties } from 'react';\nimport { tv } from 'tailwind-variants';\n\nexport type SwitchSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';\nexport type SwitchColor = 'primary' | 'success' | 'info' | 'destructive';\n\n/** Height and width of the track. The thumb is the height less 2px of padding on each side. */\nconst SIZE: Record<SwitchSize, [string, string]> = {\n  xs: ['1rem', '1.75rem'],\n  sm: ['1.25rem', '2.125rem'],\n  md: ['1.5rem', '2.625rem'],\n  lg: ['1.75rem', '3.125rem'],\n  xl: ['2rem', '3.625rem'],\n};\n\nconst SPRING = 'ease-[cubic-bezier(0.3,1.35,0.45,1)]';\n\nconst switchVariants = tv({\n  slots: {\n    root: [\n      'group/switch relative inline-flex h-(--switch-h) w-(--switch-w) shrink-0 cursor-pointer items-center rounded-full p-0.5 outline-none',\n      'bg-input transition-[background-color,box-shadow] duration-200 dark:bg-input/80',\n      'hover:not-data-disabled:bg-[color-mix(in_oklab,var(--input),var(--foreground)_8%)]',\n      'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',\n      'data-disabled:cursor-not-allowed data-disabled:opacity-50 aria-busy:cursor-progress',\n      // The fill: the whole track in the switch's colour, uncovered from the\n      // thumb's starting side as it travels.\n      \"before:absolute before:inset-0 before:rounded-[inherit] before:bg-(--switch-color) before:content-['']\",\n      'before:[clip-path:inset(0_100%_0_0_round_999px)] before:transition-[clip-path] before:duration-300 before:ease-[cubic-bezier(0.3,1.35,0.45,1)]',\n      'rtl:before:[clip-path:inset(0_0_0_100%_round_999px)]',\n      'data-checked:before:[clip-path:inset(0_0_0_0_round_999px)]',\n      'motion-reduce:before:transition-none',\n    ],\n    thumb: [\n      'relative z-10 flex size-[calc(var(--switch-h)-4px)] items-center justify-center rounded-full bg-white',\n      // On, the thumb takes the colour that reads on the fill: dark on a light primary, white on the rest.\n      'transition-colors data-checked:bg-(--switch-thumb)',\n      'shadow-[0_1px_2px_rgb(0_0_0/0.18),0_2px_6px_-1px_rgb(0_0_0/0.12)]',\n      `transition-[translate,width] duration-300 ${SPRING} motion-reduce:transition-none`,\n      // On: across by the track's width less its height, which is the room left.\n      'data-checked:translate-x-[calc(var(--switch-w)-var(--switch-h))] rtl:data-checked:-translate-x-[calc(var(--switch-w)-var(--switch-h))]',\n      // Pressed: a fifth longer, towards where it is going. When on, it grows back the way it came.\n      'group-active/switch:not-data-disabled:w-[calc((var(--switch-h)-4px)*1.22)]',\n      'group-active/switch:data-checked:not-data-disabled:translate-x-[calc(var(--switch-w)-var(--switch-h)-(var(--switch-h)-4px)*0.22)]',\n      'rtl:group-active/switch:data-checked:not-data-disabled:-translate-x-[calc(var(--switch-w)-var(--switch-h)-(var(--switch-h)-4px)*0.22)]',\n      'group-aria-busy/switch:w-[calc(var(--switch-h)-4px)]',\n    ],\n    spinner: 'size-[62%] animate-spin text-(--switch-color) group-not-data-checked/switch:text-muted-foreground motion-reduce:animate-none',\n  },\n  variants: {\n    color: {\n      primary: { root: '[--switch-color:var(--primary)] [--switch-thumb:var(--primary-foreground)]' },\n      success: { root: '[--switch-color:var(--success)] [--switch-thumb:white]' },\n      info: { root: '[--switch-color:var(--info)] [--switch-thumb:white]' },\n      destructive: { root: '[--switch-color:var(--destructive)] [--switch-thumb:white]' },\n    },\n  },\n  defaultVariants: { color: 'primary' },\n});\n\nexport interface SwitchProps extends Omit<BaseSwitch.Root.Props, 'className' | 'color'> {\n  /** Default `md`. */\n  size?: SwitchSize;\n  /** The colour it fills with when on. `primary` by default; pick another for what it means. */\n  color?: SwitchColor;\n  /**\n   * What a screen reader calls it, when there is no visible label tied to it.\n   * A `Label` wrapped round it, or pointing at its `id`, is better when there is room.\n   */\n  label?: string;\n  /** A change is being saved: a ring turns in the thumb, and it cannot be pressed again until it is done. */\n  pending?: boolean;\n  className?: string;\n  style?: CSSProperties;\n}\n\n/** A switch. Takes `checked`/`onCheckedChange` or `defaultChecked`, and `name` for a form. */\nfunction Switch({ size = 'md', color, label, pending = false, className, style, readOnly, ...props }: SwitchProps) {\n  const slots = switchVariants({ color });\n  const [height, width] = SIZE[size];\n  return (\n    <BaseSwitch.Root\n      data-slot=\"switch\"\n      data-size={size}\n      aria-label={label}\n      aria-busy={pending || undefined}\n      readOnly={pending || readOnly}\n      className={slots.root({ className })}\n      style={{ ['--switch-h' as string]: height, ['--switch-w' as string]: width, ...style }}\n      {...props}\n    >\n      <BaseSwitch.Thumb data-slot=\"switch-thumb\" className={slots.thumb()}>\n        {pending ? (\n          <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" className={slots.spinner()} fill=\"none\">\n            <circle cx=\"12\" cy=\"12\" r=\"9\" stroke=\"currentColor\" strokeOpacity={0.2} strokeWidth={3.5} />\n            <path d=\"M21 12a9 9 0 0 0-9-9\" stroke=\"currentColor\" strokeWidth={3.5} strokeLinecap=\"round\" />\n          </svg>\n        ) : null}\n      </BaseSwitch.Thumb>\n    </BaseSwitch.Root>\n  );\n}\nSwitch.displayName = 'Switch';\n\nexport { Switch };\n"
    }
  ]
}
