feat(messaging-ui): @mentions — autocomplete, resolve to ids, highlight
- contract: SendOpts.mentions (opaque userId notify-list) + optional listMembers(threadId) for autocomplete/highlight (capability-degrading) - mock: listMembers; KernelClientAdapter.send forwards mentions to the socket (which already carries them → inbox MENTION items) - composer: type @ → member/@channel/@here autocomplete; Enter picks the first; on send, mentions resolve to ids; message bodies highlight @mentions - useMembers hook; mentions.tsx helpers (trailingMentionQuery/insertMention/ resolveMentions/highlightMentions) - 4 mention tests (helpers + render autocomplete→send carries id); 56 total green Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAdapter } from '../provider';
|
||||
import type { Person } from '../types';
|
||||
|
||||
/** A thread's members (for @mention autocomplete + highlighting). Empty if the adapter
|
||||
* doesn't implement listMembers, or while loading. */
|
||||
export function useMembers(threadId: string | null): Person[] {
|
||||
const adapter = useAdapter();
|
||||
const [members, setMembers] = useState<Person[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!threadId || !adapter.listMembers) {
|
||||
setMembers([]);
|
||||
return;
|
||||
}
|
||||
let alive = true;
|
||||
adapter
|
||||
.listMembers(threadId)
|
||||
.then((m) => {
|
||||
if (alive) setMembers(m);
|
||||
})
|
||||
.catch(() => {
|
||||
if (alive) setMembers([]);
|
||||
});
|
||||
return () => {
|
||||
alive = false;
|
||||
};
|
||||
}, [adapter, threadId]);
|
||||
|
||||
return members;
|
||||
}
|
||||
Reference in New Issue
Block a user