fix(a11y): chips, grips, the panel tab and Back to top keep the focus somewhere real

- F5: a chip's × pressed from the keyboard hands the focus to the next chip (else the previous one,
  else what follows) before it unmounts — in DismissibleChip, so all five chip rows get it
  (`focusNeighbour` in lib/useFocusKeeper).
- F4: a drag grip names what it lifts (`common.order.dragNamed`: panel groups, personal views);
  the two generic "Drag to reorder" keys are gone.
- F6: the side panel's edge tab is out of the Tab order while the card covers it, names its panel,
  and a keyboard pin moves the focus into the card.
- F7: Back to top is no Tab stop while hidden, and a keyboard press leaves the focus on the page.
This commit is contained in:
2026-09-27 15:01:22 +02:00
parent 0b1d905866
commit 5ebb4cb506
17 changed files with 173 additions and 23 deletions
@@ -7,7 +7,12 @@ import { render, screen, fireEvent, cleanup, within } from "@testing-library/rea
vi.mock("react-i18next", async (importOriginal) => {
const actual = await importOriginal<typeof import("react-i18next")>();
return { ...actual, useTranslation: () => ({ t: (key: string) => key }) };
return {
...actual,
useTranslation: () => ({
t: (key: string, o?: { name?: string }) => (o?.name ? `${key}:${o.name}` : key),
}),
};
});
import PanelGroups, { type PanelItem } from "./PanelGroups";
@@ -56,3 +61,12 @@ describe("PanelGroups — reordering without a drag", () => {
expect(screen.queryByRole("button", { name: "common.order.up" })).toBeNull();
});
});
// E28 review F4: every group's grip was "Drag to reorder" — a screen reader heard the same name five
// times and could not tell which group it would lift. It names its group, as the playlist grips do.
describe("PanelGroups — the drag grip", () => {
it("is named by its group", () => {
mount(["a", "b", "c"]);
expect(screen.getByRole("button", { name: "common.order.dragNamed:Group b" })).toBeTruthy();
});
});