@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,232 @@
1
+ ---
2
+ component: ScLogoUnit
3
+ package: "@streamoid/ui"
4
+ category: sidebar
5
+ status: legacy
6
+ renders: div
7
+ tags: [sidebar, logo, wordmark, header, brand, streamoid, legacy, logo-unit]
8
+ related: [ScSideBarLogoUnit, ScStrLogo, ScStreamoidWordmark, ScStreamoidMascot, StreamoidSidebar]
9
+ do_not_confuse_with: [ScSideBarLogoUnit, ScStrLogo, ScStreamoidWordmark, ScStreamoidMascot, ScCxoCopilotLogo, ScAppcardLogos]
10
+ ---
11
+
12
+ # ScLogoUnit
13
+
14
+ **Legacy. Superseded by `ScSideBarLogoUnit`.** A fixed-width 240 px padded box holding
15
+ the full Streamoid wordmark (`ScStrLogo`). No product branding, no click target, no
16
+ app-switcher chevron — and its "collapsed" state squeezes the *whole wordmark* into a
17
+ 32 × 12 px sliver instead of showing a product mark.
18
+
19
+ ## TL;DR for agents
20
+
21
+ - **Reach for it when:** never. It cannot be clicked and cannot show a product.
22
+ - **Reach for this instead:** `ScSideBarLogoUnit` (product wordmark + switcher chevron
23
+ + `onClick` + `hover`/`disabled` + a11y label), which is what every current sidebar
24
+ passes into `StreamoidSidebar`'s `expandedLogo` / `collapsedLogo` slots.
25
+ - **Three things that will bite you:**
26
+ 1. ⚠️ **`...props` is destructured and never spread.** No `onClick`, no `style`, no
27
+ `data-*`. The interface doesn't extend `HTMLAttributes` either.
28
+ 2. Hardcoded `width: 15rem` (240 px) when expanded. It does not adapt to its rail.
29
+ 3. `state="collapsed"` still renders the **full "Streamoid" wordmark**, scaled to
30
+ 32 × 12 px. It is not a logo mark — it is an unreadable smear.
31
+
32
+ ---
33
+
34
+ ## 1. How to use it
35
+
36
+ ### Import
37
+
38
+ ```tsx
39
+ import { ScLogoUnit } from "@streamoid/ui";
40
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
41
+ ```
42
+
43
+ ### Minimal usage
44
+
45
+ ```tsx
46
+ // This is the whole API.
47
+ <ScLogoUnit state="expanded" />
48
+ ```
49
+
50
+ ### Props
51
+
52
+ | Prop | Type | Default | Notes |
53
+ |---|---|---|---|
54
+ | `state` | `"expanded"` \| `"collapsed"` | `"expanded"` | `expanded` = 240 px wide, 16 px padding, wordmark at 167 × 16. `collapsed` = 48 × 48 box, 8 px padding, wordmark at 32 × 12. |
55
+ | `className` | `string` | – | Concatenated onto the root. ⚠️ Unguarded — omitting it puts a literal `undefined` in the class list. |
56
+ | `...props` | – | – | ⚠️ **Destructured and discarded.** `IScLogoUnitProps` does **not** extend `React.HTMLAttributes`, so there is no supported way to attach `onClick`, `style` or `aria-*`. |
57
+
58
+ The child is a hardcoded `<ScStrLogo type="default" />` — the Streamoid wordmark SVG.
59
+ There is no `product`, `wordmark` or `children` prop.
60
+
61
+ ### What renders in each state
62
+
63
+ | | `expanded` | `collapsed` |
64
+ |---|---|---|
65
+ | Box | `width: 15rem` (240 px), 16 px padding | 48 × 48, 8 px padding, contents centred |
66
+ | Wordmark | `ScStrLogo` at 167 × 16 (`aspect-ratio: 167/16`) | the **same** wordmark at 32 × 12 (`aspect-ratio: 32/12`) |
67
+ | Colour | the SVG paths are filled with `--alias-text-and-icons-primary`, so it flips with the theme | same |
68
+
69
+ ### Recipes
70
+
71
+ None. Here is the replacement:
72
+
73
+ ```tsx
74
+ // Expanded rail header: product wordmark + app-switcher chevron, one click target
75
+ <ScSideBarLogoUnit
76
+ product="CXO" // "CXO" | "Catalogix" | "Artifax" | "Photogenix" | "Tactix"
77
+ onClick={() => setAppListOpen((v) => !v)}
78
+ switchAriaLabel="Switch product"
79
+ />
80
+
81
+ // Collapsed rail header: the square product icon
82
+ <ScSideBarLogoUnit
83
+ state="collapsed"
84
+ product="CXO"
85
+ onClick={() => setAppListOpen((v) => !v)}
86
+ />
87
+
88
+ // Wired into the current shell
89
+ <StreamoidSidebar
90
+ expanded={expanded}
91
+ onToggle={() => setExpanded((v) => !v)}
92
+ config={config}
93
+ iconMap={iconMap}
94
+ expandedLogo={<ScSideBarLogoUnit product="CXO" onClick={openSwitcher} />}
95
+ collapsedLogo={<ScSideBarLogoUnit state="collapsed" product="CXO" onClick={openSwitcher} />}
96
+ switchPanel={<ScAppSwitchPanel apps={apps} />}
97
+ switchPanelOpen={appListOpen}
98
+ onSwitchPanelClose={() => setAppListOpen(false)}
99
+ />
100
+
101
+ // If you only want the Streamoid mark itself, skip the wrapper entirely
102
+ <ScStreamoidWordmark width={110} height={16} />
103
+ <ScStreamoidMascot size={24} />
104
+ ```
105
+
106
+ ---
107
+
108
+ ## 2. Where to use it
109
+
110
+ Nowhere. Its only render site is the legacy `ScSidebar`
111
+ (`src/SC-Sidebar/ScSidebar.tsx:37` collapsed, `:154` expanded), which is itself unused.
112
+
113
+ The current rail header is `ScSideBarLogoUnit`, passed into `StreamoidSidebar`'s
114
+ `expandedLogo` / `collapsedLogo`. CXO, Photogenix, Catalogix and Artifax all do this.
115
+
116
+ ---
117
+
118
+ ## 3. When to use it
119
+
120
+ ### Use it when
121
+
122
+ - Never.
123
+
124
+ ### Don't use it — reach for this instead
125
+
126
+ | Situation | Use instead |
127
+ |---|---|
128
+ | The sidebar's logo + product-switch header row | `ScSideBarLogoUnit` |
129
+ | The whole rail, with the logo slotted in | `StreamoidSidebar` (`expandedLogo` / `collapsedLogo`) |
130
+ | Just the Streamoid wordmark, sized by you | `ScStreamoidWordmark` (`width`, `height`, `color`) |
131
+ | Just the Streamoid mascot/monogram | `ScStreamoidMascot` (`size`) |
132
+ | The raw legacy wordmark SVG | `ScStrLogo` (`type: "default" \| "logo-only"`) |
133
+ | A product wordmark in a page header | `ProductWordmark` / `ProductCollapsedMark` |
134
+ | A product logo inside an app card | `ScAppcardLogos` |
135
+ | The CXO Copilot lockup | `ScCxoCopilotLogo` |
136
+
137
+ ### Don't confuse with
138
+
139
+ | You may actually want | Not this |
140
+ |---|---|
141
+ | `ScSideBarLogoUnit` — the current header row: `product`/`wordmark`, `onClick`, `onSwitchClick`, `switchAriaLabel`, `hideSwitch`, `hover`, `disabled` | `ScLogoUnit` has `state` and `className`, full stop |
142
+ | `ScStreamoidWordmark` — the current brand wordmark component (110 × 16 header size) | `ScLogoUnit` embeds the older `ScStrLogo` SVG |
143
+ | `ScStreamoidMascot` — the square monogram, which is what a *collapsed* rail actually wants | `ScLogoUnit state="collapsed"` shows a 32 px-wide full wordmark |
144
+ | `ScStrLogo` — the bare SVG with no padding box | `ScLogoUnit` is `ScStrLogo` + a 240 px box |
145
+
146
+ The names are one word apart: **`ScLogoUnit`** (legacy, Streamoid-only, inert) vs
147
+ **`ScSideBarLogoUnit`** (current, per-product, clickable). Autocomplete will offer both.
148
+
149
+ ---
150
+
151
+ ## 4. Why to use it
152
+
153
+ You wouldn't. What it still gets right:
154
+
155
+ - The wordmark SVG's paths are filled with `var(--alias-text-and-icons-primary)`, so
156
+ the logo inverts correctly between dark and light mode with no conditional.
157
+ - `aspect-ratio` is pinned in both states, so the mark never distorts when the box
158
+ is squeezed.
159
+
160
+ What you lose versus `ScSideBarLogoUnit`: the product wordmark, the switcher chevron,
161
+ the single unified click target, hover/disabled states, and the `switchAriaLabel`
162
+ accessible name.
163
+
164
+ ---
165
+
166
+ ## Gotchas
167
+
168
+ **1. It is completely inert.** `...props` is destructured out and never spread onto the
169
+ root `<div>`, and the props interface doesn't extend `HTMLAttributes`. You cannot make
170
+ it clickable, cannot pass `style`, cannot pass `aria-*`.
171
+
172
+ ```tsx
173
+ // WRONG — does not compile, and would be dropped anyway
174
+ <ScLogoUnit onClick={openAppSwitcher} />
175
+
176
+ // RIGHT
177
+ <ScSideBarLogoUnit product="CXO" onClick={openAppSwitcher} />
178
+ ```
179
+
180
+ **2. Hardcoded 240 px width.** `.scLogoUnit { width: 15rem }` in the expanded state.
181
+ `StreamoidSidebar`'s expanded rail is 16 rem wide with 8 px padding, so this box
182
+ overflows it. And since `style` is dropped (Gotcha 1) you can only fix it with a
183
+ `className` override.
184
+
185
+ **3. "Collapsed" is not a logo mark.** It renders the same full wordmark at
186
+ `width: 2rem; height: 0.75rem`. Every current rail shows a square product icon there
187
+ instead — `ScSideBarLogoUnit state="collapsed"`, or `ScStreamoidMascot`.
188
+
189
+ **4. Streamoid-only.** `ScStrLogo type="default"` is hardcoded. There is no way to show
190
+ CXO, Catalogix, Artifax, Photogenix or Tactix branding.
191
+
192
+ **5. `className` produces a literal `undefined` class when omitted.**
193
+ `styles.scLogoUnit + " " + className + " " + variantsClassName`.
194
+
195
+ **6. Padding, not gap, does the spacing.** Expanded uses 16 px padding on all four
196
+ sides; collapsed drops to 8 px and centres. If you nest it in a rail that also pads,
197
+ the logo drifts out of alignment with the nav rows below it.
198
+
199
+ **7. Don't pass the app switcher next to it.** The whole reason
200
+ `StreamoidSidebar` grew `switchPanel` / `switchPanelOpen` is that rendering an app list
201
+ inline beside the logo pushes the nav down. Use the overlay slot.
202
+
203
+ ---
204
+
205
+ ## In the wild
206
+
207
+ _No host render site found — used by the agent runtime / composed internally._
208
+
209
+ Composed only inside the legacy sidebar:
210
+
211
+ ```tsx
212
+ // npm-components packages/ui/src/SC-Sidebar/ScSidebar.tsx:154
213
+ <ScLogoUnit className={styles.scLogoUnitInstance}></ScLogoUnit>
214
+ ```
215
+
216
+ Where it *would* belong — the rail header — is now `ScSideBarLogoUnit`, passed into
217
+ `StreamoidSidebar`'s `expandedLogo` / `collapsedLogo` (see
218
+ `cxo-dashboard src/app/components/app-sidebar.tsx`).
219
+
220
+ ---
221
+
222
+ ## Related
223
+
224
+ - `ScSideBarLogoUnit` — **the replacement.** Product wordmark + switcher, clickable.
225
+ - `StreamoidSidebar` — the shell with `expandedLogo` / `collapsedLogo` slots.
226
+ - `ScStreamoidWordmark` / `ScStreamoidMascot` (`SC-Brand`) — the current brand marks.
227
+ The plain header wordmark (110 × 16) and the app-switcher lockup are different
228
+ things; don't conflate them.
229
+ - `ScStrLogo` — the raw legacy wordmark SVG this component wraps.
230
+ - `ScAppcardLogos` / `ProductWordmark` / `ScCxoCopilotLogo` — other branded marks.
231
+ - `ScSidebar` / `ScSidebarProfile` / `ScSidebarIcons` / `ScVersion` — the rest of this
232
+ legacy sidebar family.
@@ -0,0 +1,241 @@
1
+ ---
2
+ component: ScMappingCard
3
+ package: "@streamoid/ui"
4
+ category: feed-taxonomy
5
+ status: stable
6
+ renders: div
7
+ tags: [feed, mapping, map-attributes, column, source-target, catalogix, slot]
8
+ related: [ScValueMappingL1, ScDefaultCard, ScSelect, ScTaxonomyPill]
9
+ do_not_confuse_with: [ScValueMappingL1, ScDefaultCard, ScTableList]
10
+ used_by: [catalogix]
11
+ required_props: [columnName]
12
+ ---
13
+
14
+ # ScMappingCard
15
+
16
+ **One row of the Catalogix feed Map-Attributes screen.** A source feed column on the
17
+ left, the target attribute(s) it maps to on the right, and the confirm/ignore
18
+ actions for that pairing — as a single card with three mutually exclusive states.
19
+
20
+ ## TL;DR for agents
21
+
22
+ - **Reach for it when:** you are building a source→target mapping review list where
23
+ each row can be confirmed, ignored, or is still pending.
24
+ - **Don't reach for it when:** you are mapping *values* rather than *columns*
25
+ (→ `ScValueMappingL1`), or you just need a generic titled option card
26
+ (→ `ScDefaultCard`).
27
+ - **Three things that will bite you:**
28
+ 1. `status` gates almost every other prop. In `confirmed`/`ignored`, the `targets`
29
+ slot, `sampleRows`, `warning` and `validityText` are **not rendered at all**.
30
+ 2. `targets` is a **slot** — you render your own dropdowns into it. The card
31
+ supplies no select control.
32
+ 3. The card sets `overflow: hidden`. Dropdowns opened inside the slot **must be
33
+ portalled to `<body>`** or they get clipped.
34
+
35
+ ---
36
+
37
+ ## 1. How to use it
38
+
39
+ ### Import
40
+
41
+ ```tsx
42
+ import { ScMappingCard } from "@streamoid/ui";
43
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
44
+ ```
45
+
46
+ ### Minimal usage
47
+
48
+ ```tsx
49
+ <ScMappingCard
50
+ columnName="STYLE ID"
51
+ status="default"
52
+ targets={<MyTargetSelect value={target} onChange={setTarget} />}
53
+ onIgnore={() => ignore(col)}
54
+ onConfirm={() => confirm(col)}
55
+ />
56
+ ```
57
+
58
+ ### Props
59
+
60
+ | Prop | Type | Default | Notes |
61
+ |---|---|---|---|
62
+ | `columnName` | `string` | — | **Required.** Source feed-column name, e.g. `"STYLE ID"`. Truncates with a `title` tooltip. |
63
+ | `status` | `"default"` \| `"confirmed"` \| `"ignored"` | `"default"` | The state machine. Gates every region below. |
64
+ | `badge` | `string` | – | Single letter for the narrow left gutter, e.g. `"A"`. Gutter is omitted entirely when unset. `aria-hidden`. |
65
+ | `sampleRows` | `string[]` | `[]` | Sample-value preview lines under the column name. **`default` status only.** |
66
+ | `targets` | `ReactNode` | – | **SLOT** for your target dropdown rows. **`default` status only.** |
67
+ | `confirmedTargets` | `string[]` | `[]` | Mapped target names as read-only boxes with connector arrows. **`confirmed` status only.** |
68
+ | `validityText` | `string` | – | Data-quality line, e.g. `"50% of rows … (200 out of 400)"`. **`default` status only.** |
69
+ | `warning` | `ReactNode` | – | Link-warning message with an error icon. **`default` status only.** |
70
+ | `canConfirm` | `boolean` | `false` | Shows "Confirm Mapping". Gate on "at least one target chosen". **`default` status only.** |
71
+ | `onAddColumn` | `() => void` | – | The `+` in the source card header ("map this column to another target too"). **`default` status only.** |
72
+ | `onIgnore` | `() => void` | – | "Ignore Column". **`default` status only.** |
73
+ | `onConfirm` | `() => void` | – | "Confirm Mapping". Only reachable when `canConfirm`. |
74
+ | `onEdit` | `() => void` | – | "Edit". **`confirmed` and `ignored` status only** — reopens the pairing. |
75
+ | `className` | `string` | – | Appended after internal classes. |
76
+ | `...props` | `HTMLAttributes<HTMLDivElement>` | – | Spread onto the card root. |
77
+
78
+ ### What renders in each status
79
+
80
+ | Region | `default` | `confirmed` | `ignored` |
81
+ |---|---|---|---|
82
+ | Source | expanded card: name + `+` button + `sampleRows` | collapsed: name only | collapsed: name only |
83
+ | Target | your `targets` slot | `confirmedTargets` as read-only boxes | a single `-` box |
84
+ | Warning | `warning` if set | — | — |
85
+ | Actions | "Ignore Column" + "Confirm Mapping" (if `canConfirm`) + `validityText` | ✓ "Column Confirmed" + "Edit" | ✕ "Column Ignored" + "Edit" |
86
+
87
+ ### Recipes
88
+
89
+ ```tsx
90
+ // Driving the full list from mapping state
91
+ {mappings.map((m, i) => (
92
+ <ScMappingCard
93
+ key={m.feedCol}
94
+ badge={m.headerLetter}
95
+ columnName={m.feedCol}
96
+ sampleRows={m.rows?.slice(0, 2).map((r) => r || "-")}
97
+ status={m.status} // "default" | "confirmed" | "ignored"
98
+ targets={<TargetRows mapping={m} />} // your selects go here
99
+ confirmedTargets={[...m.mappedCols, ...m.customCols]}
100
+ validityText={m.validityText}
101
+ warning={m.warning?.msg}
102
+ canConfirm={[...m.mappedCols, ...m.customCols].length > 0}
103
+ onAddColumn={() => showExtraTarget(i)}
104
+ onIgnore={() => act(i, "ignore")}
105
+ onConfirm={() => act(i, "confirm")}
106
+ onEdit={() => act(i, "edit")}
107
+ />
108
+ ))}
109
+
110
+ // The dropdown inside `targets` MUST portal out of the card
111
+ <Select
112
+ menuPortalTarget={document.body}
113
+ styles={{ menuPortal: (b) => ({ ...b, zIndex: 9999 }) }}
114
+ />
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 2. Where to use it
120
+
121
+ - **The Catalogix feed Map-Attributes screen** — one card per source column, stacked
122
+ in a scrolling list. This is its reason for existing.
123
+ - Any future **schema/import mapping review** flow with the same
124
+ source→target→confirm shape.
125
+
126
+ Currently rendered from `catalogix/dashboard app/components/FeedMapping/MapSingleAttribute`.
127
+
128
+ ---
129
+
130
+ ## 3. When to use it
131
+
132
+ ### Use it when
133
+
134
+ - You are reviewing a **column-to-attribute** pairing, one card per source column.
135
+ - Each row needs a **three-way lifecycle** (pending → confirmed | ignored) that the
136
+ user can reopen.
137
+ - The target control is **product-specific** and you want to supply it yourself
138
+ while inheriting the card's layout, states and actions.
139
+
140
+ ### Don't use it — reach for this instead
141
+
142
+ | Situation | Use instead |
143
+ |---|---|
144
+ | Mapping individual **values** within an attribute (Map-Values / curation) | `ScValueMappingL1` |
145
+ | A generic pick-one-option card (title + description) | `ScDefaultCard` |
146
+ | A flat data row in a table | `ScTableList` / `ScCatalogixStoreTableList` |
147
+ | The target dropdown itself | `ScSelect`, or your app's select — this card only provides the slot |
148
+ | A taxonomy tree node | `ScTaxonomyPill` |
149
+
150
+ ### Don't confuse with
151
+
152
+ | You may actually want | Not this |
153
+ |---|---|
154
+ | `ScValueMappingL1` — a single value-mapping row with `default`/`hover`/`active` + an "updated" dot | `ScMappingCard` is the column-level card with its own action footer |
155
+ | `ScDefaultCard` — generic option card, no states, no actions | This card carries a mapping lifecycle |
156
+
157
+ ---
158
+
159
+ ## 4. Why to use it
160
+
161
+ - **The state machine is already correct.** Three statuses × four regions is a lot
162
+ of conditional rendering to get wrong; the card collapses the source, swaps the
163
+ target region, and switches the footer to a status label in one prop.
164
+ - **Slot design keeps product logic out of the DS.** Feed target dropdowns need
165
+ app-specific data, search and portalling, so `targets` stays a slot — you get the
166
+ chrome without the DS needing to know about your data layer.
167
+ - **Two-tone surfaces that survive light mode.** The source card and card body use
168
+ two distinct tokens (`fill-neutral-*` body / raised source) that stay visually
169
+ separate in both themes, instead of relying on a grey that collapses to white.
170
+ - **Status semantics are tokenised** — the ✓/✕ and their colours come from
171
+ `--alias-text-and-icons-success` / `-error`, so they match every other status in
172
+ the product.
173
+
174
+ ---
175
+
176
+ ## Gotchas
177
+
178
+ **1. `status` silently drops props.** Passing `targets` while `status="confirmed"`
179
+ renders nothing — a very common "my dropdowns disappeared" bug.
180
+
181
+ ```tsx
182
+ // WRONG — targets ignored; confirmed status renders confirmedTargets instead
183
+ <ScMappingCard columnName="COLOR" status="confirmed" targets={<MySelect />} />
184
+
185
+ // RIGHT
186
+ <ScMappingCard columnName="COLOR" status="confirmed" confirmedTargets={["color"]} onEdit={reopen} />
187
+ ```
188
+
189
+ **2. Dropdowns get clipped.** The card root is `overflow: hidden`. Any menu opened
190
+ from inside `targets` must be portalled to `document.body` with an explicit z-index.
191
+
192
+ **3. `canConfirm` defaults to `false`.** Forget it and "Confirm Mapping" never
193
+ appears, no matter how many targets are selected.
194
+
195
+ **4. Button labels are hardcoded English.** "Ignore Column", "Confirm Mapping",
196
+ "Edit", "Column Confirmed", "Column Ignored" and the `"Add column"` aria-label are
197
+ baked into the component. There is no label prop — do not use this card in a
198
+ localised surface without changing the DS first.
199
+
200
+ **5. `columnName` is the only required prop.** Everything else is optional, so a
201
+ typo'd prop name fails silently rather than erroring. Check spelling against the
202
+ table above.
203
+
204
+ **6. `onEdit` is unreachable in `default` status,** and `onIgnore`/`onConfirm`/
205
+ `onAddColumn` are unreachable in the other two. Wire all of them; the card decides
206
+ which are live.
207
+
208
+ **7. `badge` is `aria-hidden`.** It is decoration, not information — don't put
209
+ anything meaning-bearing there.
210
+
211
+ ---
212
+
213
+ ## In the wild
214
+
215
+ ```tsx
216
+ // catalogix/dashboard app/components/FeedMapping/MapSingleAttribute/index.jsx:302
217
+ <ScMappingCard
218
+ badge={headerColumnName}
219
+ columnName={feedCol}
220
+ sampleRows={rows?.slice(0, 2).map((rowItem) => rowItem || "-")}
221
+ status={status}
222
+ targets={targets}
223
+ confirmedTargets={[...mappedCols, ...customCols]}
224
+ validityText={validityText}
225
+ warning={warningInfo ? warningInfo.msg : undefined}
226
+ canConfirm={[...mappedCols, ...customCols].length > 0}
227
+ onAddColumn={() => setShowAdditionalMappingOption(true)}
228
+ onIgnore={() => handleActionForMapAttribute(mappingItemIdx, "ignore")}
229
+ onConfirm={() => handleActionForMapAttribute(mappingItemIdx, "confirm")}
230
+ onEdit={() => handleActionForMapAttribute(mappingItemIdx, "edit")}
231
+ />
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Related
237
+
238
+ - `ScValueMappingL1` — the value-level sibling (Map-Values / curation rows).
239
+ - `ScDefaultCard` — generic option card when you don't need the lifecycle.
240
+ - `ScSelect` — a DS select you can render into the `targets` slot.
241
+ - `ScTaxonomyPill` — taxonomy nodes on adjacent Catalogix screens.