diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-06-26 01:36:49 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-06-26 01:36:49 +0200 |
| commit | 0f470ba7a7a8c3c51ed6fffed46cbc404139f617 (patch) | |
| tree | 44403fed8912dea1641407aad00196def2d0dd91 /apps/web | |
| parent | dd80064be6edf45b0d93aa1881db5de4e3789840 (diff) | |
| download | opencut-0f470ba7a7a8c3c51ed6fffed46cbc404139f617.tar.gz | |
fix: clip being deselected after dragging it
Diffstat (limited to 'apps/web')
| -rw-r--r-- | apps/web/src/components/editor/timeline.tsx | 86 |
1 files changed, 44 insertions, 42 deletions
diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index 765e2aa1..18e1e915 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -936,6 +936,16 @@ export function Timeline() { y: e.clientY, }); }} + onClick={(e) => { + // If clicking empty area (not on a clip), deselect all clips + if ( + !(e.target as HTMLElement).closest(".timeline-clip") + ) { + const { clearSelectedClips } = + useTimelineStore.getState(); + clearSelectedClips(); + } + }} > <TimelineTrackContent track={track} @@ -1162,8 +1172,10 @@ function TimelineTrackContent({ const [dropPosition, setDropPosition] = useState<number | null>(null); const [wouldOverlap, setWouldOverlap] = useState(false); const dragCounterRef = useRef(0); - - const [justFinishedDrag, setJustFinishedDrag] = useState(false); + const [mouseDownLocation, setMouseDownLocation] = useState<{ + x: number; + y: number; + } | null>(null); // Set up mouse event listeners for drag useEffect(() => { @@ -1252,20 +1264,10 @@ function TimelineTrackContent({ ]); const handleClipMouseDown = (e: React.MouseEvent, clip: TypeTimelineClip) => { - // Handle selection first - if (!justFinishedDrag) { - const isSelected = selectedClips.some( - (c) => c.trackId === track.id && c.clipId === clip.id - ); - - if (e.metaKey || e.ctrlKey || e.shiftKey) { - // Multi-selection mode: toggle the clip - selectClip(track.id, clip.id, true); - } else if (!isSelected) { - // If clip is not selected, select it (replacing other selections) - selectClip(track.id, clip.id, false); - } - // Note: Don't deselect if already selected, as user might want to drag + setMouseDownLocation({ x: e.clientX, y: e.clientY }); + // Handle multi-selection only in mousedown + if (e.metaKey || e.ctrlKey || e.shiftKey) { + selectClip(track.id, clip.id, true); } // Calculate the offset from the left edge of the clip to where the user clicked @@ -1286,35 +1288,39 @@ function TimelineTrackContent({ const handleClipClick = (e: React.MouseEvent, clip: TypeTimelineClip) => { e.stopPropagation(); - console.log( - "handleClipClick called, contextMenu:", - JSON.stringify(contextMenu) - ); - console.log("Boolean check:", !!contextMenu, "Type:", typeof contextMenu); - - // Don't handle click if we just finished dragging - if (justFinishedDrag) { - console.log("Skipping because justFinishedDrag"); - return; + // Check if mouse moved significantly + if (mouseDownLocation) { + const deltaX = Math.abs(e.clientX - mouseDownLocation.x); + const deltaY = Math.abs(e.clientY - mouseDownLocation.y); + // If it moved more than a few pixels, consider it a drag and not a click. + if (deltaX > 5 || deltaY > 5) { + setMouseDownLocation(null); // Reset for next interaction + return; + } } // Close context menu if it's open if (contextMenu) { - console.log("Closing context menu"); setContextMenu(null); return; // Don't handle selection when closing context menu } - console.log("Proceeding to selection logic"); + // Skip selection logic for multi-selection (handled in mousedown) + if (e.metaKey || e.ctrlKey || e.shiftKey) { + return; + } - // Only handle deselection here (selection is handled in mouseDown) + // Handle single selection/deselection const isSelected = selectedClips.some( (c) => c.trackId === track.id && c.clipId === clip.id ); - if (isSelected && !e.metaKey && !e.ctrlKey && !e.shiftKey) { - // If clip is already selected and no modifier keys, deselect it + if (isSelected) { + // If clip is selected, deselect it deselectClip(track.id, clip.id); + } else { + // If clip is not selected, select it (replacing other selections) + selectClip(track.id, clip.id, false); } }; @@ -1330,17 +1336,6 @@ function TimelineTrackContent({ }); }; - // Reset drag flag when drag ends - useEffect(() => { - if (!dragState.isDragging && justFinishedDrag) { - const timer = setTimeout(() => setJustFinishedDrag(false), 50); - return () => clearTimeout(timer); - } else if (!dragState.isDragging && dragState.clipId && !justFinishedDrag) { - // Only set justFinishedDrag when a drag actually ends (not when it starts) - setJustFinishedDrag(true); - } - }, [dragState.isDragging, justFinishedDrag, dragState.clipId]); - const handleTrackDragOver = (e: React.DragEvent) => { e.preventDefault(); @@ -1685,6 +1680,13 @@ function TimelineTrackContent({ }); } }} + onClick={(e) => { + // If clicking empty area (not on a clip), deselect all clips + if (!(e.target as HTMLElement).closest(".timeline-clip")) { + const { clearSelectedClips } = useTimelineStore.getState(); + clearSelectedClips(); + } + }} onDragOver={handleTrackDragOver} onDragEnter={handleTrackDragEnter} onDragLeave={handleTrackDragLeave} |
