Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
d8d2389
feat(scraps): Add chat primitives (Spinner, ChatMessageBubble, ToolCa…
priscilawebdev Jul 13, 2026
4f63a56
ref(scraps): Build ChatMessageBubble on Container instead of styled div
priscilawebdev Jul 13, 2026
0f1b284
ref(scraps): Group chat stories and drop product names from primitives
priscilawebdev Jul 13, 2026
550454f
ref(scraps): Keep chat Spinner internal to ToolCallStatusIcon
priscilawebdev Jul 14, 2026
622857a
ref(scraps): Rename chat primitives to MessageBubble and ToolCallIndi…
priscilawebdev Jul 14, 2026
12af92d
fix(scraps): Color ToolCallIndicator icons via the icon variant prop
priscilawebdev Jul 14, 2026
18d8c14
ref(scraps): Use Stack instead of Flex direction=column in MessageBub…
priscilawebdev Jul 14, 2026
7362e3b
ref(scraps): Mark chat index exports @public for knip
priscilawebdev Jul 14, 2026
fc4c289
ref: Adopt chat primitives in Seer Explorer and rename to UserBubble
priscilawebdev Jul 14, 2026
b8081e1
ref: Reuse ToolCallStatus in Seer Explorer and inline UserBubble styles
priscilawebdev Jul 14, 2026
9a8e599
ref(scraps): Drop redundant Stack wrapper in UserBubble story
priscilawebdev Jul 15, 2026
4108258
ref(scraps): Reuse chat Spinner primitive in Seer Explorer
priscilawebdev Jul 15, 2026
494e7ea
fix(scraps): Label placeholder spinner and stop size prop DOM leak
priscilawebdev Jul 15, 2026
bb51e41
ref(scraps): Add MessageRow chat primitive and adopt in Seer Explorer
priscilawebdev Jul 15, 2026
67bb703
Merge remote-tracking branch 'origin/master' into seer/chat-scraps-me…
priscilawebdev Jul 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions static/app/components/core/chat/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export {UserBubble} from './userBubble';
export {ToolCallIndicator, type ToolCallStatus} from './toolCallIndicator';
export {Spinner} from './spinner';
export {MessageRow} from './messageRow';
49 changes: 49 additions & 0 deletions static/app/components/core/chat/messageRow.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: MessageRow
description: The full-width row that positions a single message turn in a conversation.
category: chat
source: '@sentry/scraps/chat'
resources:
js: https://github.com/getsentry/sentry/blob/master/static/app/components/core/chat/messageRow.tsx
---

import {MessageRow, UserBubble} from '@sentry/scraps/chat';
import {Container} from '@sentry/scraps/layout';

import * as Storybook from 'sentry/stories';

export const documentation = import('!!type-loader!@sentry/scraps/chat/messageRow');

The `MessageRow` lays out a single message turn within a conversation. It is
presentation only — it owns alignment and the consistent gutter around a turn,
while the bubble or content is the caller's responsibility.

## Alignment

Use `justify="end"` for the sender's own messages and the default `justify="start"`
for the agent's responses, so the two sides sit opposite each other.

<Storybook.Demo>
<Container width="100%" background="secondary" radius="md">
<MessageRow justify="end">
<UserBubble>Which of my issues are getting worse?</UserBubble>
</MessageRow>
<MessageRow>Here are the three escalating issues I found.</MessageRow>
</Container>
</Storybook.Demo>

```jsx
<MessageRow justify="end">
<UserBubble>Which of my issues are getting worse?</UserBubble>
</MessageRow>
<MessageRow>Here are the three escalating issues I found.</MessageRow>
```

## Padding

The row applies a consistent gutter (`md xl`) around each turn. Override
`padding` for surfaces that need a different gutter.

```jsx
<MessageRow padding="xl">…</MessageRow>
```
29 changes: 29 additions & 0 deletions static/app/components/core/chat/messageRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {Flex, type FlexProps} from '@sentry/scraps/layout';

interface MessageRowProps extends Omit<FlexProps, 'justify'> {
children: React.ReactNode;
/**
* Which side of the conversation the message sits on: `end` for the sender's
* own messages, `start` (default) for the agent's responses.
*/
justify?: 'start' | 'end';
}

/**
* The full-width row that positions a single message turn within a conversation.
*
* Presentation only — it owns alignment and the consistent gutter around a turn;
* the bubble or content is the caller's responsibility.
*/
export function MessageRow({
children,
justify = 'start',
padding = 'md xl',
...props
}: MessageRowProps) {
return (
<Flex align="start" justify={justify} width="100%" padding={padding} {...props}>
{children}
</Flex>
);
}
6 changes: 3 additions & 3 deletions static/app/views/seerExplorer/components/chat/shared.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Spinner, type ToolCallStatus} from '@sentry/scraps/chat';
import {MessageRow, Spinner, type ToolCallStatus} from '@sentry/scraps/chat';
import {Flex} from '@sentry/scraps/layout';

import {SeerMarkdown} from 'sentry/components/seer/markdown';
Expand Down Expand Up @@ -66,7 +66,7 @@ export function hasValidContent(content: string | null | undefined): content is

export function MessagePlaceholder({content}: {content?: string}) {
return (
<Flex align="center" gap="md" padding="xl" width="100%">
<MessageRow align="center" gap="md" padding="xl">
<Flex
display="inline-flex"
align="center"
Expand All @@ -78,7 +78,7 @@ export function MessagePlaceholder({content}: {content?: string}) {
<Spinner role="status" aria-label={t('Loading')} />
</Flex>
{hasValidContent(content) && <SeerMarkdown raw={content} />}
</Flex>
</MessageRow>
);
}

Expand Down
7 changes: 3 additions & 4 deletions static/app/views/seerExplorer/components/chat/user.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import {UserBubble} from '@sentry/scraps/chat';
import {Flex} from '@sentry/scraps/layout';
import {MessageRow, UserBubble} from '@sentry/scraps/chat';

import type {UserBlockProps} from './shared';

export function UserBlock({block}: UserBlockProps) {
return (
<Flex align="start" justify="end" width="100%" padding="xl">
<MessageRow justify="end" padding="xl">
<UserBubble>{block.message.content ?? ''}</UserBubble>
</Flex>
</MessageRow>
);
}
Loading