diff --git a/frontend/src/app/components/overlays/GlobalSearchPalette.tsx b/frontend/src/app/components/overlays/GlobalSearchPalette.tsx index 2633bbae..ce50cbb4 100644 --- a/frontend/src/app/components/overlays/GlobalSearchPalette.tsx +++ b/frontend/src/app/components/overlays/GlobalSearchPalette.tsx @@ -16,6 +16,7 @@ import { createDashboard } from '@/shared/state/dashboardsSlice'; import { openSettingsModal } from '@/shared/state/settingsSlice'; import { useClaudeTokens } from '@/shared/styles/ThemeContext'; import { friendlyStatusLabel } from '@/shared/statusLabel'; +import TopLayerPortal from '@/shared/TopLayerPortal'; interface Props { open: boolean; @@ -205,7 +206,7 @@ const GlobalSearchPalette: React.FC = ({ open, onClose }) => { const isStillSearching = !!query.trim() && searchLoading && searchQuery !== query.trim(); return ( - <> + {/* Backdrop */} = ({ open, onClose }) => { esc close - + ); }; diff --git a/frontend/src/app/pages/Dashboard/controls/CardSearchPalette.tsx b/frontend/src/app/pages/Dashboard/controls/CardSearchPalette.tsx index 2445e758..19dbfd97 100644 --- a/frontend/src/app/pages/Dashboard/controls/CardSearchPalette.tsx +++ b/frontend/src/app/pages/Dashboard/controls/CardSearchPalette.tsx @@ -4,6 +4,7 @@ import InputBase from '@mui/material/InputBase'; import Typography from '@mui/material/Typography'; import SearchIcon from '@mui/icons-material/Search'; import { useClaudeTokens } from '@/shared/styles/ThemeContext'; +import TopLayerPortal from '@/shared/TopLayerPortal'; import type { CardPosition, ViewCardPosition, BrowserCardPosition } from '@/shared/state/dashboardLayoutSlice'; import type { AgentSession } from '@/shared/state/agentsSlice'; @@ -125,7 +126,7 @@ const CardSearchPalette: React.FC = ({ }; return ( - <> + {/* Backdrop */} = ({ )} - + ); }; diff --git a/frontend/src/shared/TopLayerPortal.tsx b/frontend/src/shared/TopLayerPortal.tsx new file mode 100644 index 00000000..bdc47ceb --- /dev/null +++ b/frontend/src/shared/TopLayerPortal.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { createPortal } from 'react-dom'; + +// A low-z or transformed ancestor traps position:fixed, so anything that must win every stacking fight mounts on body instead. +const TOP_LAYER = 2147483647; + +interface Props { + children: React.ReactNode; +} + +const TopLayerPortal: React.FC = ({ children }) => createPortal( +
{children}
, + document.body, +); + +export default TopLayerPortal;