fix: Ctrl+click+drag copies pre-toggle selection, not post-toggle

Ctrl+click toggle selection THEN drag started -> selIds.has(itemId)
returned false because the item was just removed from snapshot.
Fix: snapshot selectedItemIds BEFORE toggle, pass to pendingDrag.
Drag always copies the original group; toggle is only visual.
This commit is contained in:
2026-07-27 22:31:29 +07:00
parent 292c787a31
commit 1ca2ec6d01
2 changed files with 15 additions and 18 deletions
+10 -13
View File
@@ -1084,14 +1084,14 @@ const WaveformLane = ({
e.stopPropagation();
if (e.ctrlKey) {
// Ctrl+Click: toggle selection only, never start drag immediately
var ctrlWasSelected = selectedItemIds && selectedItemIds.has(hitItem.id);
if (ctrlWasSelected) {
var preToggleSnapshot = selectedItemIds ? new Set(selectedItemIds) : new Set();
if (selectedItemIds && selectedItemIds.has(hitItem.id)) {
if (onDeselectItem) onDeselectItem(hitItem.id);
} else if (onAddToSelection) {
onAddToSelection(hitItem.id);
}
// Store pending drag so mousemove can start copy-drag
if (onSetPendingDrag) onSetPendingDrag(track.id, hitItem.type, hitItem.id, time - hitItem.start, e.nativeEvent || e, ctrlWasSelected);
// Store pre-toggle snapshot so drag copies the ORIGINAL group
if (onSetPendingDrag) onSetPendingDrag(track.id, hitItem.type, hitItem.id, time - hitItem.start, e.nativeEvent || e, preToggleSnapshot);
} else {
// No modifier: start drag immediately (single or multi move)
if (onSectionItemDragStart) onSectionItemDragStart(track.id, hitItem.type, hitItem.id, time - hitItem.start, false);
@@ -1151,15 +1151,15 @@ const WaveformLane = ({
e.preventDefault();
e.stopPropagation();
if (e.ctrlKey) {
// Ctrl+Click: toggle selection, store pending drag
// Ctrl+Click: toggle selection, store pending drag w/ pre-toggle snapshot
var clipCanonicalId = clickedClip.id === 'default' ? 'default_' + track.id : clickedClip.id;
var ctrlClipSelected = selectedItemIds && selectedItemIds.has(clipCanonicalId);
if (ctrlClipSelected) {
var clipPreToggleSnapshot = selectedItemIds ? new Set(selectedItemIds) : new Set();
if (selectedItemIds && selectedItemIds.has(clipCanonicalId)) {
if (onDeselectItem) onDeselectItem(clipCanonicalId);
} else if (onAddToSelection) {
onAddToSelection(clipCanonicalId);
}
if (onSetPendingDrag) onSetPendingDrag(track.id, 'clip', clipCanonicalId, time - clickedClip.startTime, e.nativeEvent || e, ctrlClipSelected);
if (onSetPendingDrag) onSetPendingDrag(track.id, 'clip', clipCanonicalId, time - clickedClip.startTime, e.nativeEvent || e, clipPreToggleSnapshot);
} else {
// Alt+Click: move immediately
if (onClipDragStart) onClipDragStart(track.id, clickedClip.id, time - clickedClip.startTime, false);
@@ -11666,11 +11666,8 @@ const App = () => {
return next;
});
};
const handleSetPendingDrag = (trackId, itemType, itemId, clickOffset, e, wasAlreadySelected) => {
var snap = new Set(selectedItemIds);
if (wasAlreadySelected) snap.delete(itemId);
else snap.add(itemId);
pendingDragRef.current = { trackId, itemType, itemId, clickOffset, startX: e.clientX, startY: e.clientY, selectedIds: snap };
const handleSetPendingDrag = (trackId, itemType, itemId, clickOffset, e, preToggleSnapshot) => {
pendingDragRef.current = { trackId, itemType, itemId, clickOffset, startX: e.clientX, startY: e.clientY, selectedIds: preToggleSnapshot || new Set(selectedItemIds) };
};
// Sweep Select