From 8c4a42f0e6a33ecaf752c5ae8898773816e160df Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Mon, 1 Jul 2024 19:31:36 +0800 Subject: [PATCH] fix: cmd-k keybinding not show when editor input is active (#7398) --- .../core/src/commands/registry/command.ts | 1 + .../core/src/commands/registry/registry.ts | 64 +++++++++++++++---- .../hooks/use-register-workspace-commands.ts | 7 +- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/packages/frontend/core/src/commands/registry/command.ts b/packages/frontend/core/src/commands/registry/command.ts index bda81c391527d..f113cb9954b7d 100644 --- a/packages/frontend/core/src/commands/registry/command.ts +++ b/packages/frontend/core/src/commands/registry/command.ts @@ -30,6 +30,7 @@ export type CommandCategory = export interface KeybindingOptions { binding: string; + capture?: boolean; // some keybindings are already registered in blocksuite // we can skip the registration of these keybindings __FOR NOW__ skipRegister?: boolean; diff --git a/packages/frontend/core/src/commands/registry/registry.ts b/packages/frontend/core/src/commands/registry/registry.ts index f6f637141308e..582bb8e397eaa 100644 --- a/packages/frontend/core/src/commands/registry/registry.ts +++ b/packages/frontend/core/src/commands/registry/registry.ts @@ -1,12 +1,50 @@ import { DebugLogger } from '@affine/debug'; // @ts-expect-error upstream type is wrong -import { tinykeys } from 'tinykeys'; +import { createKeybindingsHandler } from 'tinykeys'; import type { AffineCommand, AffineCommandOptions } from './command'; import { createAffineCommand } from './command'; const commandLogger = new DebugLogger('command:registry'); +interface KeyBindingMap { + [keybinding: string]: (event: KeyboardEvent) => void; +} + +export interface KeyBindingOptions { + /** + * Key presses will listen to this event (default: "keydown"). + */ + event?: 'keydown' | 'keyup'; + + /** + * Whether to capture the event during the capture phase (default: false). + */ + capture?: boolean; + + /** + * Keybinding sequences will wait this long between key presses before + * cancelling (default: 1000). + * + * **Note:** Setting this value too low (i.e. `300`) will be too fast for many + * of your users. + */ + timeout?: number; +} + +const bindKeys = ( + target: Window | HTMLElement, + keyBindingMap: KeyBindingMap, + options: KeyBindingOptions = {} +) => { + const event = options.event ?? 'keydown'; + const onKeyEvent = createKeybindingsHandler(keyBindingMap, options); + target.addEventListener(event, onKeyEvent, options.capture); + return () => { + target.removeEventListener(event, onKeyEvent, options.capture); + }; +}; + export const AffineCommandRegistry = new (class { readonly commands: Map = new Map(); @@ -25,17 +63,21 @@ export const AffineCommandRegistry = new (class { !command.keyBinding.skipRegister && typeof window !== 'undefined' ) { - const { binding: keybinding } = command.keyBinding; - unsubKb = tinykeys(window, { - [keybinding]: async (e: Event) => { - e.preventDefault(); - try { - await command.run(); - } catch (e) { - console.error(`Failed to invoke keybinding [${keybinding}]`, e); - } + const { binding: keybinding, capture } = command.keyBinding; + unsubKb = bindKeys( + window, + { + [keybinding]: (e: Event) => { + e.preventDefault(); + command.run()?.catch(e => { + console.error(`Failed to run command [${command.id}]`, e); + }); + }, }, - }); + { + capture, + } + ); } commandLogger.debug(`Registered command ${command.id}`); diff --git a/packages/frontend/core/src/hooks/use-register-workspace-commands.ts b/packages/frontend/core/src/hooks/use-register-workspace-commands.ts index 87fa031e98731..a6f773adca769 100644 --- a/packages/frontend/core/src/hooks/use-register-workspace-commands.ts +++ b/packages/frontend/core/src/hooks/use-register-workspace-commands.ts @@ -23,9 +23,9 @@ import { useNavigateHelper } from './use-navigate-helper'; function hasLinkPopover(editor: AffineEditorContainer | null) { const textSelection = editor?.host?.std.selection.find('text'); - if (textSelection && textSelection.from.length > 0) { - const linkPopup = document.querySelector('link-popup'); - if (linkPopup) { + if (editor && textSelection && textSelection.from.length > 0) { + const formatBar = editor.host.querySelector('affine-format-bar-widget'); + if (formatBar) { return true; } } @@ -42,6 +42,7 @@ function registerCMDKCommand( category: 'affine:general', keyBinding: { binding: '$mod+K', + capture: true, }, label: '', icon: '',