fix(ui): toasts raised while a full-screen player is open show inside it, not under its scrim
The app's Toaster lives in the content column, which is a stacking context (its `@container` implies layout containment), so both full-screen players — portalled to <body> at the same z-index — painted over every toast. Round 1's "a failed Remove is reported" fix was therefore still silent inside the player: its toast sat under an 80% black, blurred scrim (elementFromPoint returned the scrim), and a click on it closed the player. An overlay now mounts its own `<Toaster overlay />`, and exactly one host shows the toasts: the most recently mounted overlay, else the app's. Same component, same look — and inside the aria-modal dialog, where a screen reader can still reach it. A click on a toast inside an overlay stays there. Both players get one (the Plex player's also works in native fullscreen, where nothing outside the fullscreen element is drawn). Verified on localdev: the removal failure reads above the scrim, bottom-left, and clicking it leaves the player open.
This commit is contained in:
@@ -31,6 +31,7 @@ vi.mock("./DownloadButton", () => ({ default: () => null }));
|
||||
import PlayerModal from "./PlayerModal";
|
||||
import { ConfirmProvider, useConfirm } from "./ConfirmProvider";
|
||||
import { api, type Video } from "../lib/api";
|
||||
import { clearAll, notify } from "../lib/notifications";
|
||||
|
||||
beforeAll(() => {
|
||||
class Stub {
|
||||
@@ -249,3 +250,19 @@ describe("PlayerModal — removing the playing video from its playlist", () => {
|
||||
await waitFor(() => expect(document.activeElement).toBe(trash("A")));
|
||||
});
|
||||
});
|
||||
|
||||
describe("PlayerModal — toasts raised while it is open", () => {
|
||||
afterEach(() => act(() => clearAll()));
|
||||
|
||||
it("shows them inside the player, not under its scrim", async () => {
|
||||
// The app's Toaster is in a stacking context below this body-level portal: a failed Remove
|
||||
// reported by a toast was drawn under the 80% black scrim, i.e. still silent.
|
||||
vi.spyOn(api, "videoDetail").mockReturnValue(new Promise(() => {}));
|
||||
const A = vid("A", 0);
|
||||
renderModal(
|
||||
<PlayerModal video={A} queue={[A]} startIndex={0} onClose={() => {}} onState={() => {}} />,
|
||||
);
|
||||
act(() => void notify({ level: "error", message: "Couldn't remove the video." }));
|
||||
expect(screen.getByTestId("player-modal").textContent).toContain("Couldn't remove the video.");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user