fix: tempo track height 40px fixed + clamp selection >= 0

- TempoTrackLane canvas height fixed to 40px, wrapper h-10 shrink-0 overflow-hidden
- selLeft/selRight clamped to Math.max(0, ...)
- rulerAnchorRef/setSelectionStart/setSelectionEnd clamped >= 0
This commit is contained in:
2026-07-25 10:55:46 +07:00
parent e14006ffcc
commit 8be4ce99e1
3 changed files with 25 additions and 16 deletions
+15 -12
View File
@@ -1292,7 +1292,7 @@ const TempoTrackLane = ({
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1;
const scrollLeftVal = scrollLeft || 0;
const height = canvas.parentElement ? canvas.parentElement.clientHeight : 40;
const height = 40;
canvas.width = Math.min(Math.round(drawWidth * dpr), 32768);
canvas.height = Math.min(Math.round(height * dpr), 32768);
ctx.scale(dpr, dpr);
@@ -8676,17 +8676,17 @@ const App = () => {
const playheadLeftPos = useMemo(() => (currentTime + leadInMargin) * zoom, [currentTime, zoom, leadInMargin]);
const selLeft = useMemo(() => {
if (selectionMode === 'local' && localSelectionStart !== null && localSelectionEnd !== null) {
return Math.min(localSelectionStart, localSelectionEnd);
return Math.max(0, Math.min(localSelectionStart, localSelectionEnd));
}
if (selectionStart === null || selectionEnd === null) return null;
return Math.min(selectionStart, selectionEnd);
return Math.max(0, Math.min(selectionStart, selectionEnd));
}, [selectionStart, selectionEnd, selectionMode, localSelectionStart, localSelectionEnd]);
const selRight = useMemo(() => {
if (selectionMode === 'local' && localSelectionStart !== null && localSelectionEnd !== null) {
return Math.max(localSelectionStart, localSelectionEnd);
return Math.max(0, Math.max(localSelectionStart, localSelectionEnd));
}
if (selectionStart === null || selectionEnd === null) return null;
return Math.max(selectionStart, selectionEnd);
return Math.max(0, Math.max(selectionStart, selectionEnd));
}, [selectionStart, selectionEnd, selectionMode, localSelectionStart, localSelectionEnd]);
const dspSelectionStats = useMemo(() => {
@@ -10032,14 +10032,14 @@ const App = () => {
e.stopPropagation();
// Shift+click on ruler: lock existing anchor (or currentTime fallback) and extend global selection
const anchor = rulerAnchorRef.current !== null && rulerAnchorRef.current !== undefined ? rulerAnchorRef.current : selectionStart !== null && selectionStart !== undefined ? selectionStart : currentTime;
const selS = Math.min(anchor, time);
const selE = Math.max(anchor, time);
const selS = Math.max(0, Math.min(anchor, time));
const selE = Math.max(0, Math.max(anchor, time));
setSelectionStart(selS);
setSelectionEnd(selE);
} else {
rulerAnchorRef.current = time;
setSelectionStart(time);
setSelectionEnd(time);
rulerAnchorRef.current = Math.max(0, time);
setSelectionStart(Math.max(0, time));
setSelectionEnd(Math.max(0, time));
}
handlePlayheadSet(time);
};
@@ -14960,7 +14960,10 @@ const App = () => {
onRulerMouseDown: handleRulerMouseDown,
scrollLeft: scrollLeft,
canvasRedrawCount: canvasRedrawCount
}), /*#__PURE__*/React.createElement(TempoTrackLane, {
}), /*#__PURE__*/React.createElement("div", {
className: "h-10 shrink-0 relative overflow-hidden",
style: { height: '40px' }
}, /*#__PURE__*/React.createElement(TempoTrackLane, {
bpm: parseInt(bpm) || 120,
zoom: zoom,
timelineWidth: timelineWidth,
@@ -14970,7 +14973,7 @@ const App = () => {
onRulerMouseDown: handleRulerMouseDown,
scrollLeft: scrollLeft,
canvasRedrawCount: canvasRedrawCount
}), selectionMode === 'global' && selLeft !== null && selRight !== null && selRight > selLeft && /*#__PURE__*/React.createElement("div", {
})), selectionMode === 'global' && selLeft !== null && selRight !== null && selRight > selLeft && /*#__PURE__*/React.createElement("div", {
className: "absolute inset-0 pointer-events-none z-20",
style: {
left: `${selLeft * zoom}px`,