| 1 | import { useEffect, useRef } from "react"; |
| 2 | import type { SlashArgItem } from "../lib/types"; |
| 3 | |
| 4 | // ArgMenu is the autocomplete dropdown for a slash command's arguments (the part |
| 5 | // after the command word) — e.g. /skill → list/show/new/paths, /model → refs. |
| 6 | // Like SlashMenu but the entries are bare tokens (no leading "/"); the Composer |
| 7 | // owns filtering, the active index, and key handling. Reuses .slashmenu styling. |
| 8 | export function ArgMenu({ |
| 9 | items, |
| 10 | activeIndex, |
| 11 | onPick, |
| 12 | onHover, |
| 13 | }: { |
| 14 | items: SlashArgItem[]; |
| 15 | activeIndex: number; |
| 16 | onPick: (it: SlashArgItem) => void; |
| 17 | onHover: (i: number) => void; |
| 18 | }) { |
| 19 | // Keep the keyboard-selected item in view (the list overflows at 280px). |
| 20 | const activeRef = useRef<HTMLButtonElement>(null); |
| 21 | useEffect(() => { |
| 22 | activeRef.current?.scrollIntoView({ block: "nearest" }); |
| 23 | }, [activeIndex]); |
| 24 | return ( |
| 25 | <div className="slashmenu" role="listbox"> |
| 26 | {items.map((it, i) => ( |
| 27 | <button |
| 28 | key={it.label} |
| 29 | ref={i === activeIndex ? activeRef : undefined} |
| 30 | role="option" |
| 31 | aria-selected={i === activeIndex} |
| 32 | className={`slashmenu__item ${i === activeIndex ? "slashmenu__item--active" : ""}`} |
| 33 | onMouseDown={(e) => { |
| 34 | e.preventDefault(); |
| 35 | onPick(it); |
| 36 | }} |
| 37 | onMouseMove={() => onHover(i)} |
| 38 | > |
| 39 | <span className="slashmenu__name">{it.label}</span> |
| 40 | {it.hint && <span className="slashmenu__hint">{it.hint}</span>} |
| 41 | </button> |
| 42 | ))} |
| 43 | </div> |
| 44 | ); |
| 45 | } |
| 46 |