Files
ds-chat/frontend/src/components/MentionAutocomplete.tsx
T
ksmithandClaude Sonnet 5 2a84a9c9bd Add composer autocomplete for #roomname (#47 follow-up)
Mirrors the @mention autocomplete exactly -- same trigger-detection
logic (factored into a shared detectTriggerQuery helper, parameterized
on '@' vs '#'), same arrow-key/Enter/Tab/Escape keyboard handling, same
dropdown. Suggests rooms the user belongs to, filtered by name prefix,
showing the room's description as a subtitle when it has one.

MentionAutocomplete.css is renamed to ComposerAutocomplete.css with
generic class names (composer-autocomplete-primary/-secondary instead of
-username/-display-name), now shared by both the mention and room-
reference dropdowns instead of being mention-specific.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-17 19:12:51 -06:00

37 lines
1.3 KiB
TypeScript

import type { RoomMember } from '../types'
import './ComposerAutocomplete.css'
interface MentionAutocompleteProps {
matches: RoomMember[]
activeIndex: number
onPick: (username: string) => void
onHover: (index: number) => void
}
export function MentionAutocomplete({ matches, activeIndex, onPick, onHover }: MentionAutocompleteProps) {
return (
<div className="composer-autocomplete" role="listbox">
{matches.map((member, i) => (
<button
key={member.user_id}
type="button"
role="option"
aria-selected={i === activeIndex}
className={`composer-autocomplete-item${i === activeIndex ? ' composer-autocomplete-item-active' : ''}`}
// Selecting must survive the textarea's blur (which would
// otherwise fire first and could dismiss the dropdown) --
// onMouseDown fires before blur, onClick fires after.
onMouseDown={(e) => e.preventDefault()}
onClick={() => onPick(member.username)}
onMouseEnter={() => onHover(i)}
>
<span className="composer-autocomplete-primary">@{member.username}</span>
{member.display_name && (
<span className="composer-autocomplete-secondary">{member.display_name}</span>
)}
</button>
))}
</div>
)
}