{messages.map((msg, index) => {
const prev = messages[index - 1]
const newAuthorBoundary = !prev || prev.role !== msg.role
return (
0 ? 'mt-3' : undefined}
>
{typeof msg.content === 'string' ? (
{msg.content}
) : (
msg.content
)}
)
})}
)
}
/* ──────────────────────────────────────────────────────────────────
* Multi-attachment message wrapper.
*
* Real chat UIs let one logical "message" carry several attachments
* of different kinds — e.g. a voice memo + a PDF, or two photos + an
* audio note. Each attachment renders as its own `MessageAttachment.*`
* bubble, but the whole set should read as a single visual cluster
* from the same author. To do that we:
*
* - Stack the bubbles vertically with `gap-[2px]` (the same gap
* `.str-chat__message-bubble-wrapper` uses between grouped text
* bubbles in `styles.css`).
* - Inject `groupPosition='first' | 'middle' | 'end'` on each child
* so the corners flatten on the edges that face siblings inside
* the cluster — same merging rule the `Bubble` component already
* applies to consecutive text messages.
* - Right-align for sender clusters / left-align for receiver
* clusters so the run anchors to the correct chat edge.
*
* The wrapper is intentionally local to this stories file: the real
* `CustomMessage` integration derives `groupPosition` from
* stream-chat-react's `firstOfGroup` / `endOfGroup` flags via the
* `bubbleGroupPositionFromStream` helper instead. This wrapper just
* gives the story author a clean way to express "one message, many
* attachments" without wiring up the full message-context plumbing.
* ────────────────────────────────────────────────────────────────── */
interface MultiAttachmentMessageProps {
align: 'sender' | 'receiver'
children: React.ReactNode
}
const MultiAttachmentMessage: React.FC