fix: selectedItemIds snapshot includes toggled item for drag

React batches setSelectedItemIds, so when handleSetPendingDrag
snapshots selectedItemIds, the just-toggled item isn't included
yet. Fix: pass wasAlreadySelected boolean from TimelineTrack
mousedown; handleSetPendingDrag manually applies the toggle
(add/delete) to the snapshot so drag uses correct selection.
This commit is contained in:
2026-07-27 22:25:11 +07:00
parent 74fdc2b303
commit 0992879b49
2 changed files with 23 additions and 16 deletions
+17 -10
View File
@@ -1084,13 +1084,14 @@ const WaveformLane = ({
e.stopPropagation();
if (e.ctrlKey) {
// Ctrl+Click: toggle selection only, never start drag immediately
if (selectedItemIds && selectedItemIds.has(hitItem.id)) {
var ctrlWasSelected = selectedItemIds && selectedItemIds.has(hitItem.id);
if (ctrlWasSelected) {
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);
if (onSetPendingDrag) onSetPendingDrag(track.id, hitItem.type, hitItem.id, time - hitItem.start, e.nativeEvent || e, ctrlWasSelected);
} else {
// No modifier: start drag immediately (single or multi move)
if (onSectionItemDragStart) onSectionItemDragStart(track.id, hitItem.type, hitItem.id, time - hitItem.start, false);
@@ -1152,12 +1153,13 @@ const WaveformLane = ({
if (e.ctrlKey) {
// Ctrl+Click: toggle selection, store pending drag
var clipCanonicalId = clickedClip.id === 'default' ? 'default_' + track.id : clickedClip.id;
if (selectedItemIds && selectedItemIds.has(clipCanonicalId)) {
var ctrlClipSelected = selectedItemIds && selectedItemIds.has(clipCanonicalId);
if (ctrlClipSelected) {
if (onDeselectItem) onDeselectItem(clipCanonicalId);
} else if (onAddToSelection) {
onAddToSelection(clipCanonicalId);
}
if (onSetPendingDrag) onSetPendingDrag(track.id, 'clip', clipCanonicalId, time - clickedClip.startTime, e.nativeEvent || e);
if (onSetPendingDrag) onSetPendingDrag(track.id, 'clip', clipCanonicalId, time - clickedClip.startTime, e.nativeEvent || e, ctrlClipSelected);
} else {
// Alt+Click: move immediately
if (onClipDragStart) onClipDragStart(track.id, clickedClip.id, time - clickedClip.startTime, false);
@@ -11664,8 +11666,11 @@ const App = () => {
return next;
});
};
const handleSetPendingDrag = (trackId, itemType, itemId, clickOffset, e) => {
pendingDragRef.current = { trackId, itemType, itemId, clickOffset, startX: e.clientX, startY: e.clientY };
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 };
};
// Sweep Select
@@ -11680,11 +11685,12 @@ const App = () => {
};
// Section / MIDI Item Drag Start
const handleSectionItemDragStart = (trackId, itemType, itemId, clickOffset, isDuplicate) => {
const handleSectionItemDragStart = (trackId, itemType, itemId, clickOffset, isDuplicate, pendingSelectedIds) => {
var curTracks = activeTracksRef.current || activeTracks;
var multiIds = null;
if (selectedItemIds && selectedItemIds.size > 0 && selectedItemIds.has(itemId)) {
var selArr = Array.from(selectedItemIds);
var selIds = pendingSelectedIds || selectedItemIds;
if (selIds && selIds.size > 0 && selIds.has(itemId)) {
var selArr = Array.from(selIds);
var originals = {};
curTracks.forEach(function(t) {
(t.sections || []).forEach(function(s) {
@@ -11876,8 +11882,9 @@ const App = () => {
if (!pd) return;
var dx = e.clientX - pd.startX;
if (Math.abs(dx) > 5) {
var pdSnap = pendingDragRef.current;
pendingDragRef.current = null;
if (handleSectionItemDragStartRef.current) handleSectionItemDragStartRef.current(pd.trackId, pd.itemType, pd.itemId, pd.clickOffset, true);
if (handleSectionItemDragStartRef.current) handleSectionItemDragStartRef.current(pdSnap.trackId, pdSnap.itemType, pdSnap.itemId, pdSnap.clickOffset, true, pdSnap.selectedIds);
}
};
document.addEventListener('mousemove', handleMouseMove);