import * as React from 'react'; import { useKnobTheme } from '../core/theme'; export interface SegmentSwitchProps { /** Position labels, e.g. ['LINEAR', 'RADIAL', 'CONIC']. */ options: readonly string[]; /** Controlled selected index. Pair with `onChange`. */ value?: number; defaultValue?: number; onChange?: (index: number) => void; /** Accent for the active cell's LED tick and text. */ color?: string; /** Control height in px. Default: 30. */ size?: number; /** Show the LED tick on the active cell. Default: true. */ led?: boolean; disabled?: boolean; /** Render a hidden form input carrying the selected option text. */ name?: string; className?: string; style?: React.CSSProperties; 'aria-label'?: string; } /** * Hardware-styled segmented selector — the horizontal sibling of * SteppedKnob. Renders a radiogroup; arrow keys move the selection. */ export const SegmentSwitch = React.forwardRef( function SegmentSwitch( { options, value, defaultValue = 0, onChange, color, size = 30, led = true, disabled = false, name, className, style, ...aria }, ref, ) { const theme = useKnobTheme(); const accent = color ?? theme.accent ?? '#4cc2ff'; const isControlled = value !== undefined; const [internal, setInternal] = React.useState(defaultValue); const active = Math.max(0, Math.min(options.length - 1, isControlled ? (value as number) : internal)); const btnRefs = React.useRef<(HTMLButtonElement | null)[]>([]); const select = (i: number, focus = false) => { const next = Math.max(0, Math.min(options.length - 1, i)); if (focus) btnRefs.current[next]?.focus(); if (next === active) return; if (!isControlled) setInternal(next); onChange?.(next); }; const onKeyDown = (e: React.KeyboardEvent) => { if (disabled) return; if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); select(active + 1, true); } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); select(active - 1, true); } else if (e.key === 'Home') { e.preventDefault(); select(0, true); } else if (e.key === 'End') { e.preventDefault(); select(options.length - 1, true); } }; return (
{options.map((opt, i) => { const isActive = i === active; return ( ); })} {name && }
); }, );