import { ReactNode, forwardRef } from 'react'
import { useTranslation } from 'tldraw'
import { Avatar } from './avatar'
import { CommentAuthor } from './comment-author'
/** A person the composer's \@-mention picker can offer: a {@link CommentAuthor} plus its id and
* picker-only display fields. @public */
export interface MentionMember extends CommentAuthor {
id: string
/** A secondary line under the name — e.g. an email or handle. Omit for a single-line row. */
secondary?: string
/** Marks the current user; shown as a "(You)" suffix after the name. */
you?: boolean
/** Hosts may carry extra fields; a custom `renderMember` can read them. */
[key: string]: unknown
}
/** @public */
export interface MentionListProps {
/** Members to choose from — already resolved for the current query by the host. */
members: MentionMember[]
/** Index of the highlighted row, driven by the composer's keyboard navigation. */
activeIndex?: number
/** Called when a member is chosen (click, or Enter on the active row). */
onSelect?(member: MentionMember): void
/** Shown when no member matches the query. Defaults to a translated "No matches". */
emptyLabel?: string
/** Override a row's content (inside the selectable button). Defaults to avatar + name (+ secondary). */
renderMember?(member: MentionMember): ReactNode
}
/** The default row content: avatar, name (with a "(You)" marker), and an optional secondary line. */
function DefaultMemberRow({ member }: { member: MentionMember }) {
const msg = useTranslation()
return (
<>
{member.name}
{member.you && (
{`(${msg('comments.mention-you')})`}
)}
{member.secondary && (
{member.secondary}
)}
>
)
}
/**
* The \@-mention member picker: a popover list of people to mention, shown as the user types after
* `@`. Presentational — the composer's suggestion plugin owns resolution, keyboard navigation, and
* placement, and drives this with the host-resolved `members` and the highlighted `activeIndex`.
* @public @react
*/
export const MentionList = forwardRef(function MentionList(
{ members, activeIndex = 0, onSelect, emptyLabel, renderMember },
ref
) {
const msg = useTranslation()
if (members.length === 0) {
return (