diff --git a/frontend/common/useEventListener.js b/frontend/common/useEventListener.js index 1fcb44514a..94b8911846 100644 --- a/frontend/common/useEventListener.js +++ b/frontend/common/useEventListener.js @@ -1,6 +1,11 @@ import { useCallback, useEffect } from "../imports/Preact.js" -export const useEventListener = (element, event_name, handler, deps) => { +export const useEventListener = ( + /** @type {Document | HTMLElement | Window | null} */ element, + /** @type {string} */ event_name, + /** @type {EventListenerOrEventListenerObject} */ handler, + /** @type {any[] | undefined} */ deps +) => { let handler_cached = useCallback(handler, deps) useEffect(() => { if (element == null) return diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 3f7c3266b3..22b3f6ffbd 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -1,5 +1,4 @@ import { html, useState, useEffect, useLayoutEffect, useRef, useContext, useMemo } from "../imports/Preact.js" -import observablehq_for_myself from "../common/SetupCellEnvironment.js" import _ from "../imports/lodash.js" import { utf8index_to_ut16index } from "../common/UnicodeTools.js" @@ -24,24 +23,14 @@ import { HighlightStyle, lineNumbers, highlightSpecialChars, - foldGutter, drawSelection, indentOnInput, - defaultHighlightStyle, closeBrackets, rectangularSelection, highlightSelectionMatches, closeBracketsKeymap, - searchKeymap, foldKeymap, - syntaxTree, - Decoration, - ViewUpdate, - ViewPlugin, - WidgetType, indentUnit, - StateField, - StateEffect, autocomplete, htmlLanguage, markdownLanguage, @@ -69,6 +58,7 @@ import { mod_d_command } from "./CellInput/mod_d_command.js" import { open_bottom_right_panel } from "./BottomRightPanel.js" import { timeout_promise } from "../common/PlutoConnection.js" import { LastFocusWasForcedEffect, tab_help_plugin } from "./CellInput/tab_help_plugin.js" +import { useEventListener } from "../common/useEventListener.js" import { moveLineDown } from "../imports/CodemirrorPlutoSetup.js" export const ENABLE_CM_MIXED_PARSER = window.localStorage.getItem("ENABLE_CM_MIXED_PARSER") === "true" @@ -933,7 +923,23 @@ export const CellInput = ({ const InputContextMenu = ({ on_delete, cell_id, run_cell, skip_as_script, running_disabled, any_logs, show_logs, set_show_logs, set_cell_disabled }) => { const timeout = useRef(null) let pluto_actions = useContext(PlutoActionsContext) - const [open, setOpen] = useState(false) + const [open, setOpenState] = useState(false) + const element_ref = useRef(/** @type {HTMLButtonElement?} */ (null)) + const prevously_focused_element_ref = useRef(/** @type {Element?} */ (null)) + const setOpen = (val) => { + if (val) { + prevously_focused_element_ref.current = document.activeElement + } + setOpenState(val) + } + useLayoutEffect(() => { + if (open) { + element_ref.current?.querySelector("li")?.focus() + } else { + if (prevously_focused_element_ref.current instanceof HTMLElement) prevously_focused_element_ref.current?.focus() + } + }, [open]) + const mouseenter = () => { if (timeout.current) clearTimeout(timeout.current) } @@ -966,20 +972,36 @@ const InputContextMenu = ({ on_delete, cell_id, run_cell, skip_as_script, runnin }) } + useEventListener(window, "keydown", (e) => { + if (e.key === "Escape") { + setOpen(false) + } + }) + return html`