MessageReference

Inline message references for people, conversations, tasks, message permalinks, attachment comments, and resolution states.

Preview#

AT
Atlasowner2:20 PM

Ask or to review the linked message in #raft-ui-migration before posting the rollout in release-notes.

AT
Atlas2:21 PM

Please triage #21@Ada and continue #22@Atlas with before posting the migration summary in the joint channel northstar-launch-handoff and continuing the rollout in the state-model thread or sending Noah Bennett a DM.

AT
Atlas2:21 PM
The atom model is a better fit only if we keep server state out of the local store.

Review rui#125 Compose message surfaces before posting the final migration note.

AT
Atlas2:22 PM

I'm still resolving migration-notes. The earlier legacy-brief reference was removed, so leave the original token in the draft until a replacement is confirmed.

Every inline kind in one message. Chips are the body text's size and sit on its baseline, and their letters stay centred in the coloured box; inline code is 0.875em, has no border in messages, and breaks inside tokens too long for the line. Shown at a desktop width and at a 358px phone width.

@Developer this is one long paragraph that mixes everything: ping @Noah Bennett, then #206 and the channel #general, the joint channel northstar-launch-handoff, the thread state-model and a message reference #general. Inline code comes short x, ok, pnpm test, medium useMentionChip(message), and one that cannot fit on a line: sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a089f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08. Then chips and code alternate: @Developer 1 #206 2 #general 3 state-model 4 @Noah Bennett, and the sentence keeps going so the wrapped lines show whether bold @Developer, italic #general and code all sit on the same baseline as plain words.

Quoted: @Noah Bennett asked about #206 in #general.

中文混排:@Developer 请看一下 #206,相关讨论在 #general 和 state-model,代码里是 useMentionChip(),原始消息见 #general。@Noah Bennett 也请留意。

@Developer this is one long paragraph that mixes everything: ping @Noah Bennett, then #206 and the channel #general, the joint channel northstar-launch-handoff, the thread state-model and a message reference #general. Inline code comes short x, ok, pnpm test, medium useMentionChip(message), and one that cannot fit on a line: sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a089f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08. Then chips and code alternate: @Developer 1 #206 2 #general 3 state-model 4 @Noah Bennett, and the sentence keeps going so the wrapped lines show whether bold @Developer, italic #general and code all sit on the same baseline as plain words.

Quoted: @Noah Bennett asked about #206 in #general.

中文混排:@Developer 请看一下 #206,相关讨论在 #general 和 state-model,代码里是 useMentionChip(),原始消息见 #general。@Noah Bennett 也请留意。

import {
  MessageReferenceChip,
  MessageReferenceIndicator,
  MessageReferenceLabel,
  MessageReferencePending,
  MessageReferenceText,
  MessageReferenceUnavailable,
} from "raft-ui";

<>
  <MessageReferenceText>
    <MessageReferenceIndicator />
  </MessageReferenceText>

  <MessageReferenceChip>
    {/* Caller-owned icon */}
    <MessageReferenceLabel />
  </MessageReferenceChip>

  <MessageReferencePending />
  <MessageReferenceUnavailable />
</>

Resolve a recognized @name to an agent or member, then let the consumer own profile navigation and preview content. Use the primary variant only for the viewing member's self-mention; other resolved mentions use secondary. Unknown names remain plain text instead of becoming dead controls.

Ask to review the handoff with .

Source shows read state only on an @agent mention, only to the human who sent that message, and only when read receipts are enabled. Compose a caller-owned Status inside MessageReferenceIndicator for read and unread; omit it for human mentions, optimistic messages, unhydrated data, and every other unknown state.

Ask @Atlas or @Sage, then loop in @Noah.

Use #channel for public, private, and joint channels, and dm:@member for a direct message. These top-level destinations use the accent surface. The resolved destination type chooses the caller-owned icon; unrecognized destinations remain verbatim text.

interview-debrief#private-channel

Use #channel:shortId for a channel thread and dm:@member:shortId for a DM thread. Threads use the info surface and retain the short ID because navigation needs it to resolve the parent message. A missing or unrecognized parent leaves the original token as plain text.

#state-model:29a90e07#channel:shortId
dm:@noah-bennett:feedfacedm:@member:shortId

Source always recognizes the explicit task #205 form. A bare #205 becomes interactive only when that task exists in the current channel; unknown numbers stay plain text. Render resolved tasks with TaskChip, not MessageReferenceChip, so task status remains owned by its dedicated component.

Review task #205 before posting the update. The known shorthand #206 resolves in the same channel; #999 remains plain text when no matching task exists.

When a message replies to an attachment comment, place the reference before the message body and preserve the source filename plus optional anchor label. Render it as a link only when the host message can be opened; otherwise keep the same chip as static text. An available anchor quote follows as a blockquote rather than being packed into the chip.

The atom model is a better fit only if we keep server state out of the local store.

A recognized Slock message URL becomes a permalink chip labelled with its channel or DM destination. Same-server links open in product; cross-server links open externally. The full URL belongs in the link title. Ordinary web URLs are not message references; render them with MarkdownLink instead of this chip surface.

Keep a clicked thread token visible while its parent resolves, add a spinner, and expose the busy state to assistive technology. If resolution fails, source keeps the token and lets the message layer announce a temporary unavailable/deleted notice; it does not convert the reference into a permanent unavailable chip. Unknown channels, DMs, tasks, and bare tokens remain verbatim plain text rather than disabled links.

Opening #state-model:29a90e07 may take a moment. If the thread cannot be opened, keep #state-model:29a90e07 in the message; #missing-channel also remains plain text.

API#WIP

variant
"primary" | "secondary"
Surface tone for the mention. Use primary for the viewer's self-mention.
...props
useRender.ComponentProps<"span">
Inline mention surface. Use primary for the viewer's self-mention; secondary is the default for everyone else. The caller owns entity resolution, navigation, and preview behavior.
variant
"accent" | "muted" | "info" | "link"
Visual tone for the chip. Visual only; navigation stays consumer-owned.
...props
useRender.ComponentProps<"span">
Inline chip reference. Variant is visual only; use render={<a href=… />} when the consumer owns navigation.
...props
useRender.ComponentProps<"span">
Explicit resolving surface. Loading indicators and resolution copy remain consumer-owned.
...props
useRender.ComponentProps<"span">
Opt-in unavailable surface for consumers that know a target cannot open. Source keeps unresolved tokens as plain text instead of selecting this state automatically.
...props
useRender.ComponentProps<"span">
Optional primary-label part that truncates safely inside a structured chip.
...props
useRender.ComponentProps<"span">
Optional child part that positions caller-owned status content on an inline reference. The consumer decides whether to render it.