"use client"; import * as React from "react"; import { motion } from "framer-motion"; import { cn } from "../lib/utils"; import { transitions } from "../lib/motion"; export interface SegmentedOption { value: T; label: React.ReactNode; icon?: React.ReactNode; } /** * A row of mutually exclusive choices with a sliding selection. Arrow keys * move the selection (roving focus), like a native radio group. */ export function SegmentedControl({ value, onValueChange, options, size = "md", label, className, }: { value: T; onValueChange: (value: T) => void; options: Array>; size?: "sm" | "md"; label: string; className?: string; }) { const id = React.useId(); const refs = React.useRef>([]); const selectedIndex = Math.max(0, options.findIndex((option) => option.value === value)); const move = (delta: number) => { const next = (selectedIndex + delta + options.length) % options.length; const option = options[next]; if (!option) return; onValueChange(option.value); refs.current[next]?.focus(); }; return (
{ if (event.key === "ArrowRight" || event.key === "ArrowDown") { event.preventDefault(); move(1); } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") { event.preventDefault(); move(-1); } }} > {options.map((option, index) => { const selected = option.value === value; return ( ); })}
); }