{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "segmented-control",
  "type": "registry:ui",
  "title": "Segmented control",
  "description": "Segmented control with a raised thumb that springs between options, arrow, Home and End key support, icons, badges, three sizes and reduced motion support.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/segmented-control.tsx",
      "type": "registry:ui",
      "target": "components/ui/segmented-control.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { cn } from \"@/lib/utils\"\n\n/*\n * GOLD STANDARD COMPONENT. Other components copy the patterns in this file:\n * - one visual idea (a raised thumb that glides between options),\n * - every state designed (rest, hover, pressed, focus-visible, selected, disabled),\n * - real keyboard support (roving tabindex, arrows, Home/End),\n * - controlled + uncontrolled, sizes via a lookup, tokens only.\n */\n\ntype Option = {\n  value: string\n  label: React.ReactNode\n  icon?: React.ReactNode\n  disabled?: boolean\n  /** Short trailing detail, e.g. \"-20%\" or a count. */\n  badge?: React.ReactNode\n}\n\ntype Size = \"sm\" | \"default\" | \"lg\"\n\nconst SIZE: Record<Size, { track: string; item: string; text: string }> = {\n  sm: { track: \"h-8 rounded-[9px] p-[3px]\", item: \"gap-1.5 rounded-md px-2.5 [&_svg]:size-3.5\", text: \"text-xs\" },\n  default: { track: \"h-9 rounded-[10px] p-[3px]\", item: \"gap-1.5 rounded-[7px] px-3 [&_svg]:size-4\", text: \"text-[0.8125rem]\" },\n  lg: { track: \"h-11 rounded-xl p-1\", item: \"gap-2 rounded-lg px-4 [&_svg]:size-4\", text: \"text-sm\" },\n}\n\ntype SegmentedControlProps = {\n  /** Full options. */\n  options?: Option[]\n  /** Shorthand: plain labels, value = label. */\n  items?: string[]\n  value?: string\n  defaultValue?: string\n  onChange?: (value: string) => void\n  size?: Size\n  /** Stretch to the container and split space evenly. */\n  fullWidth?: boolean\n  disabled?: boolean\n  className?: string\n  \"aria-label\"?: string\n}\n\nfunction SegmentedControl({\n  options: optionsProp,\n  items,\n  value: valueProp,\n  defaultValue,\n  onChange,\n  size = \"default\",\n  fullWidth,\n  disabled,\n  className,\n  \"aria-label\": ariaLabel = \"Options\",\n}: SegmentedControlProps) {\n  const options = React.useMemo<Option[]>(\n    () => optionsProp ?? (items ?? [\"Monthly\", \"Yearly\"]).map((i) => ({ value: i, label: i })),\n    [optionsProp, items]\n  )\n  const [inner, setInner] = React.useState(defaultValue ?? options[0]?.value)\n  const value = valueProp ?? inner\n  const layoutId = React.useId()\n  const reduce = useReducedMotion()\n  const refs = React.useRef<(HTMLButtonElement | null)[]>([])\n  const s = SIZE[size]\n\n  const select = (v: string) => {\n    if (valueProp === undefined) setInner(v)\n    onChange?.(v)\n  }\n\n  const enabled = options.map((o, i) => (o.disabled || disabled ? -1 : i)).filter((i) => i >= 0)\n  const move = (from: number, dir: 1 | -1 | \"first\" | \"last\") => {\n    const pos = enabled.indexOf(from)\n    const next =\n      dir === \"first\" ? enabled[0] : dir === \"last\" ? enabled[enabled.length - 1] : enabled[(pos + dir + enabled.length) % enabled.length]\n    if (next === undefined) return\n    refs.current[next]?.focus()\n    select(options[next].value)\n  }\n\n  return (\n    <div\n      role=\"radiogroup\"\n      aria-label={ariaLabel}\n      aria-disabled={disabled || undefined}\n      data-slot=\"segmented-control\"\n      className={cn(\n        \"relative isolate inline-flex items-stretch bg-sunken shadow-[inset_0_0_0_1px_var(--border)]\",\n        s.track,\n        fullWidth && \"flex w-full\",\n        disabled && \"opacity-50\",\n        className\n      )}\n    >\n      {options.map((o, i) => {\n        const active = o.value === value\n        const isDisabled = disabled || o.disabled\n        return (\n          <button\n            key={o.value}\n            ref={(el) => {\n              refs.current[i] = el\n            }}\n            type=\"button\"\n            role=\"radio\"\n            aria-checked={active}\n            disabled={isDisabled}\n            tabIndex={active ? 0 : -1}\n            data-state={active ? \"on\" : \"off\"}\n            onClick={() => select(o.value)}\n            onKeyDown={(e) => {\n              if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") { e.preventDefault(); move(i, 1) }\n              if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") { e.preventDefault(); move(i, -1) }\n              if (e.key === \"Home\") { e.preventDefault(); move(i, \"first\") }\n              if (e.key === \"End\") { e.preventDefault(); move(i, \"last\") }\n            }}\n            className={cn(\n              \"group/seg relative inline-flex items-center justify-center font-medium whitespace-nowrap outline-none select-none\",\n              \"transition-[color] duration-[70ms] ease-hairline\",\n              \"focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-1 focus-visible:ring-offset-sunken\",\n              \"disabled:cursor-not-allowed disabled:opacity-45\",\n              s.item,\n              s.text,\n              fullWidth && \"flex-1\",\n              active ? \"text-fg\" : \"text-fg-muted hover:text-fg\"\n            )}\n          >\n            {active ? (\n              <motion.span\n                layoutId={layoutId}\n                aria-hidden\n                data-slot=\"segmented-control-thumb\"\n                className=\"absolute inset-0 -z-10 rounded-[inherit] bg-raised shadow-[0_1px_2px_0_oklch(0_0_0/0.08),0_0_0_1px_var(--border),inset_0_1px_0_0_var(--highlight)]\"\n                transition={reduce ? { duration: 0 } : { type: \"spring\", bounce: 0.18, duration: 0.42 }}\n              />\n            ) : (\n              <span\n                aria-hidden\n                className=\"absolute inset-0 -z-10 rounded-[inherit] bg-fg/0 transition-colors duration-[70ms] group-hover/seg:bg-fg/[0.035] group-active/seg:bg-fg/[0.06]\"\n              />\n            )}\n            {o.icon}\n            <span>{o.label}</span>\n            {o.badge ? (\n              <span\n                className={cn(\n                  \"rounded-full px-1.5 py-px font-mono text-[10px] leading-4 tabular-nums transition-colors duration-[70ms]\",\n                  active ? \"bg-accent-soft text-accent-fg\" : \"bg-fg/5 text-fg-subtle\"\n                )}\n              >\n                {o.badge}\n              </span>\n            ) : null}\n          </button>\n        )\n      })}\n    </div>\n  )\n}\n\nexport { SegmentedControl }\nexport type { SegmentedControlProps }\n"
    }
  ]
}
