revert: the Modal Escape guard for a fullscreen own-content video
Chrome does not hand the page the Escape it spends on leaving fullscreen (checked with a real
keypress: the first Esc leaves fullscreen, the second closes the player). The guard defended a case
that does not happen, under a comment saying it does. This reverts 121ebeeb.
This commit is contained in:
@@ -106,39 +106,3 @@ describe("a dialog whose own content goes fullscreen", () => {
|
||||
expect(video.closest("body > div")).toBe(host);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Escape while the dialog's own content is fullscreen", () => {
|
||||
const escape = () =>
|
||||
act(() => {
|
||||
window.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }));
|
||||
});
|
||||
|
||||
it("only leaves fullscreen (the browser's part) — the dialog stays open", () => {
|
||||
// The browser spends that Escape on leaving fullscreen and still hands it to the page, with the
|
||||
// video still the fullscreen element: the dialog closed with it, and the viewer lost the player.
|
||||
const onClose = vi.fn();
|
||||
render(
|
||||
<Modal initialFocus="close" title="Player" onClose={onClose}>
|
||||
<video aria-label="film" />
|
||||
</Modal>,
|
||||
);
|
||||
setFullscreen(screen.getByLabelText("film"));
|
||||
escape();
|
||||
expect(onClose).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("still closes a dialog opened over something else that is fullscreen", () => {
|
||||
const stage = document.createElement("div");
|
||||
document.body.appendChild(stage);
|
||||
setFullscreen(stage);
|
||||
const onClose = vi.fn();
|
||||
render(
|
||||
<Modal initialFocus="close" title="Download" onClose={onClose}>
|
||||
<p>form</p>
|
||||
</Modal>,
|
||||
);
|
||||
escape();
|
||||
expect(onClose).toHaveBeenCalledTimes(1);
|
||||
stage.remove();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { X } from "lucide-react";
|
||||
import { useBackToClose } from "../../lib/history";
|
||||
import { anyBlockingLayerAbove, pushLayer, removeLayer, takeEscape } from "../../lib/layerStack";
|
||||
import { fullscreenElement, useFullscreenPortalHost } from "../../lib/fullscreen";
|
||||
import { useFullscreenPortalHost } from "../../lib/fullscreen";
|
||||
import { firstFieldIn, focusablesIn, trapTab, useDialogChrome } from "./dialogFocus";
|
||||
import { IconButton } from "./IconButton";
|
||||
import Toaster from "./Toaster";
|
||||
@@ -151,11 +151,7 @@ export default function Modal({
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (takeEscape(e, id)) {
|
||||
e.stopPropagation();
|
||||
// The browser spends an Escape on leaving fullscreen and still hands it to the page, the
|
||||
// fullscreen element still set. When that element is the dialog's own content (the library
|
||||
// player's <video>), the Escape was the browser's: closing too lost the viewer the player.
|
||||
const fs = fullscreenElement();
|
||||
if (!(fs && rootRef.current?.contains(fs))) close();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
// Focus trap: keep Tab / Shift+Tab cycling inside the dialog instead of reaching the inert
|
||||
|
||||
Reference in New Issue
Block a user