feat: chat reactions
This commit is contained in:
@@ -55,6 +55,9 @@ export function MessageList({
|
||||
starredIds,
|
||||
onRetry,
|
||||
nameFor,
|
||||
typingNames,
|
||||
onReact,
|
||||
onTrailClick,
|
||||
}: {
|
||||
/** Ascending by seq — oldest first. */
|
||||
messages: ChatMessage[];
|
||||
@@ -71,6 +74,11 @@ export function MessageList({
|
||||
starredIds: Set<string>;
|
||||
onRetry: (message: ChatMessage) => void;
|
||||
nameFor: (senderId: string | null | undefined) => string;
|
||||
/** Who is composing right now. Empty when nobody is. */
|
||||
typingNames: string[];
|
||||
onReact: (message: ChatMessage, emoji: string) => void;
|
||||
/** Tapping the reaction trail. */
|
||||
onTrailClick: (message: ChatMessage) => void;
|
||||
}) {
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const atBottomRef = useRef(true);
|
||||
@@ -173,10 +181,25 @@ export function MessageList({
|
||||
starredIds={starredIds}
|
||||
onRetry={onRetry}
|
||||
nameFor={nameFor}
|
||||
onReact={onReact}
|
||||
onTrailClick={onTrailClick}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
|
||||
{typingNames.length > 0 && (
|
||||
<p
|
||||
aria-live="polite"
|
||||
className="px-1 pt-2 text-xs italic text-muted-foreground"
|
||||
>
|
||||
{typingNames.length === 1
|
||||
? `${typingNames[0]} is typing…`
|
||||
: `${typingNames.slice(0, 2).join(", ")}${
|
||||
typingNames.length > 2 ? " and others" : ""
|
||||
} are typing…`}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user