fix(ui): a dialog whose own video goes fullscreen no longer crashes the app
The portal host followed the fullscreen element into it. When that element is the dialog's own content (the library player's <video>, by its f key or its own button), the move is into the host's own descendant, which the DOM refuses: HierarchyRequestError in a layout effect, and the crash screen replaced the app. The host now stays where it is then — the content already shows.
This commit is contained in:
@@ -85,3 +85,24 @@ describe("a dialog with an autoFocus child", () => {
|
|||||||
stage.remove();
|
stage.remove();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("a dialog whose own content goes fullscreen", () => {
|
||||||
|
it("stays where it is and keeps that content", () => {
|
||||||
|
// The library player is a <video> inside a dialog, and its fullscreen (the `f` key, or the
|
||||||
|
// video's own button) makes that video the fullscreen element. Moving the dialog's host INTO
|
||||||
|
// its own descendant is not a move the DOM allows: it threw, and the whole app went to the
|
||||||
|
// crash screen.
|
||||||
|
render(
|
||||||
|
<Modal initialFocus="close" title="Player" onClose={() => {}}>
|
||||||
|
<video aria-label="film" />
|
||||||
|
</Modal>,
|
||||||
|
);
|
||||||
|
const video = screen.getByLabelText("film");
|
||||||
|
const host = video.closest("body > div");
|
||||||
|
|
||||||
|
setFullscreen(video);
|
||||||
|
|
||||||
|
expect(video.isConnected).toBe(true);
|
||||||
|
expect(video.closest("body > div")).toBe(host);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -95,7 +95,10 @@ export function useFullscreenPortalHost(): HTMLElement | null {
|
|||||||
}, [host]);
|
}, [host]);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!host) return;
|
if (!host) return;
|
||||||
const parent = fsRoot ?? document.body;
|
// When the fullscreen element is the overlay's OWN content (a <video> inside a dialog, put in
|
||||||
|
// fullscreen by its key or its own button), it already shows; moving the host into its own
|
||||||
|
// descendant is a move the DOM refuses (HierarchyRequestError, the whole app crashed).
|
||||||
|
const parent = fsRoot && !host.contains(fsRoot) ? fsRoot : document.body;
|
||||||
if (host.parentNode === parent) return;
|
if (host.parentNode === parent) return;
|
||||||
const focused = host.contains(document.activeElement)
|
const focused = host.contains(document.activeElement)
|
||||||
? (document.activeElement as HTMLElement)
|
? (document.activeElement as HTMLElement)
|
||||||
|
|||||||
Reference in New Issue
Block a user