Files
cosmos-explorer/src/Explorer/Tabs/DocumentsTabV2/SelectionHelper.ts
Laurent Nguyen 7002da0b51 Implement ctrl-shift click to select multiple documents (#1851)
* Initial implementation of shift and ctrl click to select

* Implement shift-ctrl selection

* Fix snapshot, update selectionHelper comment

* Fix missing type

* Properly disable cursor selection

* Update snapshots

* Do not enable (multiselect) if readonly

* Consider meta key for mac and ctrl for everything else
2024-06-05 17:47:27 +02:00

93 lines
3.0 KiB
TypeScript

/**
* Utility class to help with selection.
* This emulates File Explorer selection behavior.
* ctrl: toggle selection of index.
* shift: select all rows between selectionStartIndex and index
* shift + ctrl: select or deselect all rows between selectionStartIndex and index depending on whether selectionStartIndex is selected
* No modifier only selects the clicked row
* ctrl: updates selection start index
* shift: do not update selection start index
*
* @param currentSelection current selection
* @param clickedIndex index of clicked row
* @param isShiftKey shift key is pressed
* @param isCtrlKey ctrl key is pressed
* @param selectionStartIndex index of current selected row
* @returns new selection and selection start
*/
export const selectionHelper = (
currentSelection: Set<number>,
clickedIndex: number,
isShiftKey: boolean,
isCtrlKey: boolean,
selectionStartIndex: number,
): {
selection: Set<number>;
selectionStartIndex: number;
} => {
if (isShiftKey) {
// Shift is about selecting range of rows
if (isCtrlKey) {
// shift + ctrl
const isSelectionStartIndexSelected = currentSelection.has(selectionStartIndex);
const min = Math.min(clickedIndex, selectionStartIndex);
const max = Math.max(clickedIndex, selectionStartIndex);
const newSelection = new Set<number>(currentSelection);
for (let i = min; i <= max; i++) {
// Select or deselect range depending on how selectionStartIndex is selected
if (isSelectionStartIndexSelected) {
// Select range
newSelection.add(i);
} else {
// Deselect range
newSelection.delete(i);
}
}
return {
selection: newSelection,
selectionStartIndex: undefined,
};
} else {
// shift only
// Shift only: enable everything between lastClickedIndex and clickedIndex and disable everything else
const min = Math.min(clickedIndex, selectionStartIndex);
const max = Math.max(clickedIndex, selectionStartIndex);
const newSelection = new Set<number>();
for (let i = min; i <= max; i++) {
newSelection.add(i);
}
return {
selection: newSelection,
selectionStartIndex: undefined, // do not change selection start
};
}
} else {
if (isCtrlKey) {
// Ctrl only: toggle selection where we clicked
const isNotSelected = !currentSelection.has(clickedIndex);
if (isNotSelected) {
return {
selection: new Set(currentSelection.add(clickedIndex)),
selectionStartIndex: clickedIndex,
};
} else {
// Remove
currentSelection.delete(clickedIndex);
return {
selection: new Set(currentSelection),
selectionStartIndex: clickedIndex,
};
}
} else {
// If no modifier keys are pressed, select only the clicked row
return {
selection: new Set<number>([clickedIndex]),
selectionStartIndex: clickedIndex,
};
}
}
};