fix: misc UI updates and fixes

This commit is contained in:
Xiaohan-Tian
2026-05-07 23:54:08 -07:00
parent 1e33caafc5
commit eead27dbd8
6 changed files with 150 additions and 109 deletions
@@ -26,6 +26,8 @@ interface PianoRollAutomationLaneProps {
timeSignature: { numerator: number; denominator: number };
bpm?: number;
redrawVersion?: number;
horizontalScrollLeft?: number;
onHorizontalWheel?: (delta: number) => void;
}
const AUTOMATION_COLOR = '#87CEFA';
@@ -38,6 +40,8 @@ const PianoRollAutomationLane: React.FC<PianoRollAutomationLaneProps> = ({
maxBars,
timeSignature,
redrawVersion = 0,
horizontalScrollLeft = 0,
onHorizontalWheel,
}) => {
const laneRef = useRef<HTMLDivElement | null>(null);
const [laneHeight, setLaneHeight] = useState(MIN_LANE_HEIGHT);
@@ -66,6 +70,28 @@ const PianoRollAutomationLane: React.FC<PianoRollAutomationLaneProps> = ({
};
}, []);
useEffect(() => {
const element = laneRef.current;
if (!element) {
return;
}
const handleWheel = (event: WheelEvent) => {
const horizontalDelta = Math.abs(event.deltaX) > 0 ? event.deltaX : (event.shiftKey ? event.deltaY : 0);
if (horizontalDelta === 0) {
return;
}
event.preventDefault();
onHorizontalWheel?.(horizontalDelta);
};
element.addEventListener('wheel', handleWheel, { passive: false });
return () => {
element.removeEventListener('wheel', handleWheel);
};
}, [onHorizontalWheel]);
const points = useMemo<AutomationPoint[]>(() => {
if (!activeRegion) {
return [];
@@ -160,62 +186,67 @@ const PianoRollAutomationLane: React.FC<PianoRollAutomationLaneProps> = ({
>
<div className="piano-roll-automation-track" style={{ width: totalWidth }}>
<div className="piano-roll-automation-gutter" />
<div className="piano-roll-automation-grid" />
<div className="piano-roll-automation-lane-label">{laneLabel}</div>
<svg
className="piano-roll-automation-svg"
width="100%"
height={laneHeight}
viewBox={`0 0 ${beatWidth * totalBeats + keyWidth} ${laneHeight}`}
preserveAspectRatio="none"
<div
className="piano-roll-automation-scroll-layer"
style={{ transform: `translateX(-${horizontalScrollLeft}px)` }}
>
{interpolationMode === 'linear' && points.length > 0 && (
<polyline
className="piano-roll-automation-line"
fill="none"
stroke={AUTOMATION_COLOR}
strokeWidth="2"
points={polylinePoints}
/>
)}
{interpolationMode === 'step' && stepSegments.map(segment => (
<line
key={segment.id}
className="piano-roll-automation-line"
x1={segment.x1}
y1={segment.y1}
x2={segment.x2}
y2={segment.y1}
stroke={AUTOMATION_COLOR}
strokeWidth="2"
/>
))}
{svgPoints.map(point => {
const labelY = Math.max(14, Math.min(laneHeight - 6, point.y - 10));
<div className="piano-roll-automation-grid" />
<svg
className="piano-roll-automation-svg"
width="100%"
height={laneHeight}
viewBox={`0 0 ${beatWidth * totalBeats + keyWidth} ${laneHeight}`}
preserveAspectRatio="none"
>
{interpolationMode === 'linear' && points.length > 0 && (
<polyline
className="piano-roll-automation-line"
fill="none"
stroke={AUTOMATION_COLOR}
strokeWidth="2"
points={polylinePoints}
/>
)}
{interpolationMode === 'step' && stepSegments.map(segment => (
<line
key={segment.id}
className="piano-roll-automation-line"
x1={segment.x1}
y1={segment.y1}
x2={segment.x2}
y2={segment.y1}
stroke={AUTOMATION_COLOR}
strokeWidth="2"
/>
))}
{svgPoints.map(point => {
const labelY = Math.max(14, Math.min(laneHeight - 6, point.y - 10));
return (
<g key={point.id}>
<circle
className="piano-roll-automation-point"
cx={point.x}
cy={point.y}
r="5"
fill={AUTOMATION_COLOR}
stroke="#1d2428"
strokeWidth="2"
/>
<text
className="piano-roll-automation-value"
x={point.x + 6}
y={labelY}
fill={AUTOMATION_COLOR}
>
{point.label}
</text>
</g>
);
})}
</svg>
return (
<g key={point.id}>
<circle
className="piano-roll-automation-point"
cx={point.x}
cy={point.y}
r="5"
fill={AUTOMATION_COLOR}
stroke="#1d2428"
strokeWidth="2"
/>
<text
className="piano-roll-automation-value"
x={point.x + 6}
y={labelY}
fill={AUTOMATION_COLOR}
>
{point.label}
</text>
</g>
);
})}
</svg>
</div>
{points.length === 0 && (
<div className="piano-roll-automation-empty-state">
No {laneLabel} events in this region