@amauryuh/components

中文文档
0.14.0发布于 2026/10/28MITTypeScriptES Module近 30 天下载 2803

Ready-made React components for whole features, starting with a chat and its list of conversations. Styled with Tailwind CSS v4

原始使用文档
文档目录10 节
  1. Install
  2. Chat
  3. The backend: IChat
  4. Types
  5. Other props
  6. Translations
  7. Parts
  8. Avatar
  9. Chat.List
  10. Styling

@amauryuh/components

Ready-made React components for whole features, built on @amauryuh/ui's layout and styled with Tailwind CSS v4. Starting with a chat and its list of conversations.

Install

npm install @amauryuh/components @amauryuh/ui i18next react-i18next

Peer dependencies: react and react-dom (18+), tailwindcss (v4), @amauryuh/ui (0.6.1+), i18next (23+) and react-i18next (14+).

Tailwind skips node_modules, so import both packages' stylesheets after Tailwind:

@import "tailwindcss";
@import "@amauryuh/ui/styles.css";
@import "@amauryuh/components/styles.css";

Chat

A whole messaging app in the style of Apple Messages: the list of chats in the sidebar, and the open chat beside it. It looks like Messages on the iPhone on small screens, and like Messages on the Mac from md up.

  • List: the user's avatar and name, search by title, folder tabs and a row per chat with its newest message and an unread dot (see Chat.List).
  • Title bar: a back button on mobile (it opens the list), the avatar and title, and a search that narrows the log down.
  • Log: day lines (with the year for older messages), runs of messages per sender with a tail on the last bubble, quoted replies, tapbacks, view counts and "Delivered".
  • Composer: a reply preview above the field. Replying with a single emoji reacts to the message instead.
  • Types: direct chats, groups and channels (see Types).
  • Reply: a reply button beside the bubble on hover or keyboard focus, or on touch screens a swipe to the left. Tapping a quote jumps to the original.
  • Motion: new messages spring in and push the log up. The log stays at the newest message unless the user has scrolled up.

Chat takes one backend with every chat, and keeps which one is open itself: a row of the list opens its chat, so the backend doesn't depend on the app's address or routes. Rendered without children, as below, it is ready to use: the whole Layout of @amauryuh/ui, with the list in its sidebar and the open chat beside it. With children, it only provides the state and you lay out the parts (see Parts).

import { Chat, type IChat } from "@amauryuh/components";

export default function App() {
  const { conversations, post, react, mute, read } = useMyChats(); // your data

  const backend: IChat = {
    user: { name: "Alex Kim", avatar: "/alex.jpg" },
    chats: conversations.map((c) => ({
      id: c.id,
      info: { type: c.type, title: c.title, muted: c.muted },
      messages: c.messages,
      folders: c.labels, // e.g. ["Work"]
      unread: c.unread,
    })),
    post,
    react,
    mute,
    read,
  };

  return <Chat backend={backend} />;
}

The backend: IChat

Plain data and callbacks, the same whichever chat is open. Build it on every render from your state, e.g. from a socket or a store. Every action gets the id of the chat it's for.

Field
userThe person using the app, { name, avatar? }: shown above the list's search. avatar is a picture's URL; without it, their initials.
chatsChatConversation[], below, in the order the list shows them.
post(chatId, { content, replyTo })Sends a message. Without it every chat is read-only: no composer, no reply. Channels are always read-only.
react(chatId, messageId, emoji)Toggles the user's reaction. With it, a reply that is one emoji reacts instead of being sent.
mute(chatId, muted)Turns a chat's notifications off or on. Without it, channels show no mute button.
pin(chatId, pinned)Pins a chat to the top of the list's All tab, or unpins it. With it, the title bar has a pin button left of search.
read(chatId)Called when an unread chat is on screen (beside the list, or on phones once the list is closed), and again as messages arrive while it is. Mark it read, so its dot goes away.
setDraft(chatId, draft)Keeps a chat's unsent reply ({ replyTo?: ChatMessage }), e.g. across visits; give it back as the chat's draft. Without it the drafts are kept in memory.

ChatConversation:

Field
idUnique among the chats.
infoAbout the chat: ChatInfo, below.
messagesChatMessage[], oldest first. The newest is the list's preview.
foldersThe folders it's in, by name, e.g. ["Work"]: the list's tabs.
unreadHas messages the user hasn't seen: a dot in the list.
draftIts unsent reply, kept with setDraft.

ChatInfo:

Field
type"direct", "group" or "channel". See Types.
titleShown in the list and the title bar, with an avatar of its initials.
mutedNotifications are off: a bell in the list, and the mute button offers to turn them on.
pinnedAt the top of the list's All tab, with a pin on its row; the pin button offers to unpin it.

ChatMessage:

Field
id, content, fromfrom is the sender's display name.
ownWritten by the user: on the right, in the accent colour.
timeISO 8601. Drives the day and time lines.
replyToThe quoted message, { id?, from, content }. With id, tapping the quote jumps to the original.
reactionsEmoji shown on the bubble's corner.
viewsA view count under the message, e.g. for posts in a channel.

Types

The parts adapt to info.type:

Type
directTwo people: no names or avatars on messages.
groupNames above each run and avatars next to other people's messages.
channelPosts to read, with names. The footer shows a mute button instead of the composer, and messages can't be replied to.

New kinds of chat are added to the package as a type, so every app gets them.

Other props

  • children: your own layout of the parts. Without it, Chat renders the whole Layout.
  • className: for the ready-made Layout. With children, give it to your own.
  • classNames: see Styling.

Translations

The components use your app's i18next instance through react-i18next. The package never initializes i18next and takes no locale: your app sets i18next up, as usual, with initReactI18next or an I18nextProvider, and the components follow its language. Add the translations under the components namespace (exported as namespace):

import i18n from "i18next";
import { initReactI18next } from "react-i18next";

i18n.use(initReactI18next).init({
  resources: {
    es: {
      translation: { /* your app's strings */ },
      components: {
        chat: {
          search: "Buscar en el chat",
          views_one: "{{count}} vista",
          views_other: "{{count}} vistas",
          // …
        },
      },
    },
  },
  lng: "es",
  fallbackLng: "es",
});

English is the fallback. Every key you leave out is shown in English, even when your fallbackLng is another language, so you can translate only some keys. English needs no resources; to change its wording, add en.components. Its strings are exported as en, e.g. as a template. Without an i18next instance, the components show English.

Dates and numbers are formatted in i18next's current language, so use the codes you want them in, e.g. es-419. Changing the language (i18n.changeLanguage) re-renders the chat, including its dates.

Every key, under components:

KeyEnglishWhere
chat.backBackThe title bar's back button (mobile), which opens the sidebar
chat.searchSearch in chatThe search button and the search field's placeholder
chat.closeSearchClose searchThe button that closes the search
chat.messagesMessagesThe log's accessible name
chat.emptyNo messages yet.The log when it has no messages
chat.noResultsNo messages match your search.The log when the search finds nothing
chat.todayTodayThe day line for today's messages
chat.deliveredDeliveredUnder the user's newest message
chat.views_one, chat.views_other{{count}} view, {{count}} viewsThe accessible name of a message's view count. Plural keys, with i18next's suffixes for the language (e.g. _many).
chat.messageMessageThe composer's placeholder and accessible name
chat.sendSendThe send button
chat.replyReplyThe reply button beside a bubble on hover
chat.replyToReplying to {{name}}The reply preview above the composer
chat.cancelReplyCancel replyThe button that drops the reply
chat.muteMuteThe mute button, while notifications are on
chat.unmuteUnmuteThe mute button, while notifications are off
chat.pinPinThe pin button, while the chat isn't pinned
chat.unpinUnpinThe pin button, while the chat is pinned
chat.scrollToBottomScroll to the last messageThe button that scrolls to the newest message
chatList.searchSearchThe list's search field
chatList.foldersFoldersThe folder tabs' accessible name
chatList.allAllThe first folder tab, with every chat
chatList.chatsChatsThe list's accessible name
chatList.emptyNo chats match.The list when the search or folder finds nothing
chatList.unreadUnreadThe unread dot's accessible name
chatList.mutedMutedThe muted icon's accessible name
chatList.pinnedPinnedThe pin icon's accessible name
chatList.yesterdayYesterdayA row's time for yesterday's messages

To type-check them with your other keys, add the namespace to i18next's CustomTypeOptions.

Parts

Every part is available as Chat.*. The parts take only a className: what they show and do comes from the surrounding Chat. Rendered with children, Chat is only that provider, and the children are the layout. <Chat backend={backend} /> is the same as:

import { Layout } from "@amauryuh/ui";

<Chat backend={backend}>
  <Layout>
    <Layout.Sidebar className="md:w-88">
      <Chat.List />
    </Layout.Sidebar>
    <Chat.Container>
      <Chat.Header />
      <Chat.Messages />
      <Chat.Footer />
      <Chat.ScrollToBottom />
    </Chat.Container>
  </Layout>
</Chat>

Chat.Container without children renders those four parts, so a layout of your own often only changes the shell, e.g. to add a settings button to the list's top bar:

<Chat backend={backend}>
  <Layout className="bg-white">
    <Layout.Sidebar className="md:w-88">
      <Chat.List actions={<SettingsButton />} />
    </Layout.Sidebar>
    <Chat.Container />
  </Layout>
</Chat>
Part
Chat.ListThe list of chats, for a Layout.Sidebar. See Chat.List.
Chat.ContainerThe open chat, a Layout.Container. Its children are the parts below; without children, all of them. Each chat opens fresh: its search closed, at its newest message.
Chat.HeaderTitle bar: back (mobile), the avatar and title, then pin (with pin) and search. Turns into Chat.Search while searching.
Chat.SearchThe search field and its close button.
Chat.MessagesThe log in the container's scrolling body.
Chat.FooterThe bottom bar: Chat.Composer, or in channels Chat.MuteButton. Steps aside while searching.
Chat.ComposerThe field, send button and reply preview. Renders nothing where the user can't post.
Chat.MuteButtonTurns notifications off or on, with mute from the backend. Renders nothing without it.
Chat.ScrollToBottomTakes the user back to the newest message once they scroll up.

Parts of your own can read the state:

  • useChats(), anywhere inside Chat: backend, open (the open chat), setOpen(chatId) to open another one, and draftOf(chatId).
  • useChatContext(), inside Chat.Container: the open chat, canPost, post, react, mute and pin for it, messages (filtered by the search), search, setSearch, draft, setDraft, reply and jumpTo. For example, a footer of your own could hide while search !== null, and a reply button of your own calls reply(message).

Avatar

Avatar shows a picture (src) or else a name's initials in a circle, as the chat's own avatars do. It needs no Chat around it:

import { Avatar } from "@amauryuh/components";

<Avatar className="size-9 text-sm" name={user.name} src={user.photo} />

Chat.List

The backend's chats, for a Layout.Sidebar. It has:

  • A top bar: the backend's user, with their avatar and name, on the left, and on the right your own actions (e.g. a settings button). Without either, there's no top bar.
  • Search by title.
  • Folder tabs: All, then every folder the chats are in, in the order they first appear. They're hidden when no chat has a folder.
  • A row per chat: avatar, title, muted icon, the time of its newest message (the time today, then "Yesterday", the weekday, the day and the date) and a two-line preview. Unread chats get a dot.
  • Pinned chats (info.pinned) come first in All, in the backend's order, with a pin on the right of their row. Folders keep the backend's order.

A row opens its chat, and closes the sidebar on mobile. The open chat is marked with aria-current="page" and turns blue where both panes are in view. The list's slots start with list.

Styling

Each part has a slot with default classes (chatStyles). Classes are merged with tailwind-merge, and later ones win:

  1. the slot's default,
  2. classNames given to Chat, by slot,
  3. the part's own className.

Layout and behaviour classes (flex, positions, truncation, the hidden state) always apply on top, so styles can change everything but the layout.

<Chat
  backend={backend}
  classNames={{
    bubble: "rounded-lg data-own:bg-emerald-600",
    composer: "rounded-lg bg-slate-100 shadow-none",
  }}
/>

<Chat.Composer className="bg-amber-100" />

A part's state is in data attributes, to style with Tailwind variants:

AttributeOn
data-owncolumn, bubble, quote, quoteText, reactions
data-lastbubble (last of a run: a tighter corner and the tail, drawn with ::before)
data-arrivedbubble (just came in; animates)
data-highlightedmessage (after jumping to it)
data-gap="sender" | "reactions"message (space above it)
data-hiddenfooter (while searching)

Slots of Chat.List: listPanel, listHeader, listUser, listUserAvatar, listUserName, listSearch, listSearchInput, listFolders, listFolder (data-selected on the chosen one), list, listRow (aria-current="page" on the open one), listRowText, listRowTitle, listRowMuted, listRowTime, listRowAvatar, listRowChevron, listRowPinned, listRowPreview, listUnread, listEmpty and avatar.

Slots of Chat: root, header, headerBar, headerActions, headerButton, headerAvatar, title, search, searchInput, messages, empty, log, dayLine, message, column, sender, senderAvatar, bubble, quote, quoteAuthor, quoteText, reactions, replyButton, swipeHint, views, delivered, footer, composer, replyPreview, replyPreviewTitle, replyPreviewText, cancelReply, input, sendButton, muteButton, scrollToBottom and avatar.

To restyle every part at once, redefine the theme variables in your own @theme:

@theme {
  --color-chat-accent: #0a72e8; /* own bubbles, buttons */
  --color-chat-bubble: #e9e9eb; /* other people's bubbles */
  --color-chat-label: #000;
  --color-chat-secondary: #6d6d72;
  --color-chat-separator: #d1d1d6;
  --color-chat-fill: #7676801f; /* search fields, folder tabs */
  --color-chat-panel-top: #f6f6f7; /* the list's panel (md+) */
  --color-chat-panel-bottom: #f1f1f3;
  --color-chat-avatar-top: #b5bacd;
  --color-chat-avatar-bottom: #8a8fa6;
  --text-chat-body: 1.0625rem;
  --text-chat-subhead: 0.9375rem;
  --text-chat-footnote: 0.8125rem;
}

The arrival animations are animate-chat-bubble-in and animate-chat-bubble-sent. They only run when the user doesn't ask for reduced motion.

版本与发布记录

@amauryuh/components 共发布 16 个版本,首次发布于 2026/10/27;过去 12 个月发布了 16 个版本。

版本发布日期距今
0.14.0latest2026/10/2810 天前
0.13.12026/10/2711 天前
0.13.02026/10/2711 天前
0.12.02026/10/2711 天前
0.11.02026/10/2711 天前
0.10.02026/10/2711 天前

关于 @amauryuh/components 的常见问题

@amauryuh/components 是什么?

Ready-made React components for whole features, starting with a chat and its list of conversations. Styled with Tailwind CSS v4

如何安装 @amauryuh/components?

在项目目录运行 npm install @amauryuh/components,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18)、i18next(>=23)、react-dom(>=18)、tailwindcss(^4)、@amauryuh/ui(>=0.6.1)、react-i18next(>=14)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@amauryuh/components 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@amauryuh/components 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@amauryuh/components 可以商用吗?

@amauryuh/components 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@amauryuh/components 的下载量有多少?

根据 npm 官方下载统计,@amauryuh/components 在 2026/10/06 – 2026/11/04 这 30 天内被下载 2,803 次,日均约 93 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@amauryuh/components 还在维护吗?

最新版本 0.14.0 发布于 2026/10/28(10 天前);至今共发布 16 个版本,其中过去 12 个月发布了 16 个;首次发布于 2026/10/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。