@streamoid/ui 0.6.17 → 0.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -18
- package/dist/docs/AGENTS.md +325 -0
- package/dist/docs/CreditWarningBanner.md +305 -0
- package/dist/docs/InvoiceHistoryMobile.md +222 -0
- package/dist/docs/ScAccess.md +259 -0
- package/dist/docs/ScAppCard.md +244 -0
- package/dist/docs/ScAppCardForCopilot.md +230 -0
- package/dist/docs/ScAppCardV3.md +273 -0
- package/dist/docs/ScAppField.md +308 -0
- package/dist/docs/ScAppListingCard.md +271 -0
- package/dist/docs/ScAppSwitchPanel.md +286 -0
- package/dist/docs/ScAppcardLogos.md +226 -0
- package/dist/docs/ScArtifaxInvite.md +262 -0
- package/dist/docs/ScArtifaxSidebar.md +330 -0
- package/dist/docs/ScAskAgentButton.md +307 -0
- package/dist/docs/ScBadges.md +261 -0
- package/dist/docs/ScBeacon.md +244 -0
- package/dist/docs/ScBillingHistoryHeader.md +210 -0
- package/dist/docs/ScBillingHistoryTableList.md +243 -0
- package/dist/docs/ScBillingLogsTableHeader.md +212 -0
- package/dist/docs/ScBillingLogsTableList.md +251 -0
- package/dist/docs/ScBriefCard.md +255 -0
- package/dist/docs/ScButton.md +251 -0
- package/dist/docs/ScCalendar.md +268 -0
- package/dist/docs/ScCalendarDateComps.md +264 -0
- package/dist/docs/ScCatalogixInvite.md +345 -0
- package/dist/docs/ScCatalogixSidebar.md +337 -0
- package/dist/docs/ScCatalogixStoreHeader.md +246 -0
- package/dist/docs/ScCatalogixStoreTableList.md +316 -0
- package/dist/docs/ScCheckField.md +233 -0
- package/dist/docs/ScCheckbox.md +272 -0
- package/dist/docs/ScCounter.md +235 -0
- package/dist/docs/ScCreditsUsageCard.md +247 -0
- package/dist/docs/ScCreditsUsageCardMobile.md +224 -0
- package/dist/docs/ScDefaultCard.md +269 -0
- package/dist/docs/ScDp.md +245 -0
- package/dist/docs/ScDrawer.md +318 -0
- package/dist/docs/ScFieldButton.md +255 -0
- package/dist/docs/ScFileField.md +268 -0
- package/dist/docs/ScGoogleSignIn.md +250 -0
- package/dist/docs/ScGuide.md +278 -0
- package/dist/docs/ScHDivider.md +210 -0
- package/dist/docs/ScHeader.md +222 -0
- package/dist/docs/ScImageField.md +253 -0
- package/dist/docs/ScInChatList.md +277 -0
- package/dist/docs/ScInChatMessage.md +205 -0
- package/dist/docs/ScInfoPopup.md +248 -0
- package/dist/docs/ScIntialProfileCover.md +233 -0
- package/dist/docs/ScInvoiceHistoryMobile.md +187 -0
- package/dist/docs/ScLogoUnit.md +232 -0
- package/dist/docs/ScMappingCard.md +241 -0
- package/dist/docs/ScMediaApproval.md +301 -0
- package/dist/docs/ScMediaSelect.md +310 -0
- package/dist/docs/ScMenuOptions.md +308 -0
- package/dist/docs/ScMobileBottomAction.md +252 -0
- package/dist/docs/ScMobileTopNav.md +279 -0
- package/dist/docs/ScModal.md +291 -0
- package/dist/docs/ScOnlyField.md +302 -0
- package/dist/docs/ScOnlyIcon.md +213 -0
- package/dist/docs/ScPagination.md +284 -0
- package/dist/docs/ScPairtext.md +287 -0
- package/dist/docs/ScPendingAction.md +238 -0
- package/dist/docs/ScPhtogenixInvite.md +275 -0
- package/dist/docs/ScPlanCard.md +302 -0
- package/dist/docs/ScPlanComparison.md +264 -0
- package/dist/docs/ScPlanDetailsCard.md +246 -0
- package/dist/docs/ScPlanDetailsCardMobile.md +240 -0
- package/dist/docs/ScPopUpMenu.md +224 -0
- package/dist/docs/ScProfile.md +234 -0
- package/dist/docs/ScProfileImageUpdate.md +261 -0
- package/dist/docs/ScProfileOptions.md +245 -0
- package/dist/docs/ScProfilePopup.md +396 -0
- package/dist/docs/ScProfileSettingsComp.md +250 -0
- package/dist/docs/ScProfileV2Mobile.md +216 -0
- package/dist/docs/ScProgressBar.md +267 -0
- package/dist/docs/ScQuickPrompt.md +277 -0
- package/dist/docs/ScRadio.md +228 -0
- package/dist/docs/ScReferralCardMobile.md +226 -0
- package/dist/docs/ScReferralTableHeader.md +260 -0
- package/dist/docs/ScReferralTableList.md +293 -0
- package/dist/docs/ScRole.md +226 -0
- package/dist/docs/ScRoleMobile.md +199 -0
- package/dist/docs/ScSelect.md +270 -0
- package/dist/docs/ScSelection.md +256 -0
- package/dist/docs/ScSelectionList.md +272 -0
- package/dist/docs/ScSelectionPill.md +240 -0
- package/dist/docs/ScSelectionPillGroup.md +302 -0
- package/dist/docs/ScSettingsNav.md +212 -0
- package/dist/docs/ScSettingsTabComp.md +260 -0
- package/dist/docs/ScSideBarLogoUnit.md +340 -0
- package/dist/docs/ScSidebar.md +243 -0
- package/dist/docs/ScSidebarIcons.md +232 -0
- package/dist/docs/ScSidebarMenu.md +283 -0
- package/dist/docs/ScSidebarProfile.md +231 -0
- package/dist/docs/ScSidebarSwitchMenu.md +258 -0
- package/dist/docs/ScSlider.md +194 -0
- package/dist/docs/ScStoreCard.md +252 -0
- package/dist/docs/ScStrLogo.md +253 -0
- package/dist/docs/ScStreamoidWordmark.md +302 -0
- package/dist/docs/ScSubAgent.md +226 -0
- package/dist/docs/ScTabComp.md +308 -0
- package/dist/docs/ScTabField.md +258 -0
- package/dist/docs/ScTabSwitcher.md +307 -0
- package/dist/docs/ScTableHeader.md +261 -0
- package/dist/docs/ScTableList.md +301 -0
- package/dist/docs/ScTableListMobile.md +282 -0
- package/dist/docs/ScTabs.md +268 -0
- package/dist/docs/ScTaxonomyPill.md +263 -0
- package/dist/docs/ScTextArea.md +259 -0
- package/dist/docs/ScTextField.md +324 -0
- package/dist/docs/ScThinkingStepIcon.md +249 -0
- package/dist/docs/ScTodoList.md +288 -0
- package/dist/docs/ScToggleSwitch.md +229 -0
- package/dist/docs/ScUsageHistoryMobile.md +194 -0
- package/dist/docs/ScVDivider.md +215 -0
- package/dist/docs/ScValueMappingL1.md +256 -0
- package/dist/docs/ScVersion.md +251 -0
- package/dist/docs/ScWorkspace.md +233 -0
- package/dist/docs/ScWorkspaceAccountMenu.md +115 -0
- package/dist/docs/ScWorkspaceCard.md +234 -0
- package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
- package/dist/docs/ScWorkspaceSwitchCard.md +312 -0
- package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
- package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
- package/dist/docs/StreamoidSidebar.md +413 -0
- package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
- package/dist/docs/UsageHistoryMobile.md +235 -0
- package/dist/docs/components.json +4931 -0
- package/dist/index.css +361 -36
- package/dist/index.d.mts +213 -88
- package/dist/index.d.ts +213 -88
- package/dist/index.js +2486 -1629
- package/dist/index.mjs +2487 -1620
- package/package.json +5 -3
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScInChatList
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: chat-agent
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [chat, agent, thinking, reasoning, step, tool, transcript, progress, inchat]
|
|
8
|
+
related: [ScThinkingStepIcon, ScSubAgent, ScInChatMessage, ScTodoList]
|
|
9
|
+
do_not_confuse_with: [ScSubAgent, ScInChatMessage, ScTableList, ScMenuOptions]
|
|
10
|
+
used_by: [agent]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# ScInChatList
|
|
14
|
+
|
|
15
|
+
**One reasoning step in the agent transcript — not a list.** A leading status glyph,
|
|
16
|
+
a single-line truncating title, an optional expandable description, and an optional
|
|
17
|
+
"Using <tool>…" pill. You render one per step and stack them yourself.
|
|
18
|
+
|
|
19
|
+
## TL;DR for agents
|
|
20
|
+
|
|
21
|
+
- **Reach for it when:** you are rendering the agent's thinking/tool steps in a chat
|
|
22
|
+
transcript, one row per step, each with a pending/working/done/error status.
|
|
23
|
+
- **Don't reach for it when:** you want a user or assistant message bubble
|
|
24
|
+
(→ `ScInChatMessage`), a standalone "Using X…" delegation pill
|
|
25
|
+
(→ `ScSubAgent`), the agent's task checklist (→ `ScTodoList`), or just the status
|
|
26
|
+
glyph on its own (→ `ScThinkingStepIcon`).
|
|
27
|
+
- **Four things that will bite you:**
|
|
28
|
+
1. Despite the name it renders **one row**. There is no `items` prop.
|
|
29
|
+
2. `showTool` defaults to **`true`** and `toolUsing` defaults to
|
|
30
|
+
**`"Using Catalogix..."`** — a bare `<ScInChatList />` ships Catalogix copy.
|
|
31
|
+
3. `title` defaults to a **marketing sentence**
|
|
32
|
+
(`"Infrastructure that helps modern brands scale"`).
|
|
33
|
+
4. It does **not** extend `HTMLAttributes`. Only `className` and `style` get
|
|
34
|
+
through — no `id`, no `onClick`, no `data-*`, no `aria-*`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 1. How to use it
|
|
39
|
+
|
|
40
|
+
### Import
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { ScInChatList } from "@streamoid/ui";
|
|
44
|
+
import type { IcListIconState, DescriptionVisibility } from "@streamoid/ui";
|
|
45
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Minimal usage
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<ScInChatList title="Reading the product feed" iconState="working" showTool={false} />
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Props
|
|
55
|
+
|
|
56
|
+
| Prop | Type | Default | Notes |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| `title` | `string` | `"Infrastructure that helps modern brands scale"` | ⚠️ Real, very wrong default. Single line only — `nowrap` + ellipsis at 560px. |
|
|
59
|
+
| `description` | `string` | `"Description"` | ⚠️ Real default. Only rendered when `descriptionVisibility === "visible"`. |
|
|
60
|
+
| `descriptionVisibility` | `"no"` \| `"hidden"` \| `"visible"` | `"no"` | `"no"` = no chevron, no description. `"hidden"` = chevron, collapsed. `"visible"` = chevron, expanded. |
|
|
61
|
+
| `leadingIndicator` | `boolean` | `true` | Renders a `ScThinkingStepIcon` in a fixed 20×26 gutter. `false` removes the gutter entirely (rows lose their left alignment). |
|
|
62
|
+
| `iconState` | `IcListIconState` = `"default"` \| `"working"` \| `"completed"` \| `"error"` | `"default"` | Forwarded straight to `ScThinkingStepIcon`. `"working"` spins. |
|
|
63
|
+
| `showSteps` | `boolean` | `false` | Shows the `stepCount` line above the title. |
|
|
64
|
+
| `stepCount` | `string` | `"Step 01:"` | ⚠️ Real default, hardcoded English. You format the number yourself. |
|
|
65
|
+
| `showTool` | `boolean` | `true` | ⚠️ Defaults **on**. Shows the tool pill under the title. |
|
|
66
|
+
| `toolUsing` | `string` | `"Using Catalogix..."` | ⚠️ Real default. Passing `undefined` falls back to it — gate with `showTool`, don't pass `undefined`. |
|
|
67
|
+
| `onToggle` | `() => void` | – | Fires on a click anywhere in the title row. Only wired when `descriptionVisibility` is `"hidden"` or `"visible"`. |
|
|
68
|
+
| `className` | `string` | – | Appended after the internal class. |
|
|
69
|
+
| `style` | `React.CSSProperties` | – | Applied to the root. |
|
|
70
|
+
|
|
71
|
+
### What renders in each `descriptionVisibility`
|
|
72
|
+
|
|
73
|
+
| Region | `"no"` | `"hidden"` | `"visible"` |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| Chevron | — | ▾ `SiconDown` | ▴ `SiconUp` |
|
|
76
|
+
| Title row click | inert (`cursor: default`) | calls `onToggle` | calls `onToggle` |
|
|
77
|
+
| `description` | not rendered | not rendered | rendered with a dot bullet |
|
|
78
|
+
|
|
79
|
+
### Recipes
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
// The canonical transcript: you own the array, the component owns one row
|
|
83
|
+
{steps.map((step, i) => (
|
|
84
|
+
<ScInChatList
|
|
85
|
+
key={step.id ?? i}
|
|
86
|
+
title={step.message}
|
|
87
|
+
iconState={step.status} // "default" | "working" | "completed" | "error"
|
|
88
|
+
showSteps={false}
|
|
89
|
+
descriptionVisibility={step.description ? "visible" : "no"}
|
|
90
|
+
description={step.description}
|
|
91
|
+
showTool={!!step.toolName} // gate the pill…
|
|
92
|
+
toolUsing={`Using ${step.toolName}...`} // …and format it yourself
|
|
93
|
+
leadingIndicator
|
|
94
|
+
/>
|
|
95
|
+
))}
|
|
96
|
+
|
|
97
|
+
// A collapsible step the user can expand
|
|
98
|
+
const [open, setOpen] = useState(false);
|
|
99
|
+
<ScInChatList
|
|
100
|
+
title="Resolved 412 SKUs against the taxonomy"
|
|
101
|
+
description={longExplanation}
|
|
102
|
+
descriptionVisibility={open ? "visible" : "hidden"}
|
|
103
|
+
onToggle={() => setOpen((v) => !v)}
|
|
104
|
+
iconState="completed"
|
|
105
|
+
showTool={false}
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
// Numbered steps
|
|
109
|
+
<ScInChatList showSteps stepCount={`Step ${String(i + 1).padStart(2, "0")}:`} title={s.message} showTool={false} />
|
|
110
|
+
|
|
111
|
+
// The trailing "still working" row while the last step is done
|
|
112
|
+
<ScInChatList title="Planning next steps" iconState="working" descriptionVisibility="no" showTool={false} />
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 2. Where to use it
|
|
118
|
+
|
|
119
|
+
- **The agent chat transcript**, in the reasoning/steps block that sits above the
|
|
120
|
+
assistant's answer. In the live runtime this is
|
|
121
|
+
`stream-agent frontend/src/components/chat/AgentSteps.tsx`, which maps the step
|
|
122
|
+
stream onto one `ScInChatList` per step and interleaves `ScSubAgent` pills and
|
|
123
|
+
plan cards.
|
|
124
|
+
- Anywhere else you have a **stream of short status lines with per-line state** —
|
|
125
|
+
a long-running import, a deploy log — as long as one line per row is what you want.
|
|
126
|
+
|
|
127
|
+
It composes `ScThinkingStepIcon` internally (leading indicator) and nothing else.
|
|
128
|
+
Its tool pill is visually identical to `ScSubAgent`.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 3. When to use it
|
|
133
|
+
|
|
134
|
+
### Use it when
|
|
135
|
+
|
|
136
|
+
- Each row has **its own lifecycle** (pending → working → completed | error) and you
|
|
137
|
+
want the spinner/tick/cross to be tokenised and consistent.
|
|
138
|
+
- The row's detail is **secondary** and should be collapsible behind a chevron.
|
|
139
|
+
- The row optionally names a **tool** the agent invoked.
|
|
140
|
+
|
|
141
|
+
### Don't use it — reach for this instead
|
|
142
|
+
|
|
143
|
+
| Situation | Use instead |
|
|
144
|
+
|---|---|
|
|
145
|
+
| A user or assistant chat bubble | `ScInChatMessage` |
|
|
146
|
+
| A standalone "Using <sub-agent>…" pill with no step row around it | `ScSubAgent` |
|
|
147
|
+
| The agent's editable task checklist (toggle/add/delete) | `ScTodoList` |
|
|
148
|
+
| Just the status glyph, e.g. in your own layout | `ScThinkingStepIcon` |
|
|
149
|
+
| A dashboard data row | `ScTableList` |
|
|
150
|
+
| A dropdown menu of options | `ScMenuOptions` inside `ScPopUpMenu` |
|
|
151
|
+
| A multi-line, wrapping paragraph of agent prose | `ScInChatMessage` — this title is `nowrap` and truncates |
|
|
152
|
+
|
|
153
|
+
### Don't confuse with
|
|
154
|
+
|
|
155
|
+
| You may actually want | Not this |
|
|
156
|
+
|---|---|
|
|
157
|
+
| `ScSubAgent` — the bare "Using X…" pill; a step that *is* a delegation | `ScInChatList` is the step row that can *contain* such a pill |
|
|
158
|
+
| `ScTodoList` — a checklist the **user** mutates | This is a read-only step log |
|
|
159
|
+
| A component that takes a list | It takes **one** step; "List" in the name means "list row" |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 4. Why to use it
|
|
164
|
+
|
|
165
|
+
- **The status vocabulary is already tokenised.** Pending grey, working white spinner,
|
|
166
|
+
success green, error red all come from `--alias-*` tokens via
|
|
167
|
+
`ScThinkingStepIcon`, so a transcript reads identically in dark and light mode.
|
|
168
|
+
- **The 20×26 indicator gutter is fixed**, so a stack of rows keeps its titles
|
|
169
|
+
optically aligned regardless of glyph state — the thing hand-rolled step lists
|
|
170
|
+
always get wrong when the spinner swaps in.
|
|
171
|
+
- **`prefers-reduced-motion` is honoured** for the working spinner, for free.
|
|
172
|
+
- **Truncation is decided once.** Titles are single-line with an ellipsis at 560px,
|
|
173
|
+
so a runaway tool message can never reflow the transcript.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Gotchas
|
|
178
|
+
|
|
179
|
+
**1. It renders one row, not a list.** You map.
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
// WRONG — there is no items prop; this renders one default row
|
|
183
|
+
<ScInChatList items={steps} />
|
|
184
|
+
|
|
185
|
+
// RIGHT
|
|
186
|
+
{steps.map((s) => <ScInChatList key={s.id} title={s.message} showTool={false} />)}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**2. The tool pill is on by default, and its default text says "Using Catalogix...".**
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// WRONG — renders a "Using Catalogix..." pill under your title
|
|
193
|
+
<ScInChatList title="Fetching orders" />
|
|
194
|
+
|
|
195
|
+
// RIGHT
|
|
196
|
+
<ScInChatList title="Fetching orders" showTool={false} />
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**3. `toolUsing={undefined}` does not hide the pill** — `undefined` triggers the
|
|
200
|
+
default. Gate with `showTool`.
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
// WRONG — still shows "Using Catalogix..." when toolName is empty
|
|
204
|
+
<ScInChatList title={s.message} toolUsing={s.toolName ? `Using ${s.toolName}...` : undefined} />
|
|
205
|
+
|
|
206
|
+
// RIGHT
|
|
207
|
+
<ScInChatList
|
|
208
|
+
title={s.message}
|
|
209
|
+
showTool={!!s.toolName}
|
|
210
|
+
toolUsing={s.toolName ? `Using ${s.toolName}...` : undefined}
|
|
211
|
+
/>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**4. `title` and `description` have real content defaults.** Omit `title` and you
|
|
215
|
+
ship `"Infrastructure that helps modern brands scale"`; omit `description` while
|
|
216
|
+
expanded and you ship the literal word `"Description"`.
|
|
217
|
+
|
|
218
|
+
**5. `description` is dropped unless `descriptionVisibility === "visible"`.**
|
|
219
|
+
`"hidden"` gives you the chevron but no text — that is the collapsed half of the
|
|
220
|
+
pair, and you must flip the prop in `onToggle`. There is no internal state.
|
|
221
|
+
|
|
222
|
+
**6. The title never wraps.** `.title` is `white-space: nowrap; overflow: hidden;
|
|
223
|
+
text-overflow: ellipsis; max-width: 560px`. Long tool output silently truncates —
|
|
224
|
+
put the long form in `description`, not `title`.
|
|
225
|
+
|
|
226
|
+
**7. The expander is not keyboard accessible.** The clickable title row is a plain
|
|
227
|
+
`div` with an `onClick` — no `role`, no `tabIndex`, no `aria-expanded`. If you need
|
|
228
|
+
keyboard access to the description, don't hide it behind the chevron.
|
|
229
|
+
|
|
230
|
+
**8. Only `className` and `style` pass through.** `IScInChatListProps` does **not**
|
|
231
|
+
extend `HTMLAttributes`, unlike most of the library.
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
// WRONG — type error; none of these reach the DOM
|
|
235
|
+
<ScInChatList title="x" id="step-1" data-testid="step" onClick={select} />
|
|
236
|
+
|
|
237
|
+
// RIGHT — wrap it
|
|
238
|
+
<div id="step-1" data-testid="step" onClick={select}><ScInChatList title="x" /></div>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**9. `leadingIndicator={false}` removes the gutter, not just the glyph.** The row's
|
|
242
|
+
content shifts 28px left, so mixing indicator-less rows into a stack breaks
|
|
243
|
+
alignment. Use `iconState="default"` (a faint hollow ring) if you want an empty slot.
|
|
244
|
+
|
|
245
|
+
**10. The root is capped at `max-width: 600px`.** In a wider panel the rows will not
|
|
246
|
+
fill the column; override with `className` if that matters.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## In the wild
|
|
251
|
+
|
|
252
|
+
Rendered by the **agent runtime**, not by any of the four dashboards — the live call
|
|
253
|
+
site is the chat transcript's steps block in the `stream-agent` repo (the copilot
|
|
254
|
+
widget):
|
|
255
|
+
|
|
256
|
+
```tsx
|
|
257
|
+
// stream-agent frontend/src/components/chat/AgentSteps.tsx:448
|
|
258
|
+
<ScInChatList
|
|
259
|
+
title={step.message}
|
|
260
|
+
iconState={mapIconState(step.status)}
|
|
261
|
+
showSteps={false}
|
|
262
|
+
descriptionVisibility={step.description ? 'visible' : 'no'}
|
|
263
|
+
description={step.description}
|
|
264
|
+
showTool={!!step.toolName}
|
|
265
|
+
toolUsing={step.toolName ? `Using ${step.toolName}...` : undefined}
|
|
266
|
+
leadingIndicator
|
|
267
|
+
/>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Related
|
|
273
|
+
|
|
274
|
+
- `ScThinkingStepIcon` — the leading glyph; use it alone for a bespoke row layout.
|
|
275
|
+
- `ScSubAgent` — the standalone "Using X…" pill for delegation steps.
|
|
276
|
+
- `ScInChatMessage` — the message bubble the steps block sits above.
|
|
277
|
+
- `ScTodoList` — the interactive checklist, when the user owns the items.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScInChatMessage
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: chat-agent
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [chat, message, bubble, transcript, agent, user, input, output, inchat]
|
|
8
|
+
related: [ScInChatList, ScSubAgent, ScQuickPrompt, ScBriefCard]
|
|
9
|
+
do_not_confuse_with: [ScInChatList, ScInfoPopup, ScBriefCard]
|
|
10
|
+
used_by: [agent]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# ScInChatMessage
|
|
14
|
+
|
|
15
|
+
**A single chat bubble.** One rounded, padded block of 16/24 text: `type="input"` is
|
|
16
|
+
the user's bubble (raised fill, squared bottom-right corner), `type="output"` is the
|
|
17
|
+
agent's (base surface, 1px divider border, fully rounded).
|
|
18
|
+
|
|
19
|
+
## TL;DR for agents
|
|
20
|
+
|
|
21
|
+
- **Reach for it when:** you need the bubble chrome for one turn of a chat transcript.
|
|
22
|
+
- **Don't reach for it when:** you're rendering the agent's reasoning steps
|
|
23
|
+
(→ `ScInChatList`), a "Using X…" pill (→ `ScSubAgent`), a suggested prompt card
|
|
24
|
+
(→ `ScQuickPrompt`), or **any markdown / block content** — see Gotcha 1.
|
|
25
|
+
- **Three things that will bite you:**
|
|
26
|
+
1. Children are rendered **inside a `<p>`**. Block elements (markdown, `<div>`,
|
|
27
|
+
lists, code blocks) are invalid there and React will warn / the browser will
|
|
28
|
+
re-parent them.
|
|
29
|
+
2. `type` defaults to **`"input"`** — the *user* bubble. Agent turns need
|
|
30
|
+
`type="output"` explicitly.
|
|
31
|
+
3. No avatar, no timestamp, no author, no markdown, no streaming cursor. It is
|
|
32
|
+
purely the bubble.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 1. How to use it
|
|
37
|
+
|
|
38
|
+
### Import
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { ScInChatMessage } from "@streamoid/ui";
|
|
42
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Minimal usage
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
<ScInChatMessage type="input" text={userMessage} />
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Props
|
|
52
|
+
|
|
53
|
+
| Prop | Type | Default | Notes |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `type` | `"input"` \| `"output"` | `"input"` | ⚠️ Defaults to the **user** bubble. `input` = raised fill, bottom-right corner squared to 4px. `output` = base surface + divider border, all corners 18px. |
|
|
56
|
+
| `text` | `string` | – | The bubble text. Rendered only when `children` is not supplied. Omit both and you get an empty `<p>` with full padding (a visible empty bubble). |
|
|
57
|
+
| `children` | `ReactNode` | – | Wins over `text` (`children ?? text`). **Goes inside a `<p>`** — inline content only. |
|
|
58
|
+
| `id` | `string` | – | On the root div. Useful for scroll-to-message anchors. |
|
|
59
|
+
| `className` | `string` | – | Appended after the internal classes. |
|
|
60
|
+
| `...props` | `HTMLAttributes<HTMLDivElement>` | – | `onClick`, `style`, `data-*`, `aria-*` spread onto the root. |
|
|
61
|
+
|
|
62
|
+
### Recipes
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
// The two turns
|
|
66
|
+
<ScInChatMessage type="input" text={turn.userText} />
|
|
67
|
+
<ScInChatMessage type="output" text={turn.assistantText} />
|
|
68
|
+
|
|
69
|
+
// Scroll anchor for "jump to this message"
|
|
70
|
+
<ScInChatMessage id={`msg-${turn.id}`} type="input" text={turn.userText} />
|
|
71
|
+
|
|
72
|
+
// Inline emphasis is fine — it stays inside the <p>
|
|
73
|
+
<ScInChatMessage type="output">
|
|
74
|
+
Mapped <strong>412</strong> SKUs. <em>3 need review.</em>
|
|
75
|
+
</ScInChatMessage>
|
|
76
|
+
|
|
77
|
+
// Markdown / block content: use the bubble's tokens, not the bubble
|
|
78
|
+
// (this is what the real runtime does for assistant turns)
|
|
79
|
+
<div className="chat-output-bubble">
|
|
80
|
+
<ReactMarkdown remarkPlugins={[remarkGfm]}>{md}</ReactMarkdown>
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 2. Where to use it
|
|
87
|
+
|
|
88
|
+
- **The agent chat transcript**, one per turn. In the live runtime
|
|
89
|
+
(`stream-agent frontend/src/components/chat/MessageBlocks.tsx`) only the
|
|
90
|
+
**user** turn uses it — assistant turns need markdown, lists and code blocks, so
|
|
91
|
+
they are rendered with a bespoke container (see Gotcha 1).
|
|
92
|
+
- Attachments/thumbnails for a user turn are rendered **above** it as siblings, not
|
|
93
|
+
as children.
|
|
94
|
+
- The reasoning steps (`ScInChatList`, `ScSubAgent`) sit between the input bubble and
|
|
95
|
+
the output block.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 3. When to use it
|
|
100
|
+
|
|
101
|
+
### Use it when
|
|
102
|
+
|
|
103
|
+
- You need the exact product bubble geometry and surface tokens for a **plain-text**
|
|
104
|
+
turn.
|
|
105
|
+
- The content is one paragraph of prose or a short inline-formatted string.
|
|
106
|
+
|
|
107
|
+
### Don't use it — reach for this instead
|
|
108
|
+
|
|
109
|
+
| Situation | Use instead |
|
|
110
|
+
|---|---|
|
|
111
|
+
| Agent reasoning / tool steps | `ScInChatList` |
|
|
112
|
+
| "Using <sub-agent>…" pill | `ScSubAgent` |
|
|
113
|
+
| Suggested starter prompts | `ScQuickPrompt` |
|
|
114
|
+
| A saved brief / conversation summary card | `ScBriefCard` |
|
|
115
|
+
| Markdown, code blocks, tables, lists | your own container — a `<p>` can't hold them |
|
|
116
|
+
| A hint/help popover in a dashboard | `ScInfoPopup` |
|
|
117
|
+
| A persistent warning strip in a page or sidebar | `CreditWarningBanner` (exported without the `Sc` prefix) |
|
|
118
|
+
|
|
119
|
+
### Don't confuse with
|
|
120
|
+
|
|
121
|
+
| You may actually want | Not this |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `ScInChatList` — a *step* row with a status glyph and tool pill | This is a message bubble with no status |
|
|
124
|
+
| A bubble that renders markdown | This renders a raw string inside a `<p>` |
|
|
125
|
+
| `type` as an author name | It is the surface variant only; there is no author/avatar concept |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 4. Why to use it
|
|
130
|
+
|
|
131
|
+
- **The asymmetric corner is the product's signature.** `input` squares its
|
|
132
|
+
bottom-right corner to `--radius-xs` while keeping 18px elsewhere; getting that
|
|
133
|
+
wrong is the fastest way to make a chat look off-brand.
|
|
134
|
+
- **Both surfaces are token pairs.** `--alias-surface-subtleraised` vs
|
|
135
|
+
`--alias-surface-base` + `--alias-border-divider` keep the user and agent bubbles
|
|
136
|
+
distinguishable in light mode, where a hand-rolled "slightly grey" bubble collapses
|
|
137
|
+
into the page.
|
|
138
|
+
- **`word-break: break-word`** is already set, so pasted URLs and long IDs cannot
|
|
139
|
+
blow out the transcript width.
|
|
140
|
+
- **`max-width: 600px`** matches every other chat primitive in the family
|
|
141
|
+
(`ScInChatList`, `ScSelectionList`), so a transcript has one measure.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Gotchas
|
|
146
|
+
|
|
147
|
+
**1. Children live inside a `<p>`.** The component always renders
|
|
148
|
+
`<p className={styles.text}>{children ?? text}</p>`.
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
// WRONG — <div>/<ul>/markdown inside <p>: React warns, the DOM re-parents,
|
|
152
|
+
// and your padding/radius end up on the wrong box
|
|
153
|
+
<ScInChatMessage type="output">
|
|
154
|
+
<ReactMarkdown>{md}</ReactMarkdown>
|
|
155
|
+
</ScInChatMessage>
|
|
156
|
+
|
|
157
|
+
// RIGHT — plain text through the bubble…
|
|
158
|
+
<ScInChatMessage type="output" text={plainText} />
|
|
159
|
+
|
|
160
|
+
// …or your own container for block content
|
|
161
|
+
<div className="my-output-bubble"><ReactMarkdown>{md}</ReactMarkdown></div>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**2. `type` defaults to `"input"`.** Forget it on an assistant turn and the agent's
|
|
165
|
+
reply is styled as if the user said it.
|
|
166
|
+
|
|
167
|
+
**3. `text` has no default.** `<ScInChatMessage />` renders a fully padded, bordered,
|
|
168
|
+
**empty** bubble rather than nothing. Guard on empty content yourself.
|
|
169
|
+
|
|
170
|
+
**4. `children` silently wins over `text`.** Passing both is not an error; `text` is
|
|
171
|
+
just ignored.
|
|
172
|
+
|
|
173
|
+
**5. There is no author, avatar, timestamp or "typing" state.** Anything a real
|
|
174
|
+
transcript needs beyond the bubble is your composition problem — put it in sibling
|
|
175
|
+
elements, not children.
|
|
176
|
+
|
|
177
|
+
**6. Streaming text reflows the whole bubble.** The bubble is `max-width: 600px` with
|
|
178
|
+
no min-height, so a token-by-token stream grows it line by line. If you need a stable
|
|
179
|
+
box during streaming, set a `min-height` via `className`.
|
|
180
|
+
|
|
181
|
+
**7. The font size is fixed at 16/24.** There is no `size` prop; `className` overrides
|
|
182
|
+
have to target the inner `<p>`, which is a CSS-module class you don't own. Prefer
|
|
183
|
+
wrapping in a container with your own text element if you need a different scale.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## In the wild
|
|
188
|
+
|
|
189
|
+
Rendered by the **agent runtime**, not by any of the four dashboards — the live call
|
|
190
|
+
site is the chat transcript's message block in the `stream-agent` repo (the copilot
|
|
191
|
+
widget):
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
// stream-agent frontend/src/components/chat/MessageBlocks.tsx:291
|
|
195
|
+
<ScInChatMessage type="input" text={content} />
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Related
|
|
201
|
+
|
|
202
|
+
- `ScInChatList` — the reasoning-step row that sits between the two bubbles.
|
|
203
|
+
- `ScSubAgent` — the "Using X…" delegation pill.
|
|
204
|
+
- `ScQuickPrompt` — the suggested-prompt card shown in an empty transcript.
|
|
205
|
+
- `ScBriefCard` — a saved-brief card in the chat surface.
|