// TODO -- CUSTOM DROPDOWN STYLING import { useMemo, useCallback, useEffect, useState } from 'react'; const Select = (props) => { return ( ); }; const Checkbox = (props) => { return ( props.onChange(e.target.checked)} defaultChecked={props.value} value={props.value} /> ); }; const RAD = Math.PI / 180; const START_ANGLE = Math.PI * 1.5 - (RAD * 45) / 2; const END_ANGLE = Math.PI * -0.5 + (RAD * 45) / 2; function getPointPair(r, angle, distance) { return [r + distance * Math.cos(angle), r - distance * Math.sin(angle)]; } function DialMask({ id, size, startAngle, endAngle }) { const r = size / 2; const intermediatePoints = [0, 0.25, 0.5, 0.75, 1] .map((fraction) => getPointPair( r, startAngle - (startAngle - endAngle) * fraction, r * 4 ).join(',') ) .join(' '); return ( ); } function getKnobValue(dragStart, currentY, bipolar) { const { y, value } = dragStart; const deltaY = y - currentY; const slope = 0.01; let newValue = value + deltaY * slope; if (bipolar) { const zeroCrossingResistance = 0.2; //0.3 if (value >= 0 && newValue < 0) { newValue += Math.min(zeroCrossingResistance, -newValue); } else if (value < 0 && newValue > 0) { newValue -= Math.min(zeroCrossingResistance, newValue); } } // Clamp return Math.max(bipolar ? -1 : 0, Math.min(1, newValue)); } let knob_id = 0; function Knob({ max = 127, dual = false, size = 42, value = 0, fillWidth = 4, onChange, offset = 0, }) { value = value / max; const uid = useMemo(() => knob_id++, []); const radius = size / 2; const dial_zero = dual ? Math.PI / 2 : START_ANGLE; const dial_range = dual ? (START_ANGLE - END_ANGLE) / 2 : START_ANGLE - END_ANGLE; const valueAngle = dual ? Math.PI / 2 - value * dial_range : START_ANGLE - value * dial_range; const [lineX1, lineY1] = getPointPair( size / 2, valueAngle, radius - fillWidth + 3 ); const [dragStart, setDragStart] = useState(null); const isDragging = Boolean(dragStart); const onMouseMove = useCallback( (e) => { if (!dragStart) return; const newValue = getKnobValue(dragStart, e.clientY, dual); onChange(Math.round(newValue * max)); }, [dragStart, onChange, dual, max] ); const onMouseDown = useCallback( (e) => { if (e.nativeEvent.button !== 0) return; e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); setDragStart({ value, y: e.nativeEvent.clientY }); window.addEventListener('mousemove', onMouseMove); }, [setDragStart, onMouseMove, value] ); const onMouseUp = useCallback(() => { setDragStart(null); }, [setDragStart]); useEffect(() => { if (!isDragging) { window.removeEventListener('mousemove', onMouseMove); } window.addEventListener('mousemove', onMouseMove); return () => window.removeEventListener('mousemove', onMouseMove); }, [isDragging, onMouseMove]); useEffect(() => { window.addEventListener('mouseup', onMouseUp); return () => { window.removeEventListener('mouseup', onMouseUp); }; }, [onMouseUp]); useEffect(() => { if (!onMouseMove) return; return () => window.removeEventListener('mousemove', onMouseMove); }, [onMouseMove]); return (
{/* TOOLTIP */}
{Math.round(value * max + offset)}
{/* KNOB */} {/* Track outer */} {/* Value fill */} {/* Knob */} {/* Highlight */} { }
); } export { Select, Knob, Checkbox };