@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,212 @@
1
+ ---
2
+ component: ScSettingsNav
3
+ package: "@streamoid/ui"
4
+ category: layout
5
+ status: legacy
6
+ renders: div
7
+ tags: [settings, nav, left-nav, sidebar, profile, workspace, referral, static, figma-dump]
8
+ related: [ScSidebarMenu, ScSettingsTabComp, StreamoidSidebar, ScProfileSettingsComp]
9
+ do_not_confuse_with: [ScSettingsTabComp, ScSidebarMenu, ScSidebar, StreamoidSidebar, ScProfileSettingsComp]
10
+ ---
11
+
12
+ # ScSettingsNav
13
+
14
+ **A hardcoded 256×290px settings left-nav card — Profile / Workspace / Referral, with
15
+ Profile permanently active and nothing clickable.** It takes no props other than
16
+ `className`. Treat it as a Figma snapshot, not a component: there is no way to change
17
+ the items, the active row, or to attach a handler.
18
+
19
+ > **status: legacy.** No host app renders it, and it cannot be configured. For a real
20
+ > settings nav, compose `ScSidebarMenu` rows yourself, or use `ScSettingsTabComp` for a
21
+ > horizontal tab strip.
22
+
23
+ ## TL;DR for agents
24
+
25
+ - **Reach for it when:** you need a static visual placeholder of the settings nav
26
+ (a design mock, a screenshot, a Figma-parity check).
27
+ - **Don't reach for it when:** you are building a working settings screen. It has no
28
+ `items`, no `activeItem`, no `onSelect`. → compose `ScSidebarMenu`, or use
29
+ `ScSettingsTabComp` / `StreamoidSidebar`.
30
+ - **Three things that will bite you:**
31
+ 1. The three labels — **"Profile", "Workspace", "Referral"** — are baked into the
32
+ source. No prop, no children, no localisation.
33
+ 2. **"Profile" is always `state="active"`.** Navigation cannot be reflected.
34
+ 3. **Nothing has an `onClick`.** The card is inert; clicks fall through to the parent.
35
+
36
+ ---
37
+
38
+ ## 1. How to use it
39
+
40
+ ### Import
41
+
42
+ ```tsx
43
+ import { ScSettingsNav } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+ ```
46
+
47
+ ### Minimal usage
48
+
49
+ ```tsx
50
+ <ScSettingsNav />
51
+ ```
52
+
53
+ That is also the maximal usage.
54
+
55
+ ### Props
56
+
57
+ | Prop | Type | Default | Notes |
58
+ |---|---|---|---|
59
+ | `className` | `string` | – | Appended after the internal class. Your only lever — use it to override the fixed `16rem × 18.125rem` box. |
60
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | Spread onto the root div. `onClick` here fires for the whole card, not per row — you cannot tell which item was hit. |
61
+
62
+ There are **no** item, label, icon, active or handler props.
63
+
64
+ ### What it renders, verbatim
65
+
66
+ | Row | Icon | `state` |
67
+ |---|---|---|
68
+ | `"Profile"` | `SiconTeam` | `"active"` |
69
+ | `"Workspace"` | `SiconWorkspace` | `"default"` |
70
+ | `"Referral"` | `SiconReferral` | `"default"` |
71
+
72
+ Container: `--alias-surface-base` fill, `--radius-3xl` corners, 1px
73
+ `--alias-border-subtle` border, `--spacing-md` padding, **fixed `width: 16rem` and
74
+ `height: 18.125rem`**.
75
+
76
+ ### What to write instead
77
+
78
+ ```tsx
79
+ // A working settings nav — the same look, with real behaviour
80
+ const ITEMS = [
81
+ { id: "profile", label: "Profile", icon: <SiconTeam /> },
82
+ { id: "workspace", label: "Workspace", icon: <SiconWorkspace /> },
83
+ { id: "referral", label: "Referral", icon: <SiconReferral /> },
84
+ ];
85
+
86
+ <div className={styles.navCard}> {/* your own surface/border/radius */}
87
+ {ITEMS.map((it) => (
88
+ <ScSidebarMenu
89
+ key={it.id}
90
+ icon={it.icon}
91
+ text={it.label}
92
+ state={active === it.id ? "active" : "default"}
93
+ onClick={() => setActive(it.id)}
94
+ />
95
+ ))}
96
+ </div>
97
+ ```
98
+
99
+ ---
100
+
101
+ ## 2. Where to use it
102
+
103
+ Nowhere in production today. Grepping CXO, Photogenix, Catalogix, Artifax and
104
+ `@streamoid/settings` finds zero render sites.
105
+
106
+ Where the *pattern* lives instead:
107
+
108
+ - **Desktop settings navigation** is handled by `@streamoid/settings`, which uses
109
+ `ScTabComp`-based switchers and its own layout rather than a nav card.
110
+ - **Mobile settings** uses a horizontal `ScSettingsTabComp` strip
111
+ (`cxo-dashboard src/app/components/mobile-settings-content.tsx`).
112
+ - **App-level navigation** is `StreamoidSidebar` (config-driven `topItems` / `sections`).
113
+
114
+ ---
115
+
116
+ ## 3. When to use it
117
+
118
+ ### Use it when
119
+
120
+ - You need a pixel-parity static mock of the settings nav card and nothing more.
121
+
122
+ ### Don't use it — reach for this instead
123
+
124
+ | Situation | Use instead |
125
+ |---|---|
126
+ | A functioning settings left-nav | your own container + `ScSidebarMenu` rows (see the snippet above) |
127
+ | A horizontal settings tab strip | `ScSettingsTabComp` |
128
+ | The app's primary navigation | `StreamoidSidebar` (config-driven; also `ScCatalogixSidebar` / `ScArtifaxSidebar`) |
129
+ | One nav row | `ScSidebarMenu` |
130
+ | The profile-settings screen scaffold | `ScProfileSettingsComp` |
131
+ | A compact 2–5 way view toggle | `ScTabSwitcher` + `ScTabComp` |
132
+ | A data-driven tab bar | `ScTabs` |
133
+
134
+ ### Don't confuse with
135
+
136
+ | You may actually want | Not this |
137
+ |---|---|
138
+ | `ScSettingsTabComp` — a **single horizontal underline tab** with `tabName`/`active`/`onClick` | `ScSettingsNav` is a vertical card with no API |
139
+ | `ScSidebarMenu` — the configurable nav row this card is built from | Use the row, not the card |
140
+ | `ScSidebar` / `ScSidebarIcons` / `ScSidebarProfile` — the other pre-`StreamoidSidebar` parts | Same era, same problem: superseded |
141
+ | `ScProfileSettingsComp` — the profile-settings content scaffold | Different surface |
142
+
143
+ ---
144
+
145
+ ## 4. Why to use it
146
+
147
+ Honestly: don't. The only thing you'd get is Figma parity for a static screenshot.
148
+
149
+ What you *lose* by using it: any ability to route, to reflect the current section, to
150
+ add or remove items, to localise labels, or to fit a container (it is a fixed
151
+ 256×290px box). Everything valuable in it — the token fill, the border, the row
152
+ treatment — is available directly from `ScSidebarMenu` plus four CSS declarations.
153
+
154
+ ---
155
+
156
+ ## Gotchas
157
+
158
+ **1. Hardcoded English labels.** "Profile", "Workspace", "Referral" are string
159
+ literals in the render body. No `items` prop exists.
160
+
161
+ **2. "Profile" is always the active row.** `state="active"` is hardcoded on the first
162
+ `ScSidebarMenu`, so the card contradicts your actual route the moment the user
163
+ navigates.
164
+
165
+ **3. No handlers anywhere.** Rows don't take `onClick` here. An `onClick` on the root
166
+ tells you the card was clicked, not which row.
167
+
168
+ ```tsx
169
+ // WRONG — there is no way to know which item was clicked
170
+ <ScSettingsNav onClick={(e) => route(e.target)} />
171
+
172
+ // RIGHT — build the list yourself
173
+ {items.map((it) => <ScSidebarMenu key={it.id} text={it.label} onClick={() => route(it.id)} />)}
174
+ ```
175
+
176
+ **4. Fixed size.** `width: 16rem; height: 18.125rem` — the card keeps its 290px height
177
+ with three rows and will not grow for a fourth (you can't add one anyway). Override via
178
+ `className` if you must embed it.
179
+
180
+ **5. `className` is concatenated unguarded** → `class="scSettingsNav undefined"` when
181
+ omitted.
182
+
183
+ **6. `--alias-border-subtle` at 1px, not the 0.5px divider.** If you place it beside
184
+ cards that use `--alias-shadow-*` elevation, its border reads heavier than its
185
+ neighbours in light mode.
186
+
187
+ **7. Not deprecated in source, but unused everywhere.** Nothing warns you at build
188
+ time. Its `status: legacy` here is the only signal — don't take its presence in
189
+ `index.ts` as an endorsement.
190
+
191
+ ---
192
+
193
+ ## In the wild
194
+
195
+ _No host render site found — used by the agent runtime / composed internally._
196
+
197
+ Neither is true, strictly: it has **no** consumer at all — not the four dashboards, not
198
+ `@streamoid/settings`, not another DS component. If a settings nav card is needed
199
+ again, it most likely belongs in `@streamoid/settings` beside the settings/billing
200
+ screens, rebuilt with an `items` + `activeId` + `onSelect` API on top of
201
+ `ScSidebarMenu`.
202
+
203
+ ---
204
+
205
+ ## Related
206
+
207
+ - `ScSidebarMenu` — the configurable nav row; the right building block.
208
+ - `ScSettingsTabComp` — the horizontal settings tab actually used by CXO.
209
+ - `StreamoidSidebar` — the current shared, config-driven app shell nav.
210
+ - `ScProfileSettingsComp` / `ScProfileOptions` — profile-side settings scaffolding.
211
+ - `ScSidebar`, `ScSidebarIcons`, `ScSidebarProfile`, `ScSidebarSwitchMenu`,
212
+ `ScLogoUnit` — the other superseded pre-`StreamoidSidebar` parts.
@@ -0,0 +1,260 @@
1
+ ---
2
+ component: ScSettingsTabComp
3
+ package: "@streamoid/ui"
4
+ category: layout
5
+ status: stable
6
+ renders: div
7
+ tags: [tab, underline-tab, settings, tab-strip, mobile-settings, modal-tabs, section-switch]
8
+ related: [ScTabComp, ScTabSwitcher, ScTabs, ScTabField, ScSettingsNav]
9
+ do_not_confuse_with: [ScTabComp, ScTabSwitcher, ScTabs, ScSettingsNav, ScSelectionPill]
10
+ used_by: [cxo, catalogix]
11
+ ---
12
+
13
+ # ScSettingsTabComp
14
+
15
+ **One underlined tab in a horizontal strip.** 56px tall, 12px padding, muted 16px
16
+ label; when `active` it turns primary-coloured and grows a 1.25px underline. This is
17
+ the settings/modal tab vocabulary — flat and underlined — as opposed to the filled
18
+ `ScTabComp` pill inside a `ScTabSwitcher` track.
19
+
20
+ ## TL;DR for agents
21
+
22
+ - **Reach for it when:** you need a settings-style tab strip — Profile / Workspace,
23
+ or a modal's section tabs — where the active tab is marked by an underline.
24
+ - **Don't reach for it when:** you want the bordered filled segmented control
25
+ (→ `ScTabSwitcher` + `ScTabComp`), a data-driven pill bar (→ `ScTabs`), or a form
26
+ field (→ `ScTabField`).
27
+ - **Four things that will bite you:**
28
+ 1. `active` is a **real boolean** here — the exact opposite of `ScTabComp`, whose
29
+ `active` is the string `"true"`/`"false"`.
30
+ 2. **No props are spread.** No `style`, no `role`, no `aria-selected`, no
31
+ `data-testid`, no `id`. Only `tabName`, `active`, `onClick`, `className`.
32
+ 3. It draws **only its own underline**. The strip's baseline border is the parent's job.
33
+ 4. `tabName` defaults to `"Tab"`, and the 3.5rem height is fixed.
34
+
35
+ ---
36
+
37
+ ## 1. How to use it
38
+
39
+ ### Import
40
+
41
+ ```tsx
42
+ import { ScSettingsTabComp } from "@streamoid/ui";
43
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
44
+ ```
45
+
46
+ ### Minimal usage
47
+
48
+ ```tsx
49
+ <ScSettingsTabComp tabName="Profile" active={tab === "profile"} onClick={() => setTab("profile")} />
50
+ ```
51
+
52
+ ### Props
53
+
54
+ | Prop | Type | Default | Notes |
55
+ |---|---|---|---|
56
+ | `tabName` | `string` | `"Tab"` | ⚠️ Real default. Rendered in a `<span>`, `white-space: nowrap`, no truncation. |
57
+ | `active` | `boolean` | `false` | **Boolean** (unlike `ScTabComp`). Adds the underline and switches the label to `--alias-text-and-icons-primary`. |
58
+ | `onClick` | `() => void` | – | No event argument — the handler takes no parameters. |
59
+ | `className` | `string` | – | Appended last (guarded with `?? ""`, so no stray `"undefined"`). Your only styling lever. |
60
+
61
+ Everything else is unavailable: the component destructures exactly these four props and
62
+ spreads nothing.
63
+
64
+ ### What renders in each state
65
+
66
+ | `active` | Label colour | Underline |
67
+ |---|---|---|
68
+ | `false` | `--alias-text-and-icons-muted` | none |
69
+ | `true` | `--alias-text-and-icons-primary` | `border-bottom: 1.25px solid --alias-text-and-icons-primary` |
70
+
71
+ Box in both states: `height: 3.5rem`, `padding: var(--spacing-xl)` (0.75rem),
72
+ `flex-shrink: 0`, `cursor: pointer`, centred content, 16px/1.5rem label.
73
+
74
+ ### Recipes
75
+
76
+ ```tsx
77
+ // The strip: the PARENT draws the baseline, the tab draws only its own underline
78
+ <div
79
+ className="flex shrink-0"
80
+ style={{
81
+ borderBottom: "0.5px solid var(--alias-border-divider)",
82
+ padding: "0 var(--spacing-md)",
83
+ gap: "var(--spacing-md)",
84
+ }}
85
+ >
86
+ <ScSettingsTabComp tabName="Profile" active={tab === "profile"} onClick={() => setTab("profile")} />
87
+ <ScSettingsTabComp tabName="Workspace" active={tab === "workspace"} onClick={() => setTab("workspace")} />
88
+ </div>
89
+
90
+ // From data
91
+ {sections.map((s) => (
92
+ <ScSettingsTabComp
93
+ key={s.value}
94
+ tabName={s.label}
95
+ active={activeTab === s.value}
96
+ onClick={() => onClickTab(s.value)}
97
+ />
98
+ ))}
99
+
100
+ // Need aria/roles or a test hook? wrap it — they can't be passed through
101
+ <div role="tab" aria-selected={isActive} data-testid={`tab-${id}`}>
102
+ <ScSettingsTabComp tabName={label} active={isActive} onClick={select} />
103
+ </div>
104
+ ```
105
+
106
+ ---
107
+
108
+ ## 2. Where to use it
109
+
110
+ - **CXO mobile settings** — the Profile / Workspace strip at the top of
111
+ `mobile-settings-content`.
112
+ - **Catalogix modals** — the folder-tab strip inside the shared `Modal` component
113
+ (which reverses the array to preserve the legacy `row-reverse` order).
114
+ - Any **section switcher above a scrolling content pane** where an underline reads
115
+ better than a filled pill: settings, detail screens, modal sections.
116
+
117
+ ---
118
+
119
+ ## 3. When to use it
120
+
121
+ ### Use it when
122
+
123
+ - The tabs sit **directly above the content they switch**, with a baseline rule.
124
+ - Labels are words (not icons) and the underline treatment matches the surface.
125
+ - You are matching the existing settings / modal look.
126
+
127
+ ### Don't use it — reach for this instead
128
+
129
+ | Situation | Use instead |
130
+ |---|---|
131
+ | Compact filled segmented control, 2–5 ways | `ScTabSwitcher` + `ScTabComp` |
132
+ | Icon-only tabs | `ScTabComp` (`type="icon-only"`) — this component has no icon support |
133
+ | Long or dynamic tab lists that must wrap | `ScTabs` (`allowWrap`, `isCompact`) |
134
+ | A segmented control that is a **saved form value** | `ScTabField` |
135
+ | Dark-fill selection pills (Catalogix curation) | `ScSelectionPillGroup` |
136
+ | A vertical settings nav | your own `ScSidebarMenu` list (**not** `ScSettingsNav` — see its README) |
137
+ | Something that needs `role="tab"` on the element itself | wrap this, or use `ScSelectionPill` (a real `<button>`) |
138
+
139
+ ### Don't confuse with
140
+
141
+ | You may actually want | Not this |
142
+ |---|---|
143
+ | `ScTabComp` — filled pill for a `ScTabSwitcher`; `active` is the **string** `"true"`/`"false"`; spreads DOM props | `ScSettingsTabComp` is an underline tab; `active` is a **boolean**; spreads nothing |
144
+ | `ScSettingsNav` — the static vertical settings nav card (legacy, no API) | This is one horizontal tab |
145
+ | `ScTabs` — the whole row from data | This is one tab; you map them yourself |
146
+ | `ScTabField` — label + switcher, for forms | Different surface and API |
147
+
148
+ ### The tab family at a glance
149
+
150
+ | Component | Shape | Selection API | Root | Spreads DOM props? |
151
+ |---|---|---|---|---|
152
+ | `ScSettingsTabComp` | underline tab | `active` (**boolean**) + `onClick()` | `div` | ❌ |
153
+ | `ScTabComp` | filled pill cell | `active="true" \| "false"` (**strings**) | `div` | ✅ |
154
+ | `ScTabSwitcher` | 2–5 slot bordered track | none — children own it | `div` | ✅ |
155
+ | `ScTabs` | N pills, data-driven | `activeTab` + `onClickTab(value)` | `div` | ❌ |
156
+ | `ScTabField` | field label + 2-tab switcher | `activeTab` + `onTabChange` | `div` | ❌ |
157
+ | `ScSelectionPill` | one segmented pill | `selected` (**boolean**) + `onSelect(value)` | `button[type="button"][aria-pressed]` | ✅ |
158
+ | `ScSelectionPillGroup` | segmented pill row | `value` + `onChange(value)` | `div[role="tablist"]` of `button`s | ✅ |
159
+
160
+ ---
161
+
162
+ ## 4. Why to use it
163
+
164
+ - **The active marker is a token, not a colour.** Label and underline both use
165
+ `--alias-text-and-icons-primary`, so the strip inverts correctly between themes —
166
+ a hand-rolled `border-bottom: 1.25px solid #f5f5f5` disappears on the light canvas.
167
+ - **1.25px is a real design value**, not a rounding of 1px. Getting it wrong is the
168
+ most visible way a hand-built tab strip looks "off" next to a DS one.
169
+ - **The 56px row height is shared** with the mobile settings header rhythm, so tabs
170
+ line up with adjacent chrome without magic numbers at the call site.
171
+ - **Tiny surface area** — four props, no state — which is why both CXO and Catalogix
172
+ could drop their own tab-strip implementations and keep their existing APIs.
173
+
174
+ ---
175
+
176
+ ## Gotchas
177
+
178
+ **1. `active` is a boolean — the inverse of `ScTabComp`.** Switching between the two
179
+ components is the most common mistake in this family.
180
+
181
+ ```tsx
182
+ // WRONG — TS error: Type 'string' is not assignable to type 'boolean | undefined'
183
+ <ScSettingsTabComp tabName="Profile" active={tab === "profile" ? "true" : "false"} />
184
+
185
+ // RIGHT
186
+ <ScSettingsTabComp tabName="Profile" active={tab === "profile"} />
187
+ ```
188
+
189
+ The variant class is built by concatenation (`styles["active-" + active]`), so in a
190
+ plain-JS host (Catalogix) the string form happens to resolve to the same class and the
191
+ mistake never surfaces at runtime — it only fails to typecheck. Don't rely on that.
192
+
193
+ **2. Nothing is spread onto the DOM.** `style`, `role`, `aria-selected`, `id`,
194
+ `data-*` are silently unavailable — they are not in the props type at all.
195
+
196
+ ```tsx
197
+ // WRONG — TS error; and there is no runtime pass-through either
198
+ <ScSettingsTabComp tabName="Profile" active role="tab" style={{ flex: 1 }} />
199
+
200
+ // RIGHT — wrap it, or use className
201
+ <div role="tab" aria-selected style={{ flex: 1 }}>
202
+ <ScSettingsTabComp tabName="Profile" active className={styles.tab} />
203
+ </div>
204
+ ```
205
+
206
+ **3. The strip's baseline border is yours.** The tab only paints its own 1.25px
207
+ underline; without a container `border-bottom` the inactive tabs float over nothing.
208
+ CXO's strip sets `borderBottom: 0.5px solid <divider>` on the flex row.
209
+
210
+ **4. Fixed 3.5rem height.** No `size` prop. Override with a `className` if you need a
211
+ denser strip — and expect the underline to move with it.
212
+
213
+ **5. `tabName` defaults to `"Tab"`.** Forget the prop and you ship the placeholder.
214
+
215
+ **6. No icon support.** There is no `icon` prop and no slot; `tabName` is a `string`,
216
+ not a `ReactNode`, so you cannot pass an element.
217
+
218
+ **7. No truncation.** `white-space: nowrap` with no `max-width`, no ellipsis, no
219
+ `title`. Long labels widen the strip and force horizontal overflow on mobile.
220
+
221
+ **8. `div` + `onClick`: no keyboard, no focus ring.** Not focusable, no Enter/Space,
222
+ no `aria-selected`. For an accessible strip, wrap each tab (see recipe) or use
223
+ `ScSelectionPillGroup`.
224
+
225
+ **9. `onClick` receives no event.** The signature is `() => void`, so you cannot
226
+ `stopPropagation` or read the target. Do that in a wrapper.
227
+
228
+ ---
229
+
230
+ ## In the wild
231
+
232
+ ```tsx
233
+ // cxo-dashboard src/app/components/mobile-settings-content.tsx:233
234
+ <ScSettingsTabComp
235
+ tabName="Profile"
236
+ active={activeTab === "profile"}
237
+ onClick={() => setActiveTab("profile")}
238
+ />
239
+ ```
240
+
241
+ ```jsx
242
+ // catalogix/dashboard app/components/Modal/index.jsx:354
243
+ <ScSettingsTabComp
244
+ key={`${idx}-${value}`}
245
+ tabName={formatTabLabel(label)}
246
+ active={props.activeTab == value}
247
+ onClick={() => props.onClickTab(value)}
248
+ />
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Related
254
+
255
+ - `ScTabComp` — the filled pill cell; note the string `active` prop.
256
+ - `ScTabSwitcher` — bordered 2–5 slot track for `ScTabComp`s.
257
+ - `ScTabs` — data-driven wrapping pill bar.
258
+ - `ScTabField` — labelled form field wrapping a 2-tab switcher.
259
+ - `ScSettingsNav` — **legacy** static vertical settings nav card; don't use it.
260
+ - `ScSelectionPillGroup` — accessible segmented control (real buttons).