fix: clip being deselected after dragging it

This commit is contained in:
Maze Winther
2025-06-26 01:36:49 +02:00
parent dd80064be6
commit 0f470ba7a7

View File

@ -936,6 +936,16 @@ export function Timeline() {
y: e.clientY, 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 <TimelineTrackContent
track={track} track={track}
@ -1162,8 +1172,10 @@ function TimelineTrackContent({
const [dropPosition, setDropPosition] = useState<number | null>(null); const [dropPosition, setDropPosition] = useState<number | null>(null);
const [wouldOverlap, setWouldOverlap] = useState(false); const [wouldOverlap, setWouldOverlap] = useState(false);
const dragCounterRef = useRef(0); const dragCounterRef = useRef(0);
const [mouseDownLocation, setMouseDownLocation] = useState<{
const [justFinishedDrag, setJustFinishedDrag] = useState(false); x: number;
y: number;
} | null>(null);
// Set up mouse event listeners for drag // Set up mouse event listeners for drag
useEffect(() => { useEffect(() => {
@ -1252,20 +1264,10 @@ function TimelineTrackContent({
]); ]);
const handleClipMouseDown = (e: React.MouseEvent, clip: TypeTimelineClip) => { const handleClipMouseDown = (e: React.MouseEvent, clip: TypeTimelineClip) => {
// Handle selection first setMouseDownLocation({ x: e.clientX, y: e.clientY });
if (!justFinishedDrag) { // Handle multi-selection only in mousedown
const isSelected = selectedClips.some(
(c) => c.trackId === track.id && c.clipId === clip.id
);
if (e.metaKey || e.ctrlKey || e.shiftKey) { if (e.metaKey || e.ctrlKey || e.shiftKey) {
// Multi-selection mode: toggle the clip
selectClip(track.id, clip.id, true); 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
} }
// Calculate the offset from the left edge of the clip to where the user clicked // 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) => { const handleClipClick = (e: React.MouseEvent, clip: TypeTimelineClip) => {
e.stopPropagation(); e.stopPropagation();
console.log( // Check if mouse moved significantly
"handleClipClick called, contextMenu:", if (mouseDownLocation) {
JSON.stringify(contextMenu) const deltaX = Math.abs(e.clientX - mouseDownLocation.x);
); const deltaY = Math.abs(e.clientY - mouseDownLocation.y);
console.log("Boolean check:", !!contextMenu, "Type:", typeof contextMenu); // If it moved more than a few pixels, consider it a drag and not a click.
if (deltaX > 5 || deltaY > 5) {
// Don't handle click if we just finished dragging setMouseDownLocation(null); // Reset for next interaction
if (justFinishedDrag) {
console.log("Skipping because justFinishedDrag");
return; return;
} }
}
// Close context menu if it's open // Close context menu if it's open
if (contextMenu) { if (contextMenu) {
console.log("Closing context menu");
setContextMenu(null); setContextMenu(null);
return; // Don't handle selection when closing context menu 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( const isSelected = selectedClips.some(
(c) => c.trackId === track.id && c.clipId === clip.id (c) => c.trackId === track.id && c.clipId === clip.id
); );
if (isSelected && !e.metaKey && !e.ctrlKey && !e.shiftKey) { if (isSelected) {
// If clip is already selected and no modifier keys, deselect it // If clip is selected, deselect it
deselectClip(track.id, clip.id); 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) => { const handleTrackDragOver = (e: React.DragEvent) => {
e.preventDefault(); 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} onDragOver={handleTrackDragOver}
onDragEnter={handleTrackDragEnter} onDragEnter={handleTrackDragEnter}
onDragLeave={handleTrackDragLeave} onDragLeave={handleTrackDragLeave}