Fix Ctrl+A selecting grid instead of comment text (#12193)#12283
Merged
Fix Ctrl+A selecting grid instead of comment text (#12193)#12283
Conversation
Stop keyboard events from propagating to the grid shortcut system while the comment textarea is visible and focused. This prevents grid-level shortcuts (e.g. Ctrl+A select all cells) from firing when the user intends to interact with the comment editor text. Shortcuts registered in the plugin:comments context (Escape, Ctrl+Enter, Tab) are allowed through. Co-authored-by: Marek Martuszewski <sl01k@users.noreply.github.com>
commit: |
Contributor
⚡ Performance Results
All scenarios within tolerance ✅ |
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Hardcoded shortcut allowlist duplicates registered shortcuts knowledge
- Replaced the hardcoded key allowlist with a dynamic check against registered
plugin:commentsshortcuts and added an E2E regression test for a newly registered shortcut.
- Replaced the hardcoded key allowlist with a dynamic check against registered
Or push these changes by commenting:
@cursor push befdd71603
Preview (befdd71603)
diff --git a/handsontable/src/plugins/comments/__tests__/keyboardShortcuts.spec.js b/handsontable/src/plugins/comments/__tests__/keyboardShortcuts.spec.js
--- a/handsontable/src/plugins/comments/__tests__/keyboardShortcuts.spec.js
+++ b/handsontable/src/plugins/comments/__tests__/keyboardShortcuts.spec.js
@@ -334,6 +334,45 @@
});
});
+ describe('custom comments context shortcut', () => {
+ it('should execute a shortcut registered in the plugin context while the editor is focused', async() => {
+ handsontable({
+ data: createSpreadsheetData(4, 4),
+ rowHeaders: true,
+ colHeaders: true,
+ comments: true,
+ });
+
+ await selectCell(1, 1);
+ await keyDownUp(['control', 'alt', 'm']);
+ await waitForNextAnimationFrames(1);
+
+ let wasTriggered = false;
+ const editor = getPlugin('comments').getEditorInputElement();
+ const pluginContext = getShortcutManager().getContext('plugin:comments');
+
+ pluginContext.addShortcut({
+ keys: [['Control/Meta', 'S']],
+ callback: () => {
+ wasTriggered = true;
+ },
+ group: 'test',
+ });
+
+ const keyEvent = new KeyboardEvent('keydown', {
+ key: 's',
+ ctrlKey: true,
+ bubbles: true,
+ cancelable: true,
+ });
+
+ editor.dispatchEvent(keyEvent);
+ await waitForNextAnimationFrames(1);
+
+ expect(wasTriggered).toBe(true);
+ });
+ });
+
describe('"Cmd/Ctrl" + "Enter"', () => {
it('should close the comment and save the value (comment opened by keyboard shortcut)', async() => {
handsontable({
diff --git a/handsontable/src/plugins/comments/comments.js b/handsontable/src/plugins/comments/comments.js
--- a/handsontable/src/plugins/comments/comments.js
+++ b/handsontable/src/plugins/comments/comments.js
@@ -13,6 +13,7 @@
import { CellRange } from '../../3rdparty/walkontable/src';
import { BasePlugin } from '../base';
import { throwWithCause } from '../../helpers/errors';
+import { normalizeEventKey } from '../../shortcuts/utils';
import CommentEditor from './commentEditor';
import DisplaySwitch from './displaySwitch';
import { getEditorAnchorWidth } from './utils';
@@ -851,15 +852,51 @@
return;
}
- const { key, ctrlKey, metaKey } = event;
+ if (!this.#isCommentsContextShortcut(event)) {
+ event.stopPropagation();
+ }
+ }
- const isEscape = key === 'Escape';
- const isCtrlEnter = (ctrlKey || metaKey) && key === 'Enter';
- const isTab = key === 'Tab';
+ /**
+ * Checks if the keydown event has a matching shortcut in the comments context.
+ *
+ * @param {KeyboardEvent} event The keydown event from the comment textarea.
+ * @returns {boolean}
+ */
+ #isCommentsContextShortcut(event) {
+ const shortcutContext = this.hot.getShortcutManager().getContext(SHORTCUTS_CONTEXT_NAME);
- if (!isEscape && !isCtrlEnter && !isTab) {
- event.stopPropagation();
+ if (!shortcutContext || typeof event.key !== 'string') {
+ return false;
}
+
+ const key = normalizeEventKey(event);
+ const modifiers = [];
+
+ if (event.altKey) {
+ modifiers.push('alt');
+ }
+ if (event.ctrlKey) {
+ modifiers.push('control');
+ }
+ if (event.metaKey) {
+ modifiers.push('meta');
+ }
+ if (event.shiftKey) {
+ modifiers.push('shift');
+ }
+
+ if (shortcutContext.hasShortcut([key, ...modifiers])) {
+ return true;
+ }
+
+ if (event.ctrlKey || event.metaKey) {
+ const modifiersWithoutCtrlMeta = modifiers.filter(modifier => modifier !== 'control' && modifier !== 'meta');
+
+ return shortcutContext.hasShortcut([key, ...modifiersWithoutCtrlMeta, 'control/meta']);
+ }
+
+ return false;
}
/**This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
Instead of hardcoding Escape/Ctrl+Enter/Tab in #onEditorKeyDown, query the plugin:comments shortcut context dynamically via hasShortcut(). This eliminates duplicated knowledge between registerShortcuts() and the keydown handler, so future shortcut changes in the comments context are picked up automatically. Co-authored-by: Adrian Dusinkiewicz <adrianspdev@users.noreply.github.com>
Expose getEventKeyCombinations in shortcuts/utils.js to centralize the event-to-keys conversion (normalizeEventKey + modifier extraction + control/meta unification). Add hasEventShortcut(contextName, event) to ShortcutManager as a public API method. The Comments plugin now uses this API instead of reimplementing the recorder's internal key matching logic. The normalizeEventKey import is removed from the plugin. Co-authored-by: Adrian Dusinkiewicz <adrianspdev@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9bf9317. Configure here.
Move MODIFIER_KEYS, isModifierKey, and getPressedModifierKeys from recorder.js to utils.js as shared exports. The recorder now imports them instead of defining its own copies. Add isMacOS guard to getEventKeyCombinations: the unified control/meta form is only generated when the OS-native modifier is pressed (Meta on macOS, Control on other systems), matching the recorder's existing behavior. Co-authored-by: Adrian Dusinkiewicz <adrianspdev@users.noreply.github.com>
budnix
approved these changes
Apr 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Context
Fixes #12193. When a user opens a comment editor (via context menu or Ctrl+Alt+M), types text, repositions the cursor inside the text, and presses Ctrl+A (or Cmd+A on Mac), the entire grid is selected instead of the text within the comment textarea.
Root cause: The Comments plugin's
#onAfterDocumentKeyDownhandler callsstopImmediatePropagation(event)in theafterDocumentKeyDownhook, which fires after the shortcut system has already processed the event. The grid context'sCtrl+Ashortcut (selectAllCells()) executes before the Comments plugin can block it.Fix: Added a
keydownevent listener directly on the comment textarea element that callsevent.stopPropagation()to prevent keyboard events from bubbling up to the grid's shortcut system (which listens ondocument.documentElement). Events matching shortcuts registered in theplugin:commentscontext are allowed through via the newShortcutManager.hasEventShortcut()API.Architecture: To avoid duplicating the recorder's internal key matching logic,
MODIFIER_KEYS,isModifierKey, andgetPressedModifierKeyswere extracted fromrecorder.jsintoshortcuts/utils.jsas shared exports. A newgetEventKeyCombinations(event, platformCheck)utility builds key combination arrays from aKeyboardEvent(with the OS-awareisMacOSguard forcontrol/metaunification), andhasEventShortcut(contextName, event)was added toShortcutManageras the public API. The Comments plugin calls this single method instead of reimplementing any shortcut matching.How has this been tested?
keyboardShortcuts.spec.jsverifying that Ctrl+A does not trigger grid "select all" when the comment textarea is focused (both via keyboard shortcut and context menu).Types of changes
Related issue(s):
Affected project(s):
handsontable@handsontable/angular-wrapper@handsontable/react-wrapper@handsontable/vue3Checklist: