diff --git a/.changeset/page-header-z-index-below-drawers.md b/.changeset/page-header-z-index-below-drawers.md new file mode 100644 index 0000000000..31d4dd178e --- /dev/null +++ b/.changeset/page-header-z-index-below-drawers.md @@ -0,0 +1,20 @@ +--- +'@hyperdx/app': patch +--- + +fix(z-index): keep sticky header below drawers and drawers above the fullscreen tile modal + +Two related z-index regressions: + +- `PageHeader` was pinned at `z-index: 100`, but app drawers opt into a + much lower stack via `ZIndexContext` (`contextZIndex + 10`, so a + top-level drawer renders at `z-index: 10`). The sticky header therefore + floated above the drawer overlay. The header now sits at `z-index: 2` so + drawer overlays reliably cover the page chrome while the header still + wins against normal scrolling content. +- `FullscreenPanelModal` used Mantine's default modal z-index (`200`) and + didn't propagate it through `ZIndexContext`. Clicking a row in a + fullscreen search tile opened a `DBRowSidePanel` drawer at `z-index: 10` + that was hidden behind the modal. The modal now follows the existing + `contextZIndex + 10` pattern and wraps its children in a + `ZIndexContext.Provider`, so child drawers stack on top of it. diff --git a/packages/app/src/components/FullscreenPanelModal.tsx b/packages/app/src/components/FullscreenPanelModal.tsx index e7f9c61c4a..1b3df9d793 100644 --- a/packages/app/src/components/FullscreenPanelModal.tsx +++ b/packages/app/src/components/FullscreenPanelModal.tsx @@ -1,6 +1,8 @@ import { Box, Modal } from '@mantine/core'; import { useHotkeys } from '@mantine/hooks'; +import { useZIndex, ZIndexContext } from '@/zIndex'; + export default function FullscreenPanelModal({ opened, onClose, @@ -15,6 +17,13 @@ export default function FullscreenPanelModal({ // YouTube-style 'f' key to toggle fullscreen useHotkeys([['f', () => opened && onClose()]]); + // Stack on top of any ancestor drawer/modal (`contextZIndex + 10`) and + // expose this value via `ZIndexContext` so any drawer/popover opened from + // inside the fullscreen view (e.g. clicking a row in a search tile) lands + // above the modal instead of being hidden behind it. + const contextZIndex = useZIndex(); + const modalZIndex = contextZIndex + 10; + return ( - - {children} - + + + {children} + + ); } diff --git a/packages/app/src/components/PageHeader.module.scss b/packages/app/src/components/PageHeader.module.scss index 3408b57ead..1bde82d825 100644 --- a/packages/app/src/components/PageHeader.module.scss +++ b/packages/app/src/components/PageHeader.module.scss @@ -14,7 +14,12 @@ padding: 0 var(--mantine-spacing-sm); position: sticky; top: 0; - z-index: 100; + + /* Top-level drawers in this app are rendered at z-index 10 + (`contextZIndex + 10` from `ZIndexContext`, see e.g. `DBRowSidePanel`). + Sit 8 below that so the drawer overlay always covers the page chrome, + while the header still floats above normal scrolling content. */ + z-index: 2; } /* Applied automatically when a `stickyRow` is provided: the chrome scrolls @@ -40,7 +45,10 @@ padding: var(--mantine-spacing-sm); position: sticky; top: 0; - z-index: 100; + + /* Match `.header` — sit 8 below the top-level drawer z-index (10) so + drawer overlays always cover this row. */ + z-index: 2; } /* Applied when the sticky row sits directly under chrome AND is not