fix(design): the command palette's active row takes the menus' roving highlight, not an invisible bg-card; the Plex typeahead's hand copy of it goes (E28)
The palette row was ~1.07:1 on its glass (B3 names bg-card hovers a violation). ROVING_HIGHLIGHT is exported from AnchoredPopover for the listboxes that are not PopoverItems; a contract holds that no file paints the fill itself and every hand-built option row takes the recipe.
This commit is contained in:
@@ -11,6 +11,7 @@ import { useDebounced } from "../lib/useDebounced";
|
||||
import { availablePlexFields, healPlexField, plexFieldLabelKey } from "../lib/plexSearch";
|
||||
import { Pressable } from "./ui/Pressable";
|
||||
import { SURFACE } from "./ui/surfaces";
|
||||
import { ROVING_HIGHLIGHT } from "./ui/AnchoredPopover";
|
||||
|
||||
// The Plex header search box: the shared SearchBar enriched with the S2 search scope-pill (a
|
||||
// GitHub-style field selector inside the box) and an instant typeahead of the top matches attached
|
||||
@@ -156,10 +157,9 @@ export default function PlexSearchBox() {
|
||||
onMouseEnter={() => setHi(i)}
|
||||
onClick={() => pick(i)}
|
||||
// The pointer moves `hi` too, so the highlight IS the hover: the menus' roving
|
||||
// recipe (AnchoredPopover's HIGHLIGHT_UNSELECTED), one look for the mouse and the keys.
|
||||
className={`flex w-full items-center gap-3 rounded-lg p-1.5 transition ${
|
||||
hi === i ? "bg-accent/35 text-fg ring-1 ring-inset ring-accent/60" : ""
|
||||
}`}
|
||||
// recipe (AnchoredPopover's ROVING_HIGHLIGHT), one look for the mouse and the keys.
|
||||
data-active={hi === i ? "true" : undefined}
|
||||
className={`flex w-full items-center gap-3 rounded-lg p-1.5 transition ${ROVING_HIGHLIGHT}`}
|
||||
>
|
||||
<img
|
||||
src={c.thumb}
|
||||
|
||||
@@ -96,7 +96,9 @@ type ItemRole = "menuitem" | "menuitemradio" | "menuitemcheckbox" | "option";
|
||||
// EXCEPTION: a menu whose SELECTED item paints its OWN row background (a solid bg-accent — the
|
||||
// table-filter options) passes `keepSelectedPaint`, so the highlight yields to ring-only there; a fill
|
||||
// would downgrade that solid paint to a 35% tint (the R9 concern, now scoped to just that idiom).
|
||||
const HIGHLIGHT_UNSELECTED =
|
||||
// Exported as ROVING_HIGHLIGHT for a listbox that is not a PopoverItem (the command palette, the Plex
|
||||
// typeahead): the row carries `data-active` and takes this, so the keyboard row looks the same everywhere.
|
||||
export const ROVING_HIGHLIGHT =
|
||||
"data-active:bg-accent/35 data-active:text-fg data-active:ring-1 data-active:ring-inset data-active:ring-accent/60";
|
||||
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";
|
||||
@@ -214,7 +216,7 @@ export function PopoverItem({
|
||||
? keepSelectedPaint
|
||||
? HIGHLIGHT_SELECTED_RING_ONLY
|
||||
: HIGHLIGHT_SELECTED
|
||||
: HIGHLIGHT_UNSELECTED
|
||||
: ROVING_HIGHLIGHT
|
||||
}${className ? ` ${className}` : ""}`}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -124,6 +124,19 @@ describe("CommandPalette", () => {
|
||||
).toContain("page:feed");
|
||||
});
|
||||
|
||||
// E28 F35: the active row wore `bg-card`, ~1.07:1 on the palette's glass. It is the menus' row now.
|
||||
it("marks the active row with the menus' roving highlight, and only that row", () => {
|
||||
open();
|
||||
const rows = screen.getAllByRole("option");
|
||||
const active = rows.filter((r) => r.hasAttribute("data-active"));
|
||||
expect(active).toHaveLength(1);
|
||||
expect(active[0]!.getAttribute("aria-selected")).toBe("true");
|
||||
for (const r of rows) {
|
||||
expect(r.className).toContain("data-active:bg-accent/35");
|
||||
expect(r.className).not.toMatch(/(^|\s)bg-card(\s|$)/);
|
||||
}
|
||||
});
|
||||
|
||||
// The arrows walk the flat result list, not the sections — crossing a group heading is invisible.
|
||||
it("walks results with the arrows, across group boundaries", () => {
|
||||
open();
|
||||
|
||||
@@ -7,6 +7,7 @@ import { closeTopOverlayThenRun } from "../../lib/history";
|
||||
import { pageStep, pageTarget } from "../../lib/listPaging";
|
||||
import { Pressable } from "./Pressable";
|
||||
import { InnerInput } from "./Input";
|
||||
import { ROVING_HIGHLIGHT } from "./AnchoredPopover";
|
||||
import { fieldClass } from "./fieldStyles";
|
||||
|
||||
// The app's jump-to bar: one text field over every place you can go and every app-wide thing you can
|
||||
@@ -270,9 +271,9 @@ function CommandPaletteBody({ onClose, groups }: { onClose: () => void; groups:
|
||||
if (e.movementX === 0 && e.movementY === 0) return;
|
||||
setPicked(item.id);
|
||||
}}
|
||||
className={`flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-sm ${
|
||||
item.id === activeId ? "bg-card text-fg" : "text-muted hover:text-fg"
|
||||
}`}
|
||||
// The menus' roving highlight: a `bg-card` row was ~1.07:1 on the palette's glass (E28).
|
||||
data-active={item.id === activeId ? "true" : undefined}
|
||||
className={`flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-sm text-muted hover:text-fg ${ROVING_HIGHLIGHT}`}
|
||||
>
|
||||
{item.icon && <span className="shrink-0">{item.icon}</span>}
|
||||
<span className="min-w-0 flex-1 truncate">{item.label}</span>
|
||||
|
||||
Reference in New Issue
Block a user