diff --git a/components/tracks/Track.tsx b/components/tracks/Track.tsx index 5fee5bd..fcd4daf 100644 --- a/components/tracks/Track.tsx +++ b/components/tracks/Track.tsx @@ -68,6 +68,8 @@ export function Track({ // Selection state const [isSelecting, setIsSelecting] = React.useState(false); const [selectionStart, setSelectionStart] = React.useState(null); + const [isSelectingByDrag, setIsSelectingByDrag] = React.useState(false); + const [dragStartPos, setDragStartPos] = React.useState<{ x: number; y: number } | null>(null); const handleNameClick = () => { setIsEditingName(true); @@ -224,41 +226,66 @@ export function Track({ const rect = e.currentTarget.getBoundingClientRect(); const x = e.clientX - rect.left; + const y = e.clientY - rect.top; const clickTime = (x / rect.width) * duration; - // Shift+drag to create selection - if (e.shiftKey) { - setIsSelecting(true); - setSelectionStart(clickTime); - onSelectionChange?.({ start: clickTime, end: clickTime }); - } else { - // Regular click clears selection and seeks - onSelectionChange?.(null); - if (onSeek) { - onSeek(clickTime); - } - } + // Store drag start position + setDragStartPos({ x: e.clientX, y: e.clientY }); + setIsSelectingByDrag(false); + + // Start selection immediately (will be used if user drags) + setIsSelecting(true); + setSelectionStart(clickTime); }; const handleCanvasMouseMove = (e: React.MouseEvent) => { - if (!isSelecting || selectionStart === null || !duration) return; + if (!isSelecting || selectionStart === null || !duration || !dragStartPos) return; const rect = e.currentTarget.getBoundingClientRect(); const x = e.clientX - rect.left; const currentTime = (x / rect.width) * duration; - // Clamp to valid time range - const clampedTime = Math.max(0, Math.min(duration, currentTime)); + // Check if user has moved enough to be considered dragging (threshold: 3 pixels) + const dragDistance = Math.sqrt( + Math.pow(e.clientX - dragStartPos.x, 2) + Math.pow(e.clientY - dragStartPos.y, 2) + ); - // Update selection (ensure start < end) - const start = Math.min(selectionStart, clampedTime); - const end = Math.max(selectionStart, clampedTime); + if (dragDistance > 3) { + setIsSelectingByDrag(true); + } - onSelectionChange?.({ start, end }); + // If dragging, update selection + if (isSelectingByDrag || dragDistance > 3) { + // Clamp to valid time range + const clampedTime = Math.max(0, Math.min(duration, currentTime)); + + // Update selection (ensure start < end) + const start = Math.min(selectionStart, clampedTime); + const end = Math.max(selectionStart, clampedTime); + + onSelectionChange?.({ start, end }); + } }; - const handleCanvasMouseUp = () => { + const handleCanvasMouseUp = (e: React.MouseEvent) => { + if (!duration) return; + + const rect = e.currentTarget.getBoundingClientRect(); + const x = e.clientX - rect.left; + const clickTime = (x / rect.width) * duration; + + // If user didn't drag (just clicked), clear selection and seek + if (!isSelectingByDrag) { + onSelectionChange?.(null); + if (onSeek) { + onSeek(clickTime); + } + } + + // Reset drag state setIsSelecting(false); + setIsSelectingByDrag(false); + setDragStartPos(null); }; // Handle mouse leaving canvas during selection @@ -266,6 +293,8 @@ export function Track({ const handleGlobalMouseUp = () => { if (isSelecting) { setIsSelecting(false); + setIsSelectingByDrag(false); + setDragStartPos(null); } };