docs(ui): expand bilingual component guides

This commit is contained in:
Maofeng
2026-09-21 17:27:45 +08:00
parent fb985edb20
commit 4c61e79d0d
22 changed files with 1636 additions and 192 deletions
@@ -0,0 +1,58 @@
---
title: Message thread
description: Compose a scroll container, message layout, and bubbles while preserving the reader's position in history.
order: 32
toc:
- id: structure
title: Component structure
- id: messages
title: Render messages
- id: ownership
title: State ownership
---
## Component structure {#structure}
```tsx
import {
MessageScroller,
MessageScrollerButton,
MessageScrollerContent,
MessageScrollerItem,
MessageScrollerProvider,
MessageScrollerViewport,
} from "@workspace/ui/components/message-scroller"
export function Thread({ messages }: { messages: ChatMessage[] }) {
return (
<MessageScrollerProvider>
<MessageScroller className="h-[32rem]">
<MessageScrollerViewport>
<MessageScrollerContent className="gap-5 p-4">
{messages.map((message, index) => (
<MessageScrollerItem
key={message.id}
messageId={message.id}
scrollAnchor={index === messages.length - 1}
>
<ChatMessageRow message={message} />
</MessageScrollerItem>
))}
</MessageScrollerContent>
</MessageScrollerViewport>
<MessageScrollerButton />
</MessageScroller>
</MessageScrollerProvider>
)
}
```
## Render messages {#messages}
Inside `ChatMessageRow`, use `Message`, `MessageAvatar`, `MessageContent`, `MessageHeader`, and `MessageFooter` for participant structure, then compose one or more `Bubble` elements inside the content. Sent messages can use `align="end"`; do not swap message ownership based on the language direction.
Place attachments in the same `MessageContent`. For content without a bubble background, use `Bubble variant="ghost"`; the header and footer automatically remove the horizontal padding associated with a bubble.
## State ownership {#ownership}
`MessageScroller` owns bottom-follow behavior, visibility, and the jump button. The application owns the message array, pagination, loading, read state, and retries. Keep stable IDs when prepending older messages and use the scroller API to preserve the visual anchor instead of copying another set of scroll listeners into the feature.