/** * DualRange — one bounded, dual-thumb control for an output's routing range. * The same control is used by the main-view output editor and the Outputs * drawer so min/max edits have identical interaction and clamping semantics. */ import { useRef } from 'react'; import type { PointerEvent as ReactPointerEvent } from 'react'; export interface DualRangeProps { min: number; max: number; onMin: (value: number) => void; onMax: (value: number) => void; } export function DualRange({ min, max, onMin, onMax }: DualRangeProps) { const track = useRef(null); const drag = useRef<{ which: 'min' | 'max' | null }>({ which: null }); const valueAt = (clientX: number) => { const el = track.current; if (!el) return 0; const rect = el.getBoundingClientRect(); return Math.max(0, Math.min(1, (clientX - rect.left) / rect.width)); }; const apply = (value: number) => { if (drag.current.which === 'min') onMin(Math.min(value, max)); else if (drag.current.which === 'max') onMax(Math.max(value, min)); }; const down = (event: ReactPointerEvent) => { event.currentTarget.setPointerCapture?.(event.pointerId); const value = valueAt(event.clientX); drag.current.which = Math.abs(value - min) <= Math.abs(value - max) ? 'min' : 'max'; apply(value); }; const move = (event: ReactPointerEvent) => { if (drag.current.which) apply(valueAt(event.clientX)); }; const up = () => { drag.current.which = null; }; return (
); } function Thumb({ pct, color }: { pct: number; color: string }) { return (
); }