feat(design): the channel menu's Tags and Priority submenus (C1, E28 S3e3b)
Tags A-Z as in-place checks (the menu stays open for the next); Priority as the fixed steps 10 5 3 2 1 0, an off-scale current value ticked in its place. A pick re-sorts the list at once, moving only that row (placeByPriority, the server's order), and the table / card pager and the focus follow it (DataTable and useCardPager take a reveal seq, listNav.focusNavItem lands on the row's own "…", a virtualized card revealed first). ActionMenu rows take check: many | one. The menu reads the row fresh from the cache and keys its target by id.
This commit is contained in:
@@ -84,6 +84,37 @@ describe("ActionMenu", () => {
|
||||
await vi.waitFor(() => expect(onSelect).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
it("a 'many' check row toggles in place: the menu stays open and the focus stays on it", async () => {
|
||||
const onSelect = vi.fn();
|
||||
renderMenu([
|
||||
{ id: "rust", label: "rust", check: { kind: "many", checked: true }, onSelect },
|
||||
{ id: "go", label: "go", check: { kind: "many", checked: false }, onSelect: vi.fn() },
|
||||
]);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Catalog actions" }));
|
||||
const rows = screen.getAllByRole("menuitemcheckbox", { hidden: true });
|
||||
expect(rows.map((r) => r.getAttribute("aria-checked"))).toEqual(["true", "false"]);
|
||||
fireEvent.click(rows[0]!);
|
||||
// Synchronously — no close, no deferred act — and nothing closed around it.
|
||||
expect(onSelect).toHaveBeenCalledTimes(1);
|
||||
expect(screen.getAllByRole("menuitemcheckbox", { hidden: true })).toHaveLength(2);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
expect(screen.getAllByRole("menuitemcheckbox", { hidden: true })).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("a 'one' check row is a radio that picks and closes like any row", async () => {
|
||||
const onSelect = vi.fn();
|
||||
renderMenu([
|
||||
{ id: "10", label: "10", check: { kind: "one", checked: false }, onSelect },
|
||||
{ id: "5", label: "5", check: { kind: "one", checked: true }, onSelect: vi.fn() },
|
||||
]);
|
||||
fireEvent.click(screen.getByRole("button", { name: "Catalog actions" }));
|
||||
const rows = screen.getAllByRole("menuitemradio", { hidden: true });
|
||||
expect(rows.map((r) => r.getAttribute("aria-checked"))).toEqual(["false", "true"]);
|
||||
fireEvent.click(rows[0]!);
|
||||
expect(screen.queryByRole("menuitemradio", { hidden: true })).toBeNull();
|
||||
await vi.waitFor(() => expect(onSelect).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
it("a disabled item is inert — rendered disabled and never fires onSelect", () => {
|
||||
const onSelect = vi.fn();
|
||||
renderMenu([{ id: "sync", label: "Sync", onSelect, disabled: true }]);
|
||||
|
||||
Reference in New Issue
Block a user