fix(plex): the player's ⋯ and tracks lists are real menus, and every close returns the focus
They were hand-built divs: no menu roles, no arrow keys, and Escape left the focus on <body>. Both run on the popover engine now (media-tone rows), and the tuning panel is a labelled dialog that takes the focus and hands it back to ⋯.
This commit is contained in:
@@ -104,6 +104,10 @@ const HIGHLIGHT_SELECTED =
|
||||
"data-active:bg-accent/35 data-active:text-fg data-active:ring-2 data-active:ring-inset data-active:ring-accent/80";
|
||||
const HIGHLIGHT_SELECTED_RING_ONLY =
|
||||
"data-active:ring-2 data-active:ring-inset data-active:ring-accent/70";
|
||||
// On the always-dark media chrome (a player's menus, `bg-media-chrome` under white text) the theme's
|
||||
// `text-fg` is dark in the light theme: the highlighted row would go dark-on-dark. White instead.
|
||||
const MEDIA_HIGHLIGHT =
|
||||
"data-active:bg-white/15 data-active:text-white data-active:ring-1 data-active:ring-inset data-active:ring-white/40";
|
||||
|
||||
export function PopoverItem({
|
||||
children,
|
||||
@@ -117,6 +121,7 @@ export function PopoverItem({
|
||||
elementRef,
|
||||
/** Typeahead match string; defaults to the text child. Set explicitly when children aren't plain text. */
|
||||
label,
|
||||
tone,
|
||||
...rest
|
||||
}: {
|
||||
children: ReactNode;
|
||||
@@ -134,6 +139,8 @@ export function PopoverItem({
|
||||
* aria-haspopup/aria-expanded belong on that button — not on a wrapper div around it. */
|
||||
elementRef?: (node: HTMLButtonElement | null) => void;
|
||||
label?: string;
|
||||
/** `media`: the row sits on the always-dark media chrome (a player's menu), not a theme surface. */
|
||||
tone?: "media";
|
||||
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onSelect" | "role" | "children" | "className">) {
|
||||
const ctx = useContext(PopoverListContext);
|
||||
const virtual = ctx?.virtual ?? false;
|
||||
@@ -212,11 +219,13 @@ export function PopoverItem({
|
||||
disabled={disabled}
|
||||
// touch-target: a menu row is a control primitive, 44 tall on a coarse pointer (A3).
|
||||
className={`outline-hidden touch-target ${
|
||||
checked || selected
|
||||
? keepSelectedPaint
|
||||
? HIGHLIGHT_SELECTED_RING_ONLY
|
||||
: HIGHLIGHT_SELECTED
|
||||
: ROVING_HIGHLIGHT
|
||||
tone === "media"
|
||||
? MEDIA_HIGHLIGHT
|
||||
: checked || selected
|
||||
? keepSelectedPaint
|
||||
? HIGHLIGHT_SELECTED_RING_ONLY
|
||||
: HIGHLIGHT_SELECTED
|
||||
: ROVING_HIGHLIGHT
|
||||
}${className ? ` ${className}` : ""}`}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -27,7 +27,6 @@ const PLAIN: Record<string, [number, string]> = {
|
||||
"PlaylistsRail.tsx": [1, "the load-error retry"],
|
||||
"PlexCollectionEditor.tsx": [1, "a checkbox row in a picker"],
|
||||
"PlexInfo.tsx": [1, "the rating filter (a number)"],
|
||||
"PlexPlayer.tsx": [4, "track picker rows and the ⋯ menu's rows"],
|
||||
"PlexPlayerSettings.tsx": [2, "setting options"],
|
||||
"PlexPlaylistAdd.tsx": [1, "a checkbox row in a picker"],
|
||||
"PlexPlaylistView.tsx": [1, "a show's poster stack (aria-hidden)"],
|
||||
|
||||
Reference in New Issue
Block a user