@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,293 @@
1
+ ---
2
+ component: ScReferralTableList
3
+ package: "@streamoid/ui"
4
+ category: tables
5
+ status: stable
6
+ renders: div
7
+ tags: [table, row, referral, referrals, rewards, invite, points, status, settings, referral-history]
8
+ related: [ScReferralTableHeader, ScProfile, ScBadges, ScReferralCardMobile, ScTableList, ScBillingLogsTableList]
9
+ do_not_confuse_with: [ScTableList, ScReferralTableHeader, ScReferralCardMobile, ScBillingHistoryTableList, ScBillingLogsTableList, ScBadges]
10
+ ---
11
+
12
+ # ScReferralTableList
13
+
14
+ **One row of the Referral History table.** A `ScProfile` identity cell that flexes, then
15
+ a date, a status `ScBadges` chip and a reward figure — on the widths
16
+ `ScReferralTableHeader` defines. Four columns, five string props, no state.
17
+
18
+ ## TL;DR for agents
19
+
20
+ - **Reach for it when:** you are rendering Settings → Referral → "Referral History" and
21
+ have a list of `{ name, email, date, status, points }`.
22
+ - **Don't reach for it when:** you need the members table row (→ `ScTableList` /
23
+ hand-rolled), the mobile referral entry (→ `ScReferralCardMobile`), or a billing /
24
+ usage row (→ `ScBillingHistoryTableList`, `ScBillingLogsTableList`).
25
+ - **Four things that will bite you:**
26
+ 1. **Every prop has a placeholder default**, and `userName` has none of its own — omit
27
+ it and `ScProfile`'s default leaks, so the row reads "Chris Hemsworth".
28
+ 2. The **avatar is always a broken image.** `ScProfile.profileImage` falls back to the
29
+ relative path `"profile-image0.png"` and this row exposes no way to set it.
30
+ 3. The **status chip is always the same neutral grey.** `ScBadges` is given only
31
+ `text`, so `variant` stays `"default"` — "Confirmed" is not green and "Pending" is
32
+ not amber, and there is no prop to change it.
33
+ 4. The **reward is always green** (`--alias-text-and-icons-success`), whatever string
34
+ you pass — including `"0"` or `"- 500"`.
35
+
36
+ ---
37
+
38
+ ## 1. How to use it
39
+
40
+ ### Import
41
+
42
+ ```tsx
43
+ import { ScReferralTableHeader, ScReferralTableList } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+ ```
46
+
47
+ ### Minimal usage
48
+
49
+ Pass all five — the defaults are demo data:
50
+
51
+ ```tsx
52
+ <ScReferralTableList
53
+ userName={r.name}
54
+ userEmail={r.email}
55
+ date={r.date}
56
+ status={r.status}
57
+ points={r.points}
58
+ />
59
+ ```
60
+
61
+ ### Props
62
+
63
+ | Prop | Type | Default | Notes |
64
+ |---|---|---|---|
65
+ | `userName` | `string` | – (⚠️ **effectively `"Chris Hemsworth"`**) | Passed to `ScProfile` as `name`. It has no default here, so `undefined` falls through to `ScProfile`'s own default. Line 1 of the identity cell; truncates. |
66
+ | `userEmail` | `string` | `"chris@kepler.com"` | ⚠️ Placeholder default. Passed to `ScProfile` as `subText` — line 2 of the identity cell; truncates. |
67
+ | `date` | `string` | `"Nov 9th, 2025"` | ⚠️ Placeholder default. Pre-formatted string; the row does no date formatting. `7.5rem`, truncates, no tooltip. |
68
+ | `status` | `string` | `"Confirmed"` | ⚠️ Placeholder default. Free string → `ScBadges text`. Always the neutral chip — see Gotcha 3. Forced to `5rem` wide. |
69
+ | `points` | `string` | `"+ 500"` | ⚠️ Placeholder default. Reward figure, `text-md-semibold`, **always green**. `7.5rem`, truncates. Include the sign yourself. |
70
+ | `className` | `string` | – | Appended after the internal class. |
71
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | Spread onto the root div. Unlike `ScTableList` there is **no internal `onClick`**, so `onClick`, `style`, `aria-*` and `data-*` all work normally. |
72
+
73
+ ### What renders in each column
74
+
75
+ | Column | Rendered by | Controllable? |
76
+ |---|---|---|
77
+ | USER (`flex: 1`) | `ScProfile name={userName} subText={userEmail}` | ✅ both strings. ❌ avatar — no `profileImage` prop (Gotcha 2). |
78
+ | DATE (`7.5rem`) | plain text cell | ✅ `date` |
79
+ | STATUS (`5rem`) | `ScBadges text={status}` | ✅ the text only. ❌ colour/variant (Gotcha 3). |
80
+ | REWARD (`7.5rem`) | plain text cell | ✅ `points`. ❌ colour — always success green (Gotcha 4). |
81
+
82
+ ### Recipes
83
+
84
+ ```tsx
85
+ // The whole Referral History table
86
+ <div style={{ display: "flex", flexDirection: "column" }}>
87
+ <ScReferralTableHeader />
88
+ {referrals.map((r) => (
89
+ <ScReferralTableList
90
+ key={r.id}
91
+ userName={r.name}
92
+ userEmail={r.email}
93
+ date={formatDate(r.createdAt)} // the row does not format dates
94
+ status={r.status}
95
+ points={`${r.credits >= 0 ? "+ " : "- "}${Math.abs(r.credits)}`} // sign is yours
96
+ />
97
+ ))}
98
+ </div>
99
+
100
+ // Clickable row — no onRowClick here, plain onClick works
101
+ <ScReferralTableList
102
+ userName={r.name}
103
+ userEmail={r.email}
104
+ onClick={() => openReferral(r)}
105
+ style={{ cursor: "pointer" }}
106
+ />
107
+
108
+ // Pending referral: pass an empty reward rather than a zero, so it doesn't read as green earnings
109
+ <ScReferralTableList userName={r.name} userEmail={r.email} status="Pending" points="" />
110
+
111
+ // Non-shrinking inside a scrolling settings column (the CSS omits flex-shrink: 0)
112
+ <ScReferralTableList className={styles.row} />
113
+ /* .row { flex-shrink: 0; align-self: stretch; } */
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 2. Where to use it
119
+
120
+ - **Settings → Referral → "Referral History"**, desktop, stacked under
121
+ `<ScReferralTableHeader />`. That screen lives in the shared `@streamoid/settings`
122
+ package (which ships into CXO desktop settings), and the history block there is
123
+ currently **commented out** — see "In the wild".
124
+ - Mobile uses `ScReferralCardMobile` instead; there is no header strip on mobile.
125
+ - It composes `ScProfile` (identity cell) and `ScBadges` (status chip). Those are the
126
+ two pieces to reuse if you outgrow the row.
127
+
128
+ ---
129
+
130
+ ## 3. When to use it
131
+
132
+ ### Use it when
133
+
134
+ - You have referral entries whose only display data is name, email, date, a status word
135
+ and a reward figure.
136
+ - You want the row to line up with `ScReferralTableHeader` without copying widths.
137
+
138
+ ### Don't use it — reach for this instead
139
+
140
+ | Situation | Use instead |
141
+ |---|---|
142
+ | Members / invites row (Role, Access, Invited by, pending actions) | Your own row under `ScTableHeader`; `ScTableList` only if placeholder content is acceptable |
143
+ | Mobile referral entry | `ScReferralCardMobile` |
144
+ | Invoice row with a download action | `ScBillingHistoryTableList` |
145
+ | Credit & usage log row (App / Activity / Used by / Date / Credits used / Balance) | `ScBillingLogsTableList` |
146
+ | Catalogix stores row | `ScCatalogixStoreTableList` |
147
+ | A **colour-coded** status chip (success / warning / error / info) | `ScBadges` directly, with `variant` and `styleVariant` — this row won't pass them through |
148
+ | A real avatar in the identity cell | `ScProfile` directly, with `profileImage` |
149
+ | A reward that can be negative or neutral | Compose the cell yourself; this one is hardcoded green |
150
+
151
+ ### Don't confuse with
152
+
153
+ | You may actually want | Not this |
154
+ |---|---|
155
+ | `ScTableList` — the **members** row: `ScRole` + access icons + `variant="active" \| "pending"` + `hover` + `onRowClick` | `ScReferralTableList` is four columns, no variants, no `onRowClick` (plain `onClick` works) |
156
+ | `ScReferralTableHeader` — the header strip above it | Different component; pair them |
157
+ | `ScReferralCardMobile` — the mobile card for the same data | Not a table row |
158
+ | `ScBadges` — the standalone chip, with real `variant` colours | This row renders one internally and gives it only `text` |
159
+ | `ScBillingHistoryTableList` — also a four-cell settings row, but Invoice / Amount / Date / Download | Different widths; not interchangeable |
160
+
161
+ Note the naming asymmetry with the members pair: this row has a **`userName`** prop
162
+ (`ScTableList` does not) but **no `onRowClick`** (`ScTableList` does). Don't copy prop
163
+ names between the two.
164
+
165
+ ---
166
+
167
+ ## 4. Why to use it
168
+
169
+ - **It is the alignment contract's other half.** `flex:1 / 7.5rem / 5rem / 7.5rem`,
170
+ `gap: 1.5rem`, `padding: 1.25rem 1rem` and the 1px `--alias-border-subtle` bottom rule
171
+ match `ScReferralTableHeader` exactly. Copy them if you hand-roll.
172
+ - **The identity cell truncates correctly.** `ScProfile` is overridden to `flex: 1;
173
+ width: unset`, and both its lines ellipsise, so a long email can't push the reward
174
+ column off-screen.
175
+ - **Everything is tokenised** — the row rule, the badge surface and the success green all
176
+ come from `--alias-*`, so the row survives the light/dark flip (unlike the mobile
177
+ family, whose text tokens are misnamed).
178
+ - **Props spread cleanly.** There is no internal `onClick` fighting yours, which is the
179
+ single biggest trap in `ScTableList`.
180
+
181
+ ---
182
+
183
+ ## Gotchas
184
+
185
+ **1. `userName` has no default *here*, so `ScProfile`'s default leaks.** Omit it and
186
+ every row is labelled "Chris Hemsworth". (Passing `userName=""` does render an empty
187
+ line — defaults only apply to `undefined`.)
188
+
189
+ ```tsx
190
+ // WRONG — renders "Chris Hemsworth" above every email
191
+ <ScReferralTableList userEmail={r.email} date={r.date} status={r.status} points={r.points} />
192
+
193
+ // RIGHT
194
+ <ScReferralTableList userName={r.name} userEmail={r.email} date={r.date} status={r.status} points={r.points} />
195
+ ```
196
+
197
+ **2. The avatar is a broken image.** `ScProfile`'s `profileImage` default is the relative
198
+ path `"profile-image0.png"`, resolved against the current route, and this row gives you
199
+ no way to override it — so you get a broken-image glyph (and the `<img>` has no `alt`).
200
+ If the avatar matters, compose the identity cell from `ScProfile` yourself.
201
+
202
+ **3. The status chip has no colour semantics.** `ScBadges` is rendered as
203
+ `<ScBadges text={status} />`, so `variant` stays `"default"` and `styleVariant` stays
204
+ `"solid"` — every status is the same `--alias-fill-neutral-neutralactive` grey chip with
205
+ primary text. There is no `statusVariant` prop.
206
+
207
+ ```tsx
208
+ // WRONG — expecting a green "Confirmed" / amber "Pending"
209
+ <ScReferralTableList status="Confirmed" /> // renders neutral grey either way
210
+
211
+ // RIGHT — if the colour is load-bearing, build the cell yourself
212
+ <div style={{ display: "flex", alignItems: "center", gap: "1.5rem", padding: "1.25rem 1rem" }}>
213
+ <ScProfile name={r.name} subText={r.email} style={{ flex: 1 }} />
214
+ <div style={{ width: "7.5rem" }}>{r.date}</div>
215
+ {/* ScBadges takes className only — no style, no props spread — so size it with a class */}
216
+ <ScBadges text={r.status} variant={r.status === "Confirmed" ? "success" : "warning"}
217
+ styleVariant="opaque" className={styles.statusCell} />
218
+ <div style={{ width: "7.5rem" }}>{r.points}</div>
219
+ </div>
220
+ ```
221
+
222
+ **4. The reward is always success green.** `.points` hardcodes
223
+ `--alias-text-and-icons-success`, so `"0"`, `"—"` or `"- 500"` all render as earnings.
224
+ Pass an empty string for "nothing yet" rather than a zero.
225
+
226
+ **5. All five props default to demo data.** `"chris@kepler.com"`, `"Nov 9th, 2025"`,
227
+ `"Confirmed"`, `"+ 500"` — so a typo'd prop name renders plausible fake data instead of
228
+ failing. Check spelling against the props table.
229
+
230
+ **6. It formats nothing.** `date` and `points` are printed verbatim; supply the
231
+ formatted string, including the `+`/`-` sign.
232
+
233
+ **7. It omits `flex-shrink: 0` and `align-self: stretch`.** `ScTableList` sets both; this
234
+ row does not. Inside a constrained `flex-direction: column` container (a fixed-height,
235
+ `overflow-y: auto` settings panel) rows can be compressed toward zero height. Add both
236
+ via `className` when you drop them into a scrolling column.
237
+
238
+ **8. Every row draws a bottom border, including the last one.** Suppress it on the final
239
+ row via `className` if your container already has a border.
240
+
241
+ **9. Cells truncate with no tooltip.** DATE and REWARD are fixed-width, `nowrap`,
242
+ `overflow: hidden`, `text-overflow: ellipsis`, with **no `title` attribute**. The status
243
+ badge behaves differently: the row forces it to `width: 5rem`, but `ScBadges` sets no
244
+ `nowrap`, no `overflow: hidden` and no ellipsis — so a long status word **wraps onto a
245
+ second line and grows the chip taller**, rather than truncating. Keep `status` to one
246
+ short word.
247
+
248
+ **10. Not a table row.** No `role="row"`/`cell`, no `<td>`. Cells are not associated with
249
+ `ScReferralTableHeader`'s labels for assistive tech.
250
+
251
+ **11. `className` lands as the literal string `"undefined"` when omitted** — the class
252
+ list is built by concatenation. Harmless in the browser; breaks exact-string class
253
+ assertions in tests.
254
+
255
+ ---
256
+
257
+ ## In the wild
258
+
259
+ _No host render site found — used by the agent runtime / composed internally._
260
+
261
+ More precisely: **the only integration that exists is commented out.** In the shared
262
+ settings package the Referral History block — header plus this row loop — sits inside a
263
+ `{/* Referral History section commented out … */}` comment:
264
+
265
+ ```tsx
266
+ // npm-components packages/settings/src/settings-content.tsx:1013 (inside a commented-out block)
267
+ <ScReferralTableList
268
+ key={ref.id}
269
+ userEmail={ref.email}
270
+ date={ref.date}
271
+ status={ref.status}
272
+ points={ref.points}
273
+ />
274
+ ```
275
+
276
+ Note that the parked call site omits `userName` — Gotcha 1 — so uncommenting it as-is
277
+ would ship "Chris Hemsworth" on every row, against a local `REFERRALS` demo array.
278
+
279
+ Where it belongs: **Settings → Referral**, desktop, under `<ScReferralTableHeader />`
280
+ and the "Referral History" label. CXO reaches that screen through `@streamoid/settings`,
281
+ so no CXO-side change is needed.
282
+
283
+ ---
284
+
285
+ ## Related
286
+
287
+ - `ScReferralTableHeader` — the header strip that defines this row's widths; always
288
+ render it above.
289
+ - `ScProfile` — the identity cell; use it directly when you need a real avatar.
290
+ - `ScBadges` — the status chip; use it directly when the status needs a colour.
291
+ - `ScReferralCardMobile` — the mobile form of the same data.
292
+ - `ScTableList` / `ScBillingHistoryTableList` / `ScBillingLogsTableList` /
293
+ `ScCatalogixStoreTableList` — the other domain rows, same header+row pattern.
@@ -0,0 +1,226 @@
1
+ ---
2
+ component: ScRole
3
+ package: "@streamoid/ui"
4
+ category: profile
5
+ status: stable
6
+ renders: div
7
+ tags: [role, admin, member, permission, pill, badge, team, chip]
8
+ related: [ScRoleMobile, ScBadges, ScAccess, ScTableList, ScWorkspaceSwitchCard]
9
+ do_not_confuse_with: [ScBadges, ScRoleMobile, ScAccess, ScSelectionPill, ScTaxonomyPill]
10
+ used_by: [cxo]
11
+ ---
12
+
13
+ # ScRole
14
+
15
+ **The admin/member role pill.** A fixed 80 × 40 chip: blue (`fill-info-soft` +
16
+ `border-info` + `text-and-icons-infocont`) for `admin`, neutral grey for `member`.
17
+ Two types, one optional label override, nothing else. It is a **display** chip — it
18
+ is not a picker and it does not select anything.
19
+
20
+ ## TL;DR for agents
21
+
22
+ - **Reach for it when:** you are showing someone's role in a team table or workspace
23
+ row and want the standard admin-vs-member colour coding.
24
+ - **Don't reach for it when:** you need an arbitrary status chip (→ `ScBadges`), a
25
+ per-capability permission row (→ `ScAccess`), a role *picker* (→ `ScSelect` /
26
+ `ScTabField`), or the mobile chip (→ `ScRoleMobile`).
27
+ - **Four things that will bite you:**
28
+ 1. `type` defaults to **`"admin"`** — the blue one. Forget it and everyone is an
29
+ admin.
30
+ 2. The box is a **hardcoded 5rem × 2.5rem** (80 × 40) with `justify-content: center`
31
+ and no `overflow` guard. A `label` longer than ~"Member" overflows the pill.
32
+ 3. `label` is optional and derived from `type` — but only for the two known types.
33
+ 4. Only `"admin"` and `"member"` have styles. Any other string falls through to the
34
+ base (**admin-blue**) skin.
35
+
36
+ ---
37
+
38
+ ## 1. How to use it
39
+
40
+ ### Import
41
+
42
+ ```tsx
43
+ import { ScRole } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+ ```
46
+
47
+ ### Minimal usage
48
+
49
+ ```tsx
50
+ <ScRole type="member" />
51
+ ```
52
+
53
+ ### Props
54
+
55
+ | Prop | Type | Default | Notes |
56
+ |---|---|---|---|
57
+ | `type` | `"admin"` \| `"member"` | `"admin"` | ⚠️ Real default, and it is the **blue admin** skin. Drives colour **and** the derived label. |
58
+ | `label` | `string` | `type === "admin" ? "Admin" : "Member"` | Visible text. Falls back via `??`, so `label=""` renders an **empty pill** (empty string is not nullish). |
59
+ | `className` | `string` | – | Appended (concatenated unconditionally — a literal `undefined` class when omitted). |
60
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | `style`, `onClick`, `title`, `aria-*`, `data-*` spread onto the root div. No button semantics. |
61
+
62
+ ### What each `type` renders
63
+
64
+ | `type` | Background | Border | Text |
65
+ |---|---|---|---|
66
+ | `"admin"` (base rule) | `--alias-fill-info-soft` | `--alias-border-info` | `--alias-text-and-icons-infocont` |
67
+ | `"member"` | `--alias-fill-neutral-neutral` | `--alias-border-strong` | `--alias-text-and-icons-tertiary` |
68
+
69
+ Both are `text-xs/regular`, `radius-xl`, 1px border, `0.5rem 0.75rem` padding, and
70
+ the box is fixed at 80 × 40 regardless.
71
+
72
+ ### Recipes
73
+
74
+ ```tsx
75
+ // Team table row (the standard host idiom)
76
+ <ScRole
77
+ type={member.permissions.role} // typed "admin" | "member"
78
+ label={member.permissions.role === "admin" ? "Admin" : "Member"}
79
+ className="shrink-0"
80
+ />
81
+
82
+ // Normalising an untyped role string from an API
83
+ const role = raw === "admin" ? "admin" : "member";
84
+ <ScRole type={role} />
85
+
86
+ // Wider pill for a longer label — the 80px is a class rule, so inline style wins
87
+ <ScRole type="member" label="Contributor" style={{ width: "auto", minWidth: "5rem" }} />
88
+ ```
89
+
90
+ ---
91
+
92
+ ## 2. Where to use it
93
+
94
+ - **Team / member tables** — CXO's Teams screen and the shared
95
+ `@streamoid/settings` Teams + Organization tabs render one per row.
96
+ - **`ScTableList`** composes one internally (with **no props**, so it shows the
97
+ default "Admin" — see Gotcha 5).
98
+ - **Workspace rows in the switch modal** — `StreamoidWorkspaceSwitcher` renders it
99
+ with an explicit `style={{ width: 80 }}`.
100
+
101
+ Its mobile twin `ScRoleMobile` covers the responsive surface.
102
+
103
+ ---
104
+
105
+ ## 3. When to use it
106
+
107
+ ### Use it when
108
+
109
+ - The value is genuinely the admin/member distinction and you want the product-wide
110
+ blue/grey coding.
111
+ - The chip sits in a fixed-width table column — the hardcoded 80px is a feature there.
112
+
113
+ ### Don't use it — reach for this instead
114
+
115
+ | Situation | Use instead |
116
+ |---|---|
117
+ | Any other status, count or tag chip | `ScBadges` (`variant` default/success/warning/error/info, `styleVariant` solid/opaque) |
118
+ | Per-capability permission display (read/write per module) | `ScAccess` |
119
+ | **Choosing** a role in a form | `ScSelect`, `ScTabField` or `ScRadio` — this chip has no selected state |
120
+ | A segmented filter the user clicks | `ScSelectionPill` / `ScSelectionPillGroup` |
121
+ | A taxonomy/tree node chip | `ScTaxonomyPill` |
122
+ | The mobile role chip | `ScRoleMobile` |
123
+ | A role line inside an identity row | `ScWorkspace`'s `userRole` (plain tertiary text, no pill) or `ScWorkspaceSwitchCard`'s `role` |
124
+
125
+ ### Don't confuse with
126
+
127
+ | You may actually want | Not this |
128
+ |---|---|
129
+ | `ScBadges` — free `text` + 5 semantic variants + solid/opaque, width fits content | `ScRole` is role-only with a fixed 80px box |
130
+ | `ScRoleMobile` — the mobile twin; prop is **`role`**, not `type`, and it takes no `label` | different prop names; don't swap blindly |
131
+ | `ScAccess` — permission/capability row | `ScRole` is one summary chip |
132
+ | `ScSelectionPill` — interactive segmented pill with `aria-pressed` | `ScRole` is not interactive |
133
+
134
+ Note the prop-name trap across the family: **`ScRole` uses `type`**,
135
+ **`ScRoleMobile` uses `role`**, and **`ScWorkspaceSwitchCard` / `ScWorkspaceCard` use
136
+ `role` as a free string**.
137
+
138
+ ---
139
+
140
+ ## 4. Why to use it
141
+
142
+ - **The two skins are a tokenised pair.** Admin uses the full info triplet
143
+ (`fill-info-soft` / `border-info` / `text-and-icons-infocont`) and member the
144
+ neutral triplet, so both stay legible in light and dark. A hand-rolled blue chip is
145
+ a classic light-mode contrast failure.
146
+ - **Role colour means one thing everywhere.** Admin = info blue across CXO's teams
147
+ table, the settings package and the workspace modal. (Note `ScWorkspaceSwitchCard`
148
+ deliberately breaks this: it paints admin **warning-amber** and member info-blue.)
149
+ - **Fixed geometry keeps table columns aligned** without a width prop at every call
150
+ site.
151
+ - **Label override without losing the skin** — `label` lets you localise or relabel
152
+ ("Owner") while keeping the admin colours.
153
+
154
+ ---
155
+
156
+ ## Gotchas
157
+
158
+ **1. `type` defaults to `"admin"`.** The base CSS rule *is* the admin skin, so
159
+ omitting `type` paints a blue "Admin" pill.
160
+
161
+ ```tsx
162
+ // WRONG — everyone is an Admin
163
+ <ScRole />
164
+
165
+ // RIGHT
166
+ <ScRole type={member.role} />
167
+ ```
168
+
169
+ **2. Unknown `type` values silently render as admin.** `styles["type-" + type]`
170
+ resolves to `undefined` for anything else, leaving only the base rule.
171
+
172
+ ```tsx
173
+ // WRONG — "owner" is a type error; cast past it and you get the blue admin skin
174
+ <ScRole type={"owner" as "admin"} />
175
+
176
+ // RIGHT — normalise first, relabel with `label`
177
+ <ScRole type="admin" label="Owner" />
178
+ ```
179
+
180
+ **3. The pill is a hardcoded 80 × 40 with no overflow guard.** `.scRole` sets
181
+ `width: 5rem; height: 2.5rem` and `.role` has no `overflow`/`ellipsis`. A long
182
+ `label` spills outside the border. Override `width` inline if you must relabel.
183
+
184
+ **4. `label=""` renders an empty pill.** The fallback is `label ?? derived`, and `""`
185
+ is not nullish. Pass `undefined` to get the derived label.
186
+
187
+ **5. `ScTableList` renders `<ScRole />` with no props** — every row of that table
188
+ shows "Admin" until the row component is given a role prop. If you are using
189
+ `ScTableList` for a real member list, this is a DS gap to raise, not something you can
190
+ fix from the call site.
191
+
192
+ **6. It is a `<div>` with props spread.** `onClick` fires but there is no `role`,
193
+ `tabIndex`, keyboard activation or focus ring. It is not a picker; don't make it one.
194
+
195
+ **7. Trailing space in the text node** (`{displayLabel} `) — `trim()` before
196
+ asserting.
197
+
198
+ **8. `className` is concatenated unconditionally** → `class="scRole undefined type-admin"`.
199
+
200
+ ---
201
+
202
+ ## In the wild
203
+
204
+ ```tsx
205
+ // cxo-dashboard src/app/components/teams-content.tsx:604
206
+ <ScRole
207
+ type={member.permissions.role}
208
+ label={member.permissions.role === "admin" ? "Admin" : "Member"}
209
+ className="shrink-0"
210
+ />
211
+ ```
212
+
213
+ The same call exists in the shared settings package
214
+ (`packages/settings/src/teams-content.tsx:588` and
215
+ `packages/settings/src/organization-content.tsx:172`), which is what CXO's desktop
216
+ Settings actually renders.
217
+
218
+ ---
219
+
220
+ ## Related
221
+
222
+ - `ScRoleMobile` — the mobile twin (prop is `role`, no `label`).
223
+ - `ScBadges` — the general-purpose chip for anything that is not a role.
224
+ - `ScAccess` — per-capability permission row.
225
+ - `ScTableList` / `ScTableHeader` — the team table this chip lives in.
226
+ - `ScWorkspaceSwitchCard` — shows a role too, but as coloured text (admin = amber), not this pill.