october-statement.csv18.4 kB
Which orders are pending this week?

AI · ChatMessage
A message in a chat with an assistant: the bubble, who says it, its footer and the usual actions -copy, regenerate, edit-.
Conversation.Alert.Keyboard: the actions are buttons and appear on hover or when focus is inside; on a touch screen they are always in view. Only the ones asked for exist (copyText, onRegenerate, onEdit), plus yours in actions (cancel, retry, save as template): they are grouped with the rest and appear the same way. actionsVisibility="always" keeps them always in view.
Editing in place: with editor the content is replaced by an editor (a TextArea with save and cancel) inside the same bubble, which becomes neutral and takes the full width; the actions hide while it lasts. Match of a search: highlighted marks the message with a fixed ring -not an animation, which would be lost with reduced motion- and announces it; whoever searches brings it into view and turns it off after a few seconds.
Accessibility: each message is an article named after who says it, "You" or "Assistant" (or the author that is passed); the avatar is decorative. While it is being written it is marked busy and says "Writing". The error is marked with data-tone and a border, not just with colour. Copying is announced with a status region.
Fine-tuning: CSS variables --amset-chat-message-max (maximum width of the bubble), -gap, -bubble, -ink and -border. Markdown is not interpreted here: whoever uses the component renders it.
<ChatMessage from="user" copyText={pregunta}>
<Attachment name="october-statement.csv" size={18_400} status="done" compact />
<p>{pregunta}</p>
</ChatMessage>
<ChatMessage
from="assistant"
avatar={<Avatar name="AMSET" size="sm" />}
streaming={escribiendo}
copyText={respuesta}
onRegenerate={regenerar}
meta={<UsageBadge tokens={1234} cost={0.03} />}
>
<Reasoning durationMs={4200}>First I look at this week's orders…</Reasoning>
<ToolCall name="listar_pedidos" status="success" input={consulta} output="3 orders" durationMs={850} />
<p>{respuesta}</p>
</ChatMessage>
<Suggestions groups={sugerencias} onSelect={(respuestas) => enviar(respuestas[0].option)} />
<PromptInput label="Message to the assistant" busy={ocupado} onStop={parar} onSubmit={enviar} onFiles={adjuntar} />Import it with import { ChatMessage } from '@amset/ui'. Required props are marked.
| Prop | Type | What it does |
|---|---|---|
childrenrequired | ReactNode | The content. Markdown is not interpreted here: whatever arrives is painted. |
fromrequired | ChatMessageFrom | Who writes it. It decides the side, the colour and the name a reader hears. |
actions | ReactNode | More actions, after the usual ones: cancel, retry, save as template, automate. They are yours: an `IconButton` with its `aria-label`. They are grouped with copy, regenerate and edit and appear the same way. |
actionsVisibility | ChatMessageActionsVisibility | When the actions are visible. By default on hover or when focus is inside; with a finger, always. |
author | string | What the writer is called. Defaults to "You" or "Assistant". |
avatar | ReactNode | Their photo or orb. It is decorative: the author is said with text. |
className | string | Merged with the library classes; it does not replace them. |
copyText | string | The text that gets copied. With this the copy button appears. |
editor | ReactNode | The message is being edited: the editor goes here (a `TextArea` with save and cancel) INSTEAD of the content, inside the same bubble, without moving the message. The actions hide while it lasts. |
highlighted | boolean | It is the match of a search: it is marked for a moment and announced. Whoever searches brings the message into view (`scrollIntoView` or `scrollTop`) and sets this to `true` for a few seconds. |
meta | ReactNode | Below: the time, the tokens, the engine. |
onEdit | () => void | With this "Edit message" appears. |
onRegenerate | () => void | With this "Regenerate response" appears. |
streaming | boolean | Still being written: it carries a cursor at the end and is marked busy. |
tone | ChatMessageTone | — |
It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.
Every state and variant, to try one at a time, on its page at ui.amset.tech: