From 97cd88405d92c7910ea21c223c8bc91685a5361f Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Sat, 18 Apr 2026 20:35:30 +0100 Subject: [PATCH] fix(base): close property menu on escape from main and options panels --- .../base/components/grid/grid-header-cell.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/client/src/features/base/components/grid/grid-header-cell.tsx b/apps/client/src/features/base/components/grid/grid-header-cell.tsx index 9fe7bebe..0d2f8d28 100644 --- a/apps/client/src/features/base/components/grid/grid-header-cell.tsx +++ b/apps/client/src/features/base/components/grid/grid-header-cell.tsx @@ -1,4 +1,4 @@ -import { memo, useCallback, useRef } from "react"; +import { memo, useCallback, useEffect, useRef } from "react"; import { Header, flexRender } from "@tanstack/react-table"; import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; @@ -106,6 +106,21 @@ export const GridHeaderCell = memo(function GridHeaderCell({ setActivePropertyMenu(null); }, [setActivePropertyMenu]); + // Mantine's built-in `closeOnEscape` only fires when focus is inside the + // dropdown, but opening the property menu (clicking the header) leaves + // focus on the header itself. Add a document-level ESC handler that + // closes the menu when it's open and not dirty. + useEffect(() => { + if (!menuOpened) return; + const handler = (e: KeyboardEvent) => { + if (e.key !== "Escape") return; + if (propertyMenuDirty) return; + handleMenuClose(); + }; + document.addEventListener("keydown", handler); + return () => document.removeEventListener("keydown", handler); + }, [menuOpened, propertyMenuDirty, handleMenuClose]); + const TypeIcon = property ? typeIcons[property.type] : undefined; const sortableStyle = transform