-
Notifications
You must be signed in to change notification settings - Fork 17
Description
[BUG] [alpha] Systemic Failure: Stacked Modals cause "Scroll Leakage" to underlying UI
Description
A systemic regression exists in the CortexModal component where closing a nested (top-level) modal prematurely restores the body scroll of the underlying IDE, even if a parent modal is still active. This creates "Scroll Leakage" where the user can scroll the code editor or other UI elements behind a blocking dialog.
Impact
- Context Loss: Users can accidentally scroll away from their current focus while a modal is still open.
- UX Instability: Breaking the "blocking" promise of modals leads to a confusing and unpolished experience.
- Systemic: Affects every combination of stacked modals in the IDE (e.g., Search Replace + File Delete, extension installs + confirmations).
Reproduction Steps
- Trigger Modal A: Open the Search Sidebar, perform any search, and click the Replace All button. This opens a "Replace All" confirmation modal. (Verify background is NOT scrollable).
- Trigger Modal B: While the "Replace All" modal is open, go to the Explorer and right-click any file, then select Delete. This opens a second modal (Delete confirmation) on top.
- The Leak: Click Cancel on the top (Delete) modal to close it.
- Observer Bug: Notice that the main editor/UI background is now SCROLLABLE even though the "Replace All" modal is still open and blocking the view.
Root Cause Analysis
The bug is located in CortexModal.tsx.
The restoreDocumentState function (line 94) blindly resets the body overflow to empty:
94: const restoreDocumentState = () => {
95: if (typeof document !== "undefined") {
96: document.body.style.overflow = ""; // <--- ERROR: Resets overflow regardless of other modals
97: }
98: previousActiveElement?.focus();
99: };This function is triggered in the createEffect block whenever open becomes false (line 179):
175: } else {
176: setIsVisible(false);
177: closeAnimationTimeout = setTimeout(() => {
178: setIsAnimating(false);
179: restoreDocumentState(); // <--- ERROR: Triggered on any modal close
180: closeAnimationTimeout = undefined;
181: }, 200);Suggested Fix
Implement a global modal counter or use the existing useModalActiveOptional context to track the number of active modals. restoreDocumentState should only be called if the active modal count is zero.
Verified on Linux (Cortex IDE Alpha)