{
setQuery(e.target.value);
setPicked(null);
}}
onKeyDown={onInputKey}
placeholder={t("palette.placeholder")}
aria-label={t("palette.placeholder")}
// A minimal combobox tree: the arrows move a VIRTUAL selection while the caret stays in
// the field, so a screen reader has to be told which row is current. `aria-expanded`
// follows the results: with nothing to choose from there is no popup to be in.
role="combobox"
aria-expanded={flat.length > 0}
aria-controls={listId}
aria-activedescendant={activeId ? `${listId}-${activeId}` : undefined}
/>
{announced}
{/* Stays mounted (hidden) while empty, so the input's aria-controls never names a missing
element; the "nothing matches" line sits OUTSIDE it, since a listbox may hold only options
and groups. */}
{visible.map((g) => (
{g.label}
{g.items.map((item) => (
choose(item)}
onMouseMove={(e) => {
// Only a pointer that actually MOVED may take the selection. After the arrow keys
// scroll a row past the fold, Blink re-dispatches a mousemove at the unchanged
// cursor position to refresh hover — which handed the highlight straight back to
// whatever row slid under a resting cursor. The browser
// reports zero movement for exactly that synthetic event, so ask it directly:
// remembering the last position instead could not judge the FIRST
// move of a session and went stale across a close.
if (e.movementX === 0 && e.movementY === 0) return;
setPicked(item.id);
}}
// The menus' roving highlight: a `bg-card` row was ~1.07:1 on the palette's glass.
data-active={item.id === activeId ? "true" : undefined}
className={`flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-sm text-muted hover:text-fg ${ROVING_HIGHLIGHT}`}
>
{item.icon && {item.icon}}
{item.label}
{item.hint && {item.hint}}
))}
))}
{flat.length === 0 && (
{t("palette.empty")}
)}
);
}