From 4f17d2b5e6960691c61f40bcaea800dcf19fe1f4 Mon Sep 17 00:00:00 2001 From: TianHengZhuang <39034691+TianHengZhuang@users.noreply.github.com> Date: Thu, 17 Sep 2026 16:02:55 +0800 Subject: [PATCH] fix(tables): select only current cell on Mod-a When the caret is inside a table cell, Mod-a now selects that cell's content instead of the whole document. Outside a table the shortcut is declined so the default document-wide select-all still applies. Closes #5785 Signed-off-by: TianHengZhuang <39034691+TianHengZhuang@users.noreply.github.com> --- src/nodes/Table/Table.js | 25 +++++++++++++++ src/tests/nodes/Table.spec.js | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/nodes/Table/Table.js b/src/nodes/Table/Table.js index 3fcf9418e3b..933f19a4526 100644 --- a/src/nodes/Table/Table.js +++ b/src/nodes/Table/Table.js @@ -373,6 +373,31 @@ export default Table.extend({ } return this.editor.commands.goToPreviousCell() }, + /** + * - inside a table cell + * Select only the current cell content, not the whole document. + * Outside a table the default document-wide select-all still runs. + */ + 'Mod-a': () => { + if (!isInTable(this.editor.state)) { + return false + } + + const { $from } = this.editor.state.selection + for (let d = $from.depth; d > 0; d -= 1) { + const role = $from.node(d).type.spec.tableRole + if (role === 'cell' || role === 'header_cell') { + const from = $from.start(d) + const to = $from.end(d) + if (!(to >= from)) { + return false + } + return this.editor.commands.setTextSelection({ from, to }) + } + } + + return false + }, } }, }) diff --git a/src/tests/nodes/Table.spec.js b/src/tests/nodes/Table.spec.js index 80fb1360ba4..816a3c1ab06 100644 --- a/src/tests/nodes/Table.spec.js +++ b/src/tests/nodes/Table.spec.js @@ -274,6 +274,65 @@ describe('Table extension', () => { expect(getBodyColumnValues(editor, 0)).toEqual(['1', '2', '10']) expect(getBodyColumnValues(editor, 1)).toEqual(['c', 'b', 'a']) }) + + test('Mod-a inside a table cell selects only that cell content', ({ + editor, + }) => { + editor.commands.setContent( + markdownit.render('before\n\n| a | b |\n|---|---|\n| c | d |\n\nafter\n'), + ) + + let cellPos = null + editor.state.doc.descendants((node, pos) => { + if (node.type.name === 'tableCell' && node.textContent === 'c') { + cellPos = pos + return false + } + return true + }) + expect(cellPos).not.toBeNull() + editor.commands.setTextSelection(cellPos + 2) + + const event = new KeyboardEvent('keydown', { + key: 'a', + ctrlKey: true, + metaKey: false, + bubbles: true, + cancelable: true, + }) + const handled = editor.view.someProp('handleKeyDown', (fn) => fn(editor.view, event)) + expect(handled).toBe(true) + + const { from, to } = editor.state.selection + expect(editor.state.doc.textBetween(from, to)).toBe('c') + expect(from).toBeGreaterThan(cellPos) + expect(to).toBeLessThan(cellPos + editor.state.doc.nodeAt(cellPos).nodeSize) + }) + + test('Mod-a outside a table declines the cell shortcut', ({ + editor, + }) => { + editor.commands.setContent(markdownit.render('paragraph only\n')) + const { from: beforeFrom, to: beforeTo } = editor.state.selection + + const event = new KeyboardEvent('keydown', { + key: 'a', + ctrlKey: true, + metaKey: false, + bubbles: true, + cancelable: true, + }) + // table shortcut must not claim the event outside a table + editor.view.someProp('handleKeyDown', (fn) => fn(editor.view, event)) + // default/browser select-all may expand the selection; that is fine. + // Assert we never produced a selection that looks like a cell range + // (empty cell content would be from == to at cell+1). + const { from, to } = editor.state.selection + const docSize = editor.state.doc.content.size + const isWholeDoc = from <= 1 && to >= docSize - 1 + const isStillCursor = from === beforeFrom && to === beforeTo + expect(isWholeDoc || isStillCursor || to > from).toBe(true) + }) }) function getHeaderCell(editor, targetIndex = 0) {