@streamoid/ui 0.6.17 → 0.6.19
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 +325 -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 +210 -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/ScWorkspaceAccountMenu.md +115 -0
- package/dist/docs/ScWorkspaceCard.md +234 -0
- package/dist/docs/ScWorkspaceSettingsMobile.md +265 -0
- package/dist/docs/ScWorkspaceSwitchCard.md +312 -0
- package/dist/docs/ScWorkspaceSwitchMobile.md +241 -0
- package/dist/docs/ScWorkspaceSwitchMobileV2.md +278 -0
- package/dist/docs/StreamoidSidebar.md +413 -0
- package/dist/docs/StreamoidWorkspaceSwitcher.md +307 -0
- package/dist/docs/UsageHistoryMobile.md +235 -0
- package/dist/docs/components.json +4931 -0
- package/dist/index.css +361 -36
- package/dist/index.d.mts +213 -88
- package/dist/index.d.ts +213 -88
- package/dist/index.js +2486 -1629
- package/dist/index.mjs +2487 -1620
- package/package.json +5 -3
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScPendingAction
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: actions
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [pending, invite, cancel, resend, teams, members, action-pair, divider]
|
|
8
|
+
related: [ScButton, ScVDivider, ScTableList, ScRole, ScArtifaxInvite]
|
|
9
|
+
do_not_confuse_with: [ScButton, ScMobileBottomAction, ScSelectionList, ScMenuOptions]
|
|
10
|
+
used_by: [cxo]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# ScPendingAction
|
|
14
|
+
|
|
15
|
+
**A fixed 160px "Cancel | Resend" button pair.** Two hardcoded `ScButton`s — `Cancel`
|
|
16
|
+
in `variant="error" type="tertiary"` and `Resend` in `variant="tertiary"`, both
|
|
17
|
+
`size="sm"` — separated by a `ScVDivider`. It is the trailing cell of a pending-invite
|
|
18
|
+
row in the CXO Teams table.
|
|
19
|
+
|
|
20
|
+
## TL;DR for agents
|
|
21
|
+
|
|
22
|
+
- **Reach for it when:** you are rendering a **pending invite** row and want the exact
|
|
23
|
+
Cancel/Resend pair used in CXO Teams.
|
|
24
|
+
- **Don't reach for it when:** you need *any* other labels, *any* callbacks per button,
|
|
25
|
+
or a general action pair — compose two `ScButton`s with a `ScVDivider` yourself.
|
|
26
|
+
- **Three things that will bite you:**
|
|
27
|
+
1. It takes **no callbacks and no labels**. `className` plus `HTMLAttributes` is the
|
|
28
|
+
entire API. The only way to know which button was clicked is to inspect
|
|
29
|
+
`event.target` on a root-level `onClick`.
|
|
30
|
+
2. Because of (1), it is **keyboard-inaccessible**: the inner `ScButton`s call their
|
|
31
|
+
own (undefined) `onClick` on Enter/Space, and no click event bubbles to your root
|
|
32
|
+
handler.
|
|
33
|
+
3. Fixed `width: 10rem` (160px). It will not adapt to its cell.
|
|
34
|
+
|
|
35
|
+
> **Category note:** `docs/COMPONENT-CATALOG.md` lists this under the Chat/InChat
|
|
36
|
+
> family. That is wrong — it has nothing to do with the agent runtime. Its one real
|
|
37
|
+
> call site is the CXO Teams pending-invite row, so it is documented here as an
|
|
38
|
+
> **actions** component.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 1. How to use it
|
|
43
|
+
|
|
44
|
+
### Import
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { ScPendingAction } from "@streamoid/ui";
|
|
48
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Minimal usage
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<ScPendingAction />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
That already renders "Cancel" and "Resend". Wiring them is the hard part — see the
|
|
58
|
+
recipe.
|
|
59
|
+
|
|
60
|
+
### Props
|
|
61
|
+
|
|
62
|
+
| Prop | Type | Default | Notes |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| `className` | `string` | – | **Always concatenated**, so omitting it puts a literal `undefined` class on the root. |
|
|
65
|
+
| `...props` | `HTMLAttributes<HTMLDivElement>` | – | `onClick`, `style`, `data-*`, `aria-*` on the root. **This is the only wiring point.** |
|
|
66
|
+
|
|
67
|
+
There is no `onCancel`, no `onResend`, no `cancelText`, no `resendText`, no `disabled`,
|
|
68
|
+
no `loading`. Everything below is baked into the render body:
|
|
69
|
+
|
|
70
|
+
| Rendered child | Fixed configuration |
|
|
71
|
+
|---|---|
|
|
72
|
+
| Button 1 | `text="Cancel"`, `variant="error"`, `type="tertiary"`, `size="sm"` |
|
|
73
|
+
| Divider | `ScVDivider` |
|
|
74
|
+
| Button 2 | `text="Resend"`, `variant="tertiary"`, `size="sm"` |
|
|
75
|
+
|
|
76
|
+
Both buttons are also passed `icon={<SiconHome />}` — but `styleVariant` is left at its
|
|
77
|
+
default `"default"`, and `ScButton` only renders `icon` for `icon-left`/`icon-right`/
|
|
78
|
+
`icon-only`. **The icons are dead code and never appear.**
|
|
79
|
+
|
|
80
|
+
### Recipes
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// The only way to route the two actions: one root onClick + child hit-testing.
|
|
84
|
+
// This is what CXO does. Child 0 is Cancel, the last child is Resend.
|
|
85
|
+
<ScPendingAction
|
|
86
|
+
className="shrink-0"
|
|
87
|
+
onClick={(event) => {
|
|
88
|
+
event.stopPropagation(); // the row itself is clickable
|
|
89
|
+
const target = event.target as HTMLElement | null;
|
|
90
|
+
if (!target) return;
|
|
91
|
+
const root = event.currentTarget as HTMLElement;
|
|
92
|
+
const cancelAction = root.children.item(0) as HTMLElement | null;
|
|
93
|
+
const resendAction = root.children.item(root.children.length - 1) as HTMLElement | null;
|
|
94
|
+
if (cancelAction?.contains(target)) return onCancelInvite?.();
|
|
95
|
+
if (resendAction?.contains(target)) return onResendInvite?.();
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
// PREFER THIS for anything that isn't literally the CXO Teams row:
|
|
100
|
+
// compose the pair yourself and get real callbacks, labels and keyboard support.
|
|
101
|
+
<div style={{ display: "flex", gap: 4, alignItems: "center" }}>
|
|
102
|
+
<ScButton text="Cancel" variant="error" type="tertiary" size="sm" onClick={onCancel} />
|
|
103
|
+
<ScVDivider />
|
|
104
|
+
<ScButton text="Resend" variant="tertiary" size="sm" onClick={onResend} />
|
|
105
|
+
</div>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 2. Where to use it
|
|
111
|
+
|
|
112
|
+
- **The CXO Teams / members table**, in the "signed on" column of a row whose invite is
|
|
113
|
+
still pending: the date is replaced by this pair. See
|
|
114
|
+
`cxo-dashboard src/app/components/teams-content.tsx`.
|
|
115
|
+
- Nowhere else currently. The three invite components (`ScArtifaxInvite`,
|
|
116
|
+
`ScCatalogixInvite`, `ScPhtogenixInvite`) are the surrounding invite vocabulary, and
|
|
117
|
+
`ScRole` / `ScTableList` are the row primitives it sits beside.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 3. When to use it
|
|
122
|
+
|
|
123
|
+
### Use it when
|
|
124
|
+
|
|
125
|
+
- You are rebuilding **the CXO pending-invite row** and want pixel parity with it,
|
|
126
|
+
including the 160px width that lines the column up with the date text it replaces.
|
|
127
|
+
|
|
128
|
+
### Don't use it — reach for this instead
|
|
129
|
+
|
|
130
|
+
| Situation | Use instead |
|
|
131
|
+
|---|---|
|
|
132
|
+
| Any other label pair ("Approve/Deny", "Retry/Dismiss") | two `ScButton`s + `ScVDivider` |
|
|
133
|
+
| You need per-button callbacks, disabled or loading states | two `ScButton`s — this component exposes none |
|
|
134
|
+
| A single action | `ScButton`, or `ScOnlyIcon` for a bare icon |
|
|
135
|
+
| A confirm/cancel pair in a modal or drawer footer | two `ScButton`s (`variant="mono"` / `variant="outline"`) |
|
|
136
|
+
| A mobile sticky footer with 1–2 actions | `ScMobileBottomAction` |
|
|
137
|
+
| A menu of row actions behind a `⋯` | `ScPopUpMenu` + `ScMenuOptions` |
|
|
138
|
+
| Accepting/declining an agent suggestion in chat | `ScSelectionList` |
|
|
139
|
+
|
|
140
|
+
### Don't confuse with
|
|
141
|
+
|
|
142
|
+
| You may actually want | Not this |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `ScButton` — the actual primitive, with `onClick`, labels and states | This is a frozen pair of two of them |
|
|
145
|
+
| `ScMobileBottomAction` — the mobile sticky action bar | Different surface, real props |
|
|
146
|
+
| `ScSelectionList` — approve/reject **toggles** in the chat transcript | Different family entirely; it *does* have callbacks |
|
|
147
|
+
| Something in the chat/agent family, from the name and the catalog listing | It's a Teams-table cell |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 4. Why to use it
|
|
152
|
+
|
|
153
|
+
- **Exactly one reason: parity with the CXO Teams row.** The 160px width, the 4px gap,
|
|
154
|
+
the `error/tertiary` + `tertiary` emphasis pairing and the divider between them are a
|
|
155
|
+
Figma spec, and this component is that spec frozen.
|
|
156
|
+
- Everything else you would want from it — labels, callbacks, disabled, keyboard — is
|
|
157
|
+
better served by composing `ScButton` + `ScVDivider` directly, which costs three lines
|
|
158
|
+
and gives you a correct component.
|
|
159
|
+
|
|
160
|
+
If you are choosing between this and hand-composing, **hand-compose** unless you are
|
|
161
|
+
editing the CXO Teams table.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Gotchas
|
|
166
|
+
|
|
167
|
+
**1. There are no callbacks.** Not "they're optional" — they don't exist. The sanctioned
|
|
168
|
+
workaround is a root `onClick` plus DOM hit-testing against `root.children` (see the
|
|
169
|
+
recipe). That couples your call site to the component's child order: if the DS ever adds
|
|
170
|
+
a wrapper or reorders the buttons, your handlers silently swap or stop firing.
|
|
171
|
+
|
|
172
|
+
**2. It is keyboard-inaccessible.** Each `ScButton` is a `div[role="button"]
|
|
173
|
+
tabIndex={0}` whose Enter/Space handler invokes **its own** `props.onClick` — which is
|
|
174
|
+
`undefined` here — and does not dispatch a DOM click. So focusing "Cancel" and pressing
|
|
175
|
+
Enter does nothing, and your root `onClick` never runs. Keyboard and screen-reader users
|
|
176
|
+
cannot cancel or resend an invite through this component. Treat that as a blocking bug
|
|
177
|
+
for any accessible surface.
|
|
178
|
+
|
|
179
|
+
**3. Fixed `width: 10rem`.** The root is 160px regardless of content or container. In a
|
|
180
|
+
narrower cell it overflows; in a wider one the two buttons stretch (each is
|
|
181
|
+
`flex: 1 !important`) rather than hugging their labels.
|
|
182
|
+
|
|
183
|
+
**4. The labels are hardcoded English.** "Cancel" and "Resend" cannot be changed. Not
|
|
184
|
+
localisable.
|
|
185
|
+
|
|
186
|
+
**5. The `SiconHome` icons never render.** Both buttons get `icon={<SiconHome/>}` but
|
|
187
|
+
`styleVariant` stays `"default"`, and `ScButton` only draws `icon` for the `icon-*`
|
|
188
|
+
variants. Harmless, but don't read the source and assume there are icons.
|
|
189
|
+
|
|
190
|
+
**6. No pending/disabled state.** While a resend request is in flight you cannot dim or
|
|
191
|
+
block the pair; the user can fire it repeatedly. Guard in your handler.
|
|
192
|
+
|
|
193
|
+
**7. Omitting `className` puts a literal `undefined` class on the root** — the class list
|
|
194
|
+
is plain string concatenation. Cosmetic, but visible in snapshot tests.
|
|
195
|
+
|
|
196
|
+
**8. `event.stopPropagation()` is usually required.** The Teams row itself is clickable,
|
|
197
|
+
so without it a Cancel click also opens the member drawer.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## In the wild
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
// cxo-dashboard src/app/components/teams-content.tsx:644
|
|
205
|
+
<ScPendingAction
|
|
206
|
+
className="shrink-0"
|
|
207
|
+
onClick={(event) => {
|
|
208
|
+
event.stopPropagation();
|
|
209
|
+
const target = event.target as HTMLElement | null;
|
|
210
|
+
if (!target) return;
|
|
211
|
+
const root = event.currentTarget as HTMLElement;
|
|
212
|
+
const cancelAction = root.children.item(0) as HTMLElement | null;
|
|
213
|
+
const resendAction = root.children.item(
|
|
214
|
+
root.children.length - 1,
|
|
215
|
+
) as HTMLElement | null;
|
|
216
|
+
if (cancelAction && cancelAction.contains(target)) {
|
|
217
|
+
onCancelInvite?.();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (resendAction && resendAction.contains(target)) {
|
|
221
|
+
onResendInvite?.();
|
|
222
|
+
}
|
|
223
|
+
}}
|
|
224
|
+
/>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
That handler is the tell: the DS gap (no `onCancel`/`onResend`) is being paid for at the
|
|
228
|
+
call site.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Related
|
|
233
|
+
|
|
234
|
+
- `ScButton` — the primitive this freezes two of; use it directly for any variation.
|
|
235
|
+
- `ScVDivider` — the separator between the pair.
|
|
236
|
+
- `ScTableList` / `ScRole` — the Teams row primitives it sits inside.
|
|
237
|
+
- `ScArtifaxInvite` / `ScCatalogixInvite` / `ScPhtogenixInvite` — the invite-flow cards.
|
|
238
|
+
- `ScMobileBottomAction` — the mobile action-pair equivalent, with real props.
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ScPhtogenixInvite
|
|
3
|
+
package: "@streamoid/ui"
|
|
4
|
+
category: cards
|
|
5
|
+
status: stable
|
|
6
|
+
renders: div
|
|
7
|
+
tags: [invite, app-access, photogenix, toggle, permissions, user-management, settings, onboarding, row]
|
|
8
|
+
related: [ScArtifaxInvite, ScCatalogixInvite, ScAppCard, ScToggleSwitch, ScAccess]
|
|
9
|
+
do_not_confuse_with: [ScArtifaxInvite, ScCatalogixInvite, ScAppCard, ScAppListingCard, ScAppCardV3, ScAppCardForCopilot, ScAccess]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ScPhtogenixInvite
|
|
13
|
+
|
|
14
|
+
**The Photogenix "does this user get the app?" row for the invite / edit-user
|
|
15
|
+
modal.** Markup-identical to `ScArtifaxInvite` — `ScAppCard` on the left,
|
|
16
|
+
`ScToggleSwitch` on the right, hairline divider underneath — but with a different
|
|
17
|
+
(worse) props API and no DOM prop forwarding.
|
|
18
|
+
|
|
19
|
+
> **Note the spelling.** The export and the folder are `ScPhtogenixInvite` /
|
|
20
|
+
> `SC-phtogenixInvite` — missing the **o** in "Photogenix". `ScPhotogenixInvite`
|
|
21
|
+
> does not exist; importing it fails.
|
|
22
|
+
|
|
23
|
+
## TL;DR for agents
|
|
24
|
+
|
|
25
|
+
- **Reach for it when:** you need the **Photogenix** row in a per-app access list
|
|
26
|
+
and want it to match the neighbouring rows exactly.
|
|
27
|
+
- **Don't reach for it when:** the app needs a nested resource picker
|
|
28
|
+
(→ `ScCatalogixInvite`), or you're writing a new row and can pick the cleaner
|
|
29
|
+
API (→ `ScArtifaxInvite`, which takes `appName`/`appDescription`/`appIcon` and
|
|
30
|
+
forwards DOM props).
|
|
31
|
+
- **Five things that will bite you:**
|
|
32
|
+
1. The content props are **prefixed**: `scAppCardappName`,
|
|
33
|
+
`scAppCardappDescription`, `scAppCardappIcon`. `appName` is not a prop here.
|
|
34
|
+
2. ⚠️ It defaults to **ON** (`active = "true"`). Pass `enabled` explicitly.
|
|
35
|
+
3. ⚠️ The default icon is `SiconArtifacts` — the **Artifax** icon on a
|
|
36
|
+
Photogenix row. Pass `scAppCardappIcon={<SiconPhotogenix />}`.
|
|
37
|
+
4. `...props` is destructured and **never spread**. `onClick`, `style`,
|
|
38
|
+
`data-*`, `id` reach nothing.
|
|
39
|
+
5. Default description is `"Info about photogenix"` — Figma filler copy.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 1. How to use it
|
|
44
|
+
|
|
45
|
+
### Import
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { ScPhtogenixInvite } from "@streamoid/ui";
|
|
49
|
+
import { SiconPhotogenix } from "@streamoid/icons";
|
|
50
|
+
import "@streamoid/ui/dist/index.css"; // once, at your app root
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Minimal usage
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<ScPhtogenixInvite
|
|
57
|
+
enabled={photogenixOn}
|
|
58
|
+
onToggle={setPhotogenixOn}
|
|
59
|
+
scAppCardappDescription="AI product photography"
|
|
60
|
+
scAppCardappIcon={<SiconPhotogenix size={24} />}
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Props
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Default | Notes |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| `enabled` | `boolean` | – | The real on/off. Overrides `active` whenever defined. **Use this one.** |
|
|
69
|
+
| `active` | `"true"` \| `"false"` | `"true"` | ⚠️ Figma-variant leftover, a *string*. Consulted only when `enabled` is `undefined` — so the row renders **ON** by default. |
|
|
70
|
+
| `onToggle` | `(active: boolean) => void` | – | Fires with the **next** value. Omit it and the switch is inert. |
|
|
71
|
+
| `scAppCardappName` | `string` | `"Photogenix"` | ⚠️ Note the prefix and the lowercase `app`. Passed to `ScAppCard`'s `appName`. |
|
|
72
|
+
| `scAppCardappDescription` | `string` | `"Info about photogenix"` | ⚠️ Real default, and it is placeholder copy. |
|
|
73
|
+
| `scAppCardappIcon` | `JSX.Element` | `<SiconArtifacts />` | ⚠️ The **wrong brand's** icon by default (see Gotcha 3). |
|
|
74
|
+
| `className` | `string` | – | Appended after internal classes. |
|
|
75
|
+
|
|
76
|
+
There is **no** `...props` pass-through: the interface does not extend
|
|
77
|
+
`React.HTMLAttributes`, and the rest parameter the component collects is never
|
|
78
|
+
applied to the DOM.
|
|
79
|
+
|
|
80
|
+
### Recipes
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// The Photogenix row done properly: explicit state, real copy, right icon
|
|
84
|
+
<ScPhtogenixInvite
|
|
85
|
+
enabled={access.photogenix}
|
|
86
|
+
onToggle={(next) => setAccess((a) => ({ ...a, photogenix: next }))}
|
|
87
|
+
scAppCardappName="Photogenix"
|
|
88
|
+
scAppCardappDescription="AI product photography"
|
|
89
|
+
scAppCardappIcon={<SiconPhotogenix size={24} />}
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
// Need a click target, a data-attribute or a style? Wrap it — nothing is forwarded.
|
|
93
|
+
<div data-testid="access-photogenix" onClick={onRowClick}>
|
|
94
|
+
<ScPhtogenixInvite enabled={photogenixOn} onToggle={setPhotogenixOn} />
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
// Drop the divider on the last row of the stack
|
|
98
|
+
<ScPhtogenixInvite
|
|
99
|
+
enabled={photogenixOn}
|
|
100
|
+
onToggle={setPhotogenixOn}
|
|
101
|
+
className={styles.lastRow} // .lastRow { border-bottom-width: 0 }
|
|
102
|
+
/>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 2. Where to use it
|
|
108
|
+
|
|
109
|
+
- **The invite-user modal's "App access" section**, between the Artifax row and the
|
|
110
|
+
Catalogix row.
|
|
111
|
+
- **The edit-user / manage-access drawer.**
|
|
112
|
+
- **First-run onboarding** product picker.
|
|
113
|
+
|
|
114
|
+
It composes `ScAppCard` (`flex: 1`) + `ScToggleSwitch` (`flex-shrink: 0`) and draws
|
|
115
|
+
its own bottom hairline, so stacked rows need no `ScHDivider`.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 3. When to use it
|
|
120
|
+
|
|
121
|
+
### Use it when
|
|
122
|
+
|
|
123
|
+
- You want the Photogenix row and you want it visually identical to the rest of the
|
|
124
|
+
access list (same 16px padding, same divider, same switch).
|
|
125
|
+
|
|
126
|
+
### Don't use it — reach for this instead
|
|
127
|
+
|
|
128
|
+
| Situation | Use instead |
|
|
129
|
+
|---|---|
|
|
130
|
+
| You need `onClick` / `style` / `data-*` on the row itself | `ScArtifaxInvite` — same markup, spreads `...props` |
|
|
131
|
+
| The app needs a nested resource picker (stores, projects) | `ScCatalogixInvite` |
|
|
132
|
+
| App icon + name + description with **no** toggle | `ScAppCard` |
|
|
133
|
+
| A read-only "which apps does this user have" indicator | `ScAccess` |
|
|
134
|
+
| A marketing/launcher card for an app | `ScAppListingCard` / `ScAppCardV3` |
|
|
135
|
+
| The app card on the copilot/agent surface | `ScAppCardForCopilot` |
|
|
136
|
+
| Just the switch, in your own row | `ScToggleSwitch` |
|
|
137
|
+
| A labelled boolean with real form semantics | `ScCheckField` / `ScCheckbox` |
|
|
138
|
+
|
|
139
|
+
### Don't confuse with
|
|
140
|
+
|
|
141
|
+
| You may actually want | Not this |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `ScArtifaxInvite` — the same row with **clean** prop names (`appName`, `appDescription`, `appIcon`) and DOM prop forwarding | `ScPhtogenixInvite`'s props are `scAppCardapp*` and nothing is forwarded |
|
|
144
|
+
| `ScCatalogixInvite` — header row **plus** a store-access panel when enabled; defaults to **OFF** | This row is header-only and defaults to **ON** |
|
|
145
|
+
| `ScAppCard` — the inner icon/name/description block | This row wraps one |
|
|
146
|
+
| `ScPhotogenixInvite` (correct spelling) | Doesn't exist — the export is `ScPhtogenixInvite` |
|
|
147
|
+
|
|
148
|
+
Nothing but the default strings ties this component to Photogenix. If you're
|
|
149
|
+
adding a *new* app row, prefer `ScArtifaxInvite` with overridden copy: same
|
|
150
|
+
result, better API.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 4. Why to use it
|
|
155
|
+
|
|
156
|
+
- **Pixel parity with the rest of the access list** — the flex/divider/padding
|
|
157
|
+
combination is the actual spec, and it's what keeps a stack of rows from going
|
|
158
|
+
ragged when one app has a longer description.
|
|
159
|
+
- **The shared toggle.** `ScToggleSwitch` draws the exact Figma on/off SVGs from
|
|
160
|
+
alias tokens, so it flips with the theme and matches every other switch.
|
|
161
|
+
- **Controlled boolean contract** (`enabled` + `onToggle(next)`), which is what an
|
|
162
|
+
invite form submits.
|
|
163
|
+
- **It deletes duplicated markup.** `@streamoid/settings` hand-writes this row —
|
|
164
|
+
including the string `"Info about photogenix"` — with its own local
|
|
165
|
+
`ToggleSwitch`.
|
|
166
|
+
|
|
167
|
+
If you're choosing between the trio for a new row, note plainly: this one is the
|
|
168
|
+
weakest of the three (prefixed props, dropped DOM props, wrong default icon). It
|
|
169
|
+
exists because it was generated per-Figma-frame, not because Photogenix needs
|
|
170
|
+
different behaviour.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Gotchas
|
|
175
|
+
|
|
176
|
+
**1. The content props are prefixed and oddly cased.** `scAppCardappName`, not
|
|
177
|
+
`appName`; `scAppCardappDescription`, not `appDescription`. Written as JSX
|
|
178
|
+
attributes the unprefixed names are a TS error (the interface does not extend
|
|
179
|
+
`HTMLAttributes`, so there is nothing for them to fall into) — but spread from a
|
|
180
|
+
variable they slip past excess-property checking and vanish silently, leaving the
|
|
181
|
+
Photogenix defaults on screen (same mechanism as Gotcha 4).
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
// WRONG — type error as written; silent no-op if spread from an object
|
|
185
|
+
<ScPhtogenixInvite appName="Photogenix Studio" appDescription="AI photography" />
|
|
186
|
+
|
|
187
|
+
// RIGHT
|
|
188
|
+
<ScPhtogenixInvite
|
|
189
|
+
scAppCardappName="Photogenix Studio"
|
|
190
|
+
scAppCardappDescription="AI photography"
|
|
191
|
+
/>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**2. It renders ON unless you pass `enabled`.** `active` defaults to `"true"`.
|
|
195
|
+
(`ScCatalogixInvite` defaults to `"false"` — the trio is inconsistent.)
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
// WRONG — invite form starts with Photogenix already granted
|
|
199
|
+
<ScPhtogenixInvite onToggle={setPhotogenixOn} />
|
|
200
|
+
|
|
201
|
+
// RIGHT
|
|
202
|
+
<ScPhtogenixInvite enabled={photogenixOn} onToggle={setPhotogenixOn} />
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**3. The default icon is the Artifax icon.** `scAppCardappIcon` defaults to
|
|
206
|
+
`<SiconArtifacts />`. Ship it and the Photogenix row wears Artifax's mark. There
|
|
207
|
+
is a correct icon: `SiconPhotogenix` (see `packages/icons/ICONS.md`).
|
|
208
|
+
|
|
209
|
+
**4. `...props` goes nowhere.** The root `<div>` receives only `className`.
|
|
210
|
+
Spreading extra props from a variable type-checks (no excess-property check on
|
|
211
|
+
spreads) and then vanishes at runtime.
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
// WRONG — the handler and the test id are dropped on the floor
|
|
215
|
+
<ScPhtogenixInvite {...{ onClick: onRowClick, "data-testid": "photogenix-row" }} />
|
|
216
|
+
|
|
217
|
+
// RIGHT — wrap it
|
|
218
|
+
<div onClick={onRowClick} data-testid="photogenix-row">
|
|
219
|
+
<ScPhtogenixInvite enabled={photogenixOn} onToggle={setPhotogenixOn} />
|
|
220
|
+
</div>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**5. `active` is a string, not a boolean,** and `enabled` silently wins when both
|
|
224
|
+
are present. Never pass both.
|
|
225
|
+
|
|
226
|
+
**6. It is stateless.** No `onToggle` → clicking the switch does nothing, because
|
|
227
|
+
`checked` is derived from your props on every render.
|
|
228
|
+
|
|
229
|
+
**7. You cannot disable the toggle.** `ScToggleSwitch` has a `disabled` prop; this
|
|
230
|
+
row never forwards it and exposes none. For read-only access, render `ScAppCard`
|
|
231
|
+
plus your own indicator.
|
|
232
|
+
|
|
233
|
+
**8. No keyboard or screen-reader support.** The switch is a `<div onClick>`, not
|
|
234
|
+
an `<input type="checkbox">`; the row has no `role` and no focusable element. Use
|
|
235
|
+
`ScCheckField` if the control must be operable without a mouse.
|
|
236
|
+
|
|
237
|
+
**9. `styles["active-true"]` doesn't exist.** Only `.active-false` is defined (it
|
|
238
|
+
thickens the divider from 0.5px to 1px), so in the ON state the variant class
|
|
239
|
+
resolves to `undefined` and appears in the class attribute as the literal
|
|
240
|
+
`"undefined"`, as does an omitted `className`. Don't assert on the class list.
|
|
241
|
+
|
|
242
|
+
**10. Every row draws its own bottom divider,** including the last one. Strip it
|
|
243
|
+
via `className`.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## In the wild
|
|
248
|
+
|
|
249
|
+
_No host render site found — used by the agent runtime / composed internally._
|
|
250
|
+
|
|
251
|
+
The surface exists but is hand-rolled in the shared settings package, which
|
|
252
|
+
duplicates this row rather than importing it:
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
// @streamoid/settings packages/settings/src/invite-update-modal.tsx:689
|
|
256
|
+
<ToggleSwitch // local component, not ScToggleSwitch
|
|
257
|
+
active={photogenixOn}
|
|
258
|
+
onClick={() => { setPhotogenixOn(!photogenixOn); markChanged(); }}
|
|
259
|
+
/>
|
|
260
|
+
// …preceded by hand-written markup duplicating ScAppCard, with the literal
|
|
261
|
+
// string "Info about photogenix" (line 685). Local ToggleSwitch: line 84.
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
That modal (CXO settings → Teams → invite/edit user) is where this component
|
|
265
|
+
belongs.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Related
|
|
270
|
+
|
|
271
|
+
- `ScArtifaxInvite` — the same row with the cleaner API; prefer it for new rows.
|
|
272
|
+
- `ScCatalogixInvite` — the same row plus a store-access panel when enabled.
|
|
273
|
+
- `ScAppCard` — the icon/name/description block inside it.
|
|
274
|
+
- `ScToggleSwitch` — the switch on the right, standalone.
|
|
275
|
+
- `ScAccess` — read-only app-access icon row.
|