дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
fix(terminal): keep focus in the terminal after its context menu closes (#566)
Right-clicking the terminal did not focus it, and closing any context menu sent focus to the editor. Popup recorded the element to restore in an effect, after Menu had already focused its first item, so it restored the menu item; focus then fell to the body and the workbench fallback focused the editor. Popup now records the focused element while rendering, and the terminal takes focus when its context menu opens. Enter after the menu closes goes to the shell. This covers every context menu: focus returns to what held it before the menu opened. Co-authored-by: a-rookie-of-C-language <[email protected]>
Цей коміт міститься в:
1 джерело
5329ddc469
коміт
b2d1188049
3 files changed
+31
-3
No files matched your search
@@ -86,6 +86,9 @@ function paneMenu(e: MouseEvent, key: string) {
|
||||
e.preventDefault();
|
||||
const session = getSession(key);
|
||||
if (!session) return;
|
||||
// Right-clicking focuses the terminal, like IDEA; otherwise the menu closing
|
||||
// restores focus to whatever was focused before it, often the editor.
|
||||
session.focus();
|
||||
const exited = session.state.status === "exited" || session.state.status === "error";
|
||||
const mac = usePlatform.getState().os === "macos";
|
||||
const items: MenuItem[] = [
|
||||
|
||||
@@ -4,7 +4,7 @@ import { act, fireEvent, render, screen } from "@testing-library/react";
|
||||
import { getContext, setContext } from "@/platform/context";
|
||||
import { registerAction } from "@/platform/actions";
|
||||
import { Popup } from "./Popup";
|
||||
import { Menu, MenuList } from "./Menu";
|
||||
import { ContextMenuHost, Menu, MenuList, hideContextMenu, showContextMenu } from "./Menu";
|
||||
import { Dialog } from "./Dialog";
|
||||
|
||||
function Harness({ onClose }: { onClose?: (r: string) => void }) {
|
||||
@@ -177,6 +177,21 @@ describe("Dialog initial focus", () => {
|
||||
});
|
||||
|
||||
describe("Menu action enablement", () => {
|
||||
it("returns focus to the element focused before a context menu opened", () => {
|
||||
render(
|
||||
<>
|
||||
<textarea aria-label="input" />
|
||||
<ContextMenuHost />
|
||||
</>,
|
||||
);
|
||||
const input = screen.getByRole("textbox", { name: "input" });
|
||||
input.focus();
|
||||
act(() => showContextMenu({ x: 0, y: 0 }, [{ label: "Paste", run: () => undefined }]));
|
||||
expect(screen.getByRole("menuitem", { name: /Paste/ })).toHaveFocus();
|
||||
act(() => hideContextMenu());
|
||||
expect(input).toHaveFocus();
|
||||
});
|
||||
|
||||
it("follows context changes after the menu opened", () => {
|
||||
const dispose = registerAction({ id: "test.menuWhen", title: "Needs Flag", when: "qaMenuFlag", run: () => {} });
|
||||
setContext("qaMenuFlag", false);
|
||||
|
||||
+12
-2
@@ -3,7 +3,16 @@
|
||||
* window-deactivation dismissal (top-most popup only for Escape), optional
|
||||
* focus trap and focus restore.
|
||||
*/
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef, type CSSProperties, type ReactNode, type RefObject } from "react";
|
||||
import {
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
type CSSProperties,
|
||||
type ReactNode,
|
||||
type RefObject,
|
||||
} from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import clsx from "clsx";
|
||||
import {
|
||||
@@ -108,10 +117,11 @@ function PopupInner({
|
||||
useLayoutEffect(() => {
|
||||
onCloseRef.current = onClose;
|
||||
});
|
||||
// Read while rendering: content such as a menu focuses itself before any effect here runs.
|
||||
const [previous] = useState(() => document.activeElement as HTMLElement | null);
|
||||
|
||||
useEffect(() => {
|
||||
const layer = openLayer(() => elRef.current);
|
||||
const previous = document.activeElement as HTMLElement | null;
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (!layer.isTop()) return;
|
||||
|
||||
Reference in new issue
Заблокувати користувача