From 2a7f2fe1d0711240c4fe0c6c98074855666cae44 Mon Sep 17 00:00:00 2001 From: Antonella Sgarlatta Date: Tue, 14 Jul 2026 02:06:37 -0300 Subject: [PATCH] fix: Fix keyboard shortcut handling from within iframe editors --- .../Domain/Abstract/Component/MessageData.ts | 6 +++ .../Keyboard/ComponentKeyboardEventInit.ts | 11 +++++ .../src/Keyboard/KeyboardService.ts | 7 +++ packages/ui-services/src/index.ts | 2 + .../ComponentView/IframeFeatureView.tsx | 43 ++++++++++++++++++- 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 packages/ui-services/src/Keyboard/ComponentKeyboardEventInit.ts diff --git a/packages/models/src/Domain/Abstract/Component/MessageData.ts b/packages/models/src/Domain/Abstract/Component/MessageData.ts index 72b1f1c8f06..6b9328aadf2 100644 --- a/packages/models/src/Domain/Abstract/Component/MessageData.ts +++ b/packages/models/src/Domain/Abstract/Component/MessageData.ts @@ -27,4 +27,10 @@ export type MessageData = Partial<{ content_type?: string /** Related to key-pressed action */ keyboardModifier?: KeyboardModifier + key?: string + code?: string + ctrlKey?: boolean + metaKey?: boolean + shiftKey?: boolean + altKey?: boolean }> diff --git a/packages/ui-services/src/Keyboard/ComponentKeyboardEventInit.ts b/packages/ui-services/src/Keyboard/ComponentKeyboardEventInit.ts new file mode 100644 index 00000000000..bc51be1fb68 --- /dev/null +++ b/packages/ui-services/src/Keyboard/ComponentKeyboardEventInit.ts @@ -0,0 +1,11 @@ +export type ComponentKeyboardEventInit = Pick< + KeyboardEvent, + 'key' | 'code' | 'ctrlKey' | 'metaKey' | 'shiftKey' | 'altKey' +> + +export function isComponentKeyboardEventInit(data: { + key?: string + code?: string +}): data is ComponentKeyboardEventInit { + return data.key !== undefined && data.code !== undefined +} diff --git a/packages/ui-services/src/Keyboard/KeyboardService.ts b/packages/ui-services/src/Keyboard/KeyboardService.ts index 527a5d2e2ca..bf5ac968f62 100644 --- a/packages/ui-services/src/Keyboard/KeyboardService.ts +++ b/packages/ui-services/src/Keyboard/KeyboardService.ts @@ -1,4 +1,5 @@ import { Environment, Platform, UuidGenerator } from '@standardnotes/snjs' +import { ComponentKeyboardEventInit } from './ComponentKeyboardEventInit' import { eventMatchesKeyAndModifiers } from './eventMatchesKeyAndModifiers' import { KeyboardCommand } from './KeyboardCommands' import { KeyboardKeyEvent } from './KeyboardKeyEvent' @@ -101,6 +102,12 @@ export class KeyboardService { this.removeActiveModifier(modifier) } + public handleComponentKeyboardEvent = (eventInit: ComponentKeyboardEventInit, keyEvent: KeyboardKeyEvent): void => { + const event = new KeyboardEvent(keyEvent === KeyboardKeyEvent.Down ? 'keydown' : 'keyup', eventInit) + this.updateAllModifiersFromEvent(event) + this.handleKeyboardEvent(event, keyEvent) + } + private handleKeyDown = (event: KeyboardEvent): void => { this.updateAllModifiersFromEvent(event) diff --git a/packages/ui-services/src/index.ts b/packages/ui-services/src/index.ts index 91d4f55d850..49ed2047f72 100644 --- a/packages/ui-services/src/index.ts +++ b/packages/ui-services/src/index.ts @@ -7,6 +7,8 @@ export * from './Changelog/ChangelogServiceInterface' export * from './Keyboard/KeyboardService' export * from './Keyboard/KeyboardShortcut' export * from './Keyboard/KeyboardCommands' +export * from './Keyboard/KeyboardKeyEvent' +export * from './Keyboard/ComponentKeyboardEventInit' export * from './Keyboard/platformCheck' export * from './Keyboard/KeyboardKey' export * from './Keyboard/KeyboardModifier' diff --git a/packages/web/src/javascripts/Components/ComponentView/IframeFeatureView.tsx b/packages/web/src/javascripts/Components/ComponentView/IframeFeatureView.tsx index f86bc6d3ea9..d6b63d5ad6a 100644 --- a/packages/web/src/javascripts/Components/ComponentView/IframeFeatureView.tsx +++ b/packages/web/src/javascripts/Components/ComponentView/IframeFeatureView.tsx @@ -7,6 +7,7 @@ import { ComponentInterface, SubscriptionManagerEvent, } from '@standardnotes/snjs' +import { KeyboardKeyEvent, type KeyboardModifier } from '@standardnotes/ui-services' import { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { observer } from 'mobx-react-lite' import OfflineRestricted from '@/Components/ComponentView/OfflineRestricted' @@ -153,12 +154,50 @@ const IframeFeatureView: FunctionComponent = ({ useEffect(() => { const removeActionObserver = componentViewer.addActionObserver((action, data) => { + const keyboardData = data as { + key?: string + code?: string + ctrlKey?: boolean + metaKey?: boolean + shiftKey?: boolean + altKey?: boolean + keyboardModifier?: KeyboardModifier + } + switch (action) { case ComponentAction.KeyDown: - application.keyboardService.handleComponentKeyDown(data.keyboardModifier) + if (keyboardData.key !== undefined && keyboardData.code !== undefined) { + application.keyboardService.handleComponentKeyboardEvent( + { + key: keyboardData.key, + code: keyboardData.code, + ctrlKey: keyboardData.ctrlKey ?? false, + metaKey: keyboardData.metaKey ?? false, + shiftKey: keyboardData.shiftKey ?? false, + altKey: keyboardData.altKey ?? false, + }, + KeyboardKeyEvent.Down, + ) + } else { + application.keyboardService.handleComponentKeyDown(keyboardData.keyboardModifier) + } break case ComponentAction.KeyUp: - application.keyboardService.handleComponentKeyUp(data.keyboardModifier) + if (keyboardData.key !== undefined && keyboardData.code !== undefined) { + application.keyboardService.handleComponentKeyboardEvent( + { + key: keyboardData.key, + code: keyboardData.code, + ctrlKey: keyboardData.ctrlKey ?? false, + metaKey: keyboardData.metaKey ?? false, + shiftKey: keyboardData.shiftKey ?? false, + altKey: keyboardData.altKey ?? false, + }, + KeyboardKeyEvent.Up, + ) + } else { + application.keyboardService.handleComponentKeyUp(keyboardData.keyboardModifier) + } break case ComponentAction.Click: application.notesController.setContextMenuOpen(false)