@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,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScPopUpMenu
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: overlays
|
|
5
|
+
status: legacy
|
|
6
|
+
tags: [menu, menu-row, popup, kebab, context-menu, option, legacy]
|
|
7
|
+
renders: div
|
|
8
|
+
related: [ScMenuOptions, ScProfilePopup, ScProfileOptions, ScModal]
|
|
9
|
+
do_not_confuse_with: [ScMenuOptions, ScProfilePopup, ScModal, ScInfoPopup]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ScPopUpMenu
|
|
13
|
+
|
|
14
|
+
**A single 242px-wide menu *row* — despite the name, not a popup and not a menu.**
|
|
15
|
+
It renders one `<div>` with an optional icon and a label, plus a `state="clicked"`
|
|
16
|
+
background flag. It creates no overlay, no list, no positioning and no dismissal.
|
|
17
|
+
|
|
18
|
+
> **status: legacy.** `ScMenuOptions` is the row every app actually renders (CXO,
|
|
19
|
+
> Photogenix, Artifax, and `ScProfilePopup`/`ScProfileOptions` internally), and it
|
|
20
|
+
> has hover states, an `error` variant, a version slot and a props spread that this
|
|
21
|
+
> one lacks. `ScPopUpMenu` has **no call site anywhere** — host repos or DS
|
|
22
|
+
> internals. **Use `ScMenuOptions`.** It is documented here only so an agent that
|
|
23
|
+
> greps the name is redirected instead of adopting it.
|
|
24
|
+
|
|
25
|
+
## TL;DR for agents
|
|
26
|
+
|
|
27
|
+
- **Reach for it when:** never, in new code.
|
|
28
|
+
- **Reach for this instead:** `ScMenuOptions` for the row, `ScProfilePopup` /
|
|
29
|
+
`ScProfileOptions` for the panel that contains the rows, `ScModal` / `ScDrawer`
|
|
30
|
+
if you actually wanted an overlay.
|
|
31
|
+
- **Three things that will bite you:**
|
|
32
|
+
1. The name promises a popover. There is none — this is one row of chrome.
|
|
33
|
+
2. The label prop is `menu`, not `text` or `label`, and it defaults to
|
|
34
|
+
`"Options"` ⚠️.
|
|
35
|
+
3. There is **no `:hover` rule in its CSS at all.** The row gives zero pointer
|
|
36
|
+
feedback unless you drive `state="clicked"` yourself.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 1. How to use it
|
|
41
|
+
|
|
42
|
+
### Import
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { ScPopUpMenu } from "@streamoid/ui";
|
|
46
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Minimal usage
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
<ScPopUpMenu menu="Duplicate" icon={<SiconCopy size={24} />} onClick={duplicate} />
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The `ScMenuOptions` equivalent, which is what you should ship:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
<ScMenuOptions
|
|
59
|
+
text="Duplicate"
|
|
60
|
+
icon={<SiconCopy size={24} />}
|
|
61
|
+
variant="default"
|
|
62
|
+
style={{ width: "100%", cursor: "pointer" }}
|
|
63
|
+
role="button"
|
|
64
|
+
tabIndex={0}
|
|
65
|
+
onClick={duplicate}
|
|
66
|
+
/>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Props
|
|
70
|
+
|
|
71
|
+
| Prop | Type | Default | Notes |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| `menu` | `string` | `"Options"` | ⚠️ The label — note the prop name, and the real default. `ScMenuOptions` calls the same thing `text`. |
|
|
74
|
+
| `state` | `"default"` \| `"clicked"` | `"default"` | `"clicked"` paints `--alias-surface-canvas` behind the row. Purely a style flag — the component never sets it itself. |
|
|
75
|
+
| `icon` | `JSX.Element` | – | No default (unlike `ScMenuOptions`, which defaults to `SiconTeam`). Rendered in a 24×24 `flex-shrink: 0` box **only when truthy** — no reserved gutter when absent. |
|
|
76
|
+
| `onClick` | `(e: React.MouseEvent) => void` | – | Plain click on the root `<div>`. |
|
|
77
|
+
| `className` | `string` | – | Concatenated unconditionally — see Gotcha 4. |
|
|
78
|
+
| `...props` | `HTMLAttributes<HTMLDivElement>` | – | Spread onto the root div (`style`, `role`, `tabIndex`, `data-*`, `aria-*`, `onKeyDown`). |
|
|
79
|
+
|
|
80
|
+
### What it actually renders
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<div class="scPopUpMenu state-default {className}">
|
|
84
|
+
<!-- width:242px · display:flex · gap:12px · padding:12px 4px · radius:8px · cursor:pointer -->
|
|
85
|
+
<span class="icon">{icon}</span> <!-- only when icon is truthy; 24×24 -->
|
|
86
|
+
<p class="menuText">{menu}</p> <!-- 16px/24 medium; --alias-text-and-icons-secondary; nowrap -->
|
|
87
|
+
</div>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 2. Where to use it
|
|
93
|
+
|
|
94
|
+
Nowhere new. The surfaces it was drawn for are all served by other parts:
|
|
95
|
+
|
|
96
|
+
| Surface | What actually ships there |
|
|
97
|
+
|---|---|
|
|
98
|
+
| Profile / account flyout rows | `ScMenuOptions` inside `ScProfilePopup` (CXO `profile-popup.tsx`, Artifax `DashboardSidebar.tsx`) |
|
|
99
|
+
| Sidebar settings rows (Teams / Billing / Settings / What's new) | `ScMenuOptions` (`variant="with-v"` for the version row) |
|
|
100
|
+
| Kebab / row-overflow menus | `ScMenuOptions` in an app-positioned container (Photogenix `studio/BatchList.tsx`) |
|
|
101
|
+
| The container/overlay itself | `ScProfilePopup` (panel body), or `ScModal` / `ScDrawer` |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 3. When to use it
|
|
106
|
+
|
|
107
|
+
### Use it when
|
|
108
|
+
|
|
109
|
+
- Never in new code. If you are maintaining something that already imports it,
|
|
110
|
+
migrating to `ScMenuOptions` is a rename of `menu` → `text` plus dropping
|
|
111
|
+
`state` (real `:hover` replaces it).
|
|
112
|
+
|
|
113
|
+
### Don't use it — reach for this instead
|
|
114
|
+
|
|
115
|
+
| Situation | Use instead |
|
|
116
|
+
|---|---|
|
|
117
|
+
| A row in any menu, flyout or sidebar list | `ScMenuOptions` |
|
|
118
|
+
| The profile/account flyout panel itself | `ScProfilePopup` (body only) or `ScProfileOptions` |
|
|
119
|
+
| An actual popover/overlay container | `ScModal` (centered) or `ScDrawer` (edge) |
|
|
120
|
+
| A contextual help bubble | `ScInfoPopup` — the only thing here that really pops up |
|
|
121
|
+
| A destructive row ("Delete", "Log out") | `ScMenuOptions variant="error"` (this component has no error variant) |
|
|
122
|
+
| A row that needs a trailing version/meta string | `ScMenuOptions variant="with-v"` + `version` |
|
|
123
|
+
| A button | `ScButton` |
|
|
124
|
+
|
|
125
|
+
### Don't confuse with
|
|
126
|
+
|
|
127
|
+
| You may actually want | Not this |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `ScMenuOptions` — the current menu row: hover fills, `error` variant, `with-v` version slot, 200px wide, `text` prop | `ScPopUpMenu` — 242px, no hover, no variants, `menu` prop |
|
|
130
|
+
| `ScProfilePopup` — the panel that holds menu rows | `ScPopUpMenu` holds nothing |
|
|
131
|
+
| `ScInfoPopup` — an actual click-to-open popover | `ScPopUpMenu` never opens anything |
|
|
132
|
+
| `ScModal` / `ScDrawer` — the overlay primitives | `ScPopUpMenu` renders no overlay |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 4. Why to use it
|
|
137
|
+
|
|
138
|
+
You shouldn't. What you'd be giving up by picking it over `ScMenuOptions`:
|
|
139
|
+
|
|
140
|
+
- **Hover feedback.** `ScMenuOptions` has real `:hover` fills
|
|
141
|
+
(`--alias-fill-neutral-neutralhover`, and `--alias-fill-error-secondary` for the
|
|
142
|
+
error variant). `ScPopUpMenu.module.css` contains no `:hover` rule, so the row is
|
|
143
|
+
inert under the pointer.
|
|
144
|
+
- **Semantic variants.** No `error` colouring, no version/meta slot.
|
|
145
|
+
- **Truncation.** `ScMenuOptions`'s label is `flex: 1` with
|
|
146
|
+
`text-overflow: ellipsis`; this one is `white-space: nowrap` with no ellipsis and
|
|
147
|
+
no flex, so a long label overflows the fixed 242px box.
|
|
148
|
+
- **Battle-tested defaults.** Every app already passes the same
|
|
149
|
+
`style={{ width: "100%", cursor: "pointer" }}` to `ScMenuOptions`; that idiom, and
|
|
150
|
+
the Enter/Space `onKeyDown` helper in `ScProfilePopup`, exist for the row that is
|
|
151
|
+
actually in use.
|
|
152
|
+
|
|
153
|
+
Both use `--alias-*` tokens, so theme correctness is not the differentiator — reach
|
|
154
|
+
is.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Gotchas
|
|
159
|
+
|
|
160
|
+
**1. The name is wrong.** It is a row, not a popup and not a menu. It has no
|
|
161
|
+
`open`, no anchor, no portal, no outside-click. If you were looking for the thing
|
|
162
|
+
that pops up, you want `ScProfilePopup` (panel), `ScModal` / `ScDrawer` (overlay),
|
|
163
|
+
or `ScInfoPopup` (bubble).
|
|
164
|
+
|
|
165
|
+
**2. `menu` defaults to `"Options"`.** Forget the prop — or reach for `text` out of
|
|
166
|
+
`ScMenuOptions` habit — and the row silently reads "Options".
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
// WRONG — `text` is not a prop here; renders "Options"
|
|
170
|
+
<ScPopUpMenu text="Duplicate" />
|
|
171
|
+
|
|
172
|
+
// RIGHT (but prefer ScMenuOptions)
|
|
173
|
+
<ScPopUpMenu menu="Duplicate" />
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**3. No hover styling exists.** `.state-default` is `background: transparent` and
|
|
177
|
+
there is no `:hover` selector, so `state="clicked"` is the only way to show any
|
|
178
|
+
fill — and you have to drive it from your own state.
|
|
179
|
+
|
|
180
|
+
**4. `className` is concatenated unconditionally.** The class attribute becomes
|
|
181
|
+
`scPopUpMenu state-default undefined` when you omit it. Harmless in the browser,
|
|
182
|
+
but it shows up in the DOM and breaks exact-match snapshot tests.
|
|
183
|
+
|
|
184
|
+
**5. Fixed `width: 242px`.** Not responsive, and different from `ScMenuOptions`'
|
|
185
|
+
200px — mixing the two in one list gives you two row widths. Override via `style`.
|
|
186
|
+
|
|
187
|
+
**6. Asymmetric padding: `12px 4px`.** 12px vertical, 4px horizontal, so any
|
|
188
|
+
background you paint via `state="clicked"` hugs the text almost edge-to-edge.
|
|
189
|
+
|
|
190
|
+
**7. `icon` has no reserved gutter.** When `icon` is falsy the 24px box is not
|
|
191
|
+
rendered at all, so labels in a mixed list of rows with and without icons do not
|
|
192
|
+
line up. Pass a spacer element if you need alignment.
|
|
193
|
+
|
|
194
|
+
**8. Plain `<div>` with `onClick` — no a11y.** No `role`, no `tabIndex`, no
|
|
195
|
+
keyboard activation. Add `role="menuitem" tabIndex={0}` plus an Enter/Space
|
|
196
|
+
`onKeyDown` via the spread (this is exactly what `ScProfilePopup` does for its
|
|
197
|
+
`ScMenuOptions` rows).
|
|
198
|
+
|
|
199
|
+
**9. `icon` is rendered raw.** No `cloneElement`, no size normalisation, no
|
|
200
|
+
`currentColor` — unlike `ScButton`, your icon keeps its own size and colour, and it
|
|
201
|
+
will not track the label's `--alias-text-and-icons-secondary`.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## In the wild
|
|
206
|
+
|
|
207
|
+
_No host render site found — used by the agent runtime / composed internally._
|
|
208
|
+
|
|
209
|
+
To be precise: it is used by **nothing** — not the four host dashboards, not the
|
|
210
|
+
chat/agent runtime, and not any other component in `packages/ui`. Every surface it
|
|
211
|
+
looks like it belongs to (profile flyout rows, sidebar settings rows, kebab menus)
|
|
212
|
+
already ships `ScMenuOptions` instead — see
|
|
213
|
+
`cxo-dashboard/src/app/components/profile-popup.tsx:298` and
|
|
214
|
+
`artifax/packages/shared/src/components/DashboardSidebar.tsx:927`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Related
|
|
219
|
+
|
|
220
|
+
- `ScMenuOptions` — **the replacement.** Same job, hover states, `error`/`with-v` variants, and it is what all four apps render.
|
|
221
|
+
- `ScProfilePopup` — the profile flyout panel body that hosts menu rows.
|
|
222
|
+
- `ScProfileOptions` — the older profile-options block, also built from `ScMenuOptions`.
|
|
223
|
+
- `ScModal` / `ScDrawer` — the real overlay primitives.
|
|
224
|
+
- `ScInfoPopup` — the only component in this category that actually opens a popover.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScProfile
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: profile
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [profile, identity, avatar-with-name, name-subtext, sidebar-footer, user-row]
|
|
8
|
+
related: [ScWorkspace, ScProfilePopup, ScDp, ScProfileV2Mobile, ScSidebarProfile]
|
|
9
|
+
do_not_confuse_with: [ScWorkspace, ScProfileOptions, ScProfilePopup, ScProfileSettingsComp, ScProfileV2Mobile]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ScProfile
|
|
13
|
+
|
|
14
|
+
**The person identity row: circular avatar + name + one grey sub-line.** 200px wide,
|
|
15
|
+
two ellipsised text lines, and a `collapsed` variant that drops the text and shrinks
|
|
16
|
+
the avatar to 32px. It is a presentation row — it owns no menu, no click behaviour
|
|
17
|
+
and no state.
|
|
18
|
+
|
|
19
|
+
## TL;DR for agents
|
|
20
|
+
|
|
21
|
+
- **Reach for it when:** you need "avatar, name, second line" as one unit inside a
|
|
22
|
+
DS composite you are building.
|
|
23
|
+
- **Don't reach for it when:** you want the whole profile menu (→ `ScProfilePopup`),
|
|
24
|
+
a **workspace** identity row (→ `ScWorkspace`), the mobile profile block
|
|
25
|
+
(→ `ScProfileV2Mobile`), or just the avatar (→ `ScDp`).
|
|
26
|
+
- **Four things that will bite you:**
|
|
27
|
+
1. `profileImage` defaults to the literal string **`"profile-image0.png"`** — a
|
|
28
|
+
relative path that 404s and renders a broken-image glyph. There is no initials
|
|
29
|
+
fallback anywhere in this component.
|
|
30
|
+
2. `collapsed` is the **string** `"false" | "true"`, not a boolean.
|
|
31
|
+
3. Defaults are placeholder identity: **"Chris Hemsworth" / "Kepler workspace"**.
|
|
32
|
+
4. `className` is concatenated unconditionally, so omitting it puts the literal
|
|
33
|
+
class `undefined` on the root. Harmless, but it shows up in snapshots.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. How to use it
|
|
38
|
+
|
|
39
|
+
### Import
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { ScProfile } from "@streamoid/ui";
|
|
43
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Minimal usage
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<ScProfile name={user.name} subText={user.email} profileImage={user.avatarUrl} />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Props
|
|
53
|
+
|
|
54
|
+
| Prop | Type | Default | Notes |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| `name` | `string` | `"Chris Hemsworth"` | ⚠️ Real default. First line, `text-sm/medium`, single line + ellipsis. |
|
|
57
|
+
| `subText` | `string` | `"Kepler workspace"` | ⚠️ Real default. Second line, `text-xs/regular`, tertiary colour. `ScProfilePopup` feeds the **email** here. |
|
|
58
|
+
| `collapsed` | `"false"` \| `"true"` | `"false"` | ⚠️ A **string** union, not a boolean. `"true"` hides both text lines and shrinks the avatar 40px → 32px. |
|
|
59
|
+
| `profileImage` | `string` | `"profile-image0.png"` | ⚠️ Real default that resolves relative to the page and 404s. Always pass a real URL. |
|
|
60
|
+
| `className` | `string` | – | Appended (see Gotcha 4). |
|
|
61
|
+
| `...props` | `HTMLAttributes<HTMLDivElement>` | – | `onClick`, `style`, `aria-*`, `data-*` are spread onto the root div — but you get **no** button semantics. |
|
|
62
|
+
|
|
63
|
+
### What renders in each `collapsed` value
|
|
64
|
+
|
|
65
|
+
| Region | `"false"` | `"true"` |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| Root width | fixed `12.5rem` (200px) | `width: unset` — shrinks to the avatar |
|
|
68
|
+
| Avatar | 2.5rem circle | 2rem circle |
|
|
69
|
+
| `name` / `subText` | rendered | **not rendered at all** |
|
|
70
|
+
|
|
71
|
+
### Recipes
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
// Sidebar footer identity, driven by the shell's collapse state
|
|
75
|
+
<ScProfile
|
|
76
|
+
name={user.name}
|
|
77
|
+
subText={user.email}
|
|
78
|
+
profileImage={user.avatarUrl ?? FALLBACK_AVATAR_URL}
|
|
79
|
+
collapsed={sidebarCollapsed ? "true" : "false"}
|
|
80
|
+
/>
|
|
81
|
+
|
|
82
|
+
// Full-width inside a flex column (it is 200px by default — override to stretch)
|
|
83
|
+
<ScProfile
|
|
84
|
+
name={member.name}
|
|
85
|
+
subText={member.email}
|
|
86
|
+
profileImage={member.avatarUrl}
|
|
87
|
+
style={{ flex: 1, width: "auto", minWidth: 0 }}
|
|
88
|
+
/>
|
|
89
|
+
|
|
90
|
+
// Interactive: give it real semantics yourself
|
|
91
|
+
<button type="button" onClick={openMenu} style={{ all: "unset", cursor: "pointer" }}>
|
|
92
|
+
<ScProfile name={user.name} subText={user.email} profileImage={user.avatarUrl} />
|
|
93
|
+
</button>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 2. Where to use it
|
|
99
|
+
|
|
100
|
+
Almost always **inside** another DS component rather than directly in a host screen.
|
|
101
|
+
It is composed by:
|
|
102
|
+
|
|
103
|
+
| Parent | Role |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `ScProfilePopup` | the panel header identity (name + email), avatar forced to 32px |
|
|
106
|
+
| `ScProfileOptions` | the legacy static profile menu header |
|
|
107
|
+
| `ScSidebarProfile` | the pre-`StreamoidSidebar` sidebar footer |
|
|
108
|
+
| `ScTableList` | the member cell of a team-table row |
|
|
109
|
+
| `ScReferralTableList` | the referred-user cell |
|
|
110
|
+
|
|
111
|
+
If you are building a host screen, you almost certainly want one of those parents.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 3. When to use it
|
|
116
|
+
|
|
117
|
+
### Use it when
|
|
118
|
+
|
|
119
|
+
- You are composing a **new DS component** that needs the standard person identity
|
|
120
|
+
row and want the type ramp, the 12px gap and the ellipsis behaviour for free.
|
|
121
|
+
- You need an expanded/collapsed identity pair that matches the sidebar shells.
|
|
122
|
+
|
|
123
|
+
### Don't use it — reach for this instead
|
|
124
|
+
|
|
125
|
+
| Situation | Use instead |
|
|
126
|
+
|---|---|
|
|
127
|
+
| The whole profile dropdown (identity + workspace + menu + theme) | `ScProfilePopup` |
|
|
128
|
+
| A **workspace** identity row (rounded-rect logo, name + role) | `ScWorkspace` — but it is **not exported**; use `ScProfilePopup`/`ScWorkspaceSwitchCard` |
|
|
129
|
+
| Mobile profile block with left/right avatar placement | `ScProfileV2Mobile` |
|
|
130
|
+
| Just the avatar, with an initials fallback | `ScDp` |
|
|
131
|
+
| Editable avatar with upload/delete | `ScProfileImageUpdate` |
|
|
132
|
+
| A team-table member row | `ScTableList` (it already renders a `ScProfile`) |
|
|
133
|
+
| The account settings form (first/last/email) | compose `ScProfileImageUpdate` + `ScTextField`; see `ScProfileSettingsComp` for why not that |
|
|
134
|
+
|
|
135
|
+
### Don't confuse with
|
|
136
|
+
|
|
137
|
+
| You may actually want | Not this |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `ScWorkspace` — same layout, **workspace** semantics: `workspaceName`/`userRole`, `radius-md` logo | `ScProfile` is the person: `name`/`subText`, circular avatar |
|
|
140
|
+
| `ScProfileOptions` — the legacy hardcoded menu panel (className-only API) | `ScProfile` is just the header row of it |
|
|
141
|
+
| `ScProfilePopup` — the current, fully-propped menu panel | `ScProfile` renders no menu |
|
|
142
|
+
| `ScProfileSettingsComp` — a static account-form scaffold | unrelated to this row |
|
|
143
|
+
| `ScProfileV2Mobile` — the mobile twin, `email` + `dpPosition` props | different prop names, mobile surface |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 4. Why to use it
|
|
148
|
+
|
|
149
|
+
- **The type ramp is the spec.** `text-sm/medium` over `text-xs/regular` with
|
|
150
|
+
`text-and-icons-primary` over `-tertiary` is the identity pattern used everywhere;
|
|
151
|
+
restating it by hand is how sidebars end up with mismatched name sizes.
|
|
152
|
+
- **Both lines already ellipsise.** `overflow: hidden` + `text-overflow: ellipsis` +
|
|
153
|
+
`nowrap` on each line, so long emails degrade instead of wrapping the row.
|
|
154
|
+
- **The collapsed variant is a single prop** and matches the sidebar's 40 → 32px
|
|
155
|
+
avatar step exactly.
|
|
156
|
+
- **One place to change.** Five DS parents render it, so the identity row stays
|
|
157
|
+
consistent across the popup, the sidebar footer and both tables.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Gotchas
|
|
162
|
+
|
|
163
|
+
**1. `profileImage` has a broken default.** `"profile-image0.png"` is a Figma export
|
|
164
|
+
artefact. With no `src` override you ship a broken-image icon — and there is **no
|
|
165
|
+
initials fallback** (that is `ScDp`, which this component does not use).
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
// WRONG — broken image glyph
|
|
169
|
+
<ScProfile name={user.name} subText={user.email} />
|
|
170
|
+
|
|
171
|
+
// RIGHT
|
|
172
|
+
<ScProfile name={user.name} subText={user.email} profileImage={user.avatarUrl ?? FALLBACK} />
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
This is why `ScProfilePopup` spreads `avatar` conditionally: pass no `avatar` to the
|
|
176
|
+
popup and this default leaks through.
|
|
177
|
+
|
|
178
|
+
**2. `collapsed` is a string.** `collapsed={true}` is a type error, and
|
|
179
|
+
`collapsed={String(isCollapsed)}` widens to `string`. Write the ternary.
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
// WRONG
|
|
183
|
+
<ScProfile collapsed={isCollapsed} />
|
|
184
|
+
|
|
185
|
+
// RIGHT
|
|
186
|
+
<ScProfile collapsed={isCollapsed ? "true" : "false"} />
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**3. It is 200px wide, always (expanded).** `.scProfile { width: 12.5rem }` is a
|
|
190
|
+
plain class rule. Inside a wider flex row it will not stretch — every DS parent
|
|
191
|
+
overrides it: `flex: 1 !important; width: unset !important` in `ScProfilePopup`
|
|
192
|
+
(plus `min-width: 0 !important`), `ScProfileOptions`, `ScTableList` and
|
|
193
|
+
`ScReferralTableList`; `align-self: stretch !important; width: unset !important` in
|
|
194
|
+
`ScSidebarProfile`. Do the same, or pass
|
|
195
|
+
`style={{ flex: 1, width: "auto", minWidth: 0 }}`.
|
|
196
|
+
|
|
197
|
+
**4. Unconditional `className` concatenation.** The root class string is
|
|
198
|
+
`` `${styles.scProfile} ${className} ${variantsClassName}` ``, so with no
|
|
199
|
+
`className` the DOM gets `class="scProfile undefined collapsed-false"`. Don't assert
|
|
200
|
+
on the exact class string in tests.
|
|
201
|
+
|
|
202
|
+
**5. The `<img>` has no `alt` attribute at all.** Not `alt=""` — absent. Screen
|
|
203
|
+
readers may announce the filename. Wrap the row in a labelled element.
|
|
204
|
+
|
|
205
|
+
**6. It is a `<div>`, and props are spread.** `onClick` will fire, but you get no
|
|
206
|
+
`role`, no `tabIndex`, no keyboard activation and no focus ring. Wrap it in a real
|
|
207
|
+
`<button>` if it opens something.
|
|
208
|
+
|
|
209
|
+
**7. Trailing spaces in the text nodes.** Both lines render `{name} ` / `{subText} `
|
|
210
|
+
with a literal trailing space (Figma export). Exact-string assertions in tests need
|
|
211
|
+
a `trim()`.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## In the wild
|
|
216
|
+
|
|
217
|
+
_No host render site found — used by the agent runtime / composed internally._
|
|
218
|
+
|
|
219
|
+
It is composed inside `ScProfilePopup` (`src/SC-ProfilePopup/ScProfilePopup.tsx:235`),
|
|
220
|
+
`ScTableList`, `ScReferralTableList`, `ScSidebarProfile` and `ScProfileOptions`. The
|
|
221
|
+
nearest host surface is Catalogix's profile menu
|
|
222
|
+
(`app/components/AppSettingsPopup/index.jsx:75`), which reaches it **through**
|
|
223
|
+
`ScProfilePopup` — that is the intended entry point for hosts. Direct host use would
|
|
224
|
+
belong in a bespoke sidebar footer or member row that no app currently hand-rolls.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Related
|
|
229
|
+
|
|
230
|
+
- `ScProfilePopup` — the current profile menu panel; renders this as its header.
|
|
231
|
+
- `ScWorkspace` — the workspace-flavoured twin (internal, not exported).
|
|
232
|
+
- `ScDp` — avatar only, with an image-error fallback this component lacks.
|
|
233
|
+
- `ScProfileV2Mobile` — the mobile identity block.
|
|
234
|
+
- `ScSidebarProfile` — legacy sidebar footer wrapper (superseded by `StreamoidSidebar`).
|