import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"; import { Check, ChevronRight, Circle } from "lucide-react"; import * as React from "react"; import { cn } from "../../lib/utils"; const menuCollisionPadding = { top: 36, bottom: 12, left: 12, right: 12 }; const CONTEXT_MENU_PORTAL_ID = "netcatty-context-menu-root"; // Dedicated portal root so context menus always sit above every other layer (dialogs, titlebar, overlays) const getContextMenuPortalEl = () => { if (typeof document === "undefined") return null; let portal = document.getElementById(CONTEXT_MENU_PORTAL_ID); if (!portal) { portal = document.createElement("div"); portal.id = CONTEXT_MENU_PORTAL_ID; Object.assign(portal.style, { position: "fixed", inset: "0px", zIndex: "2147483647", // max safe z-index to avoid being covered pointerEvents: "none", }); // Intercept aria-hidden attribute to prevent it from being set when menu is open // This avoids "Blocked aria-hidden on an element because its descendant retained focus" warnings let ariaHiddenValue: string | null = null; Object.defineProperty(portal, "ariaHidden", { get() { return ariaHiddenValue; }, set(value: string | null) { // Block aria-hidden="true" when there are children (menu is open) if (value === "true" && portal && portal.children.length > 0) { return; } ariaHiddenValue = value; }, configurable: true, }); // Also override setAttribute for aria-hidden const originalSetAttribute = portal.setAttribute.bind(portal); portal.setAttribute = function (name: string, value: string) { if (name === "aria-hidden" && value === "true" && portal && portal.children.length > 0) { return; } originalSetAttribute(name, value); }; // Override removeAttribute to sync our internal state const originalRemoveAttribute = portal.removeAttribute.bind(portal); portal.removeAttribute = function (name: string) { if (name === "aria-hidden") { ariaHiddenValue = null; } originalRemoveAttribute(name); }; document.body.appendChild(portal); } return portal; }; const ContextMenu = ContextMenuPrimitive.Root; const ContextMenuTrigger = ContextMenuPrimitive.Trigger; const ContextMenuGroup = ContextMenuPrimitive.Group; const ContextMenuPortal = ContextMenuPrimitive.Portal; const ContextMenuSub = ContextMenuPrimitive.Sub; const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup; const ContextMenuSubTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, children, ...props }, ref) => ( {children} )); ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName; const ContextMenuSubContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => { const portalContainer = React.useMemo( () => getContextMenuPortalEl() ?? undefined, [], ); return ( ); }); ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName; const ContextMenuContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => { const portalContainer = React.useMemo( () => getContextMenuPortalEl() ?? undefined, [], ); return ( ); }); ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName; const ContextMenuItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, ...props }, ref) => ( )); ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName; const ContextMenuCheckboxItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, checked, ...props }, ref) => ( {children} )); ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName; const ContextMenuRadioItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( {children} )); ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName; const ContextMenuLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, ...props }, ref) => ( )); ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName; const ContextMenuSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName; const ContextMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { return ( ); }; ContextMenuShortcut.displayName = "ContextMenuShortcut"; export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, };