From 5ecfd3e9f12589990cb684257b0a8beaedc32181 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Sat, 19 Sep 2026 01:20:23 +0200 Subject: [PATCH] fix(explorer): let clicks through the context-menu overlay (#3278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MUI menu backdrop swallowed the first click, forcing an extra dismiss click before selecting a file. The root overlay now has pointer-events:none with the paper restored to auto (same trick as HoverMenu), and a document pointerdown listener closes the menu on any outside press — the same event still selects the file beneath. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../FileManager/ContextMenu/ContextMenu.tsx | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/frontend/src/component/FileManager/ContextMenu/ContextMenu.tsx b/frontend/src/component/FileManager/ContextMenu/ContextMenu.tsx index d7e74c9b..263ecb67 100644 --- a/frontend/src/component/FileManager/ContextMenu/ContextMenu.tsx +++ b/frontend/src/component/FileManager/ContextMenu/ContextMenu.tsx @@ -1,5 +1,5 @@ import { Box, Divider, ListItemIcon, ListItemText, Menu, MenuItem, styled, Typography, useTheme } from "@mui/material"; -import { useCallback, useMemo } from "react"; +import { useCallback, useEffect, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { closeContextMenu } from "../../../redux/fileManagerSlice.ts"; import { CreateNewDialogType } from "../../../redux/globalStateSlice.ts"; @@ -107,6 +107,23 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => { dispatch(closeContextMenu({ index: fmIndex, value: undefined })); }, [dispatch]); + // The menu overlay lets pointer events fall through to the file list, so + // dismiss it manually on any click outside the menu paper — the same event + // still reaches the file underneath (upstream #3278). + useEffect(() => { + if (!contextMenuOpen) { + return; + } + const onPointerDown = (e: PointerEvent) => { + if ((e.target as HTMLElement | null)?.closest?.(".MuiMenu-paper")) { + return; + } + dispatch(closeContextMenu({ index: fmIndex, value: undefined })); + }; + document.addEventListener("pointerdown", onPointerDown, true); + return () => document.removeEventListener("pointerdown", onPointerDown, true); + }, [contextMenuOpen, dispatch, fmIndex]); + const showOpenWithCascading = displayOpt.showOpenWithCascading && displayOpt.showOpenWithCascading(); const showOpenWith = displayOpt.showOpenWith && displayOpt.showOpenWith(); let part1 = @@ -379,6 +396,14 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => { onClose={onClose} disableAutoFocusItem open={Boolean(contextMenuOpen)} + style={{ pointerEvents: "none" }} + slotProps={{ + paper: { + style: { + pointerEvents: "auto", + }, + }, + }} anchorReference="anchorPosition" anchorPosition={{ top: contextMenuPos?.y ?? 0,