@streamoid/ui 0.6.17 → 0.6.18
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 +321 -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 +213 -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/ScWorkspaceCard.md +234 -0
- package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
- package/dist/docs/ScWorkspaceSwitchCard.md +314 -0
- package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
- package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
- package/dist/docs/StreamoidSidebar.md +403 -0
- package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
- package/dist/docs/UsageHistoryMobile.md +235 -0
- package/dist/docs/components.json +4849 -0
- package/dist/index.css +36 -36
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/package.json +3 -2
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScStreamoidWordmark
|
|
3
|
+
also_exports: [ScStreamoidMascot, ScCxoCopilotLogo]
|
|
4
|
+
package: "@streamoid/ui"
|
|
5
|
+
category: brand
|
|
6
|
+
status: stable
|
|
7
|
+
renders: span[aria-hidden] (wordmark) · svg[role="img"] (mascot, CXO logo)
|
|
8
|
+
tags: [brand, logo, wordmark, mascot, streamoid, cxo, copilot, mask, svg, gradient, sidebar-header]
|
|
9
|
+
related: [ScSideBarLogoUnit, StreamoidSidebar, ScAppcardLogos, ScAppSwitchPanel, ScStrLogo]
|
|
10
|
+
do_not_confuse_with: [ScStrLogo, ScLogoUnit, ScAppcardLogos, ProductWordmark, ScSideBarLogoUnit, ScCxoCopilotLogo]
|
|
11
|
+
used_by: [cxo]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# ScStreamoidWordmark · ScStreamoidMascot · ScCxoCopilotLogo
|
|
15
|
+
|
|
16
|
+
**The company's own brand marks, so no host app ships a brand SVG.** Three leaf
|
|
17
|
+
components in one folder: the plain "streamoid" wordmark (110×16, painted as a CSS
|
|
18
|
+
mask so a token colours it), the colourful mascot glyph used in the collapsed
|
|
19
|
+
sidebar (teal→purple gradient, 48×48 viewBox), and the CXO Copilot lockup
|
|
20
|
+
(98×32, red→orange gradient).
|
|
21
|
+
|
|
22
|
+
## TL;DR for agents
|
|
23
|
+
|
|
24
|
+
- **Reach for it when:** you need the *Streamoid* wordmark or mascot, or the *CXO
|
|
25
|
+
Copilot* logo, as a bare mark you position yourself — typically as the
|
|
26
|
+
`wordmark` node you hand to `ScSideBarLogoUnit`.
|
|
27
|
+
- **Don't reach for it when:** you want a *product* wordmark — Artifax, Photogenix,
|
|
28
|
+
Catalogix, Tactix (→ `ScAppcardLogos`, or `ProductWordmark` inside
|
|
29
|
+
`ScSideBarLogoUnit`); you want the whole clickable sidebar header row
|
|
30
|
+
(→ `ScSideBarLogoUnit`); or you want the old 626×60 wordmark+mascot lockup
|
|
31
|
+
(→ `ScStrLogo`, legacy).
|
|
32
|
+
- **Four things that will bite you:**
|
|
33
|
+
1. `width`/`height` (and `size`) set the **box**, not the mark's scale. The art
|
|
34
|
+
scales to *fit* the box, so `width={220}` with the default `height={16}`
|
|
35
|
+
renders the same 110×16 mark, left-aligned in a 220px box. Scale both.
|
|
36
|
+
2. `ScStreamoidMascot`'s art spans only 15 of its 48 vertical viewBox units (and
|
|
37
|
+
40 of 48 horizontally), so `size={40}` paints a mark roughly 33×12.5px. It
|
|
38
|
+
looks much smaller than the number.
|
|
39
|
+
3. The wordmark is `aria-hidden` and contributes **no accessible name**. The
|
|
40
|
+
mascot and CXO logo carry hardcoded English `aria-label`s you cannot change.
|
|
41
|
+
4. None of them take `onClick`, children, or `...HTMLAttributes`. Only
|
|
42
|
+
`className` + `style` (+ `color`/`width`/`height`/`size`).
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 1. How to use it
|
|
47
|
+
|
|
48
|
+
### Import
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import {
|
|
52
|
+
ScStreamoidWordmark,
|
|
53
|
+
ScStreamoidMascot,
|
|
54
|
+
ScCxoCopilotLogo,
|
|
55
|
+
} from "@streamoid/ui";
|
|
56
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Minimal usage
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<ScStreamoidWordmark /> {/* 110×16, primary-text colour */}
|
|
63
|
+
<ScStreamoidMascot /> {/* 40×40 box */}
|
|
64
|
+
<ScCxoCopilotLogo /> {/* 98×32 */}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Props — `ScStreamoidWordmark`
|
|
68
|
+
|
|
69
|
+
| Prop | Type | Default | Notes |
|
|
70
|
+
|---|---|---|---|
|
|
71
|
+
| `width` | `number` | `110` | Box width in **px** (number only — `"100%"` is a type error). Native width. |
|
|
72
|
+
| `height` | `number` | `16` | Box height in px. The mask is `contain` + `left center`, so extra height is padding, not scale. |
|
|
73
|
+
| `color` | `string` | `"var(--alias-text---icons-primary, #f5f5f5)"` | Any solid CSS colour — it becomes `background-color` behind the mask. Gradients don't work (Gotcha 3). |
|
|
74
|
+
| `className` | `string` | – | Set on the `<span>`. |
|
|
75
|
+
| `style` | `CSSProperties` | – | Spread **last**, so it overrides the inline width/height/mask. |
|
|
76
|
+
|
|
77
|
+
### Props — `ScStreamoidMascot`
|
|
78
|
+
|
|
79
|
+
| Prop | Type | Default | Notes |
|
|
80
|
+
|---|---|---|---|
|
|
81
|
+
| `size` | `number` | `40` | Square box in px (`viewBox="0 0 48 48"`). ⚠️ The art occupies ~40×15 of those 48 units — see Gotcha 2. |
|
|
82
|
+
| `className` | `string` | – | Set on the `<svg>`. |
|
|
83
|
+
| `style` | `CSSProperties` | – | Set on the `<svg>`. Does not override `width`/`height` attributes. |
|
|
84
|
+
|
|
85
|
+
No `color` prop: the gradient (`#50DCDE` → `#7850DE`) is intrinsic to the mark —
|
|
86
|
+
but only **two** of the mascot's three arcs carry it. The **right-hand arc** (the
|
|
87
|
+
one with the "eye" dot cut out of it) is a separate path filled with
|
|
88
|
+
`--alias-text---icons-primary`, so roughly a third of the mark is token-coloured
|
|
89
|
+
and flips with the theme while the rest stays teal→purple.
|
|
90
|
+
|
|
91
|
+
### Props — `ScCxoCopilotLogo`
|
|
92
|
+
|
|
93
|
+
| Prop | Type | Default | Notes |
|
|
94
|
+
|---|---|---|---|
|
|
95
|
+
| `width` | `number` | `98` | Box width in px. |
|
|
96
|
+
| `height` | `number` | `32` | Box height in px. ⚠️ The JSDoc says height scales with the 98:32 ratio — **it does not**. Pass both (Gotcha 1). |
|
|
97
|
+
| `className` | `string` | – | Set on the `<svg>`. |
|
|
98
|
+
| `style` | `CSSProperties` | – | Set on the `<svg>`. |
|
|
99
|
+
|
|
100
|
+
No `color` prop: the red→orange gradient (`#D91536` → `#EE5E3A`) is the brand.
|
|
101
|
+
|
|
102
|
+
### Recipes
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
// The standard job: feed the sidebar header's wordmark slot (expanded + collapsed)
|
|
106
|
+
<ScSideBarLogoUnit
|
|
107
|
+
wordmark={<ScStreamoidWordmark width={110} height={16} />}
|
|
108
|
+
onClick={onToggle}
|
|
109
|
+
switchAriaLabel="Switch product"
|
|
110
|
+
/>
|
|
111
|
+
<ScSideBarLogoUnit
|
|
112
|
+
state="collapsed"
|
|
113
|
+
wordmark={<ScStreamoidMascot size={40} />}
|
|
114
|
+
onClick={onToggle}
|
|
115
|
+
/>
|
|
116
|
+
|
|
117
|
+
// A bigger wordmark on an auth / splash screen — scale BOTH axes (110:16 = 6.875)
|
|
118
|
+
<ScStreamoidWordmark width={220} height={32} />
|
|
119
|
+
|
|
120
|
+
// Recolour the wordmark for a coloured banner
|
|
121
|
+
<ScStreamoidWordmark color="var(--alias-text---icons-inverse)" />
|
|
122
|
+
|
|
123
|
+
// The CXO Copilot lockup, doubled — pass both dimensions
|
|
124
|
+
<ScCxoCopilotLogo width={196} height={64} />
|
|
125
|
+
|
|
126
|
+
// Give the mark an accessible name when it IS the page's identity
|
|
127
|
+
<h1 style={{ margin: 0 }}>
|
|
128
|
+
<span className="sr-only">Streamoid</span>
|
|
129
|
+
<ScStreamoidWordmark width={165} height={24} />
|
|
130
|
+
</h1>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 2. Where to use it
|
|
136
|
+
|
|
137
|
+
- **Sidebar header** — the near-universal use. `ScStreamoidWordmark` goes into
|
|
138
|
+
`ScSideBarLogoUnit`'s `wordmark` slot when expanded; `ScStreamoidMascot` when
|
|
139
|
+
collapsed. `StreamoidSidebar` renders that unit for you.
|
|
140
|
+
- **Auth / splash / empty-state screens** — the wordmark at 1.5–2× scale.
|
|
141
|
+
- **CXO copilot surfaces** — `ScCxoCopilotLogo` on the agent panel header, the
|
|
142
|
+
copilot marketing/first-run surface, or anywhere the *Copilot* product (not the
|
|
143
|
+
company) is being named.
|
|
144
|
+
|
|
145
|
+
CXO is the live consumer (`app-sidebar.tsx`). Photogenix/Catalogix/Artifax show
|
|
146
|
+
their **own** product wordmark in that slot via `ScSideBarLogoUnit`'s `product`
|
|
147
|
+
prop, which is why they don't import these.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 3. When to use it
|
|
152
|
+
|
|
153
|
+
### Use it when
|
|
154
|
+
|
|
155
|
+
- The mark you need is **Streamoid the company** (wordmark or mascot) or **CXO
|
|
156
|
+
Copilot** — not one of the four products.
|
|
157
|
+
- You want to position/scale the mark yourself, inside your own layout or a slot.
|
|
158
|
+
- You need it to survive a theme flip: the wordmark is a token-coloured mask, so
|
|
159
|
+
it never becomes white-on-white in light mode the way an exported PNG/`<img>` does.
|
|
160
|
+
|
|
161
|
+
### Don't use it — reach for this instead
|
|
162
|
+
|
|
163
|
+
| Situation | Use instead |
|
|
164
|
+
|---|---|
|
|
165
|
+
| A **product** wordmark (Artifax / Photogenix / Catalogix / Tactix) | `ScAppcardLogos` (14px, `currentColor`) or `ScSideBarLogoUnit product="…"` |
|
|
166
|
+
| The whole sidebar header row (mark + switch pill + click target) | `ScSideBarLogoUnit` |
|
|
167
|
+
| The app-switch list of products | `ScAppSwitchPanel` |
|
|
168
|
+
| The old 626×60 "wordmark + mascot" corporate lockup | `ScStrLogo` — legacy, don't start there |
|
|
169
|
+
| The pre-`StreamoidSidebar` logo box | `ScLogoUnit` — legacy |
|
|
170
|
+
| An app icon + name + description row | `ScAppCard` |
|
|
171
|
+
| A clickable logo | wrap it in your own `<button>`, or use `ScSideBarLogoUnit` — these are inert `span`/`svg` |
|
|
172
|
+
|
|
173
|
+
### Don't confuse with
|
|
174
|
+
|
|
175
|
+
| You may actually want | Not this |
|
|
176
|
+
|---|---|
|
|
177
|
+
| `ScStrLogo` — one 626×60 SVG containing the wordmark **and** the mascot together | `ScStreamoidWordmark` is 110×16 and has **no** mascot; `ScStreamoidMascot` is the mascot **alone** |
|
|
178
|
+
| `ScLogoUnit` — a padded 240px sidebar box that renders `ScStrLogo` inside | Legacy; superseded by `ScSideBarLogoUnit` |
|
|
179
|
+
| `ScAppcardLogos` — per-**product** wordmarks; has **no** Streamoid entry | These are the Streamoid/CXO marks |
|
|
180
|
+
| `ProductWordmark` / `ProductCollapsedMark` (SC-SideBarLogoUnit) — per-product marks for the sidebar slot | Same slot, different brand |
|
|
181
|
+
| `ScCxoCopilotLogo` — the **CXO Copilot** product lockup | Not a Streamoid company mark; different gradient, different aspect (98:32) |
|
|
182
|
+
|
|
183
|
+
Note the aspect ratios, because neighbouring docs get this wrong: the Streamoid
|
|
184
|
+
wordmark is **110×16**; **98×32** is `ScCxoCopilotLogo`.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 4. Why to use it
|
|
189
|
+
|
|
190
|
+
- **Zero brand assets in host repos.** Every consumer used to carry its own
|
|
191
|
+
hand-exported SVG component (CXO still has two dead ones under
|
|
192
|
+
`src/app/components/strLogo/`). One import replaces them, and a brand refresh
|
|
193
|
+
ships from one place.
|
|
194
|
+
- **The wordmark is theme-correct by construction.** It's rendered as a CSS
|
|
195
|
+
`mask-image` with `background-color` from `--alias-text---icons-primary`, so it
|
|
196
|
+
is *the same colour as your text* in both themes and can brighten on hover. A
|
|
197
|
+
raw white `<img>` stays white and disappears on a light canvas — this is the
|
|
198
|
+
exact bug the mask design exists to prevent.
|
|
199
|
+
- **Gradient marks stay gradient.** Mascot and CXO logo are inline multi-colour
|
|
200
|
+
SVGs (not masks) precisely so their gradients survive (the mascot deliberately
|
|
201
|
+
mixes the gradient with one token-filled arc); each one mints a
|
|
202
|
+
**unique gradient id per instance** with `useId()`, so N of them on a page don't
|
|
203
|
+
collide the way a copy-pasted SVG does.
|
|
204
|
+
- **Correct geometry, once.** The 110×16 plain wordmark is deliberately a
|
|
205
|
+
*different* asset from the 110×34 app-switcher lockup (wordmark + descriptor,
|
|
206
|
+
22 paths, in `SC-AppSwitch/wordmarks.ts`). Picking the file yourself is how you
|
|
207
|
+
end up with the descriptor showing in a sidebar.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Gotchas
|
|
212
|
+
|
|
213
|
+
**1. Size props size the *box*; the art scales to fit.** The wordmark's mask is
|
|
214
|
+
`mask-size: contain`, and both SVGs use the default `preserveAspectRatio`. Passing
|
|
215
|
+
one dimension letterboxes the mark instead of growing it.
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
// WRONG — still paints a 110×16 mark, now sitting in a 220px-wide box
|
|
219
|
+
<ScStreamoidWordmark width={220} />
|
|
220
|
+
|
|
221
|
+
// WRONG — still paints 98×32, letterboxed inside 196×32
|
|
222
|
+
<ScCxoCopilotLogo width={196} />
|
|
223
|
+
|
|
224
|
+
// RIGHT — scale both axes on the native ratio (110:16, 98:32)
|
|
225
|
+
<ScStreamoidWordmark width={220} height={32} />
|
|
226
|
+
<ScCxoCopilotLogo width={196} height={64} />
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**2. The mascot is smaller than `size` implies.** Its artwork spans about 40×15
|
|
230
|
+
units of a 48×48 viewBox, so `size={40}` yields ~33×12.5px of visible mark with
|
|
231
|
+
~14px of empty space above it. That padding is deliberate (it centres the glyph in
|
|
232
|
+
a 40px collapsed-sidebar slot) — don't "fix" it by inflating `size` unless you
|
|
233
|
+
also expect the slot to grow.
|
|
234
|
+
|
|
235
|
+
**3. `color` on the wordmark is a `background-color`, not a fill.** Solid colours
|
|
236
|
+
and `currentColor` work; `linear-gradient(...)` silently paints nothing because a
|
|
237
|
+
gradient is a `background-image`. The wordmark is single-colour by design.
|
|
238
|
+
|
|
239
|
+
**4. The wordmark is `aria-hidden`.** It contributes no accessible name. If it is
|
|
240
|
+
the only identity on the surface, label the wrapper yourself.
|
|
241
|
+
(`ScSideBarLogoUnit` already labels its row — default `"Switch product"`.)
|
|
242
|
+
|
|
243
|
+
**5. The mascot/CXO `aria-label`s are hardcoded English** (`"Streamoid"`,
|
|
244
|
+
`"CXO Copilot"`) with no prop to override. Fine for brand names; a blocker if a
|
|
245
|
+
surface must be fully localised.
|
|
246
|
+
|
|
247
|
+
**6. No event props, no children.** These interfaces are exactly
|
|
248
|
+
`{ width|height|size?, color?, className?, style? }` — they do **not** extend
|
|
249
|
+
`HTMLAttributes`. `onClick`, `id`, `data-*`, `role` are type errors.
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
// WRONG — onClick is not in the props type and nothing is spread
|
|
253
|
+
<ScStreamoidMascot size={40} onClick={goHome} />
|
|
254
|
+
|
|
255
|
+
// RIGHT
|
|
256
|
+
<button type="button" onClick={goHome} aria-label="Home">
|
|
257
|
+
<ScStreamoidMascot size={40} />
|
|
258
|
+
</button>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**7. `style` wins over the component's own inline styles on the wordmark** (it is
|
|
262
|
+
spread last). Handy for `marginLeft`, dangerous if you set `background` — that
|
|
263
|
+
kills the mask fill and the mark vanishes.
|
|
264
|
+
|
|
265
|
+
**8. `STREAMOID_WORDMARK` (the data-URI asset in `streamoid-wordmark.ts`) is
|
|
266
|
+
not public.** It is not re-exported from the package entry point. Don't try to
|
|
267
|
+
import the raw URI; render the component.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## In the wild
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
// cxo-dashboard src/app/components/app-sidebar.tsx:76
|
|
275
|
+
<ScSideBarLogoUnit
|
|
276
|
+
wordmark={<ScStreamoidWordmark width={110} height={16} />}
|
|
277
|
+
onClick={onClick}
|
|
278
|
+
switchAriaLabel="Switch product"
|
|
279
|
+
style={{ paddingBottom: 0 }}
|
|
280
|
+
/>
|
|
281
|
+
|
|
282
|
+
// cxo-dashboard src/app/components/app-sidebar.tsx:100
|
|
283
|
+
<ScSideBarLogoUnit
|
|
284
|
+
state="collapsed"
|
|
285
|
+
wordmark={<ScStreamoidMascot size={40} />}
|
|
286
|
+
onClick={onClick}
|
|
287
|
+
hover={open ? true : undefined}
|
|
288
|
+
/>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`ScCxoCopilotLogo` has no host render site yet — it is the CXO-only copilot
|
|
292
|
+
lockup, and CXO currently renders the company wordmark in its shell.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Related
|
|
297
|
+
|
|
298
|
+
- `ScSideBarLogoUnit` — the sidebar header row these marks are usually passed into.
|
|
299
|
+
- `StreamoidSidebar` — renders that unit as part of the app shell.
|
|
300
|
+
- `ScAppcardLogos` — the per-product wordmark set (no Streamoid entry).
|
|
301
|
+
- `ScAppSwitchPanel` — the product-switch list below the logo.
|
|
302
|
+
- `ScStrLogo` / `ScLogoUnit` — the legacy 626×60 lockup and its container.
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScSubAgent
|
|
3
|
+
also_exports: [formatSubAgentLabel]
|
|
4
|
+
package: "@streamoid/ui"
|
|
5
|
+
category: chat-agent
|
|
6
|
+
status: stable
|
|
7
|
+
renders: div
|
|
8
|
+
tags: [chat, agent, sub-agent, delegation, pill, badge, using, tool, inchat]
|
|
9
|
+
related: [ScInChatList, ScThinkingStepIcon, ScInChatMessage, ScBadges]
|
|
10
|
+
do_not_confuse_with: [ScInChatList, ScBadges, ScTaxonomyPill, ScSelectionPill]
|
|
11
|
+
used_by: [agent]
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# ScSubAgent
|
|
15
|
+
|
|
16
|
+
**The "Using Research Agent…" pill.** A single `fit-content` rounded chip with 12/18
|
|
17
|
+
primary text on a neutral fill, marking the moment the main agent handed work to a
|
|
18
|
+
sub-agent. Ships a `formatSubAgentLabel` helper that builds the label from a raw
|
|
19
|
+
agent name.
|
|
20
|
+
|
|
21
|
+
## TL;DR for agents
|
|
22
|
+
|
|
23
|
+
- **Reach for it when:** a step in the transcript **is** a delegation — the agent
|
|
24
|
+
invoked a named sub-agent and you want to say so in one chip.
|
|
25
|
+
- **Don't reach for it when:** the step has a title, a status glyph and a
|
|
26
|
+
tool name (→ `ScInChatList`, whose `showTool`/`toolUsing` renders the *same*
|
|
27
|
+
pill inside a full step row), or you want a status/count chip in a dashboard
|
|
28
|
+
(→ `ScBadges`).
|
|
29
|
+
- **Three things that will bite you:**
|
|
30
|
+
1. `text` **bypasses formatting entirely**. If you pass `text`, you own the whole
|
|
31
|
+
string, including the "Using …" prefix and the ellipsis.
|
|
32
|
+
2. Pass neither `text` nor `agentName` and you get the literal
|
|
33
|
+
`"Using sub-agent..."`.
|
|
34
|
+
3. `white-space: nowrap` + `width: fit-content` — a long agent name **overflows**
|
|
35
|
+
its container instead of wrapping or truncating.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 1. How to use it
|
|
40
|
+
|
|
41
|
+
### Import
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { ScSubAgent, formatSubAgentLabel } from "@streamoid/ui";
|
|
45
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Minimal usage
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<ScSubAgent agentName="research agent" /> {/* → "Using Research Agent..." */}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Props
|
|
55
|
+
|
|
56
|
+
| Prop | Type | Default | Notes |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| `text` | `string` | – | The label, **verbatim**. Wins over `agentName`; no prefix, no title-casing, no ellipsis added. |
|
|
59
|
+
| `agentName` | `string` | – | Run through `formatSubAgentLabel` → `` `Using ${TitleCased}...` ``. Only used when `text` is `undefined`. |
|
|
60
|
+
| `className` | `string` | – | Appended after the internal class (falsy values filtered). |
|
|
61
|
+
| `...props` | `HTMLAttributes<HTMLDivElement>` | – | `onClick`, `style`, `title`, `data-*`, `aria-*` spread onto the root. |
|
|
62
|
+
|
|
63
|
+
Resolution is exactly `const label = text ?? formatSubAgentLabel(agentName)` — note
|
|
64
|
+
`??`, so `text=""` renders an **empty pill**, it does not fall through to `agentName`.
|
|
65
|
+
|
|
66
|
+
### `formatSubAgentLabel(agentName?: string): string`
|
|
67
|
+
|
|
68
|
+
Exported alongside the component, so you can compute the same label for a tooltip,
|
|
69
|
+
an `aria-label`, or a log line.
|
|
70
|
+
|
|
71
|
+
| Input | Output |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `undefined` / `""` / `" "` | `"Using sub-agent..."` |
|
|
74
|
+
| `"research"` | `"Using Research..."` |
|
|
75
|
+
| `"research agent"` | `"Using Research Agent..."` |
|
|
76
|
+
| `"catalog-mapper"` | `"Using Catalog-Mapper..."` (`\b` matches after the hyphen) |
|
|
77
|
+
| `"SEO agent"` | `"Using SEO Agent..."` (already-capitalised letters are untouched) |
|
|
78
|
+
| `" feed agent "` | `"Using Feed Agent..."` (trimmed) |
|
|
79
|
+
|
|
80
|
+
It uppercases the first character of **every word** via
|
|
81
|
+
`replace(/\b\w/g, c => c.toUpperCase())`; it never lowercases anything.
|
|
82
|
+
|
|
83
|
+
### Recipes
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
// The runtime idiom: the step stream already carries a formatted label
|
|
87
|
+
{step.kind === "subAgent" ? <ScSubAgent text={step.label} /> : <ScInChatList … />}
|
|
88
|
+
|
|
89
|
+
// From a raw name off the wire
|
|
90
|
+
<ScSubAgent agentName={event.sub_agent} />
|
|
91
|
+
|
|
92
|
+
// Keep the pill and a tooltip in sync using the exported helper
|
|
93
|
+
<ScSubAgent agentName={name} title={formatSubAgentLabel(name)} />
|
|
94
|
+
|
|
95
|
+
// Long names: cap it yourself — the pill will not wrap or ellipsise
|
|
96
|
+
<ScSubAgent text={`Using ${name.length > 28 ? name.slice(0, 27) + "…" : name}...`} />
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 2. Where to use it
|
|
102
|
+
|
|
103
|
+
- **The agent chat transcript's steps block**, as one entry in the same stack as
|
|
104
|
+
`ScInChatList`. In the live runtime
|
|
105
|
+
(`stream-agent frontend/src/components/chat/AgentSteps.tsx`) the step stream is
|
|
106
|
+
discriminated on `step.kind`: `"subAgent"` renders this pill, `"plan"` renders a
|
|
107
|
+
plan card, everything else renders a `ScInChatList` row.
|
|
108
|
+
- It carries **no leading indicator gutter**, so a stack of `ScInChatList` rows with
|
|
109
|
+
a `ScSubAgent` among them is intentionally ragged on the left — the pill reads as a
|
|
110
|
+
marker, not as another step.
|
|
111
|
+
|
|
112
|
+
Its skin is byte-for-byte the same as `ScInChatList`'s internal tool pill
|
|
113
|
+
(`--alias-fill-neutral-neutraltohover`, `--radius-md`, 4/8 padding, 12/18 primary
|
|
114
|
+
text). That is deliberate: same meaning, two placements.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 3. When to use it
|
|
119
|
+
|
|
120
|
+
### Use it when
|
|
121
|
+
|
|
122
|
+
- The transcript entry's whole content is "work moved to <named agent>".
|
|
123
|
+
- You want the delegation to read as a **chip**, visually subordinate to the
|
|
124
|
+
surrounding step rows and message bubbles.
|
|
125
|
+
|
|
126
|
+
### Don't use it — reach for this instead
|
|
127
|
+
|
|
128
|
+
| Situation | Use instead |
|
|
129
|
+
|---|---|
|
|
130
|
+
| A step with a title, status glyph and optional description | `ScInChatList` |
|
|
131
|
+
| A tool pill attached **to** such a step | `ScInChatList` with `showTool` + `toolUsing` |
|
|
132
|
+
| Only the status glyph (spinner / tick / cross) | `ScThinkingStepIcon` |
|
|
133
|
+
| A status or count chip in a dashboard table/header | `ScBadges` |
|
|
134
|
+
| A taxonomy tree node chip | `ScTaxonomyPill` |
|
|
135
|
+
| A clickable segmented filter chip | `ScSelectionPill` |
|
|
136
|
+
| Prose from the agent | `ScInChatMessage` |
|
|
137
|
+
|
|
138
|
+
### Don't confuse with
|
|
139
|
+
|
|
140
|
+
| You may actually want | Not this |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `ScInChatList` — the full step row; its tool pill looks identical | `ScSubAgent` is that pill standing alone, with no title, glyph or gutter |
|
|
143
|
+
| `ScBadges` — dashboard status chip with semantic colours | This pill has one neutral skin and no tone/variant prop |
|
|
144
|
+
| A pill with an icon | There is no icon slot; it is text only |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 4. Why to use it
|
|
149
|
+
|
|
150
|
+
- **One skin, two placements.** Because it reuses `ScInChatList`'s tool-pill tokens,
|
|
151
|
+
"the agent used a tool" and "the agent used a sub-agent" look like the same class of
|
|
152
|
+
event no matter which component drew them.
|
|
153
|
+
- **The label rule lives in the DS, not in five call sites.** `formatSubAgentLabel`
|
|
154
|
+
makes "Using X…" phrasing, title-casing and the empty-name fallback a single
|
|
155
|
+
decision — and it is exported, so tooltips and aria labels can't drift from the
|
|
156
|
+
visible text.
|
|
157
|
+
- **Theme-safe on a chat surface.** `--alias-fill-neutral-neutraltohover` on
|
|
158
|
+
`--alias-text-and-icons-primary` keeps the chip readable against both the dark
|
|
159
|
+
canvas and the light-mode surface, where a hardcoded `#1f1f1f` chip would go black.
|
|
160
|
+
- **`fit-content` + `nowrap`** means the chip is exactly as wide as its text, so a
|
|
161
|
+
column of them stays visually ragged-right the way the design intends, instead of
|
|
162
|
+
stretching to the transcript's 600px measure.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Gotchas
|
|
167
|
+
|
|
168
|
+
**1. `text` skips the formatter completely.**
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
// WRONG — renders the bare name, no "Using", no ellipsis
|
|
172
|
+
<ScSubAgent text="research agent" />
|
|
173
|
+
|
|
174
|
+
// RIGHT — either let agentName do the work…
|
|
175
|
+
<ScSubAgent agentName="research agent" />
|
|
176
|
+
// …or pass a label that is already complete
|
|
177
|
+
<ScSubAgent text={formatSubAgentLabel("research agent")} />
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**2. No props at all ⇒ `"Using sub-agent..."`.** A real, shippable default. Also
|
|
181
|
+
reached when `agentName` is `""` or whitespace.
|
|
182
|
+
|
|
183
|
+
**3. `text=""` renders an empty pill.** The fallback is `??`, not `||`, so an empty
|
|
184
|
+
string is a valid label and you get a blank chip that is just its 8px-per-side
|
|
185
|
+
padding wide. Guard upstream.
|
|
186
|
+
|
|
187
|
+
**4. It never wraps or truncates.** `.label` is `white-space: nowrap` and
|
|
188
|
+
`flex-shrink: 0` on a `fit-content` root, so a 60-character agent name pushes past
|
|
189
|
+
its parent (and past `ScInChatList`'s 600px measure if they share a column). Cap the
|
|
190
|
+
string yourself.
|
|
191
|
+
|
|
192
|
+
**5. Title-casing is naive.** `\b\w` fires after every non-word character:
|
|
193
|
+
`"catalog-mapper"` → `"Catalog-Mapper"`, `"v2 agent"` → `"V2 Agent"`. It also never
|
|
194
|
+
lowercases, so `"RESEARCH"` stays `"RESEARCH"`. If the display name matters, pass
|
|
195
|
+
`text`.
|
|
196
|
+
|
|
197
|
+
**6. It is not a button.** A `div` with no `role`/`tabIndex`. `onClick` passes through
|
|
198
|
+
via `HTMLAttributes`, but you get no keyboard, no focus ring and no affordance — add
|
|
199
|
+
them yourself if the pill is meant to expand a sub-transcript.
|
|
200
|
+
|
|
201
|
+
**7. It has no status.** Unlike `ScInChatList` there is no `iconState`; a sub-agent
|
|
202
|
+
that failed looks identical to one that succeeded. If the delegation needs a state,
|
|
203
|
+
render a `ScInChatList` row instead and put the pill content in `toolUsing`.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## In the wild
|
|
208
|
+
|
|
209
|
+
Rendered by the **agent runtime**, not by any of the four dashboards — the live call
|
|
210
|
+
site is the chat transcript's steps block in the `stream-agent` repo (the copilot
|
|
211
|
+
widget):
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
// stream-agent frontend/src/components/chat/AgentSteps.tsx:443
|
|
215
|
+
<ScSubAgent text={step.label} />
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Related
|
|
221
|
+
|
|
222
|
+
- `ScInChatList` — the full step row; use its `showTool`/`toolUsing` for a tool pill
|
|
223
|
+
attached to a step.
|
|
224
|
+
- `ScThinkingStepIcon` — the status glyph, when you need state rather than a name.
|
|
225
|
+
- `ScInChatMessage` — the message bubbles the steps block sits between.
|
|
226
|
+
- `ScBadges` — the dashboard-side chip vocabulary, with semantic tones.
|