fix(popover): single hover-follows highlight without stealing input focus (UAT)

Second UAT finding on the tag popover: the keyboard-active row stayed put while
a fainter CSS :hover chased the pointer — two competing highlights. Root cause:
floating-ui's focusItemOnHover is (correctly) OFF for input-hosting menus because
setting its activeIndex on hover drags DOM focus onto the item and blurs the
create-tag input mid-typing; the only pointer feedback left was the item's own
`hover:bg-*`.

Fix, applied in the shared PopoverItem so it's general:
- Drive the visible highlight off a NEW `hoverIndex` state (highlightIndex =
  hoverIndex ?? activeIndex), decoupled from floating-ui's activeIndex — hovering
  sets only hoverIndex, never DOM focus, so one highlight follows the pointer AND
  the input keeps its caret. Keyboard nav (onNavigate/onMatch) clears hoverIndex
  so it takes the highlight back; leaving the menu clears it too.
- Split PopoverItem's `active` into focusActive (roving tabindex, keyboard) vs
  visualActive (data-active highlight).
- Remove the now-redundant `hover:bg-*` from the 5 consumers so data-active is the
  sole highlight (it was also a same-specificity tie with data-active).

Verified in-browser: hovering moves the single highlight; typing "testtag" in the
create field then hovering items keeps focus+caret on the input (caretPos intact);
mouse-leave returns the highlight to the keyboard row. Gate: tsc/eslint/prettier/
vitest 79 green.
This commit is contained in:
2026-08-08 01:38:06 +02:00
parent 22e0d286c0
commit f8e0ab1520
6 changed files with 55 additions and 14 deletions
+1 -1
View File
@@ -95,7 +95,7 @@ export default function ViewSwitcher<T extends string>({
}}
label={o.label}
className={`w-full flex items-center gap-2 px-2 py-1.5 rounded-lg text-sm text-left outline-hidden transition ${
on ? "text-accent" : "text-fg hover:bg-card"
on ? "text-accent" : "text-fg"
}`}
>
<Icon className="w-4 h-4 shrink-0" />