feat(design): reorder without a drag everywhere a grip drags (WCAG 2.5.7, E28 S3e4a)
One rule, two forms: useOrderItems (Top / Up / Down / Bottom rows of a row menu) and OrderButtons (four buttons with the place, or a compact Up / Down pair). A move that would go nowhere is shown off. - YouTube playlist rows: the four moves now come from useOrderItems. - Plex playlist rows: a block among the blocks, an episode within its show, off while a write is in flight; drag and menu share moveBlock/moveEpisode. - Saved views editor: the selected view's four buttons (owner: A), and the grip's keyboard pick-up (its instructions promised one it did not have). - Side panel groups in edit mode: an Up / Down pair (owner: A); a group the stored order does not hold yet moves too; the name wraps there. - The grip's touch-action: none is now test-held.
This commit is contained in:
@@ -184,3 +184,50 @@ describe("PersonalViewsModal — S7 editable detail pane", () => {
|
||||
await waitFor(() => expect(h.rename).toHaveBeenCalledWith(5, "Documentaries"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("PersonalViewsModal — reordering without a drag (WCAG 2.5.7)", () => {
|
||||
const view = (id: number, name: string, position: number) => ({
|
||||
id,
|
||||
name,
|
||||
filters: VIEW_FILTERS,
|
||||
position,
|
||||
is_default: false,
|
||||
});
|
||||
|
||||
it("moves the selected view with its order buttons, the moves that go nowhere held off", async () => {
|
||||
CTX.reorder.mockClear();
|
||||
CTX.views = [view(5, "Docs", 0), view(6, "Music", 1), view(7, "Tech", 2)];
|
||||
mount();
|
||||
const group = await screen.findByRole("group", { name: /common\.order\.label/ });
|
||||
const btn = (name: string) =>
|
||||
Array.from(group.querySelectorAll("button")).find(
|
||||
(b) => b.getAttribute("aria-label") === name,
|
||||
)!;
|
||||
expect(btn("common.order.top").disabled).toBe(true);
|
||||
expect(btn("common.order.up").disabled).toBe(true);
|
||||
fireEvent.click(btn("common.order.down"));
|
||||
expect(CTX.reorder).toHaveBeenLastCalledWith([6, 5, 7]);
|
||||
fireEvent.click(btn("common.order.bottom"));
|
||||
expect(CTX.reorder).toHaveBeenLastCalledWith([6, 7, 5]);
|
||||
// A view picked in the list moves from ITS place, not the first one's.
|
||||
fireEvent.click(screen.getByRole("button", { name: "Tech" }));
|
||||
await waitFor(() => expect(btn("common.order.up").disabled).toBe(false));
|
||||
fireEvent.click(btn("common.order.up"));
|
||||
expect(CTX.reorder).toHaveBeenLastCalledWith([5, 7, 6]);
|
||||
});
|
||||
|
||||
it("has no order buttons for a single view", async () => {
|
||||
mount();
|
||||
await screen.findByDisplayValue("Docs");
|
||||
expect(screen.queryByRole("group", { name: /common\.order\.label/ })).toBeNull();
|
||||
});
|
||||
|
||||
it("picks a view up from the keyboard, as its grip's instructions say", async () => {
|
||||
CTX.views = [view(5, "Docs", 0), view(6, "Music", 1)];
|
||||
mount();
|
||||
const grip = (await screen.findAllByRole("button", { name: "views.reorder" }))[0]!;
|
||||
grip.focus();
|
||||
fireEvent.keyDown(grip, { code: "Space", key: " " });
|
||||
await waitFor(() => expect(document.body.textContent).toContain("common.dnd.pickedUp"));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user