{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "segmented-control", "title": "Segmented Control", "description": "Single-selection pill navigation on Radix ToggleGroup. Bare, track and glass containers; ink, chalk and glass tones.", "dependencies": [ "class-variance-authority", "radix-ui" ], "registryDependencies": [ "http://localhost:5173/r/liquid-theme.json", "toggle-group" ], "files": [ { "path": "src/components/ui/segmented-control.tsx", "content": "import * as React from \"react\"\nimport { ToggleGroup as ToggleGroupPrimitive } from \"radix-ui\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * The Karma / Credits / Money switch. Built on Radix ToggleGroup so roving\n * focus, arrow-key navigation and single-selection semantics come for free —\n * the visual treatment is the only thing this file owns.\n */\nconst root = cva(\"inline-flex items-center\", {\n variants: {\n variant: {\n /** Free-standing pills, no container. The reference navigation. */\n bare: \"gap-2\",\n /** Pills inside a hairline track. */\n track: \"gap-1 rounded-full border border-current/12 p-1\",\n /** Pills inside a frosted track — for placement over photography. */\n glass: \"lq-glass gap-1 rounded-full p-1\",\n },\n size: {\n sm: \"text-[12px]\",\n md: \"text-[13px]\",\n lg: \"text-[15px]\",\n },\n },\n defaultVariants: { variant: \"bare\", size: \"md\" },\n})\n\nconst item = cva(\n \"relative inline-flex select-none items-center justify-center rounded-full font-sans font-medium whitespace-nowrap lq-ease transition-[background-color,color,border-color,transform] duration-300 outline-none focus-visible:ring-3 focus-visible:ring-current/25 disabled:pointer-events-none disabled:opacity-40\",\n {\n variants: {\n size: {\n sm: \"h-7 px-3\",\n md: \"h-9 px-4\",\n lg: \"h-11 px-5\",\n },\n tone: {\n /** Active fills black; inactive is a hairline outline. The reference. */\n ink: \"border border-current/15 text-current/65 hover:text-current data-[state=on]:border-transparent data-[state=on]:bg-ink data-[state=on]:text-white\",\n /** Active fills white — use on dark or photographic grounds. */\n chalk:\n \"border border-white/20 text-white/65 hover:text-white data-[state=on]:border-transparent data-[state=on]:bg-white data-[state=on]:text-ink\",\n /** Active is a frosted pill rather than a fill. */\n glass:\n \"border border-transparent text-current/60 hover:text-current data-[state=on]:lq-glass data-[state=on]:text-current\",\n },\n },\n defaultVariants: { size: \"md\", tone: \"ink\" },\n },\n)\n\nexport interface SegmentedControlProps\n extends Omit<\n React.ComponentProps,\n \"type\" | \"value\" | \"defaultValue\" | \"onValueChange\"\n >,\n VariantProps {\n options: { value: string; label: React.ReactNode; disabled?: boolean }[]\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n tone?: VariantProps[\"tone\"]\n}\n\nexport function SegmentedControl({\n options,\n value,\n defaultValue,\n onValueChange,\n variant,\n size,\n tone,\n className,\n ...props\n}: SegmentedControlProps) {\n return (\n v && onValueChange?.(v)}\n className={cn(root({ variant, size }), className)}\n {...props}\n >\n {options.map((opt) => (\n \n {opt.label}\n \n ))}\n \n )\n}\n", "type": "registry:ui" } ], "type": "registry:ui" }