@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.
Files changed (131) hide show
  1. package/README.md +35 -18
  2. package/dist/docs/AGENTS.md +321 -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 +213 -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/ScWorkspaceCard.md +234 -0
  120. package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
  121. package/dist/docs/ScWorkspaceSwitchCard.md +314 -0
  122. package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
  123. package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
  124. package/dist/docs/StreamoidSidebar.md +403 -0
  125. package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
  126. package/dist/docs/UsageHistoryMobile.md +235 -0
  127. package/dist/docs/components.json +4849 -0
  128. package/dist/index.css +36 -36
  129. package/dist/index.d.mts +10 -0
  130. package/dist/index.d.ts +10 -0
  131. package/package.json +3 -2
@@ -0,0 +1,229 @@
1
+ ---
2
+ component: ScToggleSwitch
3
+ package: "@streamoid/ui"
4
+ category: forms
5
+ status: stable
6
+ renders: div
7
+ tags: [toggle, switch, on-off, enable, disable, setting, instant-apply, boolean]
8
+ related: [ScCheckbox, ScAppField, ScCatalogixInvite, ScPhtogenixInvite, ScArtifaxInvite]
9
+ do_not_confuse_with: [ScCheckbox, ScAppSwitchPanel, ScWorkspaceSwitchCard, ScTabSwitcher, ScAppField]
10
+ used_by: [catalogix]
11
+ ---
12
+
13
+ # ScToggleSwitch
14
+
15
+ **The on/off switch — a 40×24 pill with a knob.** Two hand-traced SVGs (one per
16
+ state) inside a clickable `<div>`. Use it for settings that apply the moment they
17
+ are flipped; use `ScCheckbox` for values a form stages until Save.
18
+
19
+ ## TL;DR for agents
20
+
21
+ - **Reach for it when:** a single boolean setting applies immediately — enable a
22
+ feature, mute a rule, turn on an app for a user.
23
+ - **Don't reach for it when:** the value is staged behind a Save button
24
+ (→ `ScCheckbox` / `ScCheckField`), or you are building the CXO app-permission block
25
+ (→ `ScAppField`, which already renders these).
26
+ - **Four things that will bite you:**
27
+ 1. `active` is the **string** `"true"`/`"false"`, not a boolean. ⚠️ Prefer `checked`.
28
+ 2. `checked` **overrides** `active` whenever it is not `undefined`.
29
+ 3. The OFF artwork is 41×25 and ON is 40×24 — the element **changes size by half a
30
+ pixel** as you toggle. Wrap it if you need a stable box.
31
+ 4. There is **no animation**. The two states are separate SVGs; the knob jumps.
32
+
33
+ ---
34
+
35
+ ## 1. How to use it
36
+
37
+ ### Import
38
+
39
+ ```tsx
40
+ import { ScToggleSwitch } from "@streamoid/ui";
41
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
42
+ ```
43
+
44
+ ### Minimal usage
45
+
46
+ ```tsx
47
+ <ScToggleSwitch checked={isEnabled} onToggle={setIsEnabled} />
48
+ ```
49
+
50
+ ### Props
51
+
52
+ | Prop | Type | Default | Notes |
53
+ |---|---|---|---|
54
+ | `checked` | `boolean` | – | The modern, controlled input. **Wins over `active`** when not `undefined`. Use this. |
55
+ | `active` | `"true"` \| `"false"` | `"false"` | ⚠️ **String** union, the Figma-traced legacy axis. `active="false"` means OFF despite being a truthy string. |
56
+ | `disabled` | `boolean` | `false` | `cursor: not-allowed` + `opacity: 0.5`; the click handler early-returns before `onToggle` **and** your `onClick`. Does not stop propagation. |
57
+ | `onToggle` | `(active: boolean) => void` | – | Fires with the *next* value. The handler you want. |
58
+ | `className` | `string` | – | Concatenated between the base and state classes. |
59
+ | `...props` | `Omit<HTMLAttributes<HTMLDivElement>, "onToggle">` | – | Spread onto the root. `onClick` and `style` are **re-applied after** the spread, so the component's own versions win — but yours are still honoured (see Gotchas 5 and 6). |
60
+
61
+ ### What renders in each state
62
+
63
+ | Effective state | Artwork | Tokens | Box |
64
+ |---|---|---|---|
65
+ | ON | 40×24 rounded track, knob at `cx=28` | track `--alias-fill-base-base`, knob `--alias-text---icons-inverse` | `2.5rem × 1.5rem` |
66
+ | OFF | 41×25 track + hairline outline, knob at `cx≈12` | track `--alias-fill-neutral-neutral`, outline `--alias-border-divider`, knob `--alias-fill-neutral-neutralactive` | `2.53125rem × 1.53125rem` |
67
+
68
+ Effective state is `checked !== undefined ? checked : active === "true"`.
69
+
70
+ ### Recipes
71
+
72
+ ```tsx
73
+ // Instant-apply setting
74
+ <ScToggleSwitch
75
+ checked={rule.enabled}
76
+ onToggle={(next) => patchRule(rule.id, { enabled: next })}
77
+ />
78
+
79
+ // Read-only / not-yet-entitled
80
+ <ScToggleSwitch checked={false} disabled onToggle={noop} />
81
+
82
+ // Inside a labelled settings row (you own the label — the switch has none)
83
+ <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
84
+ <span>Auto-sync every night</span>
85
+ <ScToggleSwitch checked={autoSync} onToggle={setAutoSync} aria-label="Auto-sync" />
86
+ </div>
87
+
88
+ // Legacy event-shaped callback (the Catalogix shim), if a call site expects e.target.checked
89
+ <ScToggleSwitch
90
+ checked={!!value}
91
+ onToggle={(next) => onChange({ target: { checked: next } })}
92
+ />
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 2. Where to use it
98
+
99
+ - **Catalogix settings and product screens** — via the local
100
+ `app/components/Toggle` shim, which replaced a native `<input type=checkbox>` +
101
+ CSS slider (that version didn't theme).
102
+ - **Inside the DS's invite components** — `ScCatalogixInvite`, `ScPhtogenixInvite`
103
+ and `ScArtifaxInvite` each render one, and `ScAppField` composes those. If you are
104
+ building an app-permission block, use `ScAppField` and pass its
105
+ `onCatalogixToggle` / `onPhotogenixToggle` / `onArtifaxToggle` props rather than
106
+ nesting your own switches.
107
+ - **Settings rows** where the change is saved immediately.
108
+
109
+ ---
110
+
111
+ ## 3. When to use it
112
+
113
+ ### Use it when
114
+
115
+ - The boolean **takes effect on click** (a setting, a feature flag, an entitlement).
116
+ - There is exactly one thing being turned on or off, with its label to the left.
117
+
118
+ ### Don't use it — reach for this instead
119
+
120
+ | Situation | Use instead |
121
+ |---|---|
122
+ | A form value confirmed later with Save/Invite | `ScCheckbox` / `ScCheckField` |
123
+ | Several booleans under one caption | `ScCheckField` |
124
+ | Per-app enable + store selection in an invite/manage flow | `ScAppField` (composes `ScCatalogixInvite` etc.) |
125
+ | Choosing between two *modes* (not on/off) | `ScTabField` / `ScSelectionPillGroup` |
126
+ | Switching workspace or app | `ScWorkspaceSwitchCard` / `ScAppSwitchPanel` — "switch" in those names means navigation, not a boolean |
127
+ | A form control that submits with a `<form>` | native `<input type="checkbox" role="switch">` |
128
+
129
+ ### Don't confuse with
130
+
131
+ | You may actually want | Not this |
132
+ |---|---|
133
+ | `ScTabSwitcher` — a segmented tab bar | Not a toggle switch |
134
+ | `ScAppSwitchPanel` / `ScWorkspaceSwitchCard` — app/workspace pickers | "Switch" as in *switch to*, not on/off |
135
+ | `ScCheckbox` — staged boolean, has a `partial` state | This switch is two-state only |
136
+ | `ScAppField` — the whole app-permission block | Don't rebuild it from bare switches |
137
+
138
+ ---
139
+
140
+ ## 4. Why to use it
141
+
142
+ - **It themes.** Catalogix swapped its CSS slider for this precisely because the
143
+ hand-rolled one was baked for one theme. Track, outline and knob all come from
144
+ `--alias-*` tokens.
145
+ - **Exact Figma geometry.** 40×24 track, 10px knob radius, 12px corner — traced, not
146
+ approximated, so every switch in the product is identical.
147
+ - **One click contract.** `onToggle(next)` gives you the value you want to store; no
148
+ `e.target.checked` plumbing, no `preventDefault` dance.
149
+ - **`disabled` is handled in one place** — cursor, opacity and the handler guard —
150
+ instead of three slightly different implementations per app.
151
+
152
+ ---
153
+
154
+ ## Gotchas
155
+
156
+ **1. `active` is a string.** `"false"` is OFF. `active={false}` is a type error, and
157
+ `active` with any other string silently reads as OFF.
158
+
159
+ ```tsx
160
+ // WRONG — type error, and conceptually the wrong prop
161
+ <ScToggleSwitch active={isOn} onToggle={setIsOn} />
162
+
163
+ // RIGHT — use the boolean prop
164
+ <ScToggleSwitch checked={isOn} onToggle={setIsOn} />
165
+ ```
166
+
167
+ **2. `checked` overrides `active`.** Passing both means `active` is dead code. Pick
168
+ `checked`.
169
+
170
+ **3. No internal state.** `onToggle` firing does not change the artwork; you must move
171
+ `checked` (or `active`). A switch that "doesn't respond" is almost always this.
172
+
173
+ **4. It's not an `<input>`.** No `role="switch"`, no `aria-checked`, no `tabIndex`, no
174
+ keyboard, no `name`/`value`, no form participation, and **no label** — add
175
+ `aria-label` and your own text.
176
+
177
+ **5. `onToggle` runs before your `onClick`, and both run.** The internal handler calls
178
+ `onToggle(!isActive)` then `props.onClick?.(e)`. Don't wire the same mutation twice.
179
+
180
+ **6. You cannot replace the root `onClick` or `cursor`.** `{...props}` is spread
181
+ *before* the component's own `onClick` and `style`, so the internal ones win. Your
182
+ `props.style` **is** merged (spread last inside the style object), and your
183
+ `props.onClick` **is** invoked from inside — but you can't suppress the toggle by
184
+ passing your own `onClick`. Use `disabled` for that.
185
+
186
+ **7. Half-pixel size change on toggle.** OFF is `2.53125rem × 1.53125rem`, ON is
187
+ `2.5rem × 1.5rem`. In a tightly packed flex row this shifts neighbours by a fraction
188
+ of a pixel every flip. Wrap it in a fixed-size box if that's visible.
189
+
190
+ **8. `disabled` does not stop propagation.** The click still bubbles to a parent row
191
+ handler even though the switch ignores it.
192
+
193
+ **9. No transition.** ON and OFF are two different SVG trees, so React swaps them —
194
+ the knob teleports. Don't promise a sliding animation in a spec.
195
+
196
+ **10. jsdom tests need a stub.** Host repos mock `@streamoid/ui` (see
197
+ `catalogix/dashboard app/tests/formControls.test.jsx`, which stubs
198
+ `ScToggleSwitch` with a div exposing `data-checked`) because the barrel import
199
+ touches `CSS.registerProperty`.
200
+
201
+ ---
202
+
203
+ ## In the wild
204
+
205
+ ```jsx
206
+ // catalogix/dashboard app/components/Toggle/index.jsx:17 (legacy-API shim)
207
+ <ScToggleSwitch
208
+ checked={!!props.checked}
209
+ disabled={props.disabled}
210
+ onToggle={(next) =>
211
+ props.onChange &&
212
+ props.onChange({
213
+ target: { checked: next },
214
+ currentTarget: { checked: next },
215
+ stopPropagation: () => {},
216
+ preventDefault: () => {},
217
+ })
218
+ }
219
+ />
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Related
225
+
226
+ - `ScCheckbox` — the staged-value sibling; also has an indeterminate state.
227
+ - `ScCheckField` — several staged booleans under one caption.
228
+ - `ScAppField` — the CXO app-permission block; renders these switches for you.
229
+ - `ScCatalogixInvite` / `ScPhtogenixInvite` / `ScArtifaxInvite` — per-app rows that embed one.
@@ -0,0 +1,194 @@
1
+ ---
2
+ component: ScUsageHistoryMobile
3
+ exported: false
4
+ package: "@streamoid/ui"
5
+ category: mobile
6
+ status: deprecated
7
+ renders: div
8
+ tags: [mobile, billing, usage, credits, log, row, unexported, dead-code, superseded]
9
+ related: [UsageHistoryMobile, ScInvoiceHistoryMobile, ScBillingLogsTableList]
10
+ do_not_confuse_with: [UsageHistoryMobile, ScInvoiceHistoryMobile, InvoiceHistoryMobile]
11
+ ---
12
+
13
+ # ScUsageHistoryMobile
14
+
15
+ **Do not use — this component is not shipped.** It is an earlier copy of the mobile
16
+ credit-usage 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 `IScUsageHistoryMobileProps` is not in `dist/index.d.ts`.
19
+ The shipped component is **`UsageHistoryMobile`** (no `Sc` prefix) in
20
+ `src/SC-UsageHistoryMobile/`.
21
+
22
+ ## TL;DR for agents
23
+
24
+ - **Reach for it when:** never. Use `UsageHistoryMobile` instead.
25
+ - **Don't reach for it when:** always — importing `ScUsageHistoryMobile` from
26
+ `@streamoid/ui` fails to type-check and resolves to `undefined` at runtime.
27
+ - **Two things that will bite you:**
28
+ 1. **It is not exported.** Verified: `grep -c scUsageHistoryMobile dist/index.css`
29
+ → `0`.
30
+ 2. **Three of its five prop names differ from the shipped twin** — `title`,
31
+ `usageCount`, `totalCount` became `serviceName`, `credits`, `balance`.
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 { UsageHistoryMobile } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+
46
+ // NOT THIS — `ScUsageHistoryMobile` is not an export of @streamoid/ui
47
+ ```
48
+
49
+ ### Minimal usage
50
+
51
+ ```tsx
52
+ <UsageHistoryMobile
53
+ serviceName={log.serviceName}
54
+ credits={log.amount.toLocaleString("en-US")}
55
+ userName={log.userName}
56
+ date={formatDate(log.createdAt)}
57
+ balance={log.balanceAfter.toLocaleString("en-US")}
58
+ />
59
+ ```
60
+
61
+ ### Props
62
+
63
+ Documented only so you can recognise the difference when migrating a call site.
64
+
65
+ | Prop | Type | Default | Notes |
66
+ |---|---|---|---|
67
+ | `title` | `string` | `"Artifax Generation"` | ⚠️ Demo default. **Renamed to `serviceName`** in the shipped twin. |
68
+ | `usageCount` | `string` | `"50"` | ⚠️ Demo default. **Renamed to `credits`.** Always error-red. |
69
+ | `userName` | `string` | `"Rohan"` | ⚠️ Demo default. Same name in the shipped twin. |
70
+ | `date` | `string` | `"Nov 9th, 2025"` | ⚠️ Demo default. Same name in the shipped twin. |
71
+ | `totalCount` | `string` | `"84,902"` | ⚠️ Demo default. **Renamed to `balance`.** |
72
+ | `onClick` | `(e: React.MouseEvent) => void` | – | **Only exists here.** The shipped twin has no click handler. |
73
+ | `className` | `string` | – | Unguarded concat — renders a literal `undefined` class when omitted. |
74
+ | `...props` | `React.HTMLAttributes<HTMLDivElement>` | – | **Only exists here.** The shipped twin accepts no extra props. |
75
+
76
+ ### Mapping between the two
77
+
78
+ | This (unexported) | Shipped `UsageHistoryMobile` |
79
+ |---|---|
80
+ | `title` | `serviceName` |
81
+ | `usageCount` | `credits` |
82
+ | `userName` | `userName` |
83
+ | `date` | `date` |
84
+ | `totalCount` | `balance` |
85
+ | `onClick` | *(none — wrap the row in your own clickable `div`)* |
86
+ | `...props` spread | *(none — `className` only)* |
87
+
88
+ Styling is equivalent: 16px padding, two flex rows, a 12px 0.5px vertical rule between
89
+ user and date, red 16px/600 credit figure, tertiary balance. One cosmetic difference —
90
+ this copy's vertical rule uses `--alias-border-subtle`, the shipped one uses
91
+ `--alias-border-divider`.
92
+
93
+ ### Recipes
94
+
95
+ ```tsx
96
+ // Migrating an old call site
97
+ // BEFORE
98
+ // <ScUsageHistoryMobile title={s} usageCount={c} userName={u} date={d} totalCount={b} onClick={open} />
99
+
100
+ // AFTER
101
+ <div onClick={open} className="cursor-pointer">
102
+ <UsageHistoryMobile serviceName={s} credits={c} userName={u} date={d} balance={b} />
103
+ </div>
104
+ ```
105
+
106
+ ---
107
+
108
+ ## 2. Where to use it
109
+
110
+ Nowhere. The surface it was drawn for — the "Usage history" tab of CXO's mobile billing
111
+ screen — is served by `UsageHistoryMobile`
112
+ (`cxo-dashboard/src/app/components/mobile-billing-content.tsx:254`).
113
+
114
+ ---
115
+
116
+ ## 3. When to use it
117
+
118
+ ### Use it when
119
+
120
+ Never. Treat this folder as source to delete, or as the place to land the fix if the
121
+ team decides the shipped row should regain `onClick` and a props spread — the two
122
+ capabilities this copy has and the shipped one lacks.
123
+
124
+ ### Don't use it — reach for this instead
125
+
126
+ | Situation | Use instead |
127
+ |---|---|
128
+ | A mobile credit-usage row | `UsageHistoryMobile` (`src/SC-UsageHistoryMobile/`) |
129
+ | A mobile invoice row | `InvoiceHistoryMobile` (`src/SC-InvoiceHistoryMobile/`) |
130
+ | Desktop credit/usage log table | `ScBillingLogsTableHeader` + `ScBillingLogsTableList` |
131
+ | A clickable mobile row with DS-provided semantics | `ScTableListMobile` (`onRowClick`) |
132
+
133
+ ### Don't confuse with
134
+
135
+ | You may actually want | Not this |
136
+ |---|---|
137
+ | `UsageHistoryMobile` — the exported row; `serviceName`/`credits`/`balance`, no `onClick` | This one is unexported and uses `title`/`usageCount`/`totalCount` |
138
+ | `ScInvoiceHistoryMobile` — the *other* unexported duplicate, for invoice rows | Same situation, different data |
139
+ | `InvoiceHistoryMobile` — the exported invoice row | One text column, green amount |
140
+
141
+ The library contains **two** unexported `Sc*`-prefixed duplicates —
142
+ `ScUsageHistoryMobile` and `ScInvoiceHistoryMobile` — while the exported pair
143
+ (`UsageHistoryMobile`, `InvoiceHistoryMobile`) are the only two components in the
144
+ **mobile** family without an `Sc` prefix. (The package has other un-prefixed exports —
145
+ `CreditWarningBanner`, `StreamoidSidebar`, `NscWorkspaceSwitch` — but none of them are
146
+ mobile.) That inversion is the easiest naming mistake to make in this family.
147
+
148
+ ---
149
+
150
+ ## 4. Why to use it
151
+
152
+ There is no reason to. What the shipped twin gives you that this does not: it is
153
+ actually in the bundle. What this gives you that the shipped twin does not: `onClick`
154
+ and a props spread — both reproducible today with a wrapper `div`.
155
+
156
+ ---
157
+
158
+ ## Gotchas
159
+
160
+ **1. It is not importable.** `src/index.ts` exports
161
+ `./SC-UsageHistoryMobile/UsageHistoryMobile` and nothing from
162
+ `./SC-UsageHistory-Mobile/`. The two folder names differ only by a hyphen.
163
+
164
+ **2. Its CSS is not in the shipped stylesheet.** Nothing imports the module, so esbuild
165
+ never sees `ScUsageHistoryMobile.module.css`. Even a deep import from source would
166
+ render **unstyled** in a consumer repo.
167
+
168
+ **3. Three renamed props.** Copying an old snippet across leaves `title`,
169
+ `usageCount` and `totalCount` unrecognised, so the shipped component silently falls
170
+ back to its demo defaults (`"Artifax Generation"`, `"50"`, `"84,902"`) — a row of
171
+ believable wrong numbers rather than an error.
172
+
173
+ **4. `className` is concatenated unguarded** here, emitting a literal `undefined`
174
+ class. The shipped twin guards with `?? ""`.
175
+
176
+ ---
177
+
178
+ ## In the wild
179
+
180
+ _No host render site found — used by the agent runtime / composed internally._
181
+
182
+ To be precise: it cannot have one — it is not exported, so no host *could* render it.
183
+ It is not agent-runtime either; it is dead source. The surface it was drawn for uses
184
+ the exported twin at
185
+ `cxo-dashboard/src/app/components/mobile-billing-content.tsx:254`.
186
+
187
+ ---
188
+
189
+ ## Related
190
+
191
+ - `UsageHistoryMobile` — **use this**; the shipped mobile usage row.
192
+ - `InvoiceHistoryMobile` — the shipped mobile invoice row.
193
+ - `ScInvoiceHistoryMobile` — the other unexported duplicate, same story.
194
+ - `ScBillingLogsTableHeader` / `ScBillingLogsTableList` — the desktop table.
@@ -0,0 +1,215 @@
1
+ ---
2
+ component: ScVDivider
3
+ package: "@streamoid/ui"
4
+ category: layout
5
+ status: stable
6
+ renders: div
7
+ tags: [divider, separator, vertical, hairline, rule, column-separator, pipe]
8
+ related: [ScHDivider]
9
+ do_not_confuse_with: [ScHDivider]
10
+ used_by: [cxo, catalogix, artifax]
11
+ ---
12
+
13
+ # ScVDivider
14
+
15
+ **The vertical hairline.** A zero-width `<div>` whose entire visible body is a
16
+ `border-left: 0.5px solid var(--alias-border-divider)`, stretched to the height of
17
+ its flex-row parent. Unlike its horizontal sibling it accepts a `color` override and
18
+ a real `style` prop.
19
+
20
+ ## TL;DR for agents
21
+
22
+ - **Reach for it when:** you need a rule between two things sitting side by side —
23
+ a search field and a close button, two stat columns, a toolbar's action groups.
24
+ - **Don't reach for it when:** the rule runs horizontally between stacked sections
25
+ (→ `ScHDivider`).
26
+ - **Three things that will bite you:**
27
+ 1. It only shows up in a **flex-row** parent (it relies on `align-self: stretch`
28
+ for its height). In a flex-column parent it is invisible.
29
+ 2. It's a **border**, not a background. Setting `width` or `background` does
30
+ nothing visible; thickness is `border-left-width`.
31
+ 3. `style` is merged **after** `color`, so `style={{ borderLeftColor: … }}`
32
+ silently wins over the `color` prop.
33
+
34
+ ---
35
+
36
+ ## 1. How to use it
37
+
38
+ ### Import
39
+
40
+ ```tsx
41
+ import { ScVDivider } from "@streamoid/ui";
42
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
43
+ ```
44
+
45
+ ### Minimal usage
46
+
47
+ ```tsx
48
+ <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
49
+ <Left />
50
+ <ScVDivider />
51
+ <Right />
52
+ </div>
53
+ ```
54
+
55
+ ### Props
56
+
57
+ | Prop | Type | Default | Notes |
58
+ |---|---|---|---|
59
+ | `color` | `string` | – | Sets `borderLeftColor` inline. Pass a **token var**, e.g. `"var(--alias-border-default)"`, not a hex. Overridable by `style` — see Gotcha 3. |
60
+ | `className` | `string` | – | Appended after the internal class (guarded, so no stray `"undefined"`). |
61
+ | `style` | `CSSProperties` | – | Merged **on top of** the `color`-derived style. |
62
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | Properly typed here (unlike `ScHDivider`) — `onClick`, `role`, `aria-*`, `data-*` all compile. |
63
+
64
+ ### What the stylesheet does
65
+
66
+ | Declaration | Consequence |
67
+ |---|---|
68
+ | `width: 0` + `border-left: 0.5px solid var(--alias-border-divider)` | The line *is* the border. Total footprint ≈ 0.5px. |
69
+ | `align-self: stretch` | Height = the flex-row parent's cross size. No `height` needed. |
70
+ | `flex-shrink: 0` | Won't be crushed out of existence in a tight row. |
71
+ | `box-sizing: border-box` | The border is included in the (zero) box width. |
72
+
73
+ ### Recipes
74
+
75
+ ```tsx
76
+ // Toolbar: separate the search field from the close affordance
77
+ <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
78
+ <ScOnlyField placeholderFilled="Search..." style={{ width: 256 }} />
79
+ <ScVDivider color="var(--alias-border-default)" />
80
+ <SiconClose onClick={onClose} />
81
+ </div>
82
+
83
+ // Force full-height inside a parent that isn't `align-items: stretch`
84
+ <ScVDivider style={{ alignSelf: "stretch" }} />
85
+
86
+ // Two stat columns inside a card
87
+ <div className="flex">
88
+ <Stat label="Used" value={used} />
89
+ <ScVDivider className="mx-4" />
90
+ <Stat label="Remaining" value={left} />
91
+ </div>
92
+ ```
93
+
94
+ ---
95
+
96
+ ## 2. Where to use it
97
+
98
+ - **Toolbars / search rows** — CXO's app-switcher separates the search field from
99
+ the close button with one.
100
+ - **Workspace and profile cards** — `ScWorkspaceCard`, `ScWorkspaceSwitchCard` and
101
+ `ScProfileImageUpdate` compose it internally to split metadata columns.
102
+ - **Workspace switcher lists** — Catalogix's `LeftMenu/WorkspaceListing` and the DS
103
+ `StreamoidWorkspaceSwitcher`.
104
+ - **Chat pending-action rows** — `ScPendingAction` uses it as the left rail.
105
+
106
+ Rendered by CXO, Catalogix and Artifax. Photogenix ships `ScHDivider` but has no
107
+ `ScVDivider` call site yet (its migration list still has it as a TODO).
108
+
109
+ ---
110
+
111
+ ## 3. When to use it
112
+
113
+ ### Use it when
114
+
115
+ - Two sibling elements share a horizontal row and need a visual break that a `gap`
116
+ alone doesn't give.
117
+ - You want the rule to auto-size to the row's height instead of guessing a `height`.
118
+
119
+ ### Don't use it — reach for this instead
120
+
121
+ | Situation | Use instead |
122
+ |---|---|
123
+ | Horizontal rule between stacked sections | `ScHDivider` |
124
+ | A full-height border around a panel | the panel's own `border` token |
125
+ | A tall left rail with content in it | your own flex column — this div can hold no children usefully (0 width) |
126
+ | Purely visual breathing room | a `gap`, not a divider |
127
+
128
+ ### Don't confuse with
129
+
130
+ | You may actually want | Not this |
131
+ |---|---|
132
+ | `ScHDivider` — horizontal, `height: 0.5px` background fill, **no** `color` prop and an untyped props bag | `ScVDivider` is vertical, border-based, `color`-aware and fully typed |
133
+
134
+ ---
135
+
136
+ ## 4. Why to use it
137
+
138
+ - **Correct in both themes.** `--alias-border-divider` resolves to `#d2d2d2` in
139
+ light and a near-black neutral in dark. A hardcoded `#242424` disappears on the
140
+ light canvas.
141
+ - **Height without arithmetic.** `align-self: stretch` means it always matches its
142
+ row, so the rule never ends 2px short of the neighbouring text.
143
+ - **Typed props.** Because it extends `HTMLAttributes`, you can add
144
+ `role="separator"` / `aria-orientation="vertical"` where the separation is
145
+ meaningful — something `ScHDivider` won't let you type.
146
+
147
+ ---
148
+
149
+ ## Gotchas
150
+
151
+ **1. Invisible in a flex-column parent.** In a column, `align-self: stretch` would
152
+ stretch its *width* — but the explicit `width: 0` wins — and nothing gives it a height.
153
+ Zero area either way.
154
+
155
+ ```tsx
156
+ // WRONG — renders nothing
157
+ <div style={{ display: "flex", flexDirection: "column" }}>
158
+ <A /><ScVDivider /><B />
159
+ </div>
160
+
161
+ // RIGHT
162
+ <div style={{ display: "flex", flexDirection: "column" }}>
163
+ <A /><ScHDivider /><B />
164
+ </div>
165
+ ```
166
+
167
+ **2. `width` and `background` do nothing.** The line is a left border. To make it
168
+ 2px, set `border-left-width`, not `width`.
169
+
170
+ ```tsx
171
+ // WRONG — still 0.5px
172
+ <ScVDivider style={{ width: 2, background: "red" }} />
173
+
174
+ // RIGHT
175
+ <ScVDivider style={{ borderLeftWidth: 2, borderLeftColor: "var(--alias-border-default)" }} />
176
+ ```
177
+
178
+ **3. `style` beats `color`.** The implementation is
179
+ `style={color ? { borderLeftColor: color, ...style } : style}` — your `style` spreads
180
+ last, so a `borderLeftColor` in `style` overrides the `color` prop. Pick one.
181
+
182
+ **4. `color` accepts any string, including hex.** Nothing stops you shipping
183
+ `color="#242424"`, which breaks light mode. Pass a token var.
184
+
185
+ **5. If the parent sets `align-items: center` (or `flex-start`), `align-self:
186
+ stretch` still applies** — but if a *host* class resets `align-self`, the divider
187
+ collapses. Catalogix pins it explicitly with `style={{ alignSelf: "stretch" }}`;
188
+ Artifax uses `className="self-stretch"`. Do the same when the row's alignment is
189
+ not `stretch`-friendly.
190
+
191
+ **6. It's decorative by default.** No `role`, no `aria-orientation`. Add them
192
+ yourself if the split carries meaning.
193
+
194
+ ---
195
+
196
+ ## In the wild
197
+
198
+ ```tsx
199
+ // cxo-dashboard src/app/components/app-switcher.tsx:258
200
+ <ScVDivider color="var(--alias-border-default)" />
201
+
202
+ // catalogix/dashboard app/containers/LeftMenu/WorkspaceListing/index.jsx:322
203
+ <ScVDivider style={{ alignSelf: "stretch" }} />
204
+
205
+ // artifax packages/shared/src/components/DashboardSidebar.tsx:1111
206
+ <ScVDivider className="self-stretch" />
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Related
212
+
213
+ - `ScHDivider` — the horizontal sibling; no `color` prop, untyped props bag.
214
+ - `ScWorkspaceCard` / `ScWorkspaceSwitchCard` / `ScProfileImageUpdate` /
215
+ `ScPendingAction` — DS components that already compose one internally.