@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,248 @@
1
+ ---
2
+ component: ScInfoPopup
3
+ package: "@streamoid/ui"
4
+ category: overlays
5
+ status: stable
6
+ renders: div (inline-block wrapper) > span[role="button"] trigger + absolutely-positioned div bubble (no portal)
7
+ tags: [info, popover, tooltip, help, hint, question-mark, popup, contextual]
8
+ related: [ScTextField, ScModal, ScGuide, ScBadges]
9
+ do_not_confuse_with: [ScModal, ScPopUpMenu, ScProfilePopup, ScGuide]
10
+ used_by: [catalogix]
11
+ ---
12
+
13
+ # ScInfoPopup
14
+
15
+ **The little ⓘ that opens a help bubble.** A self-contained 18px info glyph that,
16
+ on click, reveals a small absolutely-positioned card (max 300 × 100px, scrollable)
17
+ with a ✕ in the corner. It owns its own open state and its own outside-click
18
+ dismissal — you pass only `content`.
19
+
20
+ ## TL;DR for agents
21
+
22
+ - **Reach for it when:** a label or a table header needs a short explanation, and
23
+ you want the standard ⓘ affordance next to it.
24
+ - **Don't reach for it when:** you're labelling a form field that is already a
25
+ `ScTextField` (it has an `info` prop that renders this for you), you need a
26
+ hover tooltip, you need a menu (→ `ScMenuOptions`), or the content is long
27
+ enough to need a dialog (→ `ScModal`).
28
+ - **Four things that will bite you:**
29
+ 1. **It is not portalled.** The bubble is `position: absolute` with
30
+ `z-index: 2`, so any ancestor with `overflow: hidden` clips it — that
31
+ includes `ScDrawer`, `ScMappingCard` and most cards.
32
+ 2. **No positioning logic.** Hardcoded `top: 18px; right: 0; translateX(50%)` —
33
+ it always hangs half-way off to the right and is cut by the viewport edge.
34
+ 3. **Keyboard users can focus the trigger but cannot open it.** `tabIndex={0}` +
35
+ `role="button"` with an `onClick` only — no `onKeyDown`.
36
+ 4. **You cannot control it.** No `open` / `onOpenChange` / `defaultOpen`, no
37
+ `trigger` slot, no `icon` prop. The glyph is a hardcoded inline SVG.
38
+
39
+ ---
40
+
41
+ ## 1. How to use it
42
+
43
+ ### Import
44
+
45
+ ```tsx
46
+ import { ScInfoPopup } from "@streamoid/ui";
47
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
48
+ ```
49
+
50
+ ### Minimal usage
51
+
52
+ ```tsx
53
+ <ScInfoPopup content="Only rows that passed validation are exported." />
54
+ ```
55
+
56
+ ### Props
57
+
58
+ | Prop | Type | Default | Notes |
59
+ |---|---|---|---|
60
+ | `content` | `ReactNode` | – | The bubble body. Rendered inside a `<span>`, so block-level children are technically invalid HTML — keep it to text / inline nodes. |
61
+ | `className` | `string` | – | On the **outer wrapper** (the `inline-block` that contains the trigger *and* the bubble), appended after `.scInfoPopup`. There is no way to class the bubble itself. |
62
+
63
+ That's the whole API. No `...props` spread — anything else is a type error.
64
+
65
+ ### What it actually renders
66
+
67
+ ```html
68
+ <div class="scInfoPopup {className}"> <!-- position:relative; display:inline-block -->
69
+ <span class="infoIcon" role="button" tabindex="0" aria-label="More info">
70
+ <svg width="18" height="18">…</svg> <!-- hardcoded ⓘ, --alias-text-and-icons-tertiary -->
71
+ </span>
72
+ <!-- only when open: -->
73
+ <div class="content"> <!-- position:absolute; top:18px; right:0;
74
+ translateX(50%); max-width:300px;
75
+ z-index:2; radius 6px; padding 8px;
76
+ background --alias-surface-base -->
77
+ <div class="closeIconContainer"><SiconClose size={18} /></div>
78
+ <span class="contentText">{content}</span> <!-- 12px; max-height:100px; overflow-y:auto -->
79
+ </div>
80
+ </div>
81
+ ```
82
+
83
+ ⚠️ The root is a **`<div>`**, not a span — dropping one inside a `<p>` or another
84
+ inline-only element is invalid nesting even though the wrapper is `inline-block`.
85
+
86
+ ### Recipes
87
+
88
+ ```tsx
89
+ // On a form field — DON'T nest your own; ScTextField already composes one
90
+ <ScTextField label="Feed URL" required info="We poll this URL every 6 hours." />
91
+
92
+ // Beside a table column header
93
+ <div style={{ display: "flex", alignItems: "center" }}>
94
+ <span>Match rate</span>
95
+ <ScInfoPopup content="Share of feed rows that matched an existing product." />
96
+ </div>
97
+
98
+ // Rich (inline) content
99
+ <ScInfoPopup content={<>Supported: <code>CSV</code>, <code>TSV</code>, <code>XLSX</code>.</>} />
100
+
101
+ // Neutralise the baked-in 12px side margins when it must sit tight to a label
102
+ <ScInfoPopup className="tight" content="…" />
103
+ // .tight > span:first-child { margin: 0; } /* .infoIcon has margin: 0 12px */
104
+ ```
105
+
106
+ ---
107
+
108
+ ## 2. Where to use it
109
+
110
+ - **Form field labels** — but via `ScTextField`'s `info` prop, which renders this
111
+ component at `ScTextField.tsx:106`. That is by far the highest-traffic path.
112
+ - **Table / list column headers** where the metric needs a definition.
113
+ - **Settings rows** explaining what a toggle actually does.
114
+ - **Catalogix** wraps it as `app/components/InfoPopup`, a pass-through that
115
+ preserves the old `content`-only API.
116
+
117
+ Catalogix is the only direct host consumer. CXO/Photogenix/Artifax get it
118
+ indirectly through `ScTextField`.
119
+
120
+ ---
121
+
122
+ ## 3. When to use it
123
+
124
+ ### Use it when
125
+
126
+ - The explanation is **one or two short sentences** and genuinely optional.
127
+ - The trigger belongs **inline next to a label**, not as a separate control.
128
+ - You want the standard glyph, bubble surface and dismissal without wiring state.
129
+
130
+ ### Don't use it — reach for this instead
131
+
132
+ | Situation | Use instead |
133
+ |---|---|
134
+ | Explaining a `ScTextField` label | `ScTextField`'s own `info` prop (it renders this for you) |
135
+ | A hover tooltip on an icon button | plain `title` attribute, or your app's tooltip — this is click-to-open |
136
+ | Content longer than ~2 sentences, or with actions/links to click | `ScModal` |
137
+ | A step-by-step onboarding callout with Skip / Next | `ScGuide` |
138
+ | A menu of actions | `ScMenuOptions` rows in your own positioned container |
139
+ | A status/validation message under a field | `ScTextField`'s helper/error text |
140
+ | A dismissible warning banner | `CreditWarningBanner` (exported without the `Sc` prefix), or your app's banner |
141
+ | A popover you need to open/close programmatically | roll your own — this component does not expose its state |
142
+
143
+ ### Don't confuse with
144
+
145
+ | You may actually want | Not this |
146
+ |---|---|
147
+ | `ScModal` — portalled, scrimmed, blocking, caller-controlled | `ScInfoPopup` is inline, unportalled, self-controlled |
148
+ | `ScPopUpMenu` / `ScMenuOptions` — a *menu row*, no popover at all | `ScInfoPopup` is the only component here that actually pops something up |
149
+ | `ScProfilePopup` — a large profile *panel body* you position yourself | `ScInfoPopup` positions itself (badly) and owns its own state |
150
+ | `ScGuide` — heading + body + Skip/Next, for guided tours | `ScInfoPopup` has no actions |
151
+
152
+ ---
153
+
154
+ ## 4. Why to use it
155
+
156
+ - **Zero wiring.** Open state, the outside-click listener (added/removed with
157
+ `open`) and the ✕ are all internal. There is no app-level `OutsideClick`
158
+ dependency, so it works identically in all four hosts.
159
+ - **The glyph is theme-aware and consistent.** The trigger circle, stroke and dot
160
+ are drawn with `--alias-text-and-icons-tertiary`, so the ⓘ has the same weight
161
+ and colour as every other tertiary icon in the product — the usual hand-rolled
162
+ version is a hardcoded grey that disappears in light mode.
163
+ - **The bubble is already token-correct** — `--alias-surface-base` on a soft shadow
164
+ with `--alias-text-and-icons-primary` copy at 12px.
165
+ - **Overflow is bounded.** `max-width: 300px` + `max-height: 100px; overflow-y: auto`
166
+ means an over-long help string degrades into a small scroller instead of blowing
167
+ out your layout.
168
+
169
+ ---
170
+
171
+ ## Gotchas
172
+
173
+ **1. It is not portalled — clipping is the number-one failure.** The bubble lives
174
+ inside the trigger's `position: relative` wrapper. Any ancestor with
175
+ `overflow: hidden` cuts it off: `ScDrawer` (twice over), `ScMappingCard`,
176
+ `ScProgressBar`, most cards, and any `text-overflow: ellipsis` row.
177
+
178
+ ```tsx
179
+ // WRONG — bubble is clipped by the drawer's overflow:hidden
180
+ <ScDrawer><ScInfoPopup content="…" /></ScDrawer>
181
+
182
+ // RIGHT — put the ⓘ outside the clipping container, or use ScModal for the explanation
183
+ ```
184
+
185
+ **2. `z-index: 2` only.** Anything with a higher z-index inside the same stacking
186
+ context paints over the bubble. There is no prop to raise it; you'd have to
187
+ override `.content` from an ancestor selector.
188
+
189
+ **3. Placement is hardcoded and has no collision handling.**
190
+ `top: 18px; right: 0; transform: translateX(50%)` means the bubble is *centred on
191
+ the trigger's right edge* — half of it hangs to the right of the icon. Placed near
192
+ the right edge of the screen (or of a narrow card), it is cut off. There is no
193
+ `side` / `align` / flip prop.
194
+
195
+ **4. Keyboard cannot open it.** The trigger is a `<span role="button" tabIndex={0}>`
196
+ with `onClick` and **no `onKeyDown`** — Tab focuses it, Enter and Space do nothing.
197
+ The ✕ is a bare `<div onClick>` with no role or tabIndex at all. If your surface
198
+ must be keyboard-accessible, don't hide required information here.
199
+
200
+ **5. `aria-label="More info"` is hardcoded English,** as is nothing else — but there
201
+ is no label prop, so it cannot be localised without changing the DS.
202
+
203
+ **6. The trigger carries `margin: 0 12px`.** You get 12px of horizontal space on
204
+ both sides whether you want it or not; a `gap` on your flex parent stacks on top of
205
+ it. Neutralise via `className` if you need it flush.
206
+
207
+ **7. It is click-to-open, not hover.** Users expecting a tooltip will not discover
208
+ it. Also: opening `stopPropagation()`s the click, so a click on the ⓘ never reaches
209
+ a clickable parent row — usually what you want, occasionally surprising.
210
+
211
+ **8. Dismissal is on `mousedown`, and re-clicking the ⓘ does not toggle.** The
212
+ trigger only ever calls `setOpen(true)`; the outside-click listener closes it. A
213
+ second click on the icon lands *inside* the wrapper, so it stays open. Close via
214
+ the ✕ or by clicking elsewhere.
215
+
216
+ **9. `className` styles the wrapper, not the bubble.** There is no
217
+ `contentClassName`. To restyle the bubble you must write a descendant selector from
218
+ your own class.
219
+
220
+ **10. `content` renders inside a `<span>`.** Passing a `<div>`/`<p>`/list produces
221
+ invalid nesting (it usually still renders, but don't rely on it). Keep it inline.
222
+
223
+ ---
224
+
225
+ ## In the wild
226
+
227
+ ```jsx
228
+ // catalogix/dashboard app/components/InfoPopup/index.jsx:9
229
+ export default function InfoPopup({ content }) {
230
+ return <ScInfoPopup content={content} />;
231
+ }
232
+ ```
233
+
234
+ And composed inside the DS itself:
235
+
236
+ ```tsx
237
+ // npm-components packages/ui/src/SC-textField/ScTextField.tsx:106
238
+ {info != null && <ScInfoPopup content={info} />}
239
+ ```
240
+
241
+ ---
242
+
243
+ ## Related
244
+
245
+ - `ScTextField` — pass `info` and it renders this popup beside the label; the preferred path.
246
+ - `ScModal` — for explanations too long or too interactive for a bubble.
247
+ - `ScGuide` — guided-tour callout with Skip / step / Next.
248
+ - `ScMenuOptions` — if what you actually wanted was a menu, not help text.
@@ -0,0 +1,233 @@
1
+ ---
2
+ component: ScIntialProfileCover
3
+ package: "@streamoid/ui"
4
+ category: profile
5
+ status: stable
6
+ renders: div
7
+ tags: [initials, avatar, workspace-tile, placeholder, cover, misspelled-prop, intial]
8
+ related: [ScDp, ScWorkspaceCard, ScProfile, ScWorkspaceSwitchCard]
9
+ do_not_confuse_with: [ScDp, ScProfileImageUpdate, ScProfile, ScBadges]
10
+ ---
11
+
12
+ # ScIntialProfileCover
13
+
14
+ **An initials tile — 60px rounded square, no image path at all.** One grey box
15
+ (`fill-neutral-neutralselected`, `radius-3xl`) with centred initials. Note the
16
+ misspellings: the component is `ScIntialProfileCover` and its prop is **`intial`**.
17
+ Both are load-bearing — you must reproduce them to compile.
18
+
19
+ ## TL;DR for agents
20
+
21
+ - **Reach for it when:** you need the workspace/profile *initials block* from the
22
+ Figma workspace rows and you know you will never have an image.
23
+ - **Don't reach for it when:** an image might exist (→ `ScDp`, which has an
24
+ `onError` → initials fallback), or you need any interactivity or `aria` (this
25
+ component forwards **nothing**).
26
+ - **Four things that will bite you:**
27
+ 1. The prop is **`intial`** (sic), not `initial`. `initial="AC"` is a type error;
28
+ the tile silently shows the `"WS"` default if you cast around it.
29
+ 2. It has **no image support**. Not `imageUrl`, not `children`.
30
+ 3. It accepts **only** `intial`, `size`, `className`. No `style`, no `onClick`, no
31
+ `data-*`, no `aria-*` — `IScIntialProfileCoverProps` does not extend
32
+ `HTMLAttributes`.
33
+ 4. The initials text is a fixed `1rem`; `size` does not scale it, and the box
34
+ clips (`overflow: hidden` on `.initials`).
35
+
36
+ ---
37
+
38
+ ## 1. How to use it
39
+
40
+ ### Import
41
+
42
+ ```tsx
43
+ import { ScIntialProfileCover } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+ ```
46
+
47
+ ### Minimal usage
48
+
49
+ ```tsx
50
+ <ScIntialProfileCover intial="AC" />
51
+ ```
52
+
53
+ ### Props
54
+
55
+ | Prop | Type | Default | Notes |
56
+ |---|---|---|---|
57
+ | `intial` | `string` | `"WS"` | ⚠️ **Misspelled prop name** and ⚠️ a real default. Rendered with a literal trailing space (`{intial} `). |
58
+ | `size` | `number` | – | px. When set, applies `width`/`height` **and zeroes the 1rem padding**. Unset → the CSS default of `3.75rem` (60px) **with** 1rem padding. |
59
+ | `className` | `string` | – | Appended (concatenated unconditionally — a literal `undefined` class when omitted). |
60
+
61
+ That is the entire API — three props, and no spread.
62
+
63
+ ### What `size` changes
64
+
65
+ | `size` | Box | Padding | Notes |
66
+ |---|---|---|---|
67
+ | unset | `3.75rem` × `3.75rem` from CSS | `var(--spacing-3xl)` = 1rem | the Figma default block |
68
+ | set | `{size}px` inline | `0` | inline `style` on the root; the CSS class rule is overridden |
69
+
70
+ ### Recipes
71
+
72
+ ```tsx
73
+ // Workspace row tile, initials derived from the name
74
+ <ScIntialProfileCover
75
+ intial={ws.initials || ws.name.split(/\s+/).slice(0, 2).map((w) => w[0]?.toUpperCase() ?? "").join("") || "WS"}
76
+ className="shrink-0"
77
+ />
78
+
79
+ // Smaller tile — remember one character only, the font does not scale
80
+ <ScIntialProfileCover intial="A" size={32} />
81
+
82
+ // Needs a click, an image fallback, or an aria label? use ScDp instead
83
+ <button type="button" onClick={open} aria-label={`Open ${ws.name}`}>
84
+ <ScDp type={ws.imageUrl ? "image" : "initial"} variant="workspace" initial="AC" imageUrl={ws.imageUrl} size={60} />
85
+ </button>
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 2. Where to use it
91
+
92
+ Composed inside two DS components, not usually placed directly:
93
+
94
+ | Parent | Role |
95
+ |---|---|
96
+ | `ScWorkspaceCard` | the workspace tile at the head of the card |
97
+ | `StreamoidWorkspaceSwitcher` | the tile on each workspace row in the switch modal |
98
+
99
+ Everything newer reaches for `ScDp` instead — `ScWorkspaceSwitchCard`,
100
+ `ScWorkspaceSwitchMobileV2` and the sidebar shells all use `ScDp variant="workspace"`.
101
+ Treat `ScIntialProfileCover` as the older, image-less spelling of the same idea.
102
+
103
+ ---
104
+
105
+ ## 3. When to use it
106
+
107
+ ### Use it when
108
+
109
+ - You are inside `ScWorkspaceCard` / `StreamoidWorkspaceSwitcher` territory and want
110
+ to match those tiles exactly (60px, `radius-3xl`).
111
+ - The entity provably has no avatar (a brand-new workspace, a placeholder row).
112
+
113
+ ### Don't use it — reach for this instead
114
+
115
+ | Situation | Use instead |
116
+ |---|---|
117
+ | An avatar that may have an image | `ScDp` (`type="image"` + `imageUrl`, with initials fallback) |
118
+ | A person avatar (circle) | `ScDp` with `variant="profile"` |
119
+ | Clickable / focusable / labelled tile | `ScDp` wrapped in a `<button>` — this component forwards nothing |
120
+ | Avatar upload / delete | `ScProfileImageUpdate` |
121
+ | Avatar + name + subtext row | `ScProfile` |
122
+ | A whole workspace row | `ScWorkspaceSwitchCard` |
123
+ | A small text chip / count | `ScBadges` |
124
+
125
+ ### Don't confuse with
126
+
127
+ | You may actually want | Not this |
128
+ |---|---|
129
+ | `ScDp` — `initial` (spelled correctly), `variant`, `imageUrl`, `size` default 60, error fallback, accepts `style` | `ScIntialProfileCover` is initials-only with the misspelled `intial` |
130
+ | `ScProfileImageUpdate` — editable avatar | this is display-only |
131
+ | `ScProfile` — identity **row** | this is one tile |
132
+
133
+ `ScDp` vs `ScIntialProfileCover` is the mis-pick to watch: they look identical at
134
+ 60px in the workspace variant. **If an image could ever exist, it is `ScDp`.**
135
+
136
+ ---
137
+
138
+ ## 4. Why to use it
139
+
140
+ - **It is the exact Figma block** used by the workspace card and switch modal:
141
+ 60 × 60, `radius-3xl` (1rem), `fill-neutral-neutralselected`, `text-md/medium`
142
+ centred. Re-deriving those four values by hand is how tile sizes drift between the
143
+ card and the modal.
144
+ - **Token-driven**, so the grey and the text flip with the theme.
145
+ - **Genuinely tiny** — if you know there is no image, it is a smaller commitment than
146
+ `ScDp`'s image/error state machine.
147
+
148
+ Honestly though: `ScDp` gives you all of this plus the image path, accepts `style`,
149
+ and is the one the newer components use. Prefer it in new code unless you are
150
+ matching an existing `ScIntialProfileCover` tile.
151
+
152
+ ---
153
+
154
+ ## Gotchas
155
+
156
+ **1. The prop is `intial`, not `initial`.**
157
+
158
+ ```tsx
159
+ // WRONG — type error (and if you cast past it, you get "WS")
160
+ <ScIntialProfileCover initial="AC" />
161
+
162
+ // RIGHT
163
+ <ScIntialProfileCover intial="AC" />
164
+ ```
165
+
166
+ The component name is misspelled too (`ScIntialProfileCover`). Both are the published
167
+ API — fixing them is a breaking change, so don't "correct" them locally.
168
+
169
+ **2. `intial` defaults to `"WS"`.** Forget it and every tile reads "WS".
170
+
171
+ **3. No `style` prop, no spread.** `IScIntialProfileCoverProps` is exactly
172
+ `{ intial?, size?, className? }`. `onClick`, `title`, `aria-label`, `data-testid` and
173
+ `style` are all rejected by TypeScript. Style it through `className`, and wrap it for
174
+ interaction.
175
+
176
+ ```tsx
177
+ // WRONG — type error; also no keyboard access even if it compiled
178
+ <ScIntialProfileCover intial="AC" onClick={open} />
179
+
180
+ // RIGHT
181
+ <button type="button" onClick={open} aria-label="Acme workspace">
182
+ <ScIntialProfileCover intial="AC" />
183
+ </button>
184
+ ```
185
+
186
+ **4. `size` also zeroes the padding.** The two configurations are not just different
187
+ sizes: unset gives `60px + 1rem padding`, set gives `{size}px + 0 padding`. The
188
+ initials therefore sit closer to the edge at custom sizes.
189
+
190
+ **5. Long initials clip, and the font never scales.** `.initials` is
191
+ `font-size-md` (1rem) with `overflow: hidden` + `text-overflow: ellipsis`. Three
192
+ letters, or two letters at `size={24}`, get cut.
193
+
194
+ **6. It is a rounded square, never a circle.** `radius-3xl` (1rem) is baked in. For a
195
+ person avatar you want `ScDp variant="profile"`, or override `border-radius` via
196
+ `className`.
197
+
198
+ **7. `className` is concatenated unconditionally** → `class="scIntialProfileCover undefined"`
199
+ when omitted.
200
+
201
+ **8. Trailing space in the text node** (`{intial} `) — `trim()` before asserting in
202
+ tests.
203
+
204
+ ---
205
+
206
+ ## In the wild
207
+
208
+ _No host render site found — used by the agent runtime / composed internally._
209
+
210
+ Composed at `src/SC-workspaceCard/ScWorkspaceCard.tsx:35` and
211
+ `src/SC-WorkspaceSwitcher/streamoid-workspace-switcher.tsx:101`:
212
+
213
+ ```tsx
214
+ // packages/ui src/SC-WorkspaceSwitcher/streamoid-workspace-switcher.tsx:101
215
+ <ScIntialProfileCover
216
+ intial={workspace.initials || deriveInitials(workspace.name)}
217
+ className="shrink-0"
218
+ />
219
+ ```
220
+
221
+ Host apps that need a workspace tile use `ScDp` instead (e.g. artifax
222
+ `packages/shared/src/components/DashboardSidebar.tsx:698`). If a host ever needs this
223
+ tile directly it belongs on a workspace-creation or empty-state screen, where no
224
+ avatar can exist yet.
225
+
226
+ ---
227
+
228
+ ## Related
229
+
230
+ - `ScDp` — the avatar with an image path and an error fallback; prefer it in new code.
231
+ - `ScWorkspaceCard` — renders this tile plus name/role/owner and a CTA.
232
+ - `StreamoidWorkspaceSwitcher` — the switch modal whose rows use this tile.
233
+ - `ScProfileImageUpdate` — the editable avatar.
@@ -0,0 +1,187 @@
1
+ ---
2
+ component: ScInvoiceHistoryMobile
3
+ exported: false
4
+ package: "@streamoid/ui"
5
+ category: mobile
6
+ status: deprecated
7
+ renders: div
8
+ tags: [mobile, billing, invoice, history, row, unexported, dead-code, superseded]
9
+ related: [InvoiceHistoryMobile, ScUsageHistoryMobile, ScBillingHistoryTableList]
10
+ do_not_confuse_with: [InvoiceHistoryMobile, ScUsageHistoryMobile, UsageHistoryMobile]
11
+ ---
12
+
13
+ # ScInvoiceHistoryMobile
14
+
15
+ **Do not use — this component is not shipped.** It is an earlier copy of the mobile
16
+ invoice row that never made it into the public surface: it is absent from
17
+ `src/index.ts`, so its JS is not in `dist/index.js`, its class names are not in
18
+ `dist/index.css`, and `IScInvoiceHistoryMobileProps` is not in `dist/index.d.ts`.
19
+ The shipped component is **`InvoiceHistoryMobile`** (no `Sc` prefix) in
20
+ `src/SC-InvoiceHistoryMobile/`.
21
+
22
+ ## TL;DR for agents
23
+
24
+ - **Reach for it when:** never. Use `InvoiceHistoryMobile` instead.
25
+ - **Don't reach for it when:** always — importing `ScInvoiceHistoryMobile` from
26
+ `@streamoid/ui` throws/undefined at runtime and fails to type-check.
27
+ - **Two things that will bite you:**
28
+ 1. **It is not exported.** Neither the component nor its CSS reaches `dist/`.
29
+ Verified: `grep -c scInvoiceHistoryMobile dist/index.css` → `0`.
30
+ 2. **The prop names differ from the shipped twin.** Here the id prop is
31
+ `invoiceNumber`; in `InvoiceHistoryMobile` it is `invoiceId`.
32
+
33
+ ---
34
+
35
+ ## 1. How to use it
36
+
37
+ You don't. Import the shipped sibling:
38
+
39
+ ### Import
40
+
41
+ ```tsx
42
+ // The component that actually ships:
43
+ import { InvoiceHistoryMobile } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+
46
+ // NOT THIS — `ScInvoiceHistoryMobile` is not an export of @streamoid/ui
47
+ ```
48
+
49
+ ### Minimal usage
50
+
51
+ ```tsx
52
+ <InvoiceHistoryMobile
53
+ invoiceId={`# ${inv.number}`}
54
+ date={formatDate(inv.createdAt)}
55
+ amount={`$${inv.amountPaid.toFixed(2)}`}
56
+ />
57
+ ```
58
+
59
+ ### Props
60
+
61
+ Documented only so you can recognise the difference when migrating a call site.
62
+
63
+ | Prop | Type | Default | Notes |
64
+ |---|---|---|---|
65
+ | `invoiceNumber` | `string` | `"# INV-2800-2026"` | ⚠️ Demo default. **Renamed to `invoiceId`** in the shipped twin. |
66
+ | `date` | `string` | `"Nov 9th, 2025"` | ⚠️ Demo default. Same name in the shipped twin. |
67
+ | `amount` | `string` | `"₹320.89"` | ⚠️ Demo default in rupees. Same name in the shipped twin. Always success-green. |
68
+ | `onClick` | `(e: React.MouseEvent) => void` | – | **Only exists here.** The shipped twin has no click handler. |
69
+ | `className` | `string` | – | Unguarded concat — renders a literal `undefined` class when omitted. |
70
+ | `...props` | `React.HTMLAttributes<HTMLDivElement>` | – | **Only exists here.** The shipped twin accepts no extra props. |
71
+
72
+ ### Mapping between the two
73
+
74
+ | This (unexported) | Shipped `InvoiceHistoryMobile` |
75
+ |---|---|
76
+ | `invoiceNumber` | `invoiceId` |
77
+ | `date` | `date` |
78
+ | `amount` | `amount` |
79
+ | `onClick` | *(none — wrap the row in your own clickable `div`)* |
80
+ | `...props` spread | *(none — `className` only)* |
81
+ | `className` (unguarded) | `className` (guarded with `?? ""`) |
82
+
83
+ Styling is otherwise equivalent: 16px padding, 12px gap, 0.5px bottom divider, a
84
+ truncating text column (`flex: 1 0 0` here, `flex: 1` in the shipped twin) and a
85
+ `flex-shrink: 0` green amount.
86
+
87
+ ### Recipes
88
+
89
+ ```tsx
90
+ // Migrating an old call site
91
+ // BEFORE (would not have compiled against the published package anyway)
92
+ // <ScInvoiceHistoryMobile invoiceNumber={id} date={d} amount={a} onClick={open} />
93
+
94
+ // AFTER
95
+ <div onClick={open} className="cursor-pointer">
96
+ <InvoiceHistoryMobile invoiceId={id} date={d} amount={a} />
97
+ </div>
98
+ ```
99
+
100
+ ---
101
+
102
+ ## 2. Where to use it
103
+
104
+ Nowhere. The surface it was drawn for — the "Invoice history" tab of CXO's mobile
105
+ billing screen — is served by `InvoiceHistoryMobile`
106
+ (`cxo-dashboard/src/app/components/mobile-billing-content.tsx:231`).
107
+
108
+ ---
109
+
110
+ ## 3. When to use it
111
+
112
+ ### Use it when
113
+
114
+ Never. Treat this folder as source to delete, or as the place to land the fix if the
115
+ team decides the shipped row should regain `onClick` and a props spread (which are the
116
+ two capabilities this copy has and the shipped one lacks).
117
+
118
+ ### Don't use it — reach for this instead
119
+
120
+ | Situation | Use instead |
121
+ |---|---|
122
+ | A mobile invoice row | `InvoiceHistoryMobile` (`src/SC-InvoiceHistoryMobile/`) |
123
+ | A mobile credit-usage row | `UsageHistoryMobile` (`src/SC-UsageHistoryMobile/`) |
124
+ | Desktop invoice table | `ScBillingHistoryHeader` + `ScBillingHistoryTableList` |
125
+ | A clickable mobile row with DS-provided semantics | `ScTableListMobile` (`onRowClick`) |
126
+
127
+ ### Don't confuse with
128
+
129
+ | You may actually want | Not this |
130
+ |---|---|
131
+ | `InvoiceHistoryMobile` — the exported row, prop `invoiceId`, no `onClick` | This one is unexported and uses `invoiceNumber` |
132
+ | `ScUsageHistoryMobile` — the *other* unexported duplicate, for usage rows | Same situation, different data |
133
+ | `UsageHistoryMobile` — the exported usage row | Different data (red credits, four fields) |
134
+
135
+ The library contains **two** of these unexported `Sc*`-prefixed duplicates —
136
+ `ScInvoiceHistoryMobile` and `ScUsageHistoryMobile` — while the exported pair
137
+ (`InvoiceHistoryMobile`, `UsageHistoryMobile`) are the only two components in the
138
+ **mobile** family without the `Sc` prefix. (Other un-prefixed exports exist in the
139
+ package — `CreditWarningBanner`, `StreamoidSidebar` — but none are mobile.) That
140
+ inversion is the single easiest naming mistake to make in this family.
141
+
142
+ ---
143
+
144
+ ## 4. Why to use it
145
+
146
+ There is no reason to. What the shipped twin gives you that this does not: it is
147
+ actually in the bundle. What this gives you that the shipped twin does not: `onClick`
148
+ and a props spread — capabilities you can reproduce today with a wrapper `div`.
149
+
150
+ ---
151
+
152
+ ## Gotchas
153
+
154
+ **1. It is not importable.** `src/index.ts` exports
155
+ `./SC-InvoiceHistoryMobile/InvoiceHistoryMobile` and nothing from
156
+ `./SC-InvoiceHistory-Mobile/`. The two folder names differ only by a hyphen.
157
+
158
+ **2. Its CSS is not in the shipped stylesheet.** Because nothing imports the module,
159
+ esbuild never sees `ScInvoiceHistoryMobile.module.css`. Even if you deep-imported the
160
+ `.tsx` from source, in a consumer repo the row would render **unstyled**.
161
+
162
+ **3. `invoiceNumber` vs `invoiceId`.** Copying an old snippet across produces an
163
+ undefined-prop that silently falls back to the demo default `"# INV-2800-2026"`.
164
+
165
+ **4. `className` is concatenated unguarded** here (`+ " " + className`), so it emits a
166
+ literal `undefined` class — one of the small differences from the shipped twin, which
167
+ guards with `?? ""`.
168
+
169
+ ---
170
+
171
+ ## In the wild
172
+
173
+ _No host render site found — used by the agent runtime / composed internally._
174
+
175
+ To be precise: it cannot have one — it is not exported, so no host *could* render it.
176
+ It is not agent-runtime either; it is dead source. The surface it was drawn for uses
177
+ the exported twin at
178
+ `cxo-dashboard/src/app/components/mobile-billing-content.tsx:231`.
179
+
180
+ ---
181
+
182
+ ## Related
183
+
184
+ - `InvoiceHistoryMobile` — **use this**; the shipped mobile invoice row.
185
+ - `UsageHistoryMobile` — the shipped mobile usage row.
186
+ - `ScUsageHistoryMobile` — the other unexported duplicate, same story.
187
+ - `ScBillingHistoryHeader` / `ScBillingHistoryTableList` — the desktop table.