Skip to content

Commit

Permalink
fix(ModalWindow): allow focus to go to overlays opened from within th…
Browse files Browse the repository at this point in the history
…e modal window
  • Loading branch information
alirezamirian committed Dec 12, 2024
1 parent 599372d commit 3de14eb
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
50 changes: 48 additions & 2 deletions packages/jui/cypress/integration/modal-window_menu.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,61 @@
import React, { useState } from "react";
import React, { useRef, useState } from "react";
import {
IconButton,
FocusScope,
IconButton,
Item,
Menu,
MenuOverlayFromOrigin,
MenuTrigger,
ModalWindow,
PlatformIcon,
WindowLayout,
} from "@intellij-platform/core";

it("allows the focus to go out of modal window and into nested overlays such as menu", () => {
const Example = () => {
const [showMenu, setShowMenu] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
return (
<ModalWindow>
<WindowLayout
header="Modal window"
content={
<div style={{ padding: "1rem" }}>
<input
ref={inputRef}
onInput={(e) => setShowMenu(e.currentTarget.value !== "")}
/>
{showMenu && (
<MenuOverlayFromOrigin
origin={{
clientX: inputRef.current?.getBoundingClientRect().x ?? 0,
clientY:
inputRef.current?.getBoundingClientRect().bottom ?? 0,
}}
onClose={() => {
setShowMenu(false);
}}
>
<div style={{ padding: "0.375rem", background: "#000" }}>
<button onClick={() => setShowMenu(false)}>
focused element inside nested overlay
</button>
</div>
</MenuOverlayFromOrigin>
)}
</div>
}
/>
</ModalWindow>
);
};
cy.mount(<Example />);
cy.get("input").type("a");
cy.focused().should("contain.text", "focused element inside nested overlay");
cy.realPress("Enter");
cy.get("input").should("be.focused");
});

it("moves focus to the modal window, when opened by a menu item action", () => {
cy.mount(<ModalOnMenuItem />);
cy.findByRole("button").click();
Expand Down
10 changes: 9 additions & 1 deletion packages/jui/src/ModalWindow/ModalWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,15 @@ function useFocusContainmentFix<T extends HTMLElement>() {
if (
!probablyFocusedElement ||
(probablyFocusedElement instanceof Element &&
!e.currentTarget.contains(probablyFocusedElement))
!e.currentTarget.contains(probablyFocusedElement) &&
// The following condition is added to exclude cases where the focus
// is going to an overlay that is opened from within the modal window.
// The condition is suboptimal as there is no check on whether the
// overlay is a logical child of the modal or not.
// However, it seems justified since the entire hook is a temporary hack,
// and also it doesn't seem likely for an overlay outside the modal
// to grab the focus.
!probablyFocusedElement.closest("[data-overlay-root]"))
) {
const elementToFocus = lastFocusedElementRef.current;
if (elementToFocus) {
Expand Down

0 comments on commit 3de14eb

Please sign in to comment.