Skip to content

feat(grid): spreadsheet-style keyboard selection and header column select - #683

Open
debba wants to merge 1 commit into
mainfrom
feat/grid-selection-shortcuts
Open

feat(grid): spreadsheet-style keyboard selection and header column select#683
debba wants to merge 1 commit into
mainfrom
feat/grid-selection-shortcuts

Conversation

@debba

@debba debba commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Closes #673

What changed

Spreadsheet-style (Google Sheets) selection shortcuts in the data grid. All of them are relative to the focused cell (single click or arrow navigation):

Shortcut Action
Shift+Arrow extend a rectangular cell range by one step (anchor stays fixed, the opposite corner moves)
Ctrl/Cmd+Arrow jump the focused cell to the grid edge
Ctrl/Cmd+Shift+Arrow extend the range to the grid edge
Ctrl/Cmd+Home / End first / last cell
Shift+Space select the row(s) of the focused cell or of the current range
Ctrl/Cmd+Space, or Ctrl/Cmd+Shift+Space select the column(s) of the focused cell or of the current range

Ctrl+Shift+Space is offered as an alternative because plain Ctrl+Space is often consumed before it reaches the app (ibus/fcitx on Linux, Spotlight on macOS).

Header changes:

  • A plain click on a column header now selects that column (replacing the selection). Ctrl/Cmd+click still toggles, Shift+click still range-selects.
  • Sorting moves to the sort icon next to the column name, which is now a real <button> with the sort aria-label/title. It is still revealed on hover as before.

Row, column and cell-range selection stay mutually exclusive, so Ctrl+C keeps unambiguous copy semantics. The focused cell is kept after Shift/Ctrl+Space so shortcuts can be chained (for example Shift+Down three times, then Shift+Space, selects four rows).

Other:

  • Range logic extracted into pure helpers in src/utils/dataGrid.ts (buildCellRange, getRangeCursor, moveCellPosition, extendCellRange); handleCellClick reuses buildCellRange.
  • New bindings listed in the Shortcuts settings tab (shortcuts.json, non overridable), with strings in all 11 locales.

Behaviour changes to be aware of

  1. Ctrl+Left/Right with a focused cell no longer paginates: the grid stops the event and jumps to the edge. The next_page / prev_page shortcuts still work when no cell is focused, and from the pagination buttons. If we prefer to avoid the overlap entirely, the pagination defaults could move to another combination (they are user overridable).
  2. Plain header click no longer sorts; sorting is on the icon. The existing test asserting "plain click still sorts" was replaced accordingly.

Verification

  • pnpm test --run: 235 files, 3892 tests passing (new unit tests for the range helpers and component tests for every new shortcut and the header click behaviour)
  • pnpm lint: 0 errors (one pre-existing warning in ThemeProvider.tsx, untouched)
  • pnpm build: ok

Manual testing still needed on Linux with an IME configured and on macOS, to confirm the Ctrl+Space fallback story.

…lect

Adds Google Sheets style selection shortcuts to the data grid, relative to the
focused cell: Shift+Arrow extends a cell range, Ctrl/Cmd+Arrow jumps to the grid
edge, Ctrl/Cmd+Shift+Arrow extends the range to the edge, Ctrl/Cmd+Home/End go
to the first/last cell, Shift+Space selects the row(s) and Ctrl/Cmd+Space (or
Ctrl/Cmd+Shift+Space, for systems where Ctrl+Space is taken by the IME or
Spotlight) selects the column(s).

A plain click on a column header now selects the column; sorting moves to the
sort icon, which becomes a proper button. Ctrl/Cmd+click toggling and
Shift+click range selection are unchanged.

The range logic is extracted into pure helpers in utils/dataGrid.ts with unit
tests, and the new bindings are listed in the Shortcuts settings tab.

Closes #673
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat]: Shortcuts for Row, Column & Cell Range

1 participant