fix(dashboard): put floating-modal z-index on the overlay, not the panel (fixes overlap + tap-to-front)

Verified against the live DOM: a panel z-index is trapped inside the position:fixed overlay's stacking context, so page elements that are themselves stacking contexts in body (the right dock at position:absolute z-index:20, card badge contexts) painted OVER the modal, and tap-to-front (which raised the panel z) had no effect at the body level. Move the dynamic shared-stack z onto each modal's fixed overlay (FloatingWindow, RightDockExpandModal, TerminalModal floating, NewTaskModal floating) so the whole window sits at the shared band in body's stacking context — modals now paint above all page content and tapping reliably brings a window to the front across types.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-06-22 09:14:51 -07:00
parent 296fb553b8
commit 0b34994ae4
4 changed files with 10 additions and 8 deletions

View File

@@ -276,6 +276,8 @@ export function FloatingWindow({
role="dialog"
aria-modal="false"
data-testid={`floating-window-overlay-${windowKey}`}
// FNXC:FloatingWindow 2026-06-22-23:00: The z-index MUST live on the position:fixed overlay (which creates a stacking context), not the panel. A panel z-index is trapped inside the overlay's context and loses to page elements that are stacking contexts in body's context (e.g. the right dock at position:absolute z-index:20). With z on the overlay, the whole window sits at the shared floating band in body's stacking context and reliably paints above page content + tap-to-front reorders correctly.
style={{ zIndex }}
>
<div
className="floating-window"

View File

@@ -756,6 +756,8 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
aria-modal="false"
aria-label={t("newTaskModal.title", "New Task")}
data-testid="new-task-modal-overlay"
/* FNXC:FloatingWindow 2026-06-22-23:00: In floating mode the z-index lives on the fixed overlay (it owns the stacking context); a panel z is trapped and loses to page stacking contexts like the right dock. Mobile keeps its CSS z. */
style={isFloating ? { zIndex } : undefined}
>
<div
className={`modal modal-lg new-task-modal${isFloating ? " new-task-modal--floating" : ""}`}

View File

@@ -306,7 +306,7 @@ export function RightDockExpandModal({
// FNXC:FloatingWindow 2026-06-22-22:30: Portaled to document.body so this floating modal shares the ONE root stacking context with the other floating modals (FloatingWindow/terminal/New Task) — the shared 10100+ z stack only orders correctly across types when they all live at the document root.
return createPortal(
<div className="modal-overlay open right-dock-expand-modal-overlay" role="dialog" aria-modal="false" aria-label={`${entry.label} expanded`} data-testid="right-dock-expand-modal">
<div className="modal-overlay open right-dock-expand-modal-overlay" role="dialog" aria-modal="false" aria-label={`${entry.label} expanded`} data-testid="right-dock-expand-modal" style={{ zIndex }}>
<div
className="modal right-dock-expand-modal right-dock-expand-modal--floating"
style={panelStyle}

View File

@@ -1833,13 +1833,11 @@ export function TerminalModal({ isOpen, onClose, initialCommand, initialCommandG
role="dialog"
aria-modal="true"
data-testid="terminal-modal-overlay"
style={
keyboardOverlap > 0
? {
"--overlay-padding-top": "0px",
} as CSSProperties
: undefined
}
style={{
// FNXC:FloatingWindow 2026-06-22-23:00: In floating mode the z-index lives on the fixed overlay (it owns the stacking context); a panel z is trapped inside it and loses to page stacking contexts like the right dock (position:absolute z-index:20). Docked/mobile keep their CSS z.
...(isFloatingMode ? { zIndex: floatingZ } : {}),
...(keyboardOverlap > 0 ? { "--overlay-padding-top": "0px" } : {}),
} as CSSProperties}
>
<div
ref={modalRef}