test(channels): cover ActionMenu keyboard-skip + stats ETA value; drop redundant disabledIndices

Deep-review follow-up on R13 S3.

- Add a roving-keyboard-nav test proving a disabled ActionMenu item is
  skipped by arrow keys, and assert the stats "left" row renders the
  formatEta value (formatEta had no coverage anywhere).
- Remove the disabledIndices plumbing from AnchoredPopover + ActionMenu:
  it was redundant. useListNavigation already skips items via their DOM
  disabled/aria-disabled attribute, and PopoverItem renders a native
  disabled button — verified against @floating-ui/react 0.27
  isListIndexDisabled and by a mutation test. Behaviour is unchanged and
  now guarded by the new test.
This commit is contained in:
2026-08-15 04:45:32 +02:00
parent bb2d6999fd
commit 5838cf1c56
4 changed files with 53 additions and 15 deletions
+4 -4
View File
@@ -91,9 +91,6 @@ export interface AnchoredPopoverOptions {
* lands the roving focus on it instead of the first item — the behaviour a "pick one of these
* modes" menu needs. Leave unset for action menus and multi-select toggle lists. */
selectedIndex?: number | null;
/** Indices of items that are disabled (e.g. an action whose mutation is already in flight), so
* roving keyboard nav SKIPS them instead of stranding focus on an unfocusable disabled button. */
disabledIndices?: number[];
}
// Internal: call sites use the inferred hook return, they don't name the type.
@@ -178,7 +175,10 @@ export function useAnchoredPopover(opts: AnchoredPopoverOptions) {
setHoverIndex(null);
},
selectedIndex: opts.selectedIndex ?? null,
disabledIndices: opts.disabledIndices,
// Disabled items are skipped automatically: with no `disabledIndices`, useListNavigation reads
// each item's DOM `disabled`/`aria-disabled` (PopoverItem always renders native `disabled`), so a
// pending/inert item is never a roving target. (Verified against @floating-ui/react 0.27
// `isListIndexDisabled`.) No explicit index list needed.
loop: true,
// Focus the first item on open for BOTH click and keyboard (the default 'auto' skips pointer-opens,
// which strands focus on the menu container — arrows then can't enter the roving list at all).