@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,244 @@
1
+ ---
2
+ component: ScBeacon
3
+ package: "@streamoid/ui"
4
+ category: overlays
5
+ status: stable
6
+ renders: span[aria-hidden="true"] wrapping an inline 20×20 SVG
7
+ tags: [beacon, dot, status-dot, indicator, halo, tone, success, warning, error, neutral]
8
+ related: [ScBadges, ScStoreCard, ScCatalogixStoreTableList, ScRole]
9
+ do_not_confuse_with: [ScBadges, ScProgressBar]
10
+ ---
11
+
12
+ # ScBeacon
13
+
14
+ **A two-ring status dot.** A 20×20 `<span>` holding an inline SVG: a solid 4px core
15
+ plus a 10px halo of the same colour at 24% opacity, both `currentColor`, tinted by
16
+ one of four `tone`s. It is decoration — `aria-hidden` by default.
17
+
18
+ ## TL;DR for agents
19
+
20
+ - **Reach for it when:** a row or card needs a colour-coded state marker that sits
21
+ beside a text label ("● Live", "● Needs attention").
22
+ - **Don't reach for it when:** the marker must carry the words itself
23
+ (→ `ScBadges`), it's a quantity (→ `ScProgressBar`), or you wanted an animated
24
+ "new!" nudge — **it does not animate** (see Gotcha 1).
25
+ - **Three things that will bite you:**
26
+ 1. Despite the name, **there is no pulse and no animation anywhere** in
27
+ `ScBeacon.module.css`. It's a static dot with a halo.
28
+ 2. `tone` defaults to `"neutral"` ⚠️ — a grey status dot that says nothing.
29
+ 3. `aria-hidden="true"` is baked on. Screen readers get nothing, so it must
30
+ always sit next to real text.
31
+
32
+ ---
33
+
34
+ ## 1. How to use it
35
+
36
+ ### Import
37
+
38
+ ```tsx
39
+ import { ScBeacon } from "@streamoid/ui";
40
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
41
+ ```
42
+
43
+ ### Minimal usage
44
+
45
+ ```tsx
46
+ <ScBeacon tone="success" />
47
+ ```
48
+
49
+ Practically always paired with a label:
50
+
51
+ ```tsx
52
+ <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
53
+ <ScBeacon tone="error" />
54
+ Needs attention
55
+ </span>
56
+ ```
57
+
58
+ ### Props
59
+
60
+ | Prop | Type | Default | Notes |
61
+ |---|---|---|---|
62
+ | `tone` | `"success"` \| `"warning"` \| `"error"` \| `"neutral"` | `"neutral"` | ⚠️ Real default. Sets `color:` on the span; the SVG paints with `currentColor`. **There is no `info`/blue tone** (unlike `ScBadges`). |
63
+ | `className` | `string` | – | Appended only when truthy (this component gets the concatenation right). |
64
+ | `...props` | `HTMLAttributes<HTMLSpanElement>` | – | Spread onto the `<span>` **after** `aria-hidden`, so `style`, `title`, `aria-hidden={false}` + `aria-label`, `data-*` and `onClick` all work. |
65
+
66
+ `ScBeaconTone` is exported as a standalone type and reused by `ScStoreCard`
67
+ (`tone`) and `ScCatalogixStoreTableList` (`statusTone`).
68
+
69
+ ### Tone → token
70
+
71
+ | `tone` | Colour |
72
+ |---|---|
73
+ | `success` | `--alias-text-and-icons-success` |
74
+ | `warning` | `--alias-text-and-icons-warning` |
75
+ | `error` | `--alias-text-and-icons-error` |
76
+ | `neutral` | `--alias-text-and-icons-muted` |
77
+
78
+ ### Recipes
79
+
80
+ ```tsx
81
+ // Table status cell — dot + text, one accessible label
82
+ <td>
83
+ <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
84
+ <ScBeacon tone={STATUS_TONE[row.status]} />
85
+ <span>{STATUS_LABEL[row.status]}</span>
86
+ </span>
87
+ </td>
88
+
89
+ // Smaller dot — the SVG is width/height 100%, so resizing the span scales it
90
+ <ScBeacon tone="success" style={{ width: 12, height: 12 }} />
91
+
92
+ // Expose it to assistive tech when there is genuinely no adjacent text
93
+ <ScBeacon tone="error" aria-hidden={false} role="img" aria-label="Feed sync failed" />
94
+
95
+ // Share the tone type with your own status map
96
+ import type { ScBeaconTone } from "@streamoid/ui";
97
+ const STATUS_TONE: Record<FeedStatus, ScBeaconTone> = {
98
+ live: "success", syncing: "warning", failed: "error", draft: "neutral",
99
+ };
100
+ ```
101
+
102
+ ---
103
+
104
+ ## 2. Where to use it
105
+
106
+ - **Inside `ScStoreCard`** — the card's footer renders `<ScBeacon tone={tone} />`
107
+ beside the product count and creation date. That is its main job today.
108
+ - **Table status columns** — `ScCatalogixStoreTableList` takes a `statusTone` of the
109
+ same `ScBeaconTone` type, though it paints its own dot via a
110
+ `STATUS_TONE_CLASS` map rather than mounting this component.
111
+ - **Any list where a full `ScBadges` chip is too heavy** — dense tables where one
112
+ coloured dot plus the plain status word reads better than five coloured boxes.
113
+
114
+ No host app renders it directly; it reaches the screen through `ScStoreCard`.
115
+
116
+ ---
117
+
118
+ ## 3. When to use it
119
+
120
+ ### Use it when
121
+
122
+ - The state is **already named in adjacent text** and you only need the colour cue.
123
+ - The row is **dense** and a bordered/filled chip would be visual noise.
124
+ - You are building a component that should look like `ScStoreCard`'s footer.
125
+
126
+ ### Don't use it — reach for this instead
127
+
128
+ | Situation | Use instead |
129
+ |---|---|
130
+ | The marker must carry the label itself ("Revoked", "Live") | `ScBadges` |
131
+ | Admin / Member role marker | `ScRole` / `ScRoleMobile` |
132
+ | An `info`/blue state | `ScBadges variant="info"` — this component has no blue tone |
133
+ | A numeric count on an icon (notification badge) | no DS component; build it app-local |
134
+ | Progress or a quantity | `ScProgressBar` |
135
+ | An animated onboarding "new here!" nudge | no DS component — `ScGuide` is the guided-tour callout; this dot does not animate |
136
+ | An interactive filter chip | `ScSelectionPill` |
137
+
138
+ ### Don't confuse with
139
+
140
+ | You may actually want | Not this |
141
+ |---|---|
142
+ | `ScBadges` — text chip, 5 variants (incl. `info`), 2 skins, no spread | `ScBeacon` — dot only, 4 tones, full HTML spread |
143
+ | `ScProgressBar` — a meter | Not a status marker |
144
+ | An animated attention beacon | The name suggests it; the CSS contains no `@keyframes` |
145
+
146
+ ---
147
+
148
+ ## 4. Why to use it
149
+
150
+ - **The halo is the point.** A 24%-opacity ring around a solid core makes a small
151
+ dot legible against both dark and light surfaces without a border — a plain
152
+ `border-radius: 50%` div disappears on a low-contrast row.
153
+ - **`currentColor` throughout.** Both circles paint from `currentColor`, so the tone
154
+ is set once on the span and a `color` in your own `className` overrides the whole
155
+ mark. No fills to keep in sync.
156
+ - **Four semantic tokens, not four hex values.** The tones read the same
157
+ `--alias-text-and-icons-{success,warning,error,muted}` used by `ScBadges`,
158
+ `ScMenuOptions` and `ScMappingCard`'s status icons, so a "warning" is one colour
159
+ product-wide.
160
+ - **`ScBeaconTone` is the shared status vocabulary.** Exporting the type lets store
161
+ cards, store tables and your own status maps agree on four states instead of each
162
+ inventing five.
163
+ - **It cannot break a layout.** `inline-flex`, `flex-shrink: 0`, fixed 20×20 — safe
164
+ in a table cell or a truncating flex row.
165
+
166
+ ---
167
+
168
+ ## Gotchas
169
+
170
+ **1. It does not pulse.** `ScBeacon.module.css` is 22 lines: a size, a
171
+ `flex-shrink`, and four colour classes. No `@keyframes`, no `animation`, no
172
+ `transition`. If you need the pulsing onboarding nudge the catalog describes, you
173
+ must add the animation yourself via `className`.
174
+
175
+ **2. `tone` defaults to `"neutral"`.** Forget it and you get a muted grey dot — a
176
+ status indicator communicating no status.
177
+
178
+ ```tsx
179
+ // WRONG — grey dot regardless of state
180
+ <ScBeacon />
181
+
182
+ // RIGHT
183
+ <ScBeacon tone={row.failed ? "error" : "success"} />
184
+ ```
185
+
186
+ **3. `aria-hidden="true"` is hardcoded.** By design — it's decoration. But it means
187
+ a dot-only status column is invisible to screen readers. Either keep a text label
188
+ beside it, or override: `aria-hidden={false} role="img" aria-label="…"` (the spread
189
+ comes after the attribute, so your override wins).
190
+
191
+ **4. No `size` prop.** Fixed `1.25rem` (20px). It *does* scale if you set both
192
+ `width` and `height` (the SVG is `100%`/`100%`) — but you must set both, via
193
+ `style` or `className`. Setting only one squashes it.
194
+
195
+ **5. A `color` you set on the span silently beats `tone`.** The tone class only sets
196
+ `color` on the span, and the SVG paints from `currentColor` — so
197
+ `style={{ color: … }}` (inline, always wins) or a same-specificity `.yourClass
198
+ { color: … }` that happens to come later in the stylesheet overrides the tone
199
+ entirely. An *inherited* `color` from an ancestor does **not** override it: the tone
200
+ class targets the element directly and beats inheritance. Pick one mechanism.
201
+
202
+ **6. Four tones only — no `info`.** `ScBadges` has five variants; `ScBeacon` has
203
+ four. If your status map has a blue "info" state you must collapse it to `neutral`
204
+ or use a badge.
205
+
206
+ **7. It's a `<span>`, so it inherits `font-size`-driven line boxes.** In a text run
207
+ it sits on the baseline and can look vertically off; wrap it in an
208
+ `inline-flex; align-items: center` container with the label rather than relying on
209
+ inline layout.
210
+
211
+ **8. `onClick` works (via the spread) but there is no cursor, role or focus.** If
212
+ the dot is a control, wrap it in a real button — don't just add a handler to an
213
+ `aria-hidden` span.
214
+
215
+ ---
216
+
217
+ ## In the wild
218
+
219
+ _No host render site found — used by the agent runtime / composed internally._
220
+
221
+ Concretely: it is composed inside the DS, not called from the dashboards —
222
+
223
+ ```tsx
224
+ // npm-components packages/ui/src/SC-StoreCard/ScStoreCard.tsx:33
225
+ <div className={styles.footer}>
226
+ <ScBeacon tone={tone} />
227
+ <span className={styles.products}>{noOfProducts}</span>
228
+ <span className={styles.date}>{dateCreated}</span>
229
+ </div>
230
+ ```
231
+
232
+ Where it most likely belongs next: the **Catalogix stores table**
233
+ (`ScCatalogixStoreTableList` already accepts a `statusTone: ScBeaconTone` but draws
234
+ its own dot through `STATUS_TONE_CLASS` — mounting `ScBeacon` there would remove the
235
+ duplicate), and any future feed/job status list in Catalogix or Photogenix.
236
+
237
+ ---
238
+
239
+ ## Related
240
+
241
+ - `ScBadges` — the text-carrying sibling; use it when the state must be named in the chip.
242
+ - `ScStoreCard` — the DS parent that renders a beacon today.
243
+ - `ScCatalogixStoreTableList` — reuses `ScBeaconTone` for its `statusTone` prop.
244
+ - `ScRole` — the dedicated Admin/Member marker.
@@ -0,0 +1,210 @@
1
+ ---
2
+ component: ScBillingHistoryHeader
3
+ package: "@streamoid/ui"
4
+ category: billing
5
+ status: stable
6
+ renders: div
7
+ tags: [invoice, billing-history, table-header, column-headers, invoices, header-row]
8
+ related: [ScBillingHistoryTableList, ScHeader, ScBillingLogsTableHeader, ScTableHeader]
9
+ do_not_confuse_with: [ScBillingLogsTableHeader, ScTableHeader, ScHeader, ScMobileTopNav]
10
+ used_by: [cxo]
11
+ ---
12
+
13
+ # ScBillingHistoryHeader
14
+
15
+ **The fixed column-header strip for the invoice-history table.** Four `ScHeader`
16
+ cells — `Invoice` · `Amount` · `Date` · `Action` — on a neutral fill, at the exact
17
+ widths its row sibling `ScBillingHistoryTableList` expects. It takes **no content
18
+ props at all**: the labels are baked in.
19
+
20
+ ## TL;DR for agents
21
+
22
+ - **Reach for it when:** you are rendering the Billing → *Invoice history* table
23
+ and are about to stack `ScBillingHistoryTableList` rows under it.
24
+ - **Don't reach for it when:** your columns differ in any way (→ compose `ScHeader`
25
+ cells yourself), or you need the credit-logs header (→ `ScBillingLogsTableHeader`).
26
+ - **Three things that will bite you:**
27
+ 1. `className` is the **only** prop. The four labels are hardcoded English and
28
+ cannot be renamed, reordered, removed or extended.
29
+ 2. It is **not sticky**. Wrap it yourself if rows scroll under it.
30
+ 3. `state="none"` is hardcoded on every cell, so there are **no sort arrows** even
31
+ though `ScHeader` supports `"up"`/`"down"`.
32
+
33
+ ---
34
+
35
+ ## 1. How to use it
36
+
37
+ ### Import
38
+
39
+ ```tsx
40
+ import { ScBillingHistoryHeader, ScBillingHistoryTableList } from "@streamoid/ui";
41
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
42
+ ```
43
+
44
+ ### Minimal usage
45
+
46
+ ```tsx
47
+ <ScBillingHistoryHeader />
48
+ ```
49
+
50
+ ### Props
51
+
52
+ | Prop | Type | Default | Notes |
53
+ |---|---|---|---|
54
+ | `className` | `string` | – | Appended to the root class. **The only prop.** |
55
+
56
+ The interface does **not** extend `HTMLAttributes`, and although the component
57
+ destructures `...props`, it never spreads them — so `style`, `onClick`, `id` and
58
+ `data-*` are both a type error *and* a no-op.
59
+
60
+ ### Fixed layout (must match your rows)
61
+
62
+ | Cell | Label | Width |
63
+ |---|---|---|
64
+ | 1 | `Invoice` | `flex: 1` (`align-items: flex-start`) |
65
+ | 2 | `Amount` | `7.5rem`, `flex-shrink: 0` |
66
+ | 3 | `Date` | `7.5rem`, `flex-shrink: 0` |
67
+ | 4 | `Action` | `10rem`, `flex-shrink: 0` |
68
+
69
+ Root: `padding: 0.75rem 1rem`, `gap: 1.5rem`, background
70
+ `--alias-fill-neutral-neutral`. `ScBillingHistoryTableList` uses the same gap and
71
+ horizontal padding (with `1.25rem` vertical), which is why the columns line up.
72
+
73
+ ### Recipes
74
+
75
+ ```tsx
76
+ // Sticky header over a scrolling, rounded list (the real CXO/settings pattern)
77
+ <div
78
+ className="flex-1 min-h-0 w-full relative"
79
+ style={{
80
+ backgroundColor: "var(--alias-surface-base)",
81
+ borderRadius: "var(--radius-3xl)",
82
+ border: "1px solid var(--alias-border-subtle)",
83
+ overflowY: "auto",
84
+ }}
85
+ >
86
+ <div style={{ position: "sticky", top: 0, zIndex: 1, backgroundColor: "var(--alias-surface-base)" }}>
87
+ <ScBillingHistoryHeader />
88
+ </div>
89
+
90
+ {invoices.length === 0 && <EmptyRow>No invoices found</EmptyRow>}
91
+
92
+ {invoices.map((inv) => (
93
+ <ScBillingHistoryTableList key={inv._id} invoiceNumber={inv.number} amount={inv.total} date={inv.date} />
94
+ ))}
95
+ </div>
96
+ ```
97
+
98
+ ```tsx
99
+ // Need different columns? Don't fork this component — compose ScHeader.
100
+ <div style={{ display: "flex", gap: "var(--spacing-6xl)", padding: "var(--spacing-xl) var(--spacing-3xl)",
101
+ background: "var(--alias-fill-neutral-neutral)" }}>
102
+ <ScHeader text="App" state="none" style={{ flex: 1 }} />
103
+ <ScHeader text="Credits" state="none" style={{ flexShrink: 0, width: "5rem", justifyContent: "flex-end" }} />
104
+ </div>
105
+ ```
106
+
107
+ ---
108
+
109
+ ## 2. Where to use it
110
+
111
+ - **Billing → Invoice history tab**, immediately above the invoice rows. That is
112
+ its only surface.
113
+ - Rendered from the shared **`@streamoid/settings`** billing page
114
+ (`packages/settings/src/billing-content.tsx`, `InvoiceHistoryTable`), which
115
+ **CXO** mounts through `settings-content.tsx`. The sibling tab ("Usage logs") in
116
+ that same file **hand-rolls** its header with raw `ScHeader` cells rather than
117
+ using `ScBillingLogsTableHeader` — see that component's README for why.
118
+ - No mobile twin, and none is needed: the narrow-screen invoice list uses stacked
119
+ `InvoiceHistoryMobile` cards that carry their own labels. That path is currently
120
+ wired only in CXO's `src/app/components/mobile-billing-content.tsx:231`, reached
121
+ from CXO's orphaned local `billing-content.tsx`, so mobile billing is effectively
122
+ unwired today.
123
+
124
+ ---
125
+
126
+ ## 3. When to use it
127
+
128
+ ### Use it when
129
+
130
+ - Your columns are exactly `Invoice / Amount / Date / Action`, i.e. you are
131
+ rendering `ScBillingHistoryTableList` rows.
132
+
133
+ ### Don't use it — reach for this instead
134
+
135
+ | Situation | Use instead |
136
+ |---|---|
137
+ | Credit/usage logs columns (`App`, `Activity`, `Used by`, `Date`, `Credits`) | `ScBillingLogsTableHeader` — but read its README first; production hand-rolls that one |
138
+ | Any other column set, or renamed/localised labels | `ScHeader` cells in your own flex row (see the second recipe) |
139
+ | A sortable header | `ScHeader` with `state="up"` / `"down"` and your own click handling |
140
+ | A page title bar, not a table header | `ScHeader` alone, or your page-header composition |
141
+ | Mobile invoice list | `InvoiceHistoryMobile` (self-labelling cards, no header row) |
142
+
143
+ ### Don't confuse with
144
+
145
+ | You may actually want | Not this |
146
+ |---|---|
147
+ | `ScHeader` — the single header **cell** primitive (`text`, `state`, spreads props) | This is a fixed 4-cell **strip** |
148
+ | `ScBillingLogsTableHeader` — the 6-column credit-logs strip | Same shape, different labels and widths; the two are not interchangeable |
149
+ | `ScTableHeader` — the generic list/table header used elsewhere in the library | Not billing-specific and not width-matched to the invoice rows |
150
+ | `ScMobileTopNav` — a mobile screen's top bar | Nothing to do with tables |
151
+
152
+ ---
153
+
154
+ ## 4. Why to use it
155
+
156
+ - **The widths are the contract.** The `7.5rem / 7.5rem / 10rem` trio and the
157
+ `1.5rem` gap are duplicated in `ScBillingHistoryTableList`; using both components
158
+ guarantees alignment, whereas a hand-rolled header drifts the moment either side
159
+ changes.
160
+ - **Header typography and fill come from tokens** via `ScHeader` and
161
+ `--alias-fill-neutral-neutral`, so the strip stays legible in light mode.
162
+ - **Zero API surface means zero drift** — every invoice table in the product shows
163
+ the same four labels in the same order.
164
+
165
+ ---
166
+
167
+ ## Gotchas
168
+
169
+ **1. There is nothing to configure.** No labels, no widths, no sort state, no
170
+ `style`. If you need any of that, compose `ScHeader` yourself — copying this
171
+ component's flex values is a two-line job.
172
+
173
+ **2. Not sticky, not rounded.** It renders a plain flex row with a square neutral
174
+ background. The rounded card, the sticky positioning and the top-corner clipping all
175
+ belong to your wrapper.
176
+
177
+ **3. Extra props are silently dropped.** `({ className, ...props })` destructures a
178
+ rest object that is never used. TypeScript will reject the prop, but if you spread
179
+ a wider object through `as any`, it disappears with no warning.
180
+
181
+ **4. Missing `className` leaks `"undefined"` into the class list** (root is
182
+ `styles.scBillingHistoryHeader + " " + className`).
183
+
184
+ **5. No table semantics.** No `<table>`, `<thead>`, `<th>` or `role="columnheader"`
185
+ — screen readers see four unrelated strings, and nothing associates them with the
186
+ row cells beneath.
187
+
188
+ **6. Alignment is by convention, not by grid.** If you render a custom row under
189
+ this header, you must repeat `gap: 1.5rem`, `padding: … 1rem` and the three fixed
190
+ widths, or the columns will not line up.
191
+
192
+ ---
193
+
194
+ ## In the wild
195
+
196
+ ```tsx
197
+ // npm-components packages/settings/src/billing-content.tsx:1117
198
+ <div style={{ position: "sticky", top: 0, zIndex: 1, backgroundColor: "var(--alias-surface-base)" }}>
199
+ <ScBillingHistoryHeader />
200
+ </div>
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Related
206
+
207
+ - `ScBillingHistoryTableList` — the row component this header exists for.
208
+ - `ScHeader` — the cell primitive; use it directly for any other column set.
209
+ - `ScBillingLogsTableHeader` — the credit-logs sibling strip.
210
+ - `InvoiceHistoryMobile` — the stacked mobile alternative to this whole table.
@@ -0,0 +1,243 @@
1
+ ---
2
+ component: ScBillingHistoryTableList
3
+ package: "@streamoid/ui"
4
+ category: billing
5
+ status: stable
6
+ renders: div
7
+ tags: [invoice, invoice-row, billing-history, table-row, download-invoice, receipt, billing]
8
+ related: [ScBillingHistoryHeader, InvoiceHistoryMobile, ScPairtext, ScBillingLogsTableList, ScTableList]
9
+ do_not_confuse_with: [ScBillingLogsTableList, ScTableList, InvoiceHistoryMobile]
10
+ used_by: [cxo]
11
+ ---
12
+
13
+ # ScBillingHistoryTableList
14
+
15
+ **One invoice row in the billing-history table.** Invoice number (flexible width,
16
+ ellipsised), amount in success green, date, and a "Download invoice" `ScPairtext`
17
+ with a download icon — width-matched to `ScBillingHistoryHeader` and separated by a
18
+ bottom hairline.
19
+
20
+ ## TL;DR for agents
21
+
22
+ - **Reach for it when:** you are listing invoices under a `ScBillingHistoryHeader`.
23
+ - **Don't reach for it when:** the row is a credit/usage log entry
24
+ (→ `ScBillingLogsTableList`), a generic data row (→ `ScTableList`), or the mobile
25
+ stacked invoice card (→ `InvoiceHistoryMobile`).
26
+ - **Four things that will bite you:**
27
+ 1. `onRowClick` is wired to the root's `onClick` **before** `...props` is spread,
28
+ so passing your own `onClick` **replaces** `onRowClick` entirely.
29
+ 2. The download cell has **no handler of its own**. Either treat the whole row as
30
+ the download target, or hit-test the event against the CSS-module class (what
31
+ production does).
32
+ 3. `amount` is **always success green**. Refunds, failures and zero amounts all
33
+ render as if they were paid.
34
+ 4. Every value has demo-data default (`"# INV-2800-2026"`, `"₹320.89"`,
35
+ `"Nov 9th, 2025"`), so a wrong prop name shows plausible fake data instead of
36
+ failing.
37
+
38
+ ---
39
+
40
+ ## 1. How to use it
41
+
42
+ ### Import
43
+
44
+ ```tsx
45
+ import { ScBillingHistoryHeader, ScBillingHistoryTableList } from "@streamoid/ui";
46
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
47
+ ```
48
+
49
+ ### Minimal usage
50
+
51
+ ```tsx
52
+ <ScBillingHistoryTableList
53
+ invoiceNumber="# INV-3F92A0C1"
54
+ amount="₹4,999.00"
55
+ date="Nov 9th, 2025"
56
+ onRowClick={() => downloadInvoice(inv)}
57
+ />
58
+ ```
59
+
60
+ ### Props
61
+
62
+ | Prop | Type | Default | Notes |
63
+ |---|---|---|---|
64
+ | `invoiceNumber` | `string` | `"# INV-2800-2026"` | ⚠️ Real default. `flex: 1`, ellipsised. You supply the `#` prefix. |
65
+ | `amount` | `string` | `"₹320.89"` | ⚠️ Real default. Fixed `7.5rem`. Colour is hardcoded success green. |
66
+ | `date` | `string` | `"Nov 9th, 2025"` | ⚠️ Real default. Fixed `7.5rem`. Pre-formatted by you. |
67
+ | `downloadLabel` | `string` | `"Download invoice"` | ⚠️ Real default. Label of the icon+text action cell (`10rem`). |
68
+ | `onRowClick` | `() => void` | – | Bound to the root `onClick`. **Overridden by an `onClick` you pass** — see Gotcha 1. |
69
+ | `className` | `string` | – | Appended to the root class. |
70
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | Spread onto the root **after** `onClick={onRowClick}`. |
71
+
72
+ ### Layout (matches `ScBillingHistoryHeader`)
73
+
74
+ | Cell | Width | Styling |
75
+ |---|---|---|
76
+ | `invoiceNumber` | `flex: 1` | primary text, 14px, ellipsis |
77
+ | `amount` | `7.5rem` | **`--alias-text-and-icons-success`**, 16px semibold, ellipsis |
78
+ | `date` | `7.5rem` | primary text, 14px, ellipsis |
79
+ | download `ScPairtext` | `10rem` | `cursor: pointer`, download icon + `downloadLabel` |
80
+
81
+ Root: `padding: 1.25rem 1rem`, `gap: 1.5rem`, bottom border
82
+ `--alias-border-subtle`. No background of its own — it inherits the wrapper's.
83
+
84
+ ### Recipes
85
+
86
+ ```tsx
87
+ // Whole row is the download target (simplest correct wiring)
88
+ {invoices.map((inv) => (
89
+ <ScBillingHistoryTableList
90
+ key={inv._id}
91
+ invoiceNumber={`# ${inv.transactionId.slice(0, 16).toUpperCase()}`}
92
+ amount={`${currencySymbol}${(inv.amount / 100).toFixed(2)}`}
93
+ date={formatDate(inv.createdAt)}
94
+ downloadLabel="Download invoice"
95
+ onRowClick={() => handleDownload(inv)}
96
+ />
97
+ ))}
98
+
99
+ // Only the "Download invoice" cell should act (the production pattern):
100
+ // use onClick + hit-test the pairtext by its emitted CSS-module class.
101
+ const handleRowClick = (e: React.MouseEvent<HTMLDivElement>, inv: Invoice) => {
102
+ const hit = (e.target as HTMLElement).closest(
103
+ `.${CSS.escape("ScBillingHistoryTableList_scPairtextInstance")}`,
104
+ );
105
+ if (hit) handleDownload(inv);
106
+ };
107
+
108
+ <ScBillingHistoryTableList
109
+ invoiceNumber={n}
110
+ amount={a}
111
+ date={d}
112
+ onClick={(e: React.MouseEvent<HTMLDivElement>) => handleRowClick(e, inv)}
113
+ />
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 2. Where to use it
119
+
120
+ - **Billing → Invoice history tab**, stacked directly under
121
+ `ScBillingHistoryHeader` inside a rounded, scrolling surface. Its only surface.
122
+ - Rendered from the shared **`@streamoid/settings`** billing page
123
+ (`packages/settings/src/billing-content.tsx`, `InvoiceHistoryTable`), which
124
+ **CXO** mounts through `settings-content.tsx`.
125
+ - The mobile equivalent is `InvoiceHistoryMobile` (stacked card, self-labelling) —
126
+ currently only wired from CXO's orphaned local mobile billing file.
127
+
128
+ ---
129
+
130
+ ## 3. When to use it
131
+
132
+ ### Use it when
133
+
134
+ - The row is an **invoice** with exactly the `Invoice / Amount / Date / Download`
135
+ shape, and you are pairing it with `ScBillingHistoryHeader`.
136
+ - The amount is a **successful charge** (the green is not negotiable).
137
+
138
+ ### Don't use it — reach for this instead
139
+
140
+ | Situation | Use instead |
141
+ |---|---|
142
+ | Credit/usage log entry (App, Activity, Used by, Date, Credits) | `ScBillingLogsTableList` — but read its README; production hand-rolls that table |
143
+ | A generic data row with your own columns | `ScTableList` (or raw divs mirroring the header's widths) |
144
+ | Narrow-screen invoice list | `InvoiceHistoryMobile` |
145
+ | A refunded / failed / pending amount that must not read as green | Hand-roll the row — this component cannot express a non-success amount |
146
+ | A real download link (right-click → Save as, middle-click, keyboard) | Your own `<a href download>` — this row is a `div` with no link semantics |
147
+
148
+ ### Don't confuse with
149
+
150
+ | You may actually want | Not this |
151
+ |---|---|
152
+ | `ScBillingLogsTableList` — 6 columns (`app`, `activity`, `usedBy`, `date`, `creditsUsed`, `balance`), credits hardcoded **red** | This one is 4 columns with the amount hardcoded **green** |
153
+ | `InvoiceHistoryMobile` — exported, props `invoiceId` / `date` / `amount` | Not a responsive mode of this row |
154
+ | `ScInvoiceHistoryMobile` (folder `SC-InvoiceHistory-Mobile`) | ⚠️ **Not exported from the package index** — importing it from `@streamoid/ui` fails. Use `InvoiceHistoryMobile`. |
155
+ | `ScTableList` — the generic list row used across the dashboards | Not width-matched to the invoice header |
156
+
157
+ ---
158
+
159
+ ## 4. Why to use it
160
+
161
+ - **Column widths are the contract.** `flex:1 / 7.5rem / 7.5rem / 10rem` plus a
162
+ `1.5rem` gap and `1rem` side padding mirror `ScBillingHistoryHeader` exactly, so
163
+ the header and the rows can't drift apart.
164
+ - **Every cell already truncates.** All three text cells are
165
+ `nowrap + overflow:hidden + ellipsis`, so a long transaction id degrades instead
166
+ of breaking the row.
167
+ - **The download affordance is a composed `ScPairtext`**, so the icon size, gap and
168
+ label typography match every other icon+text pair in the product.
169
+ - **Amount emphasis is tokenised** (`--alias-text-and-icons-success`), so it holds
170
+ contrast in light mode where a hardcoded `#00b96b` would not.
171
+
172
+ ---
173
+
174
+ ## Gotchas
175
+
176
+ **1. `onClick` beats `onRowClick`.** The JSX is
177
+ `onClick={onRowClick} {...props}`, so a spread `onClick` overwrites it. Never pass
178
+ both.
179
+
180
+ ```tsx
181
+ // WRONG — onRowClick never fires
182
+ <ScBillingHistoryTableList onRowClick={download} onClick={logClick} />
183
+
184
+ // RIGHT — pick one; use onClick when you need the event object
185
+ <ScBillingHistoryTableList onClick={(e) => { logClick(); download(); }} />
186
+ ```
187
+
188
+ **2. The download cell has no handler.** `ScPairtext` only gets `cursor: pointer`.
189
+ Clicking it bubbles to the row. To make *only* that cell act, hit-test
190
+ `event.target.closest(".ScBillingHistoryTableList_scPairtextInstance")` — that
191
+ class name is part of the emitted CSS-module output and is what the live billing
192
+ page relies on. It is effectively a private API: if the module class prefix ever
193
+ changes, your hit-test silently stops matching.
194
+
195
+ **3. Green amounts, always.** `.amount` is `--alias-text-and-icons-success`. There
196
+ is no `variant`/`status` prop, so credits notes and failed charges look paid.
197
+
198
+ **4. Demo defaults hide typos.** Misspell `invoiceNumber` and the row cheerfully
199
+ shows `"# INV-2800-2026"` / `"₹320.89"` / `"Nov 9th, 2025"`. Check prop names
200
+ against the table when a row looks oddly plausible.
201
+
202
+ **5. Not a link, not focusable.** It is a `div` with an `onClick` — no `role`, no
203
+ `tabIndex`, no keyboard activation, no browser download semantics. Keyboard users
204
+ cannot download an invoice from this row.
205
+
206
+ **6. The bottom border is unconditional.** The last row keeps its hairline; if your
207
+ container has its own bottom edge you get a double line. Trim it from the wrapper.
208
+
209
+ **7. No background.** The row is transparent, so the wrapper owns the surface
210
+ colour — important when you also make the header sticky (the header needs an opaque
211
+ background or rows show through).
212
+
213
+ **8. Missing `className` leaks `"undefined"` into the class list.**
214
+
215
+ **9. Trailing spaces in the DOM.** `invoiceNumber`, `amount` and `date` each render
216
+ as `{value}` plus a literal space; trim before exact-match text assertions.
217
+
218
+ ---
219
+
220
+ ## In the wild
221
+
222
+ ```tsx
223
+ // npm-components packages/settings/src/billing-content.tsx:1138
224
+ <ScBillingHistoryTableList
225
+ key={inv._id}
226
+ invoiceNumber={inv.transactionId ? `# ${inv.transactionId.slice(0, 16).toUpperCase()}` : "# INV-UNKNOWN"}
227
+ amount={inv.amountPaid != null
228
+ ? `${currencySymbol}${inv.amountPaid.toFixed(2)}`
229
+ : `${currencySymbol}${(inv.amount / 100).toFixed(2)}`}
230
+ date={formatDate(inv.createdAt)}
231
+ downloadLabel="Download invoice"
232
+ onClick={(e: React.MouseEvent<HTMLDivElement>) => handleRowClick(e, inv)}
233
+ />
234
+ ```
235
+
236
+ ---
237
+
238
+ ## Related
239
+
240
+ - `ScBillingHistoryHeader` — the header strip whose widths this row mirrors.
241
+ - `InvoiceHistoryMobile` — the stacked mobile card for the same data.
242
+ - `ScBillingLogsTableList` — the credit-logs row sibling.
243
+ - `ScPairtext` — the icon+label pair used for the download cell.