diff --git a/frontend/src/components/PlexSearchBox.dom.test.tsx b/frontend/src/components/PlexSearchBox.dom.test.tsx index cefaaa98..872fba57 100644 --- a/frontend/src/components/PlexSearchBox.dom.test.tsx +++ b/frontend/src/components/PlexSearchBox.dom.test.tsx @@ -219,4 +219,14 @@ describe("PlexSearchBox — typeahead", () => { await waitFor(() => expect(input.getAttribute("aria-expanded")).toBe("false")); expect(input.getAttribute("aria-controls")).toBeNull(); }); + + // Round 2 (F4 sibling): a listbox may own options only — "Loading…" sat inside it. + it("shows its loading line beside the listbox, not in it", async () => { + plexState.q = "matrix"; + plexLibrary.mockReturnValue(new Promise(() => {})); + renderBox(); + fireEvent.focus(screen.getByRole("combobox")); + const loading = await screen.findByText("plex.loading"); + expect(screen.getByRole("listbox").contains(loading)).toBe(false); + }); }); diff --git a/frontend/src/components/PlexSearchBox.tsx b/frontend/src/components/PlexSearchBox.tsx index 7499cc60..17c447bc 100644 --- a/frontend/src/components/PlexSearchBox.tsx +++ b/frontend/src/components/PlexSearchBox.tsx @@ -137,47 +137,46 @@ export default function PlexSearchBox() { below={ open ? (
- {error} - {onRetry && {t("common.retryWithEnter")}} -
- {onRetry && ( - // For the pointer only: this panel is a listbox, which may hold options and nothing - // else, so the keyboard's Retry is Enter in the field (said in the alert above). - - )} -{t("common.loading")}
- ) : filtered.length === 0 ? ( -- {emptyText ?? t("common.noResults", { defaultValue: "No matches" })} -
- ) : ( - <> - {visible.map((o) => { + {/* The listbox holds the options alone; the lines about the list sit beside it (F4). */} +- {t("common.moreRefine", { - count: hiddenCount, - defaultValue: "{{count}} more — refine with search", - })} -
++ {error} + {onRetry && {t("common.retryWithEnter")}} +
+ {onRetry && ( + // For the pointer: the keyboard's Retry is Enter in the field (said in the alert + // above), since the focus stays there the whole time the list is open. + )} - > +{t("common.loading")}
+ ) : filtered.length === 0 ? ( ++ {emptyText ?? t("common.noResults", { defaultValue: "No matches" })} +
+ ) : ( + hiddenCount > 0 && ( ++ {t("common.moreRefine", { + count: hiddenCount, + defaultValue: "{{count}} more — refine with search", + })} +
+ ) )}