@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,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.
|