@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,345 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScCatalogixInvite
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: cards
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [invite, app-access, catalogix, toggle, store-access, permissions, user-management, settings, search, checkbox-list]
|
|
8
|
+
related: [ScArtifaxInvite, ScPhtogenixInvite, ScAppCard, ScToggleSwitch, ScPairtext, ScOnlyField]
|
|
9
|
+
do_not_confuse_with: [ScArtifaxInvite, ScPhtogenixInvite, ScAppCard, ScAppListingCard, ScAccess, ScCatalogixStoreTableList, ScCheckField]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ScCatalogixInvite
|
|
13
|
+
|
|
14
|
+
**The Catalogix access row *plus* its store-scoping panel.** Same header as the
|
|
15
|
+
other invite rows — `ScAppCard` + `ScToggleSwitch` — and when the toggle is on it
|
|
16
|
+
reveals a nested panel: "Store access", an *N* Selected count, a search field, and
|
|
17
|
+
a checkbox list of stores. The only member of the invite trio with a sub-scope.
|
|
18
|
+
|
|
19
|
+
## TL;DR for agents
|
|
20
|
+
|
|
21
|
+
- **Reach for it when:** you're building the per-app access list in an invite /
|
|
22
|
+
edit-user flow and the Catalogix row has to pick **which stores** the user can see.
|
|
23
|
+
- **Don't reach for it when:** access is a plain on/off (→ `ScArtifaxInvite`), it's
|
|
24
|
+
the Photogenix row (→ `ScPhtogenixInvite`), or you want a standalone
|
|
25
|
+
searchable multi-select that isn't bolted to an app toggle (→ `ScOnlyField` +
|
|
26
|
+
`ScPairtext`, or `ScCheckField`).
|
|
27
|
+
- **Five things that will bite you:**
|
|
28
|
+
1. ⚠️ Omit `stores` and you ship **five dummy rows labelled "Pairtext"** — the
|
|
29
|
+
Figma placeholder. Pass `stores` (even `[]`) always.
|
|
30
|
+
2. It does **not** filter. `searchValue`/`onSearchChange` are a plain controlled
|
|
31
|
+
input; *you* filter `stores` before passing them.
|
|
32
|
+
3. Pass `searchValue` without `onSearchChange` and the search box is read-only.
|
|
33
|
+
4. The store list has **no max-height and no overflow** — 300 stores means a
|
|
34
|
+
300-row-tall modal. Cap it yourself.
|
|
35
|
+
5. ⚠️ Unlike its two siblings it defaults to **OFF** (`active = "false"`) and it
|
|
36
|
+
draws **no bottom divider**.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 1. How to use it
|
|
41
|
+
|
|
42
|
+
### Import
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { ScCatalogixInvite } from "@streamoid/ui";
|
|
46
|
+
import { SiconCatalogix } from "@streamoid/icons";
|
|
47
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Minimal usage
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<ScCatalogixInvite
|
|
54
|
+
enabled={catalogixOn}
|
|
55
|
+
onToggle={setCatalogixOn}
|
|
56
|
+
appIcon={<SiconCatalogix size={24} />}
|
|
57
|
+
appDescription="Catalog enrichment and feeds"
|
|
58
|
+
stores={visibleStores} // already filtered by your search
|
|
59
|
+
selectedStores={selectedStoreIds}
|
|
60
|
+
onStoreToggle={toggleStore}
|
|
61
|
+
searchValue={storeSearch}
|
|
62
|
+
onSearchChange={setStoreSearch}
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Props
|
|
67
|
+
|
|
68
|
+
| Prop | Type | Default | Notes |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| `enabled` | `boolean` | – | The real on/off. Overrides `active` whenever defined. **Use this one.** Also the switch that reveals the store panel. |
|
|
71
|
+
| `active` | `"true"` \| `"false"` | `"false"` | ⚠️ Figma-variant leftover, a *string*. Consulted only when `enabled` is `undefined`. Defaults **off** — the opposite of `ScArtifaxInvite`/`ScPhtogenixInvite`. |
|
|
72
|
+
| `onToggle` | `(active: boolean) => void` | – | Fires with the **next** value. Omit it and the row can never be expanded. |
|
|
73
|
+
| `appName` | `string` | `"Catalogix"` | ⚠️ Real default. Passed to `ScAppCard`. |
|
|
74
|
+
| `appDescription` | `string` | `"Info about catalogix"` | ⚠️ Real default, and it is placeholder copy. |
|
|
75
|
+
| `appIcon` | `JSX.Element` | `<SiconArtifacts />` | ⚠️ The **wrong brand's** icon by default — pass `<SiconCatalogix />`. |
|
|
76
|
+
| `stores` | `{ id: string; name: string }[]` | – | ⚠️ Undefined ≠ empty. Undefined renders 5 placeholder rows; `[]` renders "No stores found". |
|
|
77
|
+
| `selectedStores` | `string[]` | – | Ids that render checked. Also **replaces** `selectedCount` with `` `${selectedStores.length} Selected` ``. |
|
|
78
|
+
| `onStoreToggle` | `(storeId: string) => void` | – | Fires on a store row click. You compute the next selection. |
|
|
79
|
+
| `searchValue` | `string` | – | Value of the search input. Controlled — see Gotcha 3. |
|
|
80
|
+
| `onSearchChange` | `(query: string) => void` | – | Fires on every keystroke. The component does **no** filtering. |
|
|
81
|
+
| `storeAccessTitle` | `string` | `"Store access"` | Panel heading. Truncates with ellipsis (`flex: 1`, `nowrap`). |
|
|
82
|
+
| `selectedCount` | `string` | `"0 Selected"` | Right-hand count. **Ignored whenever `selectedStores` is passed.** |
|
|
83
|
+
| `searchPlaceholder` | `string` | `"Search stores..."` | Placeholder of the search input. |
|
|
84
|
+
| `className` | `string` | – | Appended after internal classes. |
|
|
85
|
+
| `...props` | `Omit<HTMLAttributes<HTMLDivElement>, "onToggle">` | – | Spread onto the root `<div>`. |
|
|
86
|
+
|
|
87
|
+
### What renders in each state
|
|
88
|
+
|
|
89
|
+
| Region | `enabled` false | `enabled` true |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| Header | `ScAppCard` + `ScToggleSwitch` | same |
|
|
92
|
+
| Store-access panel | **not rendered at all** | canvas-base panel, 16px padding, radius 16 |
|
|
93
|
+
| Panel header | — | `storeAccessTitle` + count (`selectedStores.length` if given, else `selectedCount`) |
|
|
94
|
+
| Search | — | `ScOnlyField`, search icon on the **right**, `searchPlaceholder` |
|
|
95
|
+
| List: `stores` non-empty | — | one `ScPairtext type="checkbox"` per store, name left / checkbox right |
|
|
96
|
+
| List: `stores === []` | — | hardcoded "No stores found" |
|
|
97
|
+
| List: `stores` undefined | — | ⚠️ five placeholder `ScPairtext` rows reading **"Pairtext"** |
|
|
98
|
+
|
|
99
|
+
`storeAccessTitle`, `selectedCount`, `searchPlaceholder`, `stores`,
|
|
100
|
+
`selectedStores`, `searchValue` and their handlers are all inert while the row is
|
|
101
|
+
off — the whole panel is behind `isEnabled &&`.
|
|
102
|
+
|
|
103
|
+
### Recipes
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
// The full job: toggle + search + multi-select, with YOU doing the filtering
|
|
107
|
+
const [catalogixOn, setCatalogixOn] = useState(false);
|
|
108
|
+
const [storeSearch, setStoreSearch] = useState("");
|
|
109
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
110
|
+
|
|
111
|
+
const visibleStores = useMemo(
|
|
112
|
+
() =>
|
|
113
|
+
allStores
|
|
114
|
+
.map((s) => ({ id: s._id, name: s.name || s._id }))
|
|
115
|
+
.filter((s) => s.name.toLowerCase().includes(storeSearch.toLowerCase())),
|
|
116
|
+
[allStores, storeSearch],
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
<ScCatalogixInvite
|
|
120
|
+
enabled={catalogixOn}
|
|
121
|
+
onToggle={(next) => {
|
|
122
|
+
setCatalogixOn(next);
|
|
123
|
+
if (!next) setSelected([]); // clearing on disable is YOUR job
|
|
124
|
+
}}
|
|
125
|
+
appIcon={<SiconCatalogix size={24} />}
|
|
126
|
+
appDescription="Catalog enrichment and feeds"
|
|
127
|
+
stores={visibleStores}
|
|
128
|
+
selectedStores={selected}
|
|
129
|
+
onStoreToggle={(id) =>
|
|
130
|
+
setSelected((prev) =>
|
|
131
|
+
prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
searchValue={storeSearch}
|
|
135
|
+
onSearchChange={setStoreSearch}
|
|
136
|
+
/>
|
|
137
|
+
|
|
138
|
+
// Cap the list height — the component never scrolls on its own
|
|
139
|
+
<ScCatalogixInvite
|
|
140
|
+
/* …as above… */
|
|
141
|
+
className={styles.invite}
|
|
142
|
+
/>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```css
|
|
146
|
+
/* Target the DS class from your own stylesheet, or wrap and use a descendant
|
|
147
|
+
selector — the list container is the third child of the panel. */
|
|
148
|
+
.invite [class*="storeListContainer"] { max-height: 240px; overflow-y: auto; }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
// Loading state: pass [] (NOT undefined) so you get the empty state, not placeholders
|
|
153
|
+
<ScCatalogixInvite
|
|
154
|
+
enabled={catalogixOn}
|
|
155
|
+
onToggle={setCatalogixOn}
|
|
156
|
+
stores={isLoading ? [] : visibleStores}
|
|
157
|
+
selectedStores={selected}
|
|
158
|
+
onStoreToggle={toggleStore}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 2. Where to use it
|
|
165
|
+
|
|
166
|
+
- **The invite-user modal's "App access" section**, as the Catalogix row — normally
|
|
167
|
+
last, because expanding it makes the modal grow.
|
|
168
|
+
- **The edit-user / manage-access drawer**, pre-populated with the user's current
|
|
169
|
+
store scope.
|
|
170
|
+
- Any **app-access + resource-scope** pairing with the same shape (app on/off, then
|
|
171
|
+
"which of these N things").
|
|
172
|
+
|
|
173
|
+
It composes `ScAppCard`, `ScToggleSwitch`, `ScOnlyField` (search) and `ScPairtext`
|
|
174
|
+
(checkbox rows), with a two-tone nesting: the panel sits on
|
|
175
|
+
`--alias-surface-canvasbase` and the list on `--alias-fill-neutral-neutralplus`, so
|
|
176
|
+
it reads as inset in both themes.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 3. When to use it
|
|
181
|
+
|
|
182
|
+
### Use it when
|
|
183
|
+
|
|
184
|
+
- Granting the app is **not** enough — the user also needs a subset of stores.
|
|
185
|
+
- The scope list is short enough to show inline (or you cap the height yourself).
|
|
186
|
+
- You want the row to line up with the other app rows in the same modal.
|
|
187
|
+
|
|
188
|
+
### Don't use it — reach for this instead
|
|
189
|
+
|
|
190
|
+
| Situation | Use instead |
|
|
191
|
+
|---|---|
|
|
192
|
+
| Access is a plain boolean, no sub-scope | `ScArtifaxInvite` |
|
|
193
|
+
| The Photogenix row | `ScPhtogenixInvite` (prefixed `scAppCardapp*` props) |
|
|
194
|
+
| A searchable multi-select that isn't attached to an app toggle | `ScOnlyField` + `ScPairtext`, or `ScCheckField` |
|
|
195
|
+
| A list of stores as a data table (owner, status, actions) | `ScCatalogixStoreTableList` |
|
|
196
|
+
| Read-only "which apps does this user have" | `ScAccess` |
|
|
197
|
+
| App icon + name + description, no toggle | `ScAppCard` |
|
|
198
|
+
| A launcher/marketing card for the app | `ScAppListingCard` / `ScAppCardV3` |
|
|
199
|
+
| Checkboxes with real form semantics (labels, keyboard) | `ScCheckField` / `ScCheckbox` |
|
|
200
|
+
| Hundreds of options needing virtualisation | build your own list — this one renders every row |
|
|
201
|
+
|
|
202
|
+
### Don't confuse with
|
|
203
|
+
|
|
204
|
+
| You may actually want | Not this |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `ScArtifaxInvite` — header-only row, defaults **ON**, draws a bottom divider | `ScCatalogixInvite` adds the store panel, defaults **OFF**, draws **no** divider |
|
|
207
|
+
| `ScPhtogenixInvite` — header-only row with prefixed props and no DOM prop forwarding | This one uses clean `appName`/`appDescription`/`appIcon` and spreads `...props` |
|
|
208
|
+
| `ScCatalogixStoreTableList` — the store **table** on Catalogix's own screens | This is a compact checkbox picker inside an invite modal |
|
|
209
|
+
| `ScCheckField` — a labelled group of real checkboxes | The rows here are `ScPairtext` divs: no `<input>`, no keyboard |
|
|
210
|
+
| `ScAccess` — three app icons, read-only | Not an editable control |
|
|
211
|
+
|
|
212
|
+
All three invite components are app-agnostic apart from their default copy and
|
|
213
|
+
icon. Choose by **shape**: no sub-scope → `ScArtifaxInvite`; sub-scope →
|
|
214
|
+
`ScCatalogixInvite`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 4. Why to use it
|
|
219
|
+
|
|
220
|
+
- **The disclosure logic is already right.** Toggle on → panel appears; toggle off →
|
|
221
|
+
the entire panel (and its search state's visual footprint) is gone, in one prop.
|
|
222
|
+
Hand-rolled versions leak a half-expanded panel or keep a stale search box mounted.
|
|
223
|
+
- **Two-tone inset nesting that survives light mode.** Panel on
|
|
224
|
+
`surface-canvasbase`, list on `fill-neutral-neutralplus` — two distinct tokens
|
|
225
|
+
rather than a grey that collapses to white on a light canvas.
|
|
226
|
+
- **Consistent count/heading typography.** Title is `text-sm-regular` primary,
|
|
227
|
+
count is `text-xs-regular` muted, both ellipsised — the exact spec, and the
|
|
228
|
+
detail most often missed when this row is rebuilt by hand.
|
|
229
|
+
- **It matches its sibling rows for free**: same 16px padding, same `ScAppCard`
|
|
230
|
+
flex, same `ScToggleSwitch`.
|
|
231
|
+
- **One place to change.** `@streamoid/settings` currently reimplements this whole
|
|
232
|
+
panel — local toggle, local search input, local store rows, the same
|
|
233
|
+
"Search stores..." and "No stores found" strings — in a single ~980-line modal.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Gotchas
|
|
238
|
+
|
|
239
|
+
**1. `stores` undefined renders five dummy "Pairtext" rows.** The Figma-placeholder
|
|
240
|
+
branch is still in the component, and it renders unchecked checkbox rows whose
|
|
241
|
+
label is `ScPairtext`'s own default (`"Pairtext"`), wired to nothing.
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
// WRONG — five rows reading "Pairtext" appear the moment the toggle goes on
|
|
245
|
+
<ScCatalogixInvite enabled onToggle={setOn} selectedStores={selected} />
|
|
246
|
+
|
|
247
|
+
// RIGHT — pass an array, even while loading
|
|
248
|
+
<ScCatalogixInvite enabled onToggle={setOn} stores={stores ?? []} selectedStores={selected} />
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**2. It does not filter, sort, or paginate.** `onSearchChange` just reports
|
|
252
|
+
keystrokes; the list renders exactly the `stores` array you pass. Filter upstream.
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
// WRONG — typing changes nothing on screen
|
|
256
|
+
<ScCatalogixInvite stores={allStores} searchValue={q} onSearchChange={setQ} … />
|
|
257
|
+
|
|
258
|
+
// RIGHT
|
|
259
|
+
<ScCatalogixInvite
|
|
260
|
+
stores={allStores.filter((s) => s.name.toLowerCase().includes(q.toLowerCase()))}
|
|
261
|
+
searchValue={q}
|
|
262
|
+
onSearchChange={setQ}
|
|
263
|
+
…
|
|
264
|
+
/>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**3. `searchValue` without `onSearchChange` is a read-only input.** It's forwarded
|
|
268
|
+
straight to a controlled `<input value>`; with no change handler, keystrokes are
|
|
269
|
+
discarded. Pass both, or neither.
|
|
270
|
+
|
|
271
|
+
**4. The store list never scrolls.** `.storeListContainer` sets no `max-height` and
|
|
272
|
+
no `overflow`, so the panel grows with the data and pushes your modal footer off
|
|
273
|
+
screen. Constrain it from your side (see the Recipes).
|
|
274
|
+
|
|
275
|
+
**5. It defaults to OFF, and its siblings default to ON.** `active = "false"` here
|
|
276
|
+
vs `"true"` in `ScArtifaxInvite`/`ScPhtogenixInvite`. Always pass `enabled` and
|
|
277
|
+
stop thinking about `active`.
|
|
278
|
+
|
|
279
|
+
**6. `selectedCount` is dead whenever `selectedStores` is present.** The component
|
|
280
|
+
computes `` `${selectedStores.length} Selected` ``. The `" Selected"` suffix is
|
|
281
|
+
hardcoded English; the only way to change the wording is to omit `selectedStores`
|
|
282
|
+
and drive `selectedCount` yourself — which also loses the checked state.
|
|
283
|
+
|
|
284
|
+
**7. The default `appIcon` is the Artifax icon.** `SiconArtifacts` is the fallback
|
|
285
|
+
in all three invite components. Pass `<SiconCatalogix />`.
|
|
286
|
+
|
|
287
|
+
**8. `"No stores found"` is not overridable,** and neither is the placeholder
|
|
288
|
+
branch. Only `storeAccessTitle`, `selectedCount` and `searchPlaceholder` are props.
|
|
289
|
+
Don't use this row in a localised surface without changing the DS first.
|
|
290
|
+
|
|
291
|
+
**9. The search icon is on the right, and the left one is discarded.** The
|
|
292
|
+
component passes both `tfLeftIcon` and `tfRightIcon` to `ScOnlyField` but never
|
|
293
|
+
sets `tfGroup`, which defaults to `"icon-right"` — so only the right icon renders.
|
|
294
|
+
You cannot move it or replace it.
|
|
295
|
+
|
|
296
|
+
**10. Store rows are not accessible.** `ScPairtext` renders a `<div onClick>` with
|
|
297
|
+
`cursor: pointer` and an `ScCheckbox` **visual** — no `<input>`, no `role`, no
|
|
298
|
+
`tabIndex`, no label association. Keyboard users cannot select a store. Use
|
|
299
|
+
`ScCheckField` if that matters.
|
|
300
|
+
|
|
301
|
+
**11. No bottom divider.** Unlike the other two invite rows, `.scCatalogixInvite`
|
|
302
|
+
has no border. Stack it after them and the separator sequence breaks — add your own
|
|
303
|
+
`ScHDivider` or a border via `className`.
|
|
304
|
+
|
|
305
|
+
**12. Turning the row off does not clear the selection.** `selectedStores` is your
|
|
306
|
+
state; the panel simply unmounts. Reset it in `onToggle` if a disabled app should
|
|
307
|
+
drop its scope.
|
|
308
|
+
|
|
309
|
+
**13. `styles["active-false"]` doesn't exist.** Only `.active-true` is defined
|
|
310
|
+
(it's what styles the whole panel), so in the OFF state the variant class resolves
|
|
311
|
+
to `undefined` and lands in the class attribute as the literal `"undefined"`, as
|
|
312
|
+
does an omitted `className`. Don't assert on the class list.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## In the wild
|
|
317
|
+
|
|
318
|
+
_No host render site found — used by the agent runtime / composed internally._
|
|
319
|
+
|
|
320
|
+
The surface is real but hand-rolled in the shared settings package, which
|
|
321
|
+
reimplements this component end to end:
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
// @streamoid/settings packages/settings/src/invite-update-modal.tsx:700
|
|
325
|
+
{/* Catalogix row + store access */}
|
|
326
|
+
// …~200 lines duplicating this component: local ToggleSwitch (line 84),
|
|
327
|
+
// a hand-written search input with placeholder "Search stores..." (line 838),
|
|
328
|
+
// filteredStores mapped to hand-rolled checkbox rows (line 867),
|
|
329
|
+
// and the same "No stores found" empty state (line 901).
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
That modal — CXO settings → Teams → invite/edit user — is exactly where this
|
|
333
|
+
component belongs; adopting it would delete the duplication.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Related
|
|
338
|
+
|
|
339
|
+
- `ScArtifaxInvite` — the plain header-only row; the cleanest API of the trio.
|
|
340
|
+
- `ScPhtogenixInvite` — the Photogenix twin; prefixed `scAppCardapp*` props.
|
|
341
|
+
- `ScAppCard` — the icon/name/description block in the header.
|
|
342
|
+
- `ScToggleSwitch` — the switch, standalone.
|
|
343
|
+
- `ScOnlyField` — the search field it renders; note `tfGroup` controls icon sides.
|
|
344
|
+
- `ScPairtext` — the store rows; `type="checkbox"`, `iconPosition="right"`.
|
|
345
|
+
- `ScCheckField` — reach for this when the multi-select needs real form semantics.
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScCatalogixSidebar
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: sidebar
|
|
5
|
+
status: legacy
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [sidebar, catalogix, nav, shell, rail, wrapper, stores, ai-training, insights]
|
|
8
|
+
related: [StreamoidSidebar, ScSideBarLogoUnit, ScSidebarSwitchMenu, ScAppSwitchPanel, CreditWarningBanner]
|
|
9
|
+
do_not_confuse_with: [StreamoidSidebar, ScArtifaxSidebar, ScCatalogixInvite, ScCatalogixStoreHeader]
|
|
10
|
+
required_props: [expanded, onToggle]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# ScCatalogixSidebar
|
|
14
|
+
|
|
15
|
+
**A Catalogix-flavoured preset of `StreamoidSidebar`.** It hardcodes the Catalogix
|
|
16
|
+
wordmark logo unit, a default Stores / AI Training / Insights nav, an inline
|
|
17
|
+
app-switch list built from `ScSidebarSwitchMenu`, and the credit banner — so a caller
|
|
18
|
+
only supplies `expanded` + callbacks.
|
|
19
|
+
|
|
20
|
+
> **`status: legacy`.** Catalogix's own shell no longer uses it: as of the
|
|
21
|
+
> 2026-07 redesign, `catalogix/dashboard app/containers/LeftMenu/index.jsx:991`
|
|
22
|
+
> composes **`StreamoidSidebar` directly** — it needs `assistantCta` (the "Ask CXO"
|
|
23
|
+
> gradient CTA), `activeItemId`-driven nav and `ScAppSwitchPanel`, none of which this
|
|
24
|
+
> wrapper can express. **For new work, use `StreamoidSidebar`.**
|
|
25
|
+
|
|
26
|
+
## TL;DR for agents
|
|
27
|
+
|
|
28
|
+
- **Reach for it when:** essentially never in new code. It is useful mainly as a
|
|
29
|
+
worked example of how to preset `StreamoidSidebar`.
|
|
30
|
+
- **Don't reach for it when:** you need the assistant CTA, the shared
|
|
31
|
+
`ScAppSwitchPanel` rows, the collapsed right-side switch flyout, `topItems`,
|
|
32
|
+
section labels, or a version footer — all unreachable through this wrapper
|
|
33
|
+
(→ `StreamoidSidebar`).
|
|
34
|
+
- **Three things that will bite you:**
|
|
35
|
+
1. **There is no `assistantCta` prop.** You cannot render the "Ask CXO" gradient
|
|
36
|
+
CTA through this component, despite the component catalog implying otherwise.
|
|
37
|
+
2. `switchApps` rows are `ScSidebarSwitchMenu`, **not** `ScAppSwitchPanel` — a
|
|
38
|
+
different visual language from every other app's switcher.
|
|
39
|
+
3. `switchPanel` is only built when `expanded`, so the collapsed rail gets an
|
|
40
|
+
**inline icon list** instead of `StreamoidSidebar`'s right-side flyout, and no
|
|
41
|
+
backdrop.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 1. How to use it
|
|
46
|
+
|
|
47
|
+
### Import
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import {
|
|
51
|
+
ScCatalogixSidebar,
|
|
52
|
+
type CatalogixNavItem,
|
|
53
|
+
type CatalogixSwitchApp,
|
|
54
|
+
} from "@streamoid/ui";
|
|
55
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Minimal usage
|
|
59
|
+
|
|
60
|
+
Everything except the two state props has a default:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
<ScCatalogixSidebar
|
|
64
|
+
expanded={expanded}
|
|
65
|
+
onToggle={() => setExpanded((v) => !v)}
|
|
66
|
+
activeItemId="stores"
|
|
67
|
+
onItemSelect={(item) => navigate(`/${item.id}`)}
|
|
68
|
+
/>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Props
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Default | Notes |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| `expanded` | `boolean` | — | **Required.** Forwarded to `StreamoidSidebar`. |
|
|
76
|
+
| `onToggle` | `() => void` | — | **Required.** Also the fallback for the collapsed credit-banner click. |
|
|
77
|
+
| `items` | `CatalogixNavItem[]` | ⚠️ `[Stores, AI Training, Insights]` | Real default: ids `stores` / `ai-training` / `insights`. |
|
|
78
|
+
| `iconMap` | `CatalogixSidebarIconMap` | ⚠️ `SiconBag` / `SiconBrain` / `SiconInsights` | Real default, keyed `stores` / `aiTraining` / `insights`. Replacing `items` without replacing `iconMap` leaves rows **icon-less**. |
|
|
79
|
+
| `activeItemId` | `string` | – | Matching row → `state="active"`; `active` is passed to the icon renderer. |
|
|
80
|
+
| `onItemSelect` | `(item: CatalogixNavItem) => void` | – | No `sectionId` argument (unlike `StreamoidSidebar`). |
|
|
81
|
+
| `switchApps` | `CatalogixSwitchApp[]` | – | `{ id, name, description?, icon?, onClick? }[]`. Omit to disable app switching. |
|
|
82
|
+
| `onLogoClick` | `() => void` | – | Fires **in addition to** the internal open/close of the app list. |
|
|
83
|
+
| `expandedLogo` | `ReactNode` | ⚠️ built-in `ScSideBarLogoUnit product="Catalogix"` | Overriding it **breaks the switcher** — the default node is what carries `onClick={handleSwitch}`. |
|
|
84
|
+
| `collapsedLogo` | `ReactNode` | ⚠️ built-in collapsed Catalogix mark | Same caveat, plus you lose the `hover` highlight while the list is open. |
|
|
85
|
+
| `profile` | `CatalogixSidebarProfile` | – | `{ name, subtitle?, avatar?, onClick? }`. **Required in practice** — see Gotcha 4. |
|
|
86
|
+
| `creditWarning` | `CatalogixSidebarCreditWarning \| null` | – | `{ availableCredits, remainingPct, level?, onBuyCredits, onCollapsedClick? }`. `level` defaults to `"danger"`; `onCollapsedClick` defaults to `onToggle`. |
|
|
87
|
+
| `toggleIcon` | `ReactNode \| ((expanded: boolean) => ReactNode)` | `SiconCollapse` / `SiconExpand`, muted, `size-6` | Real default, and it correctly swaps glyphs per state. |
|
|
88
|
+
| `className` | `string` | – | Forwarded to `StreamoidSidebar`'s outer wrapper. |
|
|
89
|
+
| `style` | `CSSProperties` | – | Forwarded likewise. |
|
|
90
|
+
|
|
91
|
+
### Types
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
interface CatalogixNavItem { id: string; label: string; iconKey: string }
|
|
95
|
+
interface CatalogixSwitchApp { id: string; name: string; description?: string; icon?: ReactNode; onClick?: () => void }
|
|
96
|
+
interface CatalogixSidebarProfile { name: string; subtitle?: string; avatar?: ReactNode; onClick?: () => void }
|
|
97
|
+
interface CatalogixSidebarCreditWarning {
|
|
98
|
+
availableCredits: number; remainingPct: number;
|
|
99
|
+
level?: "warning" | "danger"; // default "danger"
|
|
100
|
+
onBuyCredits: () => void;
|
|
101
|
+
onCollapsedClick?: () => void; // defaults to onToggle
|
|
102
|
+
}
|
|
103
|
+
type CatalogixSidebarIconRenderer = (ctx: { active: boolean; expanded: boolean }) => ReactNode;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### What it hardcodes on `StreamoidSidebar`
|
|
107
|
+
|
|
108
|
+
Anything in this list is **not reachable** through this wrapper:
|
|
109
|
+
|
|
110
|
+
| `StreamoidSidebar` prop | Fixed value here |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `config` | `{ sections: [] }` — no `topItems`, no `bottomItems`, no section labels |
|
|
113
|
+
| `iconMap` | `{}` |
|
|
114
|
+
| `showBody` / `bodyContent` | always on / the internal nav + collapsed switch list |
|
|
115
|
+
| `switchPanel` | the `ScSidebarSwitchMenu` rows, **and only when `expanded`** |
|
|
116
|
+
| `switchPanelOpen` / `onSwitchPanelClose` | internal `appListOpen` state |
|
|
117
|
+
| `toggleInProfile` | `true` (so `profile` is mandatory in practice) |
|
|
118
|
+
| `versionText` | `""` |
|
|
119
|
+
| `preFooterContent` | the `CreditWarningBanner` |
|
|
120
|
+
| `assistantCta` | **never passed — no way to set it** |
|
|
121
|
+
| `isMobile`, `hideFooter`, `topItems`, `highlightedItemIds`, `moreIcon`, `onMoreClick` | never passed |
|
|
122
|
+
|
|
123
|
+
### Recipes
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
// The full intended wiring
|
|
127
|
+
<ScCatalogixSidebar
|
|
128
|
+
expanded={expanded}
|
|
129
|
+
onToggle={() => setExpanded((v) => !v)}
|
|
130
|
+
activeItemId={currentSection}
|
|
131
|
+
onItemSelect={(item) => go(item.id)}
|
|
132
|
+
switchApps={otherProducts.map((p) => ({
|
|
133
|
+
id: p.id,
|
|
134
|
+
name: p.name,
|
|
135
|
+
description: p.desc,
|
|
136
|
+
icon: <ProductIcon product={p.id} />,
|
|
137
|
+
onClick: () => open(p.url),
|
|
138
|
+
}))}
|
|
139
|
+
onLogoClick={loadServiceCatalog} // lazy-load the product list
|
|
140
|
+
profile={{ name, subtitle: workspace, avatar: <ScDp type="initial" initial={initial} size={32} />, onClick: openProfilePopup }}
|
|
141
|
+
creditWarning={low ? { availableCredits: credits, remainingPct: Math.round(pct), onBuyCredits: goBilling } : null}
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
// Custom nav — replace items AND iconMap together
|
|
145
|
+
<ScCatalogixSidebar
|
|
146
|
+
expanded={expanded}
|
|
147
|
+
onToggle={toggle}
|
|
148
|
+
items={[{ id: "feeds", label: "Feeds", iconKey: "feeds" }]}
|
|
149
|
+
iconMap={{
|
|
150
|
+
feeds: ({ active }) => (
|
|
151
|
+
<SiconUpload color={active ? "var(--alias-text---icons-primary)" : "var(--alias-text---icons-tertiary)"} />
|
|
152
|
+
),
|
|
153
|
+
}}
|
|
154
|
+
/>
|
|
155
|
+
|
|
156
|
+
// What to write instead for anything non-trivial (this is what Catalogix ships):
|
|
157
|
+
<StreamoidSidebar
|
|
158
|
+
expanded={expanded}
|
|
159
|
+
onToggle={toggle}
|
|
160
|
+
config={navConfig}
|
|
161
|
+
iconMap={iconMap}
|
|
162
|
+
activeItemId={currentSection}
|
|
163
|
+
showBody={!insideStore}
|
|
164
|
+
bodyContent={workspaceServiceBody}
|
|
165
|
+
switchPanel={apps.length ? <ScAppSwitchPanel apps={apps} /> : undefined}
|
|
166
|
+
switchPanelOpen={appListOpen}
|
|
167
|
+
onSwitchPanelClose={() => setAppListOpen(false)}
|
|
168
|
+
assistantCta={{ label: "Ask CXO", icon: <SiconBolt size={20} color="currentColor" />, active: askOpen, onClick: toggleAsk }}
|
|
169
|
+
expandedLogo={<ScSideBarLogoUnit wordmark={<ProductWordmark product="Catalogix" />} onClick={() => setAppListOpen((v) => !v)} />}
|
|
170
|
+
collapsedLogo={<ScSideBarLogoUnit state="collapsed" wordmark={<ProductCollapsedMark product="Catalogix" />} onClick={() => setAppListOpen((v) => !v)} />}
|
|
171
|
+
profile={profile}
|
|
172
|
+
toggleInProfile
|
|
173
|
+
versionText=""
|
|
174
|
+
toggleIcon={(exp) => <SiconCollapse size={20} style={exp ? undefined : { transform: "rotate(180deg)" }} />}
|
|
175
|
+
/>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 2. Where to use it
|
|
181
|
+
|
|
182
|
+
- **Historically:** the Catalogix dashboard shell. **Today: nowhere** — see the
|
|
183
|
+
status note above.
|
|
184
|
+
- It composes `StreamoidSidebar`, `ScSidebarMenu`, `ScSidebarSwitchMenu`,
|
|
185
|
+
`ScHDivider`, `ScSideBarLogoUnit` (with the built-in `Catalogix` product mark) and
|
|
186
|
+
`CreditWarningBanner`.
|
|
187
|
+
- It is **presentational**: it renders chrome and fires callbacks. It fetches
|
|
188
|
+
nothing, holds no auth/workspace/theme state, and renders no popups — profile
|
|
189
|
+
menus, workspace modals and routing stay in the host.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 3. When to use it
|
|
194
|
+
|
|
195
|
+
### Use it when
|
|
196
|
+
|
|
197
|
+
- You are maintaining an existing call site (there are none in the four host repos).
|
|
198
|
+
- You want a compact reference for how to preset `StreamoidSidebar` for one product.
|
|
199
|
+
|
|
200
|
+
### Don't use it — reach for this instead
|
|
201
|
+
|
|
202
|
+
| Situation | Use instead |
|
|
203
|
+
|---|---|
|
|
204
|
+
| Any new Catalogix sidebar work | `StreamoidSidebar` (what Catalogix actually ships) |
|
|
205
|
+
| You need the "Ask CXO" gradient CTA | `StreamoidSidebar` + `assistantCta` (or `ScAskAgentSlot`) |
|
|
206
|
+
| You want the shared cross-product switcher rows | `ScAppSwitchPanel` inside `StreamoidSidebar`'s `switchPanel` |
|
|
207
|
+
| You want the collapsed switch **flyout** + backdrop | `StreamoidSidebar` (pass `switchPanel` in both rails) |
|
|
208
|
+
| Section labels, top items, bottom items, a version footer | `StreamoidSidebar` |
|
|
209
|
+
| Artifax's shell / collapsible sections | `ScArtifaxSidebar` |
|
|
210
|
+
| One nav row / one switch row | `ScSidebarMenu` / `ScSidebarSwitchMenu` |
|
|
211
|
+
|
|
212
|
+
### Don't confuse with
|
|
213
|
+
|
|
214
|
+
| You may actually want | Not this |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `StreamoidSidebar` — the component this wraps, and the one Catalogix ships | This wrapper hides two thirds of its props |
|
|
217
|
+
| `ScArtifaxSidebar` — a **standalone** sibling shell, not a wrapper | Different architecture, different prop names |
|
|
218
|
+
| `ScCatalogixInvite` — the Catalogix invite/onboarding card | Not navigation |
|
|
219
|
+
| `ScCatalogixStoreHeader` / `ScCatalogixStoreTableList` — the stores table | Not navigation |
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 4. Why to use it
|
|
224
|
+
|
|
225
|
+
The honest answer: **for the defaults, and nothing else.** What it genuinely gives you:
|
|
226
|
+
|
|
227
|
+
- **The Catalogix brand marks without importing them** — `product="Catalogix"` resolves
|
|
228
|
+
both the expanded wordmark and (unusually) a real collapsed square mark.
|
|
229
|
+
- **A correct collapse/expand glyph pair** — `SiconCollapse` when expanded,
|
|
230
|
+
`SiconExpand` when collapsed, rather than one rotated icon.
|
|
231
|
+
- **A worked example of the `StreamoidSidebar` slot contract** — `showBody` +
|
|
232
|
+
`bodyContent`, `switchPanel` + `switchPanelOpen` + `onSwitchPanelClose`,
|
|
233
|
+
`preFooterContent`, `toggleInProfile`, `versionText=""`. Copy the pattern, not
|
|
234
|
+
the component.
|
|
235
|
+
|
|
236
|
+
Everything else you get from `StreamoidSidebar` itself, with more control.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Gotchas
|
|
241
|
+
|
|
242
|
+
**1. No `assistantCta`.** The component catalog describes this wrapper as having an
|
|
243
|
+
"Ask CXO"-style CTA. It does not: `assistantCta` is never forwarded to
|
|
244
|
+
`StreamoidSidebar`, and there is no prop for it. This alone is why Catalogix stopped
|
|
245
|
+
using the wrapper.
|
|
246
|
+
|
|
247
|
+
**2. Overriding `expandedLogo` / `collapsedLogo` disables the app switcher.** The
|
|
248
|
+
default nodes are the only place `handleSwitch` (which flips the internal
|
|
249
|
+
`appListOpen`) is wired.
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
// WRONG — switchApps become unreachable
|
|
253
|
+
<ScCatalogixSidebar expandedLogo={<MyLogo />} switchApps={apps} … />
|
|
254
|
+
|
|
255
|
+
// RIGHT — keep the default logo; use onLogoClick for side effects
|
|
256
|
+
<ScCatalogixSidebar switchApps={apps} onLogoClick={loadCatalog} … />
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**3. Collapsed switching behaves differently from every other app.**
|
|
260
|
+
`switchPanelContent` is `undefined` unless `expanded`, so `StreamoidSidebar`'s
|
|
261
|
+
`hasSwitchCard` is false in the collapsed rail: no card, no 240px flyout, no
|
|
262
|
+
backdrop, no `onSwitchPanelClose`. You get an inline column of
|
|
263
|
+
`ScSidebarSwitchMenu variant="collapsed"` icons in the body instead.
|
|
264
|
+
|
|
265
|
+
**4. `profile` is effectively required.** The wrapper always passes
|
|
266
|
+
`toggleInProfile`, and `StreamoidSidebar` renders that footer branch only inside
|
|
267
|
+
`profile ? … : null`. **Omit `profile` and there is no collapse toggle at all.**
|
|
268
|
+
|
|
269
|
+
**5. Replacing `items` without `iconMap` yields icon-less rows.** Both props have
|
|
270
|
+
defaults, and they default *independently*; the default `iconMap` only knows
|
|
271
|
+
`stores` / `aiTraining` / `insights`. A missing key resolves to `null`, silently.
|
|
272
|
+
|
|
273
|
+
**6. Switch rows are hardcoded to `state="default-highlight"`** in the expanded list
|
|
274
|
+
and `state="default"` when collapsed — you cannot mark the current product, and the
|
|
275
|
+
`description` you pass only renders in the expanded rail.
|
|
276
|
+
|
|
277
|
+
**7. `onLogoClick` does not intercept the toggle.** It fires *in addition to*
|
|
278
|
+
flipping the internal list state, on every click, in both directions — so it's a
|
|
279
|
+
lazy-load hook, not an override.
|
|
280
|
+
|
|
281
|
+
**8. It inherits every `StreamoidSidebar` gotcha.** Notably: layout depends on
|
|
282
|
+
Tailwind utility classes that `dist/index.css` does **not** ship; the profile row and
|
|
283
|
+
toggle are `div`s with `onClick` (no keyboard access); widths are hardcoded 256/56px;
|
|
284
|
+
the body scrolls, so popovers must be portalled to `document.body`.
|
|
285
|
+
|
|
286
|
+
**9. It inherits `CreditWarningBanner`'s self-dismissal.** The ✕ sets internal state
|
|
287
|
+
and the banner returns `null` forever, with no callback — remount with a new `key` to
|
|
288
|
+
bring it back. `remainingPct` is printed raw, so round it yourself.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## In the wild
|
|
293
|
+
|
|
294
|
+
_No host render site found — Catalogix's shell composes `StreamoidSidebar` directly._
|
|
295
|
+
|
|
296
|
+
The nearest thing to a call site is the code that **replaced** it:
|
|
297
|
+
|
|
298
|
+
```jsx
|
|
299
|
+
// catalogix/dashboard app/containers/LeftMenu/index.jsx:991
|
|
300
|
+
<StreamoidSidebar
|
|
301
|
+
expanded={!collapsed}
|
|
302
|
+
onToggle={handleToggleCollapse}
|
|
303
|
+
config={navConfig}
|
|
304
|
+
iconMap={iconMap}
|
|
305
|
+
activeItemId={currentSection}
|
|
306
|
+
onItemSelect={handleItemSelect}
|
|
307
|
+
showBody={!insideStore}
|
|
308
|
+
bodyContent={workspaceServiceBody}
|
|
309
|
+
switchPanel={appSwitchItems.length ? <ScAppSwitchPanel apps={appSwitchItems} /> : undefined}
|
|
310
|
+
assistantCta={{ label: "Ask CXO", icon: <SiconBolt size={20} color="currentColor" />, active: askCxoOpen, onClick: toggleAskCxo }}
|
|
311
|
+
switchPanelOpen={appListOpen}
|
|
312
|
+
onSwitchPanelClose={() => setAppListOpen(false)}
|
|
313
|
+
expandedLogo={
|
|
314
|
+
<ScSideBarLogoUnit
|
|
315
|
+
state="expanded"
|
|
316
|
+
wordmark={<ProductWordmark product="Catalogix" />}
|
|
317
|
+
onClick={() => setAppListOpen((v) => !v)}
|
|
318
|
+
switchAriaLabel="Switch app"
|
|
319
|
+
/>
|
|
320
|
+
}
|
|
321
|
+
/* … profile, toggleInProfile, versionText="" … */
|
|
322
|
+
/>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
If this wrapper is kept, it belongs behind the same wiring: add an `assistantCta`
|
|
326
|
+
pass-through and pass `switchPanel` in both rails.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Related
|
|
331
|
+
|
|
332
|
+
- `StreamoidSidebar` — the component this presets, and the replacement to use.
|
|
333
|
+
- `ScSideBarLogoUnit` + `ProductWordmark` / `ProductCollapsedMark` — the Catalogix marks it renders by default.
|
|
334
|
+
- `ScAppSwitchPanel` — the shared switcher rows Catalogix now uses instead of `ScSidebarSwitchMenu`.
|
|
335
|
+
- `ScSidebarSwitchMenu` — the row type this wrapper builds its switch list from.
|
|
336
|
+
- `CreditWarningBanner` — what `creditWarning` renders.
|
|
337
|
+
- `ScArtifaxSidebar` — the other app-branded shell (standalone, not a wrapper).
|