Message Scroller
MessageScroller là vùng cuộn hội thoại biết bám đáy khi có tin mới, báo “N tin nhắn mới” khi bạn đang đọc tin cũ và giữ nguyên vị trí khi tải thêm lịch sử.
Import
Cài từ npm, chép mã nguồn vào dự án bằng @yugen-ui/cli hoặc shadcn CLI, hoặc import thẳng khi làm việc trong repo này.
// npm install yugen-uiimport { MessageScroller, MessageBubble, MessageReaction, MessageDaySeparator, TypingIndicator, ChatComposer,} from "yugen-ui";Biến thể
Mỗi ô là một mẫu độc lập: hover để Copy, hoặc bấm Code để xem mã nguồn.
Trạng thái gửi & thử lại
sending → sent → delivered → read; lỗi hiện thông báo + nút Thử lại.
Nhóm tin & cảm xúc
Tin liên tiếp cùng người gửi tự gộp: chỉ tin đầu có avatar, tên, giờ.
Tải tin cũ
Cuộn lên đầu để gọi onLoadOlder; vị trí đọc được giữ nguyên khi tin cũ chèn vào.
Tin mới khi đang đọc tin cũ
Cuộn lên rồi bấm “Nhận tin mới”: danh sách không tự nhảy, nút nổi đếm số tin mới.
Cách dùng
- Đặt key ổn định (id tin nhắn) cho mỗi phần tử để phát hiện tin mới / tin cũ chính xác.
- Luôn kéo xuống đáy khi chính người dùng gửi tin (component tự làm với side="outgoing").
- Cho tin lỗi một đường thử lại rõ ràng ngay tại tin đó.
- Không tự cuộn xuống khi người dùng đang đọc tin cũ — để nút “tin nhắn mới” làm việc đó.
- Không đặt aria-live trên cả danh sách khi stream chữ — trình đọc màn hình sẽ đọc từng mẩu.
- Không render HTML/markdown chưa làm sạch trong bong bóng — MessageBubble hiển thị văn bản thuần.
Props
| Prop · Kiểu | Mặc định | Mô tả |
|---|---|---|
| MessageScroller | Mặc định: — | Gọi khi cuộn chạm đầu; Promise chặn gọi lặp. |
| MessageScroller | Mặc định: — | Còn tin cũ không; hiện spinner ở đầu danh sách. |
| MessageScroller | Mặc định: "Conversation" | Tên truy cập của vùng log. |
| MessageScroller | Mặc định: 48 | Khoảng (px) tới đáy vẫn coi là “đang ở cuối”. |
| MessageScroller | Mặc định: true | Đọc tin đến qua live region polite. |
| MessageBubble | Mặc định: "incoming" | Tin của người khác / của mình. |
| MessageBubble | Mặc định: — | Người gửi; avatar mặc định là Avatar theo tên (tin đến). |
| MessageBubble | Mặc định: — | Giờ hiển thị và giá trị ISO cho <time>. |
| MessageBubble | Mặc định: — | Trạng thái gửi; error hiện nút Thử lại. |
| MessageBubble | Mặc định: — | Ghi đè vị trí trong nhóm (mặc định tự tính). |
| MessageBubble | Mặc định: — | Slot cảm xúc (MessageReaction). |
| MessageBubble | Mặc định: — | Đang stream: con trỏ nhấp nháy, aria-busy, chưa đọc qua live region. |
| MessageBubble | Mặc định: "bubble" | plain: không nền, rộng hết — cho câu trả lời dài của AI. |
| MessageReaction{ emoji, count?, selected?, label? } | Mặc định: — | Nút cảm xúc (aria-pressed). |
| TypingIndicator{ author?, avatar?, label? } | Mặc định: — | Ba chấm (tĩnh khi giảm chuyển động), role=status. |
Messages
Chữ có sẵn của component: nhãn, aria-label, thông báo cho trình đọc màn hình.
Mặc định là tiếng Anh. Đổi qua prop messages của YugenProvider, theo namespace bên dưới; messagesVi chứa bản tiếng Việt. Xem Ngôn ngữ giao diện.
messages.messageScroller
| Khoá · Kiểu | Mặc định (tiếng Anh) | messagesVi |
|---|---|---|
| labelstring Nhãn vùng hội thoại (khi không truyền | Mặc định (tiếng Anh)"Conversation" | messagesVi"Cuộc trò chuyện" |
| loadingOlderstring Spinner khi đang tải tin cũ. | Mặc định (tiếng Anh)"Loading earlier messages…" | messagesVi"Đang tải tin nhắn cũ…" |
| jumpToLateststring Tên nút cuộn xuống đáy khi không có tin mới. | Mặc định (tiếng Anh)"Jump to latest message" | messagesVi"Tới tin nhắn mới nhất" |
| newMessages(count: number) => string Chữ trên nút cuộn xuống đáy khi có tin mới. | Mặc định (tiếng Anh)(count) => (count === 1 ? "1 new message" : `${count} new messages`) | messagesVi(count) => `${count} tin nhắn mới` |
messages.messageBubble
| Khoá · Kiểu | Mặc định (tiếng Anh) | messagesVi |
|---|---|---|
| sendingstring Nhãn trạng thái gửi — cùng tên với | Mặc định (tiếng Anh)"Sending" | messagesVi"Đang gửi" |
| sentstring | Mặc định (tiếng Anh)"Sent" | messagesVi"Đã gửi" |
| deliveredstring | Mặc định (tiếng Anh)"Delivered" | messagesVi"Đã nhận" |
| readstring | Mặc định (tiếng Anh)"Seen" | messagesVi"Đã xem" |
| errorstring Lỗi gửi (khi không truyền | Mặc định (tiếng Anh)"Couldn't send." | messagesVi"Không gửi được." |
| retrystring | Mặc định (tiếng Anh)"Retry" | messagesVi"Thử lại" |
messages.typingIndicator
| Khoá · Kiểu | Mặc định (tiếng Anh) | messagesVi |
|---|---|---|
| label(author?: string) => string Câu đọc cho trình đọc màn hình (khi không truyền | Mặc định (tiếng Anh)(author) => `${author ?? "Someone"} is typing…` | messagesVi(author) => `${author ?? "Đối phương"} đang soạn tin…` |