@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,231 @@
1
+ ---
2
+ component: ScSidebarProfile
3
+ package: "@streamoid/ui"
4
+ category: sidebar
5
+ status: legacy
6
+ renders: div
7
+ tags: [sidebar, profile, footer, avatar, user, legacy, placeholder]
8
+ related: [ScProfile, StreamoidSidebar, ScProfilePopup, ScProfileOptions, ScDp]
9
+ do_not_confuse_with: [ScProfile, ScProfileOptions, ScProfilePopup, ScProfileSettingsComp, ScProfileV2Mobile, ScIntialProfileCover]
10
+ ---
11
+
12
+ # ScSidebarProfile
13
+
14
+ **Legacy. Superseded by `StreamoidSidebar`'s `profile` prop.** A hover-able padded
15
+ wrapper whose only job was to place a `ScProfile` in the old sidebar footer — and it
16
+ renders that `ScProfile` **with no props at all**, so it always shows
17
+ `"Chris Hemsworth" / "Kepler workspace"` and a broken `profile-image0.png`.
18
+
19
+ ## TL;DR for agents
20
+
21
+ - **Reach for it when:** never. There is no way to pass a real user through it.
22
+ - **Reach for this instead:** `StreamoidSidebar`'s
23
+ `profile={{ name, subtitle, avatar, onClick }}` for a rail footer, or `ScProfile`
24
+ directly if you just want the avatar + two-line identity block.
25
+ - **Three things that will bite you:**
26
+ 1. ⚠️ **There is no `name`, `subText` or `profileImage` prop.** The placeholder
27
+ identity is unavoidable.
28
+ 2. `variant="collapsed"` does **not** collapse the inner `ScProfile` — the name and
29
+ subtitle still render, inside a 3 rem-wide box.
30
+ 3. The root is a `<div>` with a hover background but no `role`/`tabIndex` — it looks
31
+ clickable and isn't, unless you wire it yourself.
32
+
33
+ ---
34
+
35
+ ## 1. How to use it
36
+
37
+ ### Import
38
+
39
+ ```tsx
40
+ import { ScSidebarProfile } from "@streamoid/ui";
41
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
42
+ ```
43
+
44
+ ### Minimal usage
45
+
46
+ ```tsx
47
+ // This is the whole API. The content is fixed.
48
+ <ScSidebarProfile variant="expanded" onClick={openProfilePopup} />
49
+ ```
50
+
51
+ ### Props
52
+
53
+ | Prop | Type | Default | Notes |
54
+ |---|---|---|---|
55
+ | `state` | `"default"` \| `"hover"` | `"default"` | `"hover"` force-renders the `fill-neutral-neutral` background (Figma parity). Real `:hover` already does this. |
56
+ | `variant` | `"expanded"` \| `"collapsed"` | `"expanded"` | `expanded` = `align-self: stretch`, 8 / 12 px padding. `collapsed` = fixed `width: 3rem`, 8 px padding, and grows to `height: 3rem` on hover. |
57
+ | `className` | `string` | – | Concatenated onto the root. ⚠️ Unguarded — omitting it puts a literal `undefined` in the class list. |
58
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | **Is** spread onto the root, so `onClick`, `style`, `aria-*`, `data-*` work. |
59
+
60
+ There is deliberately **nothing else**. The child is a hardcoded
61
+ `<ScProfile className={styles.scProfileInstance} />`.
62
+
63
+ ### What renders in each variant
64
+
65
+ | | `expanded` | `collapsed` |
66
+ |---|---|---|
67
+ | Box | stretches to the rail width, `radius-3xl` | fixed 48 px wide |
68
+ | `ScProfile` | avatar + name + subText | avatar + **name + subText still rendered**, squeezed into 48 px |
69
+ | Hover | `fill-neutral-neutral` | `fill-neutral-neutral` + `height: 3rem` |
70
+
71
+ ### Recipes
72
+
73
+ None worth having. Here is what replaces it:
74
+
75
+ ```tsx
76
+ // A rail footer with a real user — StreamoidSidebar owns the profile row
77
+ <StreamoidSidebar
78
+ expanded={expanded}
79
+ onToggle={() => setExpanded((v) => !v)}
80
+ config={config}
81
+ iconMap={iconMap}
82
+ profile={{
83
+ name: user.fullName,
84
+ subtitle: workspace.name,
85
+ avatar: <img src={user.photoUrl} alt="" />,
86
+ onClick: openProfilePopup,
87
+ }}
88
+ toggleInProfile // profile + a separate collapse button, no version footer
89
+ />
90
+
91
+ // Or, if you only want the identity block itself
92
+ <ScProfile
93
+ name={user.fullName}
94
+ subText={workspace.name}
95
+ profileImage={user.photoUrl}
96
+ collapsed={expanded ? "false" : "true"}
97
+ />
98
+ ```
99
+
100
+ ---
101
+
102
+ ## 2. Where to use it
103
+
104
+ Nowhere. Its only render site in the whole codebase is inside the legacy `ScSidebar`
105
+ (`src/SC-Sidebar/ScSidebar.tsx:134` and `:243`), which is itself unused.
106
+
107
+ The current rail footer is built by `StreamoidSidebar` from its `profile` prop
108
+ (optionally with `toggleInProfile` to put the collapse button beside it), and by
109
+ `ScCatalogixSidebar` / `ScArtifaxSidebar` from their own `profile` configs.
110
+
111
+ ---
112
+
113
+ ## 3. When to use it
114
+
115
+ ### Use it when
116
+
117
+ - Never.
118
+
119
+ ### Don't use it — reach for this instead
120
+
121
+ | Situation | Use instead |
122
+ |---|---|
123
+ | The profile row in a real sidebar footer | `StreamoidSidebar`'s `profile` prop (or `ScCatalogixSidebar` / `ScArtifaxSidebar`) |
124
+ | Just the avatar + name + subtitle block, with real data | `ScProfile` (`name`, `subText`, `profileImage`, `collapsed`) |
125
+ | Just the avatar | `ScDp` |
126
+ | The popup that opens when you click the footer | `ScProfilePopup` |
127
+ | The menu rows inside that popup | `ScProfileOptions` |
128
+ | The settings-page profile form | `ScProfileSettingsComp` |
129
+ | A mobile profile screen | `ScProfileV2Mobile` |
130
+ | The initials/cover block for a user with no photo | `ScIntialProfileCover` |
131
+
132
+ ### Don't confuse with
133
+
134
+ | You may actually want | Not this |
135
+ |---|---|
136
+ | `ScProfile` — the actual identity block, **with** `name` / `subText` / `profileImage` / `collapsed` props | `ScSidebarProfile` is a props-less wrapper around it |
137
+ | `ScProfileOptions` — the list of actions (Settings, Theme, Log out) inside the profile popup | not a footer row |
138
+ | `ScProfilePopup` — the whole floating popup | not a footer row |
139
+ | `ScProfileSettingsComp` — the settings-page profile editor | different surface |
140
+ | `ScProfileV2Mobile` — the mobile twin | different surface |
141
+ | `ScIntialProfileCover` — initials avatar / cover | different job |
142
+
143
+ Six profile-ish exports (`ScProfile`, `ScProfileOptions`, `ScProfilePopup`,
144
+ `ScProfileSettingsComp`, `ScProfileImageUpdate`, `ScProfileV2Mobile`) plus this
145
+ `ScSidebarProfile` — and this one is the only one you should never use. Read the table
146
+ before picking.
147
+
148
+ ---
149
+
150
+ ## 4. Why to use it
151
+
152
+ You wouldn't. What it demonstrates that's still correct:
153
+
154
+ - The rail footer's hover affordance is a **background fill**
155
+ (`--alias-fill-neutral-neutral`), not a border or an opacity change.
156
+ - Collapsed, the row is pinned to `width: 3rem` (48 px) with its height left to the
157
+ content, and `:hover` adds an explicit `height: 3rem` so the hovered box reads as a
158
+ 48 × 48 square like the collapsed nav squares.
159
+ - The 8 / 12 px padding + `radius-3xl` matches `ScSidebarMenu`, so the footer sits on
160
+ the same rhythm as the nav rows above it.
161
+
162
+ Everything else — real identity, click target, popup wiring, keyboard access — you
163
+ have to supply, and `StreamoidSidebar` already does.
164
+
165
+ ---
166
+
167
+ ## Gotchas
168
+
169
+ **1. The user is hardcoded, two levels down.** `ScSidebarProfile` renders
170
+ `<ScProfile />` with only a `className`. `ScProfile`'s own defaults then take over:
171
+ `name = "Chris Hemsworth"`, `subText = "Kepler workspace"`,
172
+ `profileImage = "profile-image0.png"`. That last one is a bare relative path, so it
173
+ 404s in every host and you get a broken-image glyph.
174
+
175
+ ```tsx
176
+ // WRONG — there is no such prop; you still get "Chris Hemsworth"
177
+ <ScSidebarProfile name={user.fullName} profileImage={user.photoUrl} />
178
+
179
+ // RIGHT — use ScProfile directly, or StreamoidSidebar's `profile`
180
+ <ScProfile name={user.fullName} subText={workspace.name} profileImage={user.photoUrl} />
181
+ ```
182
+
183
+ **2. `variant="collapsed"` doesn't collapse the child.** `ScProfile` has its own
184
+ `collapsed` prop (`"true"` / `"false"`, a *string* union), and `ScSidebarProfile` never
185
+ passes it. So the collapsed variant renders the name and subtitle inside a 48 px box.
186
+ This is a real bug, not a subtlety.
187
+
188
+ **3. It only *looks* interactive.** `cursor` is never set, and there is no `role`,
189
+ `tabIndex` or `onKeyDown` — but there **is** a hover background. `...props` does reach
190
+ the root, so an `onClick` works for mouse users; keyboard users get nothing.
191
+
192
+ **4. `className` produces a literal `undefined` class when omitted.**
193
+ `styles.scSidebarProfile + " " + className + " " + variantsClassName`.
194
+
195
+ **5. `align-self: stretch` in the expanded variant.** It assumes a stretching
196
+ flex-column parent (the rail). In a row-direction container it collapses.
197
+
198
+ **6. `state="hover"` is design parity only.** Never wire it to mouse handlers.
199
+
200
+ ---
201
+
202
+ ## In the wild
203
+
204
+ _No host render site found — used by the agent runtime / composed internally._
205
+
206
+ Its only composition site is the legacy sidebar:
207
+
208
+ ```tsx
209
+ // npm-components packages/ui/src/SC-Sidebar/ScSidebar.tsx:134
210
+ <ScSidebarProfile
211
+ variant="collapsed"
212
+ className={styles.scSidebarProfileInstance}
213
+ />
214
+ ```
215
+
216
+ Where it *would* belong — the desktop rail footer — is now owned by
217
+ `StreamoidSidebar`'s `profile` prop, which every host passes (e.g.
218
+ `cxo-dashboard src/app/components/app-sidebar.tsx`).
219
+
220
+ ---
221
+
222
+ ## Related
223
+
224
+ - `ScProfile` — the real identity block; use this if you need a props-driven avatar +
225
+ name + subtitle.
226
+ - `StreamoidSidebar` — the current rail; owns the footer via `profile` and
227
+ `toggleInProfile`.
228
+ - `ScProfilePopup` / `ScProfileOptions` — what the footer opens.
229
+ - `ScDp` — avatar-only primitive.
230
+ - `ScSidebar` / `ScLogoUnit` / `ScSidebarIcons` / `ScVersion` — the rest of this legacy
231
+ sidebar family.
@@ -0,0 +1,258 @@
1
+ ---
2
+ component: ScSidebarSwitchMenu
3
+ package: "@streamoid/ui"
4
+ category: sidebar
5
+ status: stable
6
+ renders: div
7
+ tags: [sidebar, app-switcher, product-switch, two-line, nav-row, description, switch-menu]
8
+ related: [ScSidebarMenu, ScAppSwitchPanel, ScCatalogixSidebar, StreamoidSidebar, ScSideBarLogoUnit]
9
+ do_not_confuse_with: [ScSidebarMenu, ScAppSwitchPanel, ScWorkspaceSwitchCard, StreamoidWorkspaceSwitcher, ScAppCard]
10
+ ---
11
+
12
+ # ScSidebarSwitchMenu
13
+
14
+ **The two-line row in a sidebar's app-switch list.** Icon + product name + a
15
+ description line beneath it. Expanded it is content-height (8/12 px padding, two text
16
+ lines) with a **square** hover fill; collapsed it becomes a rounded 40 × 40 icon
17
+ square that matches `ScSidebarMenu`'s collapsed row exactly.
18
+
19
+ ## TL;DR for agents
20
+
21
+ - **Reach for it when:** you're building a "switch to another product" list inside a
22
+ sidebar and each entry needs a name **and** a subtitle.
23
+ - **Don't reach for it when:** the row is ordinary nav with one line
24
+ (→ `ScSidebarMenu`), or you want the whole ready-made switch panel
25
+ (→ `ScAppSwitchPanel`, which is what CXO and Catalogix pass to `StreamoidSidebar`'s
26
+ `switchPanel` slot — note it builds its own masked-wordmark rows and does **not**
27
+ compose this component).
28
+ - **Three things that will bite you:**
29
+ 1. `text` defaults to `"Pairtext"` and `description` to `"Description"`. ⚠️ Both are
30
+ real Figma placeholder strings that will ship.
31
+ 2. `variant="collapsed"` drops **both** text lines and the kebab; only `icon`
32
+ survives. There is no tooltip.
33
+ 3. Like `ScSidebarMenu`, the root is a bare `<div>` — no `role`, no `tabIndex`, no
34
+ key handling.
35
+
36
+ ---
37
+
38
+ ## 1. How to use it
39
+
40
+ ### Import
41
+
42
+ ```tsx
43
+ import { ScSidebarSwitchMenu } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+ ```
46
+
47
+ ### Minimal usage
48
+
49
+ ```tsx
50
+ <ScSidebarSwitchMenu
51
+ icon={<img src={app.iconUrl} alt="" />}
52
+ text="Photogenix"
53
+ description="AI product photography"
54
+ onClick={() => openApp(app)}
55
+ />
56
+ ```
57
+
58
+ ### Props
59
+
60
+ | Prop | Type | Default | Notes |
61
+ |---|---|---|---|
62
+ | `icon` | `ReactNode` | – | Optional. When omitted the icon wrapper is **not rendered at all** (unlike `ScSidebarMenu`, which has a default icon). The wrapper is 20 × 20, `overflow: hidden`, and clamps its child with `max-width/max-height: 100%`. |
63
+ | `text` | `string` | `"Pairtext"` | ⚠️ Real default. Product name. Single line, ellipsised. **`expanded` only.** |
64
+ | `description` | `string` | `"Description"` | ⚠️ Real default. Subtitle line. Single line, ellipsised. **`expanded` only.** |
65
+ | `state` | `"default"` \| `"active"` \| `"hover"` \| `"default-highlight"` \| `"default-active"` | `"default"` | Same five-state vocabulary as `ScSidebarMenu`. Note: `state` only ever recolours **`text`**, never `description`. |
66
+ | `variant` | `"expanded"` \| `"collapsed"` | `"expanded"` | `collapsed` = rounded 40 × 40 square, icon only. |
67
+ | `moreIcon` | `ReactNode` | – | Trailing affordance. **`expanded` only**, hidden until `:hover`. |
68
+ | `onMoreClick` | `(e: React.MouseEvent) => void` | – | Fires from the kebab wrapper, which `stopPropagation()`s first. |
69
+ | `className` | `string` | – | Appended after the internal class. Guarded — no stray `undefined` here (this component is the fixed one in the family). |
70
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | Spread onto the root div — `onClick`, `style`, `aria-*`, `data-*`. |
71
+
72
+ ### What each `state` renders
73
+
74
+ | `state` | Background | `text` colour | `description` colour |
75
+ |---|---|---|---|
76
+ | `default` | none (hover → `fill-neutral-neutral`) | tertiary | tertiary |
77
+ | `active` | `fill-neutral-neutralselected` | primary | tertiary |
78
+ | `hover` | `fill-neutral-neutral` (forced) | tertiary | tertiary |
79
+ | `default-highlight` | none | primary | tertiary |
80
+ | `default-active` | `surface-canvas` + 0.5 px inset ring | primary | tertiary |
81
+
82
+ `default-highlight` is the idiomatic state for app-switch rows: bright title, no fill.
83
+
84
+ ### Recipes
85
+
86
+ ```tsx
87
+ // The expanded app-switch list (this is what ScCatalogixSidebar does)
88
+ <div style={{ display: "flex", flexDirection: "column", gap: "var(--spacing-md)" }}>
89
+ {switchApps.map((app) => (
90
+ <ScSidebarSwitchMenu
91
+ key={app.id}
92
+ icon={app.icon}
93
+ text={app.name}
94
+ description={app.description}
95
+ state="default-highlight"
96
+ variant="expanded"
97
+ onClick={app.onClick}
98
+ />
99
+ ))}
100
+ </div>
101
+
102
+ // The collapsed rail's inline icon list — no card, no labels
103
+ <div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
104
+ {switchApps.map((app) => (
105
+ <ScSidebarSwitchMenu
106
+ key={app.id}
107
+ icon={app.icon}
108
+ state="default"
109
+ variant="collapsed"
110
+ onClick={app.onClick}
111
+ aria-label={app.name}
112
+ />
113
+ ))}
114
+ </div>
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 2. Where to use it
120
+
121
+ - **The app-switch list inside a sidebar.** `ScCatalogixSidebar` renders it twice: as
122
+ the expanded list (inside the switch card) and as the collapsed inline icon column.
123
+ - **Any "pick a destination with a subtitle" column in a rail** — workspaces,
124
+ environments, tenants.
125
+
126
+ It is not exported for a page body: the type ramp, the square hover fill and the
127
+ `align-self: stretch` geometry are all rail-specific.
128
+
129
+ ---
130
+
131
+ ## 3. When to use it
132
+
133
+ ### Use it when
134
+
135
+ - The row needs **two lines** (name + description) and lives in a sidebar.
136
+ - You are hand-composing the switch list because your app owns the catalogue data.
137
+
138
+ ### Don't use it — reach for this instead
139
+
140
+ | Situation | Use instead |
141
+ |---|---|
142
+ | A ready-made app-switch panel from an `apps[]` array | `ScAppSwitchPanel` — pass it to `StreamoidSidebar`'s `switchPanel` prop |
143
+ | A one-line sidebar nav row | `ScSidebarMenu` |
144
+ | A whole branded sidebar with the switcher already wired | `ScCatalogixSidebar` / `ScArtifaxSidebar` / `StreamoidSidebar` |
145
+ | Switching **workspace**, not product | `StreamoidWorkspaceSwitcher` / `ScWorkspaceSwitchCard` |
146
+ | An app tile on a launcher/home grid | `ScAppCardV3` / `ScAppListingCard` |
147
+ | A row in a floating popup menu | `ScMenuOptions` |
148
+
149
+ ### Don't confuse with
150
+
151
+ | You may actually want | Not this |
152
+ |---|---|
153
+ | `ScSidebarMenu` — one line, rounded 16 px pill, has a default icon | `ScSidebarSwitchMenu` is two lines, square when expanded, and renders **no** icon if you omit it |
154
+ | `ScAppSwitchPanel` — the whole panel, driven by `apps[{ key, name, description?, onSelect }]` | It draws its own masked-wordmark rows; this component is **not** one of them |
155
+ | `ScWorkspaceSwitchCard` / `StreamoidWorkspaceSwitcher` (folder `SC-WorkspaceSwitcher`) — workspace, not product | Different domain |
156
+ | `ScAppCard` / `ScAppCardV3` / `ScAppCardForCopilot` — page-body app tiles | Rail row, not a card |
157
+
158
+ ---
159
+
160
+ ## 4. Why to use it
161
+
162
+ - **The square/rounded split is a deliberate design rule.** Expanded rows use
163
+ `border-radius: 0` so the hover fill reads as a list band inside the switch card;
164
+ collapsed squares go back to `radius-3xl` so they read as icon buttons in the rail.
165
+ Hand-rolling this is where the switch panel usually starts looking wrong.
166
+ - **Two-line truncation already works.** The text column (`.content`) is
167
+ `flex: 1 0 0; min-width: 0`, and both lines inside it are `width: 100%` with
168
+ `text-overflow: ellipsis`, so long product names shrink instead of pushing the kebab
169
+ out of the rail.
170
+ - **Icon containment.** `.iconWrapper` is a hard 20 × 20 `overflow: hidden` box with
171
+ `max-width/max-height: 100%` on its child, so a remote product logo of any intrinsic
172
+ size lands at the right optical weight.
173
+ - **Shares the state vocabulary with `ScSidebarMenu`**, so a switch row and a nav row
174
+ in the same rail agree on what "active" looks like.
175
+
176
+ ---
177
+
178
+ ## Gotchas
179
+
180
+ **1. `text` and `description` default to Figma placeholders.** `"Pairtext"` and
181
+ `"Description"` will render if you forget them (or typo the prop name).
182
+
183
+ ```tsx
184
+ // WRONG — renders "Pairtext" / "Description"
185
+ <ScSidebarSwitchMenu icon={icon} name="Photogenix" />
186
+
187
+ // RIGHT
188
+ <ScSidebarSwitchMenu icon={icon} text="Photogenix" description="AI product photography" />
189
+ ```
190
+
191
+ **2. `state` never recolours `description`.** Only `.text` gets the primary colour in
192
+ `active` / `default-highlight` / `default-active`. The subtitle stays tertiary in every
193
+ state — by design, but surprising if you expected the whole row to brighten.
194
+
195
+ **3. Collapsed loses everything but the icon.** `text`, `description`, `moreIcon` all
196
+ live inside the `variant === "expanded"` branch. And there's no `title`/`aria-label` —
197
+ pass `aria-label` yourself (it reaches the DOM via `...props`) or add a tooltip.
198
+
199
+ **4. Omitting `icon` gives you a *left-flush text row*, not a placeholder.** The icon
200
+ wrapper is conditional (`icon ? … : null`). This differs from `ScSidebarMenu`, which
201
+ always renders an icon and defaults it to `<SiconHome />`.
202
+
203
+ **5. No a11y wiring.** Plain `<div>` with `cursor: pointer`; no `role`, `tabIndex` or
204
+ `onKeyDown`. Add them via `...props` if the row is a real navigation target.
205
+
206
+ **6. `moreIcon` is `display: none` until `:hover`.** No focus-visible reveal, so it is
207
+ unreachable by keyboard and on touch.
208
+
209
+ **7. `align-self: stretch` in expanded state.** The row assumes a stretching
210
+ flex-column parent. Drop it into a `flex-direction: row` container and it collapses.
211
+ `collapsed` unsets this and pins 40 × 40.
212
+
213
+ **8. The row is not a card.** It draws no border and no background of its own — the
214
+ bordered "switch card" look comes from the sidebar shell (`StreamoidSidebar`'s
215
+ `switchPanel` renders the logo + panel inside one bordered card and dims the rest).
216
+ Don't try to reproduce that here.
217
+
218
+ ---
219
+
220
+ ## In the wild
221
+
222
+ _No host render site found — used by the agent runtime / composed internally._
223
+
224
+ It is composed inside the design system, by the Catalogix sidebar wrapper:
225
+
226
+ ```tsx
227
+ // npm-components packages/ui/src/SC-Catalogix-Sidebar/ScCatalogixSidebar.tsx:180
228
+ <ScSidebarSwitchMenu
229
+ key={app.id}
230
+ icon={app.icon}
231
+ text={app.name}
232
+ description={app.description}
233
+ state="default-highlight"
234
+ variant="expanded"
235
+ onClick={app.onClick}
236
+ />
237
+ ```
238
+
239
+ …and again at `ScCatalogixSidebar.tsx:204` for the collapsed icon column. Those are its
240
+ **only** two render sites anywhere. No host app reaches it, even indirectly: the
241
+ Catalogix dashboard builds its rail from `StreamoidSidebar` directly
242
+ (`app/containers/LeftMenu/index.jsx:991`) and hands it a `ScAppSwitchPanel`, and
243
+ `ScAppSwitchPanel` draws its own rows. If you need a direct call site, it belongs in a
244
+ sidebar's app/workspace-switch list — nowhere else.
245
+
246
+ ---
247
+
248
+ ## Related
249
+
250
+ - `ScSidebarMenu` — the one-line sibling; the workhorse rail row.
251
+ - `ScAppSwitchPanel` — the assembled switch panel; prefer it over hand-listing rows.
252
+ - `StreamoidSidebar` — pass the panel via `switchPanel` + `switchPanelOpen`, **not**
253
+ inline in the logo slot (that pushes the nav down).
254
+ - `ScCatalogixSidebar` / `ScArtifaxSidebar` — branded shells that already wire this up.
255
+ - `ScSideBarLogoUnit` — the header row whose chevron opens the switch list.
256
+ - `StreamoidWorkspaceSwitcher` / `ScWorkspaceSwitchCard` — the workspace-level equivalents.
257
+ (Note: the folder is `SC-WorkspaceSwitcher` but the export is `StreamoidWorkspaceSwitcher`;
258
+ there is no `ScWorkspaceSwitcher`.)
@@ -0,0 +1,194 @@
1
+ ---
2
+ component: ScSlider
3
+ package: "@streamoid/ui"
4
+ category: forms
5
+ status: legacy
6
+ renders: div
7
+ tags: [slider, range, steps, segmented-progress, strength, opacity, non-interactive, figma-trace]
8
+ related: [ScProgressBar, ScCounter, ScTextField]
9
+ do_not_confuse_with: [ScProgressBar, ScCounter, ScSelectionPillGroup, ScTabSwitcher]
10
+ ---
11
+
12
+ # ScSlider
13
+
14
+ **Not a working slider — a static five-segment bar.** It renders a fixed row of
15
+ 5 bars + 5 dots with the **first** segment painted warning-orange and the rest grey.
16
+ Nothing is draggable, there is no `value`, and its one callback is never called.
17
+ Treat it as an unfinished Figma trace.
18
+
19
+ ## TL;DR for agents
20
+
21
+ - **Reach for it when:** essentially never in its current form. There is no host call
22
+ site, and it cannot report or receive a value.
23
+ - **Don't reach for it when:** you need a real range input (→ native
24
+ `<input type="range">`), a progress indicator (→ `ScProgressBar`), or a bounded
25
+ numeric value (→ `ScCounter`).
26
+ - **Three things that will bite you:**
27
+ 1. **`onValueChange` is declared and never invoked.** Dead prop.
28
+ 2. There is **no `value` / `min` / `max` / `step`** — the highlighted segment is
29
+ hardcoded to the first one.
30
+ 3. The root is `overflow: hidden`, so a thumb or tooltip you try to inject gets
31
+ clipped.
32
+
33
+ ---
34
+
35
+ ## 1. How to use it
36
+
37
+ ### Import
38
+
39
+ ```tsx
40
+ import { ScSlider } from "@streamoid/ui";
41
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
42
+ ```
43
+
44
+ ### Minimal usage
45
+
46
+ ```tsx
47
+ // Renders the fixed 5-segment bar. This is all it does.
48
+ <ScSlider />
49
+ ```
50
+
51
+ ### Props
52
+
53
+ | Prop | Type | Default | Notes |
54
+ |---|---|---|---|
55
+ | `onValueChange` | `(value: number) => void` | – | ⚠️ **Never called.** Declared in the interface, destructured, and dropped. |
56
+ | `className` | `string` | – | Concatenated onto the root. |
57
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | Spread onto the root — `onClick`, `onPointerDown`, `style`, `aria-*`. The only way to make it do anything. |
58
+
59
+ ### What it actually renders
60
+
61
+ | Child | Count | Fill |
62
+ |---|---|---|
63
+ | First bar + first dot | 1 each | `--alias-fill-warning-solid` (orange) |
64
+ | Remaining bars | 4 | `--alias-fill-neutral-neutralactive` |
65
+ | Remaining dots | 4 | `--alias-text-and-icons-primary` (white) |
66
+
67
+ Container: `--alias-surface-base` background, `--radius-full`, `1rem` padding,
68
+ `0.25rem` gaps, `overflow: hidden`. Bars are `flex: 1` (they stretch); dots are
69
+ fixed `0.5rem` squares.
70
+
71
+ ### Recipes
72
+
73
+ ```tsx
74
+ // What you almost certainly want instead — a real range input, styled by you.
75
+ // (Photogenix does exactly this locally: client/src/components/viewer/views/AdjustmentsView.tsx)
76
+ <input
77
+ type="range"
78
+ min={0}
79
+ max={100}
80
+ value={strength}
81
+ onChange={(e) => setStrength(Number(e.target.value))}
82
+ />
83
+
84
+ // A determinate progress bar from the DS — `progress` is a PERCENT (0–100, clamped),
85
+ // not a 0–1 fraction. It defaults to 50.
86
+ <ScProgressBar progress={42} />
87
+
88
+ // A bounded numeric value with a stepper
89
+ <ScCounter count={strength} min={0} max={100} onChange={setStrength} label="%" />
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 2. Where to use it
95
+
96
+ Nowhere today. No render site exists in CXO, Catalogix, Photogenix or Artifax, and no
97
+ other DS component composes it. Its visual — a segmented bar with one hot segment —
98
+ reads like a **"step 1 of 5" indicator** rather than a range control, so if it gets
99
+ finished it most plausibly belongs to a **multi-step flow header** (feed import,
100
+ onboarding) or a discrete strength picker in Photogenix's adjustments panel.
101
+
102
+ ---
103
+
104
+ ## 3. When to use it
105
+
106
+ ### Use it when
107
+
108
+ - You deliberately want the static five-segment decoration and are fine with it being
109
+ non-interactive, **and** you accept that its API may change when someone finishes it.
110
+
111
+ ### Don't use it — reach for this instead
112
+
113
+ | Situation | Use instead |
114
+ |---|---|
115
+ | A draggable numeric range (strength, opacity, threshold) | native `<input type="range">` — Photogenix's `AdjustmentsView` is the reference |
116
+ | Determinate progress / percentage complete | `ScProgressBar` (`progress?: number`, 0–100, default `50`) |
117
+ | A bounded integer the user nudges or types | `ScCounter` (has real `min`/`max`) |
118
+ | Free numeric entry in a form | `ScTextField` / `ScOnlyField` |
119
+ | Discrete choice between 2–5 options | `ScSelectionPillGroup` / `ScTabSwitcher` |
120
+
121
+ ### Don't confuse with
122
+
123
+ | You may actually want | Not this |
124
+ |---|---|
125
+ | `ScProgressBar` — one bar driven by a real `progress` number | `ScSlider` has no value input at all |
126
+ | `ScCounter` — the only DS control with working `min`/`max` clamping | Not a slider, but usually the right answer |
127
+ | A "steps" indicator | This looks like one but exposes no current-step prop |
128
+
129
+ ---
130
+
131
+ ## 4. Why to use it
132
+
133
+ Honestly: little. The only things it gives you are the token-driven fills
134
+ (`--alias-fill-warning-solid`, `--alias-fill-neutral-neutralactive`) and the pill
135
+ container geometry. Because it accepts no value and emits no events, **any real
136
+ interaction has to be built on top of the spread `HTMLAttributes`**, at which point
137
+ you are writing the slider yourself and should do so with a native
138
+ `<input type="range">` that gets keyboard support, `aria-valuenow` and touch handling
139
+ for free.
140
+
141
+ If you need this component for real, the honest move is to fix it in the DS
142
+ (add `value` / `min` / `max` / `step`, wire `onValueChange`, drop `overflow: hidden`)
143
+ rather than to work around it at a call site.
144
+
145
+ ---
146
+
147
+ ## Gotchas
148
+
149
+ **1. `onValueChange` never fires.** It is destructured out of props and then unused —
150
+ so it is not even forwarded to the DOM.
151
+
152
+ ```tsx
153
+ // WRONG — the handler is dead code
154
+ <ScSlider onValueChange={setStrength} />
155
+
156
+ // RIGHT — for a real slider, don't use this component
157
+ <input type="range" min={0} max={100} value={strength}
158
+ onChange={(e) => setStrength(Number(e.target.value))} />
159
+ ```
160
+
161
+ **2. The highlighted segment is hardcoded.** The first bar/dot pair always uses the
162
+ warning colour; segments 2–5 always use the neutral pair. You cannot express "3 of 5".
163
+
164
+ **3. `overflow: hidden` on the root.** Any absolutely-positioned thumb, value bubble
165
+ or tooltip you add via children/`style` will be clipped by the pill.
166
+
167
+ **4. Bars stretch, dots don't.** Bars are `flex: 1`; dots are fixed 8px. In a narrow
168
+ container the bars collapse toward zero and you get a dotted line.
169
+
170
+ **5. It has no accessible role.** No `role="slider"`, no `aria-valuemin/now/max`, no
171
+ `tabIndex`. Screen readers see an empty group of divs.
172
+
173
+ **6. `className` is string-concatenated**, so the DOM class list contains a literal
174
+ `undefined` when you omit it.
175
+
176
+ ---
177
+
178
+ ## In the wild
179
+
180
+ _No host render site found — used by the agent runtime / composed internally._
181
+
182
+ In this case neither: nothing renders it. It exists only as an export. The nearest
183
+ real implementation of the job it looks like it does is Photogenix's local
184
+ `<input type="range">` in
185
+ `photogenix_v2 dashboard/client/src/components/viewer/views/AdjustmentsView.tsx:60`.
186
+
187
+ ---
188
+
189
+ ## Related
190
+
191
+ - `ScProgressBar` — determinate progress from a real `progress` number.
192
+ - `ScCounter` — bounded numeric stepper with working `min`/`max`.
193
+ - `ScSelectionPillGroup` / `ScTabSwitcher` — if the intent was discrete steps/choices.
194
+ - `ScTextField` — plain numeric entry inside a form.