Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion webapp/packages/core-blocks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"mobx-react-lite": "^4",
"react": "^19",
"react-dom": "^19",
"react-hotkeys-hook": "5.1.0",
"react-hotkeys-hook": "5.2.3",
"react-minisearch": "^7",
"subscript": "^9",
"tslib": "^2"
Expand Down
62 changes: 58 additions & 4 deletions webapp/packages/core-blocks/src/useHotkeys.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,108 @@
/*
* 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 FormTags =
| 'input'
| 'textarea'
| 'select'
| 'INPUT'
| 'TEXTAREA'
| 'SELECT'
| 'searchbox'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we extend the initial form tags here? slider and, spinbutton and menuitem looks strange here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it Is copy pasted types from the lib itself. added it for consistency

| 'slider'
| 'spinbutton'
| 'menuitem'
| 'menuitemcheckbox'
| 'menuitemradio'
| 'option'
| 'radio'
| 'textbox';
export type Keys = string | readonly string[];
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<string, unknown>;
};

export type HotkeysEvent = Hotkey;

export type HotkeyCallback = (keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => void;

export type Trigger = boolean | ((keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent) => boolean);

export type Options = {
// Main setting that determines if the hotkey is enabled or not. (Default: true)
enabled?: Trigger;
// Enable hotkeys on a list of tags. (Default: false)
enableOnFormTags?: readonly FormTags[] | boolean;
// Enable hotkeys on tags with contentEditable props. (Default: false)
enableOnContentEditable?: boolean;
// Ignore evenets based on a condition (Default: undefined)
ignoreEventWhen?: (e: KeyboardEvent) => boolean;
// Character to split keys in hotkeys combinations. (Default: +)
splitKey?: string;
// Character to separate different hotkeys. (Default: ,)
delimiter?: string;
// Scope of the hotkey. (Default: undefined)
scopes?: Scopes;
// Trigger on keyup event? (Default: undefined)
keyup?: boolean;
// Trigger on keydown event? (Default: true)
keydown?: boolean;
// Prevent default browser behavior? (Default: false)
preventDefault?: Trigger;
// Use this option to describe what the hotkey does. (Default: undefined)
description?: string;
// Listen to events on the document instead of the window. (Default: false)
document?: Document;
// Ignore modifiers when matching hotkeys. (Default: false)
ignoreModifiers?: boolean;
// Pass through event listener options. (Default: undefined)
eventListenerOptions?: EventListenerOptions;
// Listen to the produced key instead of the code. (Default: false)
useKey?: boolean;
// The timeout to wait for the next key to be pressed. (Default: 1000ms)
sequenceTimeoutMs?: number;
// The character to split the sequence of keys. (Default: >)
sequenceSplitKey?: string;
// MetaData | Custom data to store and retrieve with the hotkey (Default: undefined)
metadata?: Record<string, unknown>;
};
export type OptionsOrDependencyArray = Options | import('react').DependencyList;

export type OptionsOrDependencyArray = Options | DependencyList;
export function useHotkeys<T extends HTMLElement>(
keys: Keys,
callback: HotkeyCallback,
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-view/src/View/CaptureView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const CaptureView = observer<React.PropsWithChildren<ICaptureViewProps>>(
},
{
enabled: allKeys.length > 0,
useKey: true,
enableOnFormTags: ['INPUT', 'SELECT', 'TEXTAREA'],
preventDefault(event, handler) {
// Don't prevent default if event was already handled by a child view
Expand Down
6 changes: 4 additions & 2 deletions webapp/packages/core-view/src/View/parseHotkey.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* 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.
Expand Down Expand Up @@ -65,9 +65,11 @@ export function parseHotkey(hotkey: string, combinationKey = '+'): Hotkey {

return {
...modifiers,
hotkey,
keys: singleCharKeys,
isSequence: false,
useKey: false,
metadata: undefined,
useKey: true,
description: undefined,
};
}
10 changes: 5 additions & 5 deletions webapp/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,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.2.3"
react-minisearch: "npm:^7"
rimraf: "npm:^6"
subscript: "npm:^9"
Expand Down Expand Up @@ -16707,13 +16707,13 @@ __metadata:
languageName: node
linkType: hard

"react-hotkeys-hook@npm:5.1.0":
version: 5.1.0
resolution: "react-hotkeys-hook@npm:5.1.0"
"react-hotkeys-hook@npm:5.2.3":
version: 5.2.3
resolution: "react-hotkeys-hook@npm:5.2.3"
peerDependencies:
react: ">=16.8.0"
react-dom: ">=16.8.0"
checksum: 10c0/99df6d3c305b139ac7afd073b58575961bf30a819fb23e8f1251b1b3a9f1c7662737f8b6266e3fc42bd5bdfdaca81aa1e019613f95f9a6313267de265e45836d
checksum: 10c0/24ba0eaa2195bb504628aec7813c9014370ae71ab1489359690fba00f04c06d189ed191be1fbcdc3d1b6119e3e6a4051342c0a30b7c5dacd7f7b8457a1672624
languageName: node
linkType: hard

Expand Down
Loading