From d1704a5519dfea59e2bd4517eb70725df2cb1500 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Wed, 7 Oct 2026 23:59:32 +0200 Subject: [PATCH] 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. --- .../ui/Modal.fullscreen.dom.test.tsx | 36 ------------------- frontend/src/components/ui/Modal.tsx | 8 ++--- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/frontend/src/components/ui/Modal.fullscreen.dom.test.tsx b/frontend/src/components/ui/Modal.fullscreen.dom.test.tsx index 07d5b65c..ac0771fa 100644 --- a/frontend/src/components/ui/Modal.fullscreen.dom.test.tsx +++ b/frontend/src/components/ui/Modal.fullscreen.dom.test.tsx @@ -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( - - , - ); - 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( - -

form

-
, - ); - escape(); - expect(onClose).toHaveBeenCalledTimes(1); - stage.remove(); - }); -}); diff --git a/frontend/src/components/ui/Modal.tsx b/frontend/src/components/ui/Modal.tsx index 9f65bfec..d3babaf4 100644 --- a/frontend/src/components/ui/Modal.tsx +++ b/frontend/src/components/ui/Modal.tsx @@ -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