diff --git a/packages/insomnia/src/common/hotkeys.ts b/packages/insomnia/src/common/hotkeys.ts index 0f4d7fb3e..88d039149 100644 --- a/packages/insomnia/src/common/hotkeys.ts +++ b/packages/insomnia/src/common/hotkeys.ts @@ -10,6 +10,7 @@ import { strings } from './strings'; export const keyboardShortcutDescriptions: Record = { 'workspace_showSettings': `Show ${strings.document.singular} / ${strings.collection.singular} Settings`, 'request_showSettings': 'Show Request Settings', + 'workspace_closeModal': 'Close Modal Dialog', 'preferences_showKeyboardShortcuts': 'Show Keyboard Shortcuts', 'preferences_showGeneral': 'Show App Preferences', 'request_quickSwitch': 'Switch Requests', @@ -47,6 +48,10 @@ const defaultRegistry: HotKeyRegistry = { macKeys: [{ shift: true, meta: true, keyCode: keyboardKeys.comma.keyCode }], winLinuxKeys: [{ ctrl: true, shift: true, keyCode: keyboardKeys.comma.keyCode }], }, + workspace_closeModal: { + macKeys: [{ keyCode: keyboardKeys.esc.keyCode }], + winLinuxKeys: [{ keyCode: keyboardKeys.esc.keyCode }], + }, request_showSettings: { macKeys: [{ alt: true, shift: true, meta: true, keyCode: keyboardKeys.comma.keyCode }], winLinuxKeys: [{ ctrl: true, alt: true, shift: true, keyCode: keyboardKeys.comma.keyCode }], diff --git a/packages/insomnia/src/common/settings.ts b/packages/insomnia/src/common/settings.ts index 1b80a8385..294cf3d9e 100644 --- a/packages/insomnia/src/common/settings.ts +++ b/packages/insomnia/src/common/settings.ts @@ -57,7 +57,8 @@ export type KeyboardShortcut = | 'request_togglePin' | 'environment_showVariableSourceAndValue' | 'beautifyRequestBody' - | 'graphql_explorer_focus_filter'; + | 'graphql_explorer_focus_filter' + | 'workspace_closeModal'; /** * The collection of defined hotkeys. diff --git a/packages/insomnia/src/ui/components/base/editable.tsx b/packages/insomnia/src/ui/components/base/editable.tsx index 11d0b897b..3f22183d9 100644 --- a/packages/insomnia/src/ui/components/base/editable.tsx +++ b/packages/insomnia/src/ui/components/base/editable.tsx @@ -73,6 +73,7 @@ export const Editable: FC = ({ const handleKeyDown = createKeybindingsHandler({ 'Enter': handleEditEnd, + // TODO: is this also broken for vim mode? 'Escape': () => { if (inputRef.current) { // Set the input to the original value diff --git a/packages/insomnia/src/ui/components/base/modal.tsx b/packages/insomnia/src/ui/components/base/modal.tsx index 5f7846d4a..cc9a36bd6 100644 --- a/packages/insomnia/src/ui/components/base/modal.tsx +++ b/packages/insomnia/src/ui/components/base/modal.tsx @@ -1,7 +1,7 @@ import classnames from 'classnames'; import React, { forwardRef, ReactNode, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { createKeybindingsHandler } from '../keydown-binder'; +import { useDocBodyKeyboardShortcuts } from '../keydown-binder'; // Keep global z-index reference so that every modal will // appear over top of an existing one. let globalZIndex = 1000; @@ -79,23 +79,15 @@ export const Modal = forwardRef(({ } }, [hide, open]); - const handleKeydown = createKeybindingsHandler({ - 'Escape': () => { + useDocBodyKeyboardShortcuts({ + workspace_closeModal: () => { hide(); }, }); - useEffect(() => { - document.body.addEventListener('keydown', handleKeydown); - - return () => { - document.body.removeEventListener('keydown', handleKeydown); - }; - }, [handleKeydown]); return (open ?
(({ 'showAutocomplete': settings.hotKeyRegistry.showAutocomplete, }); // Stop the editor from handling global keyboard shortcuts except for the autocomplete binding + // This includes the shortcut for closing modals, which defaults to Escape const isShortcutButNotAutocomplete = isUserDefinedKeyboardShortcut && !isAutoCompleteBinding; - // Should not capture escape in order to exit modals - const isEscapeKey = event.code === 'Escape'; if (isShortcutButNotAutocomplete) { // @ts-expect-error -- unsound property assignment event.codemirrorIgnore = true; // Stop the editor from handling the escape key - } else if (isEscapeKey) { - // @ts-expect-error -- unsound property assignment - event.codemirrorIgnore = true; } else { event.stopPropagation(); diff --git a/packages/insomnia/src/ui/components/codemirror/extensions/autocomplete.ts b/packages/insomnia/src/ui/components/codemirror/extensions/autocomplete.ts index bb63de929..83625f3cf 100644 --- a/packages/insomnia/src/ui/components/codemirror/extensions/autocomplete.ts +++ b/packages/insomnia/src/ui/components/codemirror/extensions/autocomplete.ts @@ -188,7 +188,8 @@ CodeMirror.defineOption('environmentAutocomplete', null, (cm: CodeMirror.Editor, let keydownTimeoutHandle: NodeJS.Timeout | null = null; cm.on('keydown', (cm: CodeMirror.Editor, event) => { - // Close autocomplete on Escape if it's open + // Close autocomplete on Escape if it's open. In vim mode, this will require + // a second keypress to leave insert mode. if (cm.isHintDropdownActive() && event.key === 'Escape') { if (!cm.state.completionActive) { return; diff --git a/packages/insomnia/src/ui/components/codemirror/one-line-editor.tsx b/packages/insomnia/src/ui/components/codemirror/one-line-editor.tsx index 478add2e5..67ebaa1f3 100644 --- a/packages/insomnia/src/ui/components/codemirror/one-line-editor.tsx +++ b/packages/insomnia/src/ui/components/codemirror/one-line-editor.tsx @@ -144,16 +144,11 @@ export const OneLineEditor = forwardRef 'showAutocomplete': settings.hotKeyRegistry.showAutocomplete, }); // Stop the editor from handling global keyboard shortcuts except for the autocomplete binding + // This includes the shortcut for closing modals, which is Escape by default const isShortcutButNotAutocomplete = isUserDefinedKeyboardShortcut && !isAutoCompleteBinding; - // Should not capture escape in order to exit modals - const isEscapeKey = event.code === 'Escape'; if (isShortcutButNotAutocomplete) { // @ts-expect-error -- unsound property assignment event.codemirrorIgnore = true; - // Stop the editor from handling the escape key - } else if (isEscapeKey) { - // @ts-expect-error -- unsound property assignment - event.codemirrorIgnore = true; } else { event.stopPropagation(); } diff --git a/packages/insomnia/src/ui/components/settings/general.tsx b/packages/insomnia/src/ui/components/settings/general.tsx index c5003927f..c0a5d36be 100644 --- a/packages/insomnia/src/ui/components/settings/general.tsx +++ b/packages/insomnia/src/ui/components/settings/general.tsx @@ -156,10 +156,17 @@ export const General: FC = () => { label="Text Editor Key Map" setting="editorKeyMap" - help={isMac() && settings.editorKeyMap === EditorKeyMap.vim && ( + help={settings.editorKeyMap === EditorKeyMap.vim && ( - To enable key-repeating with Vim on macOS, see - documentation + To prevent the Escape key from closing modals, you can set a custom + keyboard shortcut for 'Close Modal Dialog'. + {isMac() && ( + +

+ To enable key-repeating with Vim on macOS, see + documentation +
+ )}
)} values={[