@streamoid/ui 0.6.16 → 0.6.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -18
- package/dist/docs/AGENTS.md +321 -0
- package/dist/docs/CreditWarningBanner.md +305 -0
- package/dist/docs/InvoiceHistoryMobile.md +222 -0
- package/dist/docs/ScAccess.md +259 -0
- package/dist/docs/ScAppCard.md +244 -0
- package/dist/docs/ScAppCardForCopilot.md +230 -0
- package/dist/docs/ScAppCardV3.md +273 -0
- package/dist/docs/ScAppField.md +308 -0
- package/dist/docs/ScAppListingCard.md +271 -0
- package/dist/docs/ScAppSwitchPanel.md +286 -0
- package/dist/docs/ScAppcardLogos.md +226 -0
- package/dist/docs/ScArtifaxInvite.md +262 -0
- package/dist/docs/ScArtifaxSidebar.md +330 -0
- package/dist/docs/ScAskAgentButton.md +307 -0
- package/dist/docs/ScBadges.md +261 -0
- package/dist/docs/ScBeacon.md +244 -0
- package/dist/docs/ScBillingHistoryHeader.md +210 -0
- package/dist/docs/ScBillingHistoryTableList.md +243 -0
- package/dist/docs/ScBillingLogsTableHeader.md +212 -0
- package/dist/docs/ScBillingLogsTableList.md +251 -0
- package/dist/docs/ScBriefCard.md +255 -0
- package/dist/docs/ScButton.md +251 -0
- package/dist/docs/ScCalendar.md +268 -0
- package/dist/docs/ScCalendarDateComps.md +264 -0
- package/dist/docs/ScCatalogixInvite.md +345 -0
- package/dist/docs/ScCatalogixSidebar.md +337 -0
- package/dist/docs/ScCatalogixStoreHeader.md +246 -0
- package/dist/docs/ScCatalogixStoreTableList.md +316 -0
- package/dist/docs/ScCheckField.md +233 -0
- package/dist/docs/ScCheckbox.md +272 -0
- package/dist/docs/ScCounter.md +235 -0
- package/dist/docs/ScCreditsUsageCard.md +247 -0
- package/dist/docs/ScCreditsUsageCardMobile.md +224 -0
- package/dist/docs/ScDefaultCard.md +269 -0
- package/dist/docs/ScDp.md +245 -0
- package/dist/docs/ScDrawer.md +318 -0
- package/dist/docs/ScFieldButton.md +255 -0
- package/dist/docs/ScFileField.md +268 -0
- package/dist/docs/ScGoogleSignIn.md +250 -0
- package/dist/docs/ScGuide.md +278 -0
- package/dist/docs/ScHDivider.md +213 -0
- package/dist/docs/ScHeader.md +222 -0
- package/dist/docs/ScImageField.md +253 -0
- package/dist/docs/ScInChatList.md +277 -0
- package/dist/docs/ScInChatMessage.md +205 -0
- package/dist/docs/ScInfoPopup.md +248 -0
- package/dist/docs/ScIntialProfileCover.md +233 -0
- package/dist/docs/ScInvoiceHistoryMobile.md +187 -0
- package/dist/docs/ScLogoUnit.md +232 -0
- package/dist/docs/ScMappingCard.md +241 -0
- package/dist/docs/ScMediaApproval.md +301 -0
- package/dist/docs/ScMediaSelect.md +310 -0
- package/dist/docs/ScMenuOptions.md +308 -0
- package/dist/docs/ScMobileBottomAction.md +252 -0
- package/dist/docs/ScMobileTopNav.md +279 -0
- package/dist/docs/ScModal.md +291 -0
- package/dist/docs/ScOnlyField.md +302 -0
- package/dist/docs/ScOnlyIcon.md +213 -0
- package/dist/docs/ScPagination.md +284 -0
- package/dist/docs/ScPairtext.md +287 -0
- package/dist/docs/ScPendingAction.md +238 -0
- package/dist/docs/ScPhtogenixInvite.md +275 -0
- package/dist/docs/ScPlanCard.md +302 -0
- package/dist/docs/ScPlanComparison.md +264 -0
- package/dist/docs/ScPlanDetailsCard.md +246 -0
- package/dist/docs/ScPlanDetailsCardMobile.md +240 -0
- package/dist/docs/ScPopUpMenu.md +224 -0
- package/dist/docs/ScProfile.md +234 -0
- package/dist/docs/ScProfileImageUpdate.md +261 -0
- package/dist/docs/ScProfileOptions.md +245 -0
- package/dist/docs/ScProfilePopup.md +396 -0
- package/dist/docs/ScProfileSettingsComp.md +250 -0
- package/dist/docs/ScProfileV2Mobile.md +216 -0
- package/dist/docs/ScProgressBar.md +267 -0
- package/dist/docs/ScQuickPrompt.md +277 -0
- package/dist/docs/ScRadio.md +228 -0
- package/dist/docs/ScReferralCardMobile.md +226 -0
- package/dist/docs/ScReferralTableHeader.md +260 -0
- package/dist/docs/ScReferralTableList.md +293 -0
- package/dist/docs/ScRole.md +226 -0
- package/dist/docs/ScRoleMobile.md +199 -0
- package/dist/docs/ScSelect.md +270 -0
- package/dist/docs/ScSelection.md +256 -0
- package/dist/docs/ScSelectionList.md +272 -0
- package/dist/docs/ScSelectionPill.md +240 -0
- package/dist/docs/ScSelectionPillGroup.md +302 -0
- package/dist/docs/ScSettingsNav.md +212 -0
- package/dist/docs/ScSettingsTabComp.md +260 -0
- package/dist/docs/ScSideBarLogoUnit.md +340 -0
- package/dist/docs/ScSidebar.md +243 -0
- package/dist/docs/ScSidebarIcons.md +232 -0
- package/dist/docs/ScSidebarMenu.md +283 -0
- package/dist/docs/ScSidebarProfile.md +231 -0
- package/dist/docs/ScSidebarSwitchMenu.md +258 -0
- package/dist/docs/ScSlider.md +194 -0
- package/dist/docs/ScStoreCard.md +252 -0
- package/dist/docs/ScStrLogo.md +253 -0
- package/dist/docs/ScStreamoidWordmark.md +302 -0
- package/dist/docs/ScSubAgent.md +226 -0
- package/dist/docs/ScTabComp.md +308 -0
- package/dist/docs/ScTabField.md +258 -0
- package/dist/docs/ScTabSwitcher.md +307 -0
- package/dist/docs/ScTableHeader.md +261 -0
- package/dist/docs/ScTableList.md +301 -0
- package/dist/docs/ScTableListMobile.md +282 -0
- package/dist/docs/ScTabs.md +268 -0
- package/dist/docs/ScTaxonomyPill.md +263 -0
- package/dist/docs/ScTextArea.md +259 -0
- package/dist/docs/ScTextField.md +324 -0
- package/dist/docs/ScThinkingStepIcon.md +249 -0
- package/dist/docs/ScTodoList.md +288 -0
- package/dist/docs/ScToggleSwitch.md +229 -0
- package/dist/docs/ScUsageHistoryMobile.md +194 -0
- package/dist/docs/ScVDivider.md +215 -0
- package/dist/docs/ScValueMappingL1.md +256 -0
- package/dist/docs/ScVersion.md +251 -0
- package/dist/docs/ScWorkspace.md +233 -0
- package/dist/docs/ScWorkspaceCard.md +234 -0
- package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
- package/dist/docs/ScWorkspaceSwitchCard.md +314 -0
- package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
- package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
- package/dist/docs/StreamoidSidebar.md +403 -0
- package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
- package/dist/docs/UsageHistoryMobile.md +235 -0
- package/dist/docs/components.json +4849 -0
- package/dist/index.css +43 -37
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- 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.
|