@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.
Files changed (134) hide show
  1. package/README.md +35 -18
  2. package/dist/docs/AGENTS.md +325 -0
  3. package/dist/docs/CreditWarningBanner.md +305 -0
  4. package/dist/docs/InvoiceHistoryMobile.md +222 -0
  5. package/dist/docs/ScAccess.md +259 -0
  6. package/dist/docs/ScAppCard.md +244 -0
  7. package/dist/docs/ScAppCardForCopilot.md +230 -0
  8. package/dist/docs/ScAppCardV3.md +273 -0
  9. package/dist/docs/ScAppField.md +308 -0
  10. package/dist/docs/ScAppListingCard.md +271 -0
  11. package/dist/docs/ScAppSwitchPanel.md +286 -0
  12. package/dist/docs/ScAppcardLogos.md +226 -0
  13. package/dist/docs/ScArtifaxInvite.md +262 -0
  14. package/dist/docs/ScArtifaxSidebar.md +330 -0
  15. package/dist/docs/ScAskAgentButton.md +307 -0
  16. package/dist/docs/ScBadges.md +261 -0
  17. package/dist/docs/ScBeacon.md +244 -0
  18. package/dist/docs/ScBillingHistoryHeader.md +210 -0
  19. package/dist/docs/ScBillingHistoryTableList.md +243 -0
  20. package/dist/docs/ScBillingLogsTableHeader.md +212 -0
  21. package/dist/docs/ScBillingLogsTableList.md +251 -0
  22. package/dist/docs/ScBriefCard.md +255 -0
  23. package/dist/docs/ScButton.md +251 -0
  24. package/dist/docs/ScCalendar.md +268 -0
  25. package/dist/docs/ScCalendarDateComps.md +264 -0
  26. package/dist/docs/ScCatalogixInvite.md +345 -0
  27. package/dist/docs/ScCatalogixSidebar.md +337 -0
  28. package/dist/docs/ScCatalogixStoreHeader.md +246 -0
  29. package/dist/docs/ScCatalogixStoreTableList.md +316 -0
  30. package/dist/docs/ScCheckField.md +233 -0
  31. package/dist/docs/ScCheckbox.md +272 -0
  32. package/dist/docs/ScCounter.md +235 -0
  33. package/dist/docs/ScCreditsUsageCard.md +247 -0
  34. package/dist/docs/ScCreditsUsageCardMobile.md +224 -0
  35. package/dist/docs/ScDefaultCard.md +269 -0
  36. package/dist/docs/ScDp.md +245 -0
  37. package/dist/docs/ScDrawer.md +318 -0
  38. package/dist/docs/ScFieldButton.md +255 -0
  39. package/dist/docs/ScFileField.md +268 -0
  40. package/dist/docs/ScGoogleSignIn.md +250 -0
  41. package/dist/docs/ScGuide.md +278 -0
  42. package/dist/docs/ScHDivider.md +210 -0
  43. package/dist/docs/ScHeader.md +222 -0
  44. package/dist/docs/ScImageField.md +253 -0
  45. package/dist/docs/ScInChatList.md +277 -0
  46. package/dist/docs/ScInChatMessage.md +205 -0
  47. package/dist/docs/ScInfoPopup.md +248 -0
  48. package/dist/docs/ScIntialProfileCover.md +233 -0
  49. package/dist/docs/ScInvoiceHistoryMobile.md +187 -0
  50. package/dist/docs/ScLogoUnit.md +232 -0
  51. package/dist/docs/ScMappingCard.md +241 -0
  52. package/dist/docs/ScMediaApproval.md +301 -0
  53. package/dist/docs/ScMediaSelect.md +310 -0
  54. package/dist/docs/ScMenuOptions.md +308 -0
  55. package/dist/docs/ScMobileBottomAction.md +252 -0
  56. package/dist/docs/ScMobileTopNav.md +279 -0
  57. package/dist/docs/ScModal.md +291 -0
  58. package/dist/docs/ScOnlyField.md +302 -0
  59. package/dist/docs/ScOnlyIcon.md +213 -0
  60. package/dist/docs/ScPagination.md +284 -0
  61. package/dist/docs/ScPairtext.md +287 -0
  62. package/dist/docs/ScPendingAction.md +238 -0
  63. package/dist/docs/ScPhtogenixInvite.md +275 -0
  64. package/dist/docs/ScPlanCard.md +302 -0
  65. package/dist/docs/ScPlanComparison.md +264 -0
  66. package/dist/docs/ScPlanDetailsCard.md +246 -0
  67. package/dist/docs/ScPlanDetailsCardMobile.md +240 -0
  68. package/dist/docs/ScPopUpMenu.md +224 -0
  69. package/dist/docs/ScProfile.md +234 -0
  70. package/dist/docs/ScProfileImageUpdate.md +261 -0
  71. package/dist/docs/ScProfileOptions.md +245 -0
  72. package/dist/docs/ScProfilePopup.md +396 -0
  73. package/dist/docs/ScProfileSettingsComp.md +250 -0
  74. package/dist/docs/ScProfileV2Mobile.md +216 -0
  75. package/dist/docs/ScProgressBar.md +267 -0
  76. package/dist/docs/ScQuickPrompt.md +277 -0
  77. package/dist/docs/ScRadio.md +228 -0
  78. package/dist/docs/ScReferralCardMobile.md +226 -0
  79. package/dist/docs/ScReferralTableHeader.md +260 -0
  80. package/dist/docs/ScReferralTableList.md +293 -0
  81. package/dist/docs/ScRole.md +226 -0
  82. package/dist/docs/ScRoleMobile.md +199 -0
  83. package/dist/docs/ScSelect.md +270 -0
  84. package/dist/docs/ScSelection.md +256 -0
  85. package/dist/docs/ScSelectionList.md +272 -0
  86. package/dist/docs/ScSelectionPill.md +240 -0
  87. package/dist/docs/ScSelectionPillGroup.md +302 -0
  88. package/dist/docs/ScSettingsNav.md +212 -0
  89. package/dist/docs/ScSettingsTabComp.md +260 -0
  90. package/dist/docs/ScSideBarLogoUnit.md +340 -0
  91. package/dist/docs/ScSidebar.md +243 -0
  92. package/dist/docs/ScSidebarIcons.md +232 -0
  93. package/dist/docs/ScSidebarMenu.md +283 -0
  94. package/dist/docs/ScSidebarProfile.md +231 -0
  95. package/dist/docs/ScSidebarSwitchMenu.md +258 -0
  96. package/dist/docs/ScSlider.md +194 -0
  97. package/dist/docs/ScStoreCard.md +252 -0
  98. package/dist/docs/ScStrLogo.md +253 -0
  99. package/dist/docs/ScStreamoidWordmark.md +302 -0
  100. package/dist/docs/ScSubAgent.md +226 -0
  101. package/dist/docs/ScTabComp.md +308 -0
  102. package/dist/docs/ScTabField.md +258 -0
  103. package/dist/docs/ScTabSwitcher.md +307 -0
  104. package/dist/docs/ScTableHeader.md +261 -0
  105. package/dist/docs/ScTableList.md +301 -0
  106. package/dist/docs/ScTableListMobile.md +282 -0
  107. package/dist/docs/ScTabs.md +268 -0
  108. package/dist/docs/ScTaxonomyPill.md +263 -0
  109. package/dist/docs/ScTextArea.md +259 -0
  110. package/dist/docs/ScTextField.md +324 -0
  111. package/dist/docs/ScThinkingStepIcon.md +249 -0
  112. package/dist/docs/ScTodoList.md +288 -0
  113. package/dist/docs/ScToggleSwitch.md +229 -0
  114. package/dist/docs/ScUsageHistoryMobile.md +194 -0
  115. package/dist/docs/ScVDivider.md +215 -0
  116. package/dist/docs/ScValueMappingL1.md +256 -0
  117. package/dist/docs/ScVersion.md +251 -0
  118. package/dist/docs/ScWorkspace.md +233 -0
  119. package/dist/docs/ScWorkspaceAccountMenu.md +115 -0
  120. package/dist/docs/ScWorkspaceCard.md +234 -0
  121. package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
  122. package/dist/docs/ScWorkspaceSwitchCard.md +312 -0
  123. package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
  124. package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
  125. package/dist/docs/StreamoidSidebar.md +413 -0
  126. package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
  127. package/dist/docs/UsageHistoryMobile.md +235 -0
  128. package/dist/docs/components.json +4931 -0
  129. package/dist/index.css +361 -36
  130. package/dist/index.d.mts +213 -88
  131. package/dist/index.d.ts +213 -88
  132. package/dist/index.js +2486 -1629
  133. package/dist/index.mjs +2487 -1620
  134. package/package.json +5 -3
@@ -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.