diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index dfbeda648c..173fa419cc 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -5784,6 +5784,7 @@ const { restoreCellSelectionState, cellIsSelected, columnIsSelected, + columnIsExclusivelySelected, selectedRangeStart, selectedRowIds, selectedColumnIndexes, @@ -10543,7 +10544,7 @@ watch( function onHeaderContext(col: string, columnIndex: number) { invalidateContextMenuTarget(); const visibleColIdx = visibleColumnIndexes.value.indexOf(columnIndex); - if (visibleColIdx >= 0 && !columnIsSelected(visibleColIdx)) { + if (visibleColIdx >= 0 && !columnIsExclusivelySelected(visibleColIdx)) { selectColumn(visibleColIdx); } contextHeaderColumn.value = col; diff --git a/apps/desktop/src/composables/__tests__/useDataGridSelection.spec.ts b/apps/desktop/src/composables/__tests__/useDataGridSelection.spec.ts index a19b60dcc5..c2754e7439 100644 --- a/apps/desktop/src/composables/__tests__/useDataGridSelection.spec.ts +++ b/apps/desktop/src/composables/__tests__/useDataGridSelection.spec.ts @@ -122,6 +122,38 @@ describe("useDataGridSelection", () => { expect(selection.selectedColumnIndexes.value).toEqual(new Set([0, 1, 2])); }); + it("distinguishes a column merely covered by a wider full-height range from one exclusively selected", () => { + const selection = createSelection(); + + // Full-height rectangle spanning columns 1-2 (e.g. dragged across two columns). + selection.selectSingleCell(0, 1); + selection.extendCellSelectionTo(3, 2); + + expect(selection.columnIsSelected(1)).toBe(true); + expect(selection.columnIsSelected(2)).toBe(true); + expect(selection.columnIsExclusivelySelected(1)).toBe(false); + expect(selection.columnIsExclusivelySelected(2)).toBe(false); + + // Narrowing to just column 1 (what a header click/selectColumn does) makes it exclusive. + selection.selectColumn(1); + + expect(selection.columnIsExclusivelySelected(1)).toBe(true); + expect(selection.columnIsExclusivelySelected(2)).toBe(false); + }); + + it("treats an explicit multi-column header selection as exclusive for every column it contains", () => { + const selection = createSelection(); + + // Deliberate multi-column selection via header click + shift-click (not a stray cell range). + selection.selectColumn(0); + selection.selectColumn(1, rowEvent({ shift: true })); + + expect(selection.hasColumnSelection.value).toBe(true); + expect(selection.columnIsExclusivelySelected(0)).toBe(true); + expect(selection.columnIsExclusivelySelected(1)).toBe(true); + expect(selection.columnIsExclusivelySelected(2)).toBe(false); + }); + it("moves a single-column rectangular cell selection with its column after reordering", () => { const selection = createSelection(); diff --git a/apps/desktop/src/composables/useDataGridSelection.ts b/apps/desktop/src/composables/useDataGridSelection.ts index 6e954ef988..de269f0d3b 100644 --- a/apps/desktop/src/composables/useDataGridSelection.ts +++ b/apps/desktop/src/composables/useDataGridSelection.ts @@ -694,6 +694,18 @@ export function useDataGridSelection(options: UseDataGridSelectionOptions) { return range.startCol <= colIndex && range.endCol >= colIndex && range.startRow === 0 && range.endRow >= displayItems.value.length - 1; } + // Unlike columnIsSelected (used for header highlighting, where any column touched by a + // wider selection should light up), this requires the selected cell RANGE to cover this + // column only. An explicit multi-column header selection (hasColumnSelection) is left as-is: + // that's a deliberate user gesture (click/shift-click/ctrl-click headers), not a stray + // full-height cell range left over from selecting a block in the grid body. + function columnIsExclusivelySelected(colIndex: number): boolean { + if (hasColumnSelection.value) return selectedColumnIndexes.value.has(colIndex); + const range = selectedRange.value; + if (!range) return false; + return range.startCol === colIndex && range.endCol === colIndex && range.startRow === 0 && range.endRow >= displayItems.value.length - 1; + } + function selectedRangeStart(): CellPosition | null { const range = selectedRange.value; if (!range) return null; @@ -727,6 +739,7 @@ export function useDataGridSelection(options: UseDataGridSelectionOptions) { isCellSelectionDragConfirmed, cellIsSelected, columnIsSelected, + columnIsExclusivelySelected, selectedRangeStart, selectedRowIds, selectedColumnIndexes,