fix(keymap): clear shortcuts when a focused tree is removed (#1940)

Цей коміт міститься в:
Jaw authored and GitHub committed 2026-11-07 16:15:13 +08:00
1 джерело a36c7ed3d5
коміт d3ea6f6daf
5 files changed
+62 -17

No files matched your search

+2 -6
Переглянути файл
@@ -7,7 +7,6 @@
*/
import { useEffect, useMemo, useRef, type CSSProperties } from "react";
import type { DbDatabases, DbTableDetails } from "@/platform/ipc";
import { setContext } from "@/platform/context";
import { executeAction } from "@/platform/actions";
import { shortcutLabel } from "@/platform/keymap";
import {
@@ -378,13 +377,10 @@ export function DatabaseView() {
return (
<div className={styles.dbView}>
<DatabaseToolbar />
<div
className={styles.treeHost}
onFocus={(e) => setContext(DB_VIEW_FOCUS, (e.target as HTMLElement).getAttribute("role") === "tree")}
onBlur={() => setContext(DB_VIEW_FOCUS, false)}
>
<div className={styles.treeHost}>
<Tree<Node>
aria-label="Data sources"
focusContext={DB_VIEW_FOCUS}
roots={roots}
handleRef={tree}
expanded={st.treeExpanded}
+1 -3
Переглянути файл
@@ -20,7 +20,6 @@ import { createPortal } from "react-dom";
import clsx from "clsx";
import { revealRange, useEditorRegistry } from "@/editor/api";
import { executeAction } from "@/platform/actions";
import { setContext } from "@/platform/context";
import { tx, useTxTemplate } from "@/platform/i18n";
import { isTauri } from "@/platform/ipc";
import { nativeDropPoint } from "@/platform/nativeDrop";
@@ -779,8 +778,6 @@ export function ProjectView() {
onCopy={(e) => onClipboard(e, "project.copy")}
onCut={(e) => onClipboard(e, "project.cut")}
onPaste={(e) => onClipboard(e, "project.paste")}
onFocus={(e) => setContext("projectViewFocus", (e.target as HTMLElement).getAttribute("role") === "tree")}
onBlur={() => setContext("projectViewFocus", false)}
>
{mode === "unity" && unity && !unity.projects.length && (
<div className={styles.unityNotice} role="status">
@@ -795,6 +792,7 @@ export function ProjectView() {
<Tree<ProjectNode>
horizontalScroll
aria-label="Project"
focusContext="projectViewFocus"
handleRef={setTreeHandle}
roots={model.roots}
getKey={getKey}
+2 -8
Переглянути файл
@@ -5,7 +5,6 @@
*/
import { useEffect, useMemo, useRef } from "react";
import clsx from "clsx";
import { setContext } from "@/platform/context";
import { useTxTemplate, tx } from "@/platform/i18n";
import { shortcutLabel } from "@/platform/keymap";
import { useProject } from "@/platform/project";
@@ -208,15 +207,10 @@ export function ServicesTreeView() {
) : (
<SplitGroup orientation="horizontal" className={styles.split}>
<SplitPanel defaultSize="40%" minSize="160px">
<div
className={styles.tree}
onFocus={(e) =>
setContext(SERVICES_VIEW_FOCUS, (e.target as HTMLElement).getAttribute("role") === "tree")
}
onBlur={() => setContext(SERVICES_VIEW_FOCUS, false)}
>
<div className={styles.tree}>
<Tree<ServiceTreeItem>
key={location}
focusContext={SERVICES_VIEW_FOCUS}
reorder={reorder}
roots={roots}
getKey={(n) => n.key}
+28
Переглянути файл
@@ -30,6 +30,7 @@ import { fuzzyMatch } from "./match";
import { acquirePopup } from "./popupState";
import styles from "./Tree.module.css";
import { T } from "./T";
import { setContext } from "@/platform/context";
import { tx } from "@/platform/i18n";
import { useTreeReorder, type TreeReorder } from "./treeReorder";
import { useTreeDirectoryContext } from "./treeDirectoryContext";
@@ -116,6 +117,8 @@ export interface TreeProps<T> {
rowClassName?: (node: T) => string | undefined;
"aria-label"?: string;
handleRef?: Ref<TreeHandle>;
/** Context key set while the tree itself has keyboard focus. */
focusContext?: string;
empty?: ReactNode;
/** Rows wider than the pane scroll horizontally instead of clipping. */
horizontalScroll?: boolean;
@@ -592,6 +595,31 @@ export function Tree<T>(props: TreeProps<T>) {
);
const noMatch = !!query && matchMap.size === 0;
const { focusContext } = props;
useLayoutEffect(() => {
const element = scrollRef.current;
if (!focusContext || !element) return;
let focused = false;
const focus = () => {
focused = true;
setContext(focusContext, true);
};
const blur = () => {
if (!focused) return;
focused = false;
setContext(focusContext, false);
};
element.addEventListener("focus", focus);
element.addEventListener("blur", blur);
if (element.ownerDocument.activeElement === element) focus();
return () => {
element.removeEventListener("focus", focus);
element.removeEventListener("blur", blur);
// Removing a focused tree can skip blur, leaving its shortcuts active.
blur();
};
}, [emptyState, focusContext]);
if (emptyState) return <div className={clsx(styles.tree, styles.emptyWrap, className)}>{empty}</div>;
return (