fix(ui): every full-screen overlay hosts its own toasts, above the players' controls, without re-announcing them
Deep-review round 3 of bug hunt 2026-09 (the round-2 overlay toast host, finished). - Inside an overlay the toast stack sits above the bottom band (bottom-24, the UpNextCard rung) and lets clicks between cards through: at the app's own spot it covered the Plex transport row and PlayerModal's docked bar and took their clicks while a toast was up (measured: play/pause, ±10, stop, prev/next, mute all hit the toast). - ui/Modal and the onboarding wizard mount an overlay host too, so a toast raised under any dialog is readable and a click on it no longer closes the dialog; the Modal's Tab trap spans the whole dialog, so a toast's action and dismiss are keyboard-reachable. A test now enforces the convention: a component that covers the viewport at z-overlay must mount <Toaster overlay />. - PlayerModal's host moves into the stage in true fullscreen (outside the element holding the lock it was painted under it). - A host that takes over shows the toasts it inherits silently (no second role=alert, its region aria-live=off until they are in), and each countdown bar starts as far in as its toast already is instead of restarting while the real dismiss timer does not. - The overlay-host registry uses lib/store instead of a hand-rolled listener triad.
This commit is contained in:
@@ -586,6 +586,7 @@ export default function PlayerModal({
|
||||
the exit button also re-arms our shortcuts. Add-to-playlist works in true fullscreen (its
|
||||
popover portals INTO the fullscreen element); download stays hidden there because it opens
|
||||
a Modal, which still portals to <body> — outside the fullscreen element. */}
|
||||
{isFullscreen && <Toaster overlay />}
|
||||
{(maximized || isFullscreen) && (
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
@@ -962,8 +963,9 @@ export default function PlayerModal({
|
||||
)}
|
||||
</div>
|
||||
{/* Toasts raised while the player is open (a failed Remove, a lost connection) — the app's own
|
||||
Toaster is underneath this scrim. See ui/Toaster. */}
|
||||
<Toaster overlay />
|
||||
Toaster is underneath this scrim. See ui/Toaster. In true fullscreen it moves into the
|
||||
stage, the element holding the lock: out here it was painted under it, i.e. not at all. */}
|
||||
{!isFullscreen && <Toaster overlay />}
|
||||
</div>,
|
||||
document.body,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user