From af11aaa8feab3e2650a907c6c9200f99d0cb19cb Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Tue, 7 Jul 2026 14:09:27 +0200 Subject: [PATCH] dbeaver/cloudbeaver#3815 upgrades lib to version where it works (#4165) * dbeaver/cloudbeaver#3815 upgrades lib to version where it works * dbeaver/pro#3815 updates react-hotkeys-hook lib * dbeaver/pro#3815 fixes build * dbeaver/pro#3815 fixes case dependant hotkeys activation * dbeaver/pro#3815 allows textbox form tag to support sql editor --------- Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> --- webapp/packages/core-blocks/package.json | 2 +- webapp/packages/core-blocks/src/useHotkeys.ts | 62 +++++++++++-------- .../core-view/src/View/CaptureView.tsx | 3 +- .../core-view/src/View/parseHotkey.test.ts | 8 ++- .../core-view/src/View/parseHotkey.ts | 11 ++-- webapp/yarn.lock | 22 +++---- 6 files changed, 63 insertions(+), 45 deletions(-) diff --git a/webapp/packages/core-blocks/package.json b/webapp/packages/core-blocks/package.json index bc590cf240..bdc4118bcd 100644 --- a/webapp/packages/core-blocks/package.json +++ b/webapp/packages/core-blocks/package.json @@ -42,7 +42,7 @@ "mobx-react-lite": "^4", "react": "^19", "react-dom": "^19", - "react-hotkeys-hook": "5.1.0", + "react-hotkeys-hook": "^5", "react-minisearch": "^7", "subscript": "^9", "tslib": "^2" diff --git a/webapp/packages/core-blocks/src/useHotkeys.ts b/webapp/packages/core-blocks/src/useHotkeys.ts index d5c6c90ea5..14f66bb166 100644 --- a/webapp/packages/core-blocks/src/useHotkeys.ts +++ b/webapp/packages/core-blocks/src/useHotkeys.ts @@ -1,54 +1,66 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ + +import type { DependencyList } from 'react'; export { useHotkeys, type Hotkey } from 'react-hotkeys-hook'; // TODO: types broken in ESM declare module 'react-hotkeys-hook' { - export type FormTags = 'input' | 'textarea' | 'select' | 'INPUT' | 'TEXTAREA' | 'SELECT'; - export type Keys = string | readonly string[]; + export type FormTags = + | 'input' + | 'textarea' + | 'select' + | 'INPUT' + | 'TEXTAREA' + | 'SELECT' + | 'searchbox' + | 'slider' + | 'spinbutton' + | 'menuitem' + | 'menuitemcheckbox' + | 'menuitemradio' + | 'option' + | 'radio' + | 'textbox'; export type Scopes = string | readonly string[]; + + export type EventListenerOptions = + | { + capture?: boolean; + once?: boolean; + passive?: boolean; + signal?: AbortSignal; + } + | boolean; // useCapture + export type KeyboardModifiers = { alt?: boolean; ctrl?: boolean; meta?: boolean; shift?: boolean; mod?: boolean; - useKey?: boolean; + useKey?: boolean; // Custom modifier to listen to the produced key instead of the code }; + export type Hotkey = KeyboardModifiers & { keys?: readonly string[]; scopes?: Scopes; description?: string; isSequence?: boolean; + hotkey: string; + metadata?: Record; }; + export type HotkeysEvent = Hotkey; - export type HotkeyCallback = (keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => void; + export type Trigger = boolean | ((keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean); - export type Options = { - enabled?: Trigger; - enableOnFormTags?: readonly FormTags[] | boolean; - enableOnContentEditable?: boolean; - ignoreEventWhen?: (e: KeyboardEvent) => boolean; - splitKey?: string; - delimiter?: string; - scopes?: Scopes; - keyup?: boolean; - keydown?: boolean; - preventDefault?: Trigger; - description?: string; - document?: Document; - ignoreModifiers?: boolean; - eventListenerOptions?: EventListenerOptions; - useKey?: boolean; - sequenceTimeoutMs?: number; - sequenceSplitKey?: string; - }; - export type OptionsOrDependencyArray = Options | import('react').DependencyList; + + export type OptionsOrDependencyArray = Options | DependencyList; export function useHotkeys( keys: Keys, callback: HotkeyCallback, diff --git a/webapp/packages/core-view/src/View/CaptureView.tsx b/webapp/packages/core-view/src/View/CaptureView.tsx index 0788a0185c..8da700bf57 100644 --- a/webapp/packages/core-view/src/View/CaptureView.tsx +++ b/webapp/packages/core-view/src/View/CaptureView.tsx @@ -66,7 +66,8 @@ export const CaptureView = observer>( }, { enabled: allKeys.length > 0, - enableOnFormTags: ['INPUT', 'SELECT', 'TEXTAREA'], + useKey: true, + enableOnFormTags: ['INPUT', 'SELECT', 'TEXTAREA', 'textbox'], preventDefault(event, handler) { // Don't prevent default if event was already handled by a child view if (EventContext.has(event, EventStopPropagationFlag)) { diff --git a/webapp/packages/core-view/src/View/parseHotkey.test.ts b/webapp/packages/core-view/src/View/parseHotkey.test.ts index 8e56d2212a..8e75581857 100644 --- a/webapp/packages/core-view/src/View/parseHotkey.test.ts +++ b/webapp/packages/core-view/src/View/parseHotkey.test.ts @@ -139,10 +139,14 @@ describe('parseHotkey', () => { expect(result.keys).toContain('a'); }); - it('sets isSequence and useKey to false', () => { + it('sets isSequence to false', () => { const result = parseHotkey('ctrl+a'); expect(result.isSequence).toBe(false); - expect(result.useKey).toBe(false); + }); + + it('sets useKey to true', () => { + const result = parseHotkey('ctrl+a'); + expect(result.useKey).toBe(true); }); it('does not include modifiers in keys array', () => { diff --git a/webapp/packages/core-view/src/View/parseHotkey.ts b/webapp/packages/core-view/src/View/parseHotkey.ts index 3ea281f85d..18f38b3150 100644 --- a/webapp/packages/core-view/src/View/parseHotkey.ts +++ b/webapp/packages/core-view/src/View/parseHotkey.ts @@ -82,10 +82,9 @@ export function isBindingPressed(event: KeyboardEvent, } export function parseHotkey(hotkey: string, combinationKey = '+'): Hotkey { - const keys = hotkey - .toLocaleLowerCase() - .split(combinationKey) - .map(k => mapKey(k)); + hotkey = hotkey.toLocaleLowerCase(); + + const keys = hotkey.split(combinationKey).map(k => mapKey(k)); const modifiers: Record = { alt: keys.includes('alt'), @@ -99,9 +98,11 @@ export function parseHotkey(hotkey: string, combinationKey = '+'): Hotkey { return { ...modifiers, + hotkey, keys: singleCharKeys, isSequence: false, - useKey: false, + metadata: undefined, + useKey: true, description: undefined, }; } diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 0aeb995cff..a4c67cd01a 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -1531,7 +1531,7 @@ __metadata: mobx-react-lite: "npm:^4" react: "npm:^19" react-dom: "npm:^19" - react-hotkeys-hook: "npm:5.1.0" + react-hotkeys-hook: "npm:^5" react-minisearch: "npm:^7" rimraf: "npm:^6" subscript: "npm:^9" @@ -17220,16 +17220,6 @@ __metadata: languageName: node linkType: hard -"react-hotkeys-hook@npm:5.1.0": - version: 5.1.0 - resolution: "react-hotkeys-hook@npm:5.1.0" - peerDependencies: - react: ">=16.8.0" - react-dom: ">=16.8.0" - checksum: 10c0/99df6d3c305b139ac7afd073b58575961bf30a819fb23e8f1251b1b3a9f1c7662737f8b6266e3fc42bd5bdfdaca81aa1e019613f95f9a6313267de265e45836d - languageName: node - linkType: hard - "react-hotkeys-hook@npm:^4.6.1": version: 4.6.2 resolution: "react-hotkeys-hook@npm:4.6.2" @@ -17240,6 +17230,16 @@ __metadata: languageName: node linkType: hard +"react-hotkeys-hook@npm:^5": + version: 5.3.3 + resolution: "react-hotkeys-hook@npm:5.3.3" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 10c0/311f3b749cdd5ba20832fb2ea97cd94248f25ebe8417f0da2a76be7a2ca0fa94dfd2fe9eb1d399f41305f65937690825d167708f5d5c27652cb90a97ce0dbf06 + languageName: node + linkType: hard + "react-inspector@npm:^6.0.2": version: 6.0.2 resolution: "react-inspector@npm:6.0.2"