@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,302 @@
1
+ ---
2
+ component: ScOnlyField
3
+ package: "@streamoid/ui"
4
+ category: forms
5
+ status: stable
6
+ renders: div > div > input
7
+ tags: [input, search, searchbox, bare-input, unlabelled, compact, size, sidebar-search, filter]
8
+ related: [ScTextField, ScTextArea, ScSelect, ScOnlyIcon, ScFieldButton]
9
+ do_not_confuse_with: [ScOnlyIcon, ScTextField, ScAppField]
10
+ used_by: [cxo, catalogix, photogenix, artifax]
11
+ ---
12
+
13
+ # ScOnlyField
14
+
15
+ **A bare input in a pill — no label, ever.** One rounded container, an optional
16
+ icon on either side, and a borderless `<input>` inside. Unlike `ScTextField` it
17
+ has three heights (`48 / 40 / 32 px`) and reports changes as a plain string via
18
+ `onInputChange`. This is the component behind almost every search box in the
19
+ product.
20
+
21
+ ## TL;DR for agents
22
+
23
+ - **Reach for it when:** you need a search box, a filter input, or a compact
24
+ input inside a toolbar, sidebar or modal row — with no label above it.
25
+ - **Don't reach for it when:** the field needs a label, a `*`, a helper line or a
26
+ ref (→ `ScTextField`), or it is multi-line (→ `ScTextArea`).
27
+ - **Five things that will bite you:**
28
+ 1. `tfGroup` defaults to `"icon-right"` and `tfRightIcon` defaults to a
29
+ **lightning bolt**. Pass `tfGroup="none"` or supply a real icon.
30
+ 2. `labelGroup` is **vestigial** — this component renders no label element at
31
+ all. There is no `label` prop either.
32
+ 3. `state="active"`, `state="error"` and `state="disabled"` paint **nothing**.
33
+ Only `filled` (and `:hover`) have styles; the focus rule in the stylesheet
34
+ is misspelled `state-ative-focused` and is unreachable.
35
+ 4. It's fully controlled but has **no `onChange`** — use `onInputChange(value)`.
36
+ Passing `inputProps.onChange` silently replaces it.
37
+ 5. `inputProps.style` **replaces** the component's inline input styles, which
38
+ brings back the browser's default input border and background.
39
+
40
+ ---
41
+
42
+ ## 1. How to use it
43
+
44
+ ### Import
45
+
46
+ ```tsx
47
+ import { ScOnlyField } from "@streamoid/ui";
48
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
49
+ ```
50
+
51
+ ### Minimal usage
52
+
53
+ ```tsx
54
+ <ScOnlyField
55
+ tfGroup="icon-right"
56
+ tfRightIcon={<SiconSearch />}
57
+ placeholderFilled="Search…"
58
+ value={query}
59
+ onInputChange={setQuery}
60
+ />
61
+ ```
62
+
63
+ ### Props
64
+
65
+ Extends `React.HTMLAttributes<HTMLDivElement>`; unlisted props (`style`,
66
+ `onClick`, `data-*`, `id`) are spread onto the **root div**.
67
+
68
+ | Prop | Type | Default | Notes |
69
+ |---|---|---|---|
70
+ | `value` | `string` | – | Controlled value. No internal state — without `onInputChange` typing does nothing. |
71
+ | `onInputChange` | `(value: string) => void` | – | Receives the **string**, not an event. The only change hook. |
72
+ | `size` | `"default"` \| `"medium"` \| `"small"` | `"default"` | 48 px / 40 px / 32 px tall; radius `3xl`/`xl`/`lg`; icon box 24/20/16 px. |
73
+ | `tfGroup` | `"icon-right"` \| `"icon-left"` \| `"icon-left-right"` \| `"none"` | `"icon-right"` | ⚠️ Which icons render. `"none"` for a plain input. |
74
+ | `tfRightIcon` | `JSX.Element` | `<SiconBolt />` | ⚠️ Real default. Force-sized by CSS to the `size` icon box. |
75
+ | `tfLeftIcon` | `JSX.Element` | `<SiconBolt />` | ⚠️ Real default. Same sizing. |
76
+ | `placeholderFilled` | `string` | `"Placeholder"` | ⚠️ Real default. Overridable via `inputProps.placeholder`. |
77
+ | `state` | `"default"` \| `"active"` \| `"error"` \| `"disabled"` \| `"filled"` | `"default"` | Only `"filled"` changes anything (raised fill). See Gotcha 3. |
78
+ | `labelGroup` | `"none"` \| `"label"` \| `"text"` \| `"icon"` | `"none"` | ⚠️ **Dead prop** — no label is ever rendered. |
79
+ | `inputProps` | `React.InputHTMLAttributes<HTMLInputElement>` | – | Spread onto the `<input>` **after** the component's own attributes, so it can override `onChange`, `placeholder` and `style`. Use it for `autoFocus`, `maxLength`, `onKeyDown`, `readOnly`. |
80
+ | `className` | `string` | – | Appended to the root class list. |
81
+
82
+ #### What each `state` actually paints
83
+
84
+ | `state` | Effect |
85
+ |---|---|
86
+ | `default` | base fill (`fill-neutral-neutralplus`); in light mode a 0.5 px subtle border |
87
+ | `filled` | raised fill (`fill-neutral-neutral`); light mode border → `border-default` |
88
+ | `active` | **nothing** — the stylesheet rule is typo'd `state-ative-focused` |
89
+ | `error` | **nothing** — no rule exists |
90
+ | `disabled` | **nothing** — no rule exists, and the input stays editable |
91
+ | `:hover` | same as `filled` (real CSS hover, always live) |
92
+
93
+ ### Recipes
94
+
95
+ ```tsx
96
+ // Toolbar / panel search — the CXO app-switcher idiom
97
+ <ScOnlyField
98
+ tfGroup="icon-right"
99
+ size="medium"
100
+ tfRightIcon={<SiconSearch className="w-6 h-6" color="var(--alias-text-and-icons-primary)" />}
101
+ placeholderFilled="Search..."
102
+ value={searchQuery}
103
+ onInputChange={setSearchQuery}
104
+ style={{ width: 256 }} // style lands on the ROOT (root is width:100%)
105
+ />
106
+
107
+ // Repeated option rows with a trailing delete — the Catalogix taxonomy idiom
108
+ <ScOnlyField
109
+ value={option.value}
110
+ placeholderFilled="Option 1"
111
+ state={hasValue ? "filled" : "default"}
112
+ tfGroup={hasValue ? "icon-right" : "none"}
113
+ tfRightIcon={
114
+ <SiconDelete
115
+ size={24}
116
+ color="var(--alias-text-and-icons-error)"
117
+ style={{ cursor: "pointer" }}
118
+ onClick={removeOption}
119
+ />
120
+ }
121
+ onInputChange={(val) => updateOption(idx, val)}
122
+ inputProps={{ autoFocus: shouldFocus, onKeyDown: onEnterAddRow }}
123
+ />
124
+
125
+ // Dense 32 px input inside a table row
126
+ <ScOnlyField size="small" tfGroup="none" value={v} onInputChange={setV} />
127
+
128
+ // Truly disabled — the `state` prop won't do it
129
+ <ScOnlyField tfGroup="none" value={v} inputProps={{ disabled: true }} />
130
+ ```
131
+
132
+ ---
133
+
134
+ ## 2. Where to use it
135
+
136
+ - **Sidebar / workspace-listing search** — Photogenix `Sidebar.tsx`, Artifax
137
+ `DashboardSidebar.tsx`, Catalogix `LeftMenu/WorkspaceListing`.
138
+ - **App-switcher and panel headers** — CXO `app-switcher.tsx` (256 px, medium).
139
+ - **Store / member filters** — CXO `teams-content.tsx`, the
140
+ `@streamoid/settings` teams and organization screens.
141
+ - **Repeatable value rows in modals** — Catalogix taxonomy "Options" lists,
142
+ where each row is an `ScOnlyField` with a trailing red delete icon.
143
+ - **Composed inside other DS components** — `ScCatalogixInvite` renders one as
144
+ its store-search box.
145
+
146
+ All four host apps use it; it is part of the universal core.
147
+
148
+ ---
149
+
150
+ ## 3. When to use it
151
+
152
+ ### Use it when
153
+
154
+ - There is **no label** — the surrounding heading or icon already says what the
155
+ input is for.
156
+ - You need a **40 px or 32 px** field; `ScTextField` is fixed at 48 px.
157
+ - The value is a plain string in local state and you want the terser
158
+ `onInputChange` signature.
159
+
160
+ ### Don't use it — reach for this instead
161
+
162
+ | Situation | Use instead |
163
+ |---|---|
164
+ | The field needs a label, a `*`, an info popover or helper text | `ScTextField` |
165
+ | You need a `ref` on the input, or full native `onChange`/form props | `ScTextField` (it forwards a ref) |
166
+ | Multi-line input | `ScTextArea` |
167
+ | Pick from a list | `ScSelect` |
168
+ | A visible error state on the field | `ScTextField` + `desc`, or `ScTextArea` (which has a real `state="error"`) |
169
+ | An icon-only button (no text entry) | `ScButton` with `styleVariant="icon-only"` |
170
+ | A non-editable icon/control + label row | `ScPairtext` (one text line, no input — **not** a label:value pair) |
171
+
172
+ ### Don't confuse with
173
+
174
+ | You may actually want | Not this |
175
+ |---|---|
176
+ | `ScOnlyIcon` — a 40 px icon square with a hover background, **not an input** | `ScOnlyField` is a text input. The names are one character apart. |
177
+ | `ScTextField` — labelled, ref-forwarding, native `onChange`, 48 px only | `ScOnlyField` is unlabelled, no ref, `onInputChange`, three sizes |
178
+ | `ScAppField` — a hardcoded three-app permission block, not a generic field | neither of these |
179
+
180
+ ---
181
+
182
+ ## 4. Why to use it
183
+
184
+ - **Three sizes that match the spec.** Height, padding, radius *and* icon box all
185
+ step together (48/40/32 → 24/20/16 icons). Hand-rolled search boxes get the
186
+ icon size wrong almost every time.
187
+ - **Icons are force-sized.** `.iconWrapper > *` sets `width/height: 100%`, so any
188
+ `Sicon*` you pass lands at exactly the right box size regardless of its own
189
+ `size` prop.
190
+ - **Light mode is explicitly handled.** The neutral fills are near-white in the
191
+ light theme, so `[data-theme="Light"]` adds a persistent 0.5 px border across
192
+ all states — which also removes the 1 px layout shift on focus.
193
+ - **The placeholder uses the muted token** via `::placeholder`, so it can't drift
194
+ from the rest of the product.
195
+
196
+ ---
197
+
198
+ ## Gotchas
199
+
200
+ **1. The default field contains a lightning bolt.**
201
+
202
+ ```tsx
203
+ // WRONG — renders a ⚡ on the right
204
+ <ScOnlyField value={q} onInputChange={setQ} />
205
+
206
+ // RIGHT
207
+ <ScOnlyField tfGroup="none" value={q} onInputChange={setQ} />
208
+ ```
209
+
210
+ **2. There is no label and no `label` prop.** `labelGroup` is accepted and
211
+ ignored — the component's JSX has no label element. If you need one, either use
212
+ `ScTextField` or render your own text above it.
213
+
214
+ **3. Only `filled` is a real state.** `active` is misspelled in the stylesheet
215
+ (`state-ative-focused`), and `error`/`disabled` have no rules at all. So:
216
+
217
+ ```tsx
218
+ // WRONG — looks identical to default, and is still editable
219
+ <ScOnlyField state="disabled" value={v} />
220
+
221
+ // RIGHT
222
+ <ScOnlyField tfGroup="none" value={v} inputProps={{ disabled: true }} />
223
+ ```
224
+
225
+ For an error, put the red on the icon or draw the border yourself via a
226
+ `className` on the root — the component gives you nothing.
227
+
228
+ **4. `inputProps` overrides the component's own input wiring.** It is spread
229
+ last, so `inputProps.onChange` replaces the internal handler and `onInputChange`
230
+ stops firing.
231
+
232
+ ```tsx
233
+ // WRONG — onInputChange never fires
234
+ <ScOnlyField value={v} onInputChange={setV} inputProps={{ onChange: log }} />
235
+
236
+ // RIGHT — keep one owner of the change
237
+ <ScOnlyField value={v} inputProps={{ onChange: (e) => { setV(e.target.value); log(e); } }} />
238
+ ```
239
+
240
+ **5. `inputProps.style` wipes the transparent-input styling.** The `<input>`
241
+ carries inline `background: transparent; border: none; outline: none; font:
242
+ inherit; color: primary; width: 100%; padding: 0`. Passing `style` replaces the
243
+ whole object, so the native grey box comes back. Pass only the properties you
244
+ need *plus* those, or style via `className` on the root instead.
245
+
246
+ **6. No ref is forwarded.** For autofocus use `inputProps={{ autoFocus: true }}`
247
+ (Catalogix does). If you genuinely need a DOM handle, use `ScTextField`.
248
+
249
+ **7. `style` lands on the root, not the input.** The root is `width: 100%`, so
250
+ `style={{ width: 256 }}` is the right way to make it narrower.
251
+
252
+ **8. Typing does nothing without `onInputChange`.** `value` is passed straight to
253
+ a controlled input. This looks like a broken field, not a read-only one — if you
254
+ want read-only, say `inputProps={{ readOnly: true }}`.
255
+
256
+ **9. The class attribute contains the literal `undefined`** when `className` is
257
+ omitted (raw string concatenation) and for state/group names with no matching
258
+ rule. Harmless, but don't write CSS or tests that depend on the class list.
259
+
260
+ ---
261
+
262
+ ## In the wild
263
+
264
+ ```tsx
265
+ // cxo-dashboard src/app/components/app-switcher.tsx:246
266
+ <ScOnlyField
267
+ tfGroup="icon-right"
268
+ size="medium"
269
+ tfRightIcon={<SiconSearch className="w-6 h-6" color={PRIMARY_ICON} />}
270
+ placeholderFilled="Search..."
271
+ value={searchQuery}
272
+ onInputChange={setSearchQuery}
273
+ style={{ width: 256 }}
274
+ />
275
+ ```
276
+
277
+ ```jsx
278
+ // catalogix/dashboard app/components/TaxonomyComponent/AddHierarchyModal/AddHierarchyContent.jsx:379
279
+ <ScOnlyField
280
+ key={indx}
281
+ value={option.value}
282
+ placeholderFilled="Option 1"
283
+ state={option.error ? "error" : hasValue ? "filled" : "default"}
284
+ tfGroup={hasValue ? "icon-right" : "none"}
285
+ tfRightIcon={<SiconDelete size={24} color="var(--alias-text-and-icons-error)" onClick={removeOption} />}
286
+ onInputChange={(val) => { /* writes optionValues[indx].value, clears the error */ }}
287
+ inputProps={{ autoFocus: changeFocus, /* … */ }}
288
+ />
289
+ ```
290
+
291
+ *(Note: that call site's `state="error"` renders no error styling — see Gotcha 3.)*
292
+
293
+ ---
294
+
295
+ ## Related
296
+
297
+ - `ScTextField` — use it the moment you need a label, a ref, or helper text.
298
+ - `ScTextArea` — multi-line sibling with real `error`/`disabled` skins.
299
+ - `ScSelect` — dropdown instead of free text.
300
+ - `ScOnlyIcon` — the confusable namesake; an icon square, not an input.
301
+ - `ScFieldButton` — the compact action that sits beside a field.
302
+ - `@streamoid/icons` — `SiconSearch`, `SiconDelete`, `SiconClose`; see `packages/icons/ICONS.md`.
@@ -0,0 +1,213 @@
1
+ ---
2
+ component: ScOnlyIcon
3
+ package: "@streamoid/ui"
4
+ category: actions
5
+ status: legacy
6
+ renders: div
7
+ tags: [icon-button, icon-only, settings-icon, square, hover, affordance, orphan]
8
+ related: [ScButton, ScFieldButton, ScSidebarIcons, ScMenuOptions]
9
+ do_not_confuse_with: [ScOnlyField, ScButton, ScFieldButton, ScSidebarIcons]
10
+ ---
11
+
12
+ # ScOnlyIcon
13
+
14
+ **A 40 × 40 hover square that always renders the settings gear.** That is the
15
+ whole component: a `div` with 8 px padding, a 16 px radius, a hover background,
16
+ and a hardcoded `<SiconSettings />` inside. **There is no `icon` prop.**
17
+
18
+ > **Use `ScButton` with `styleVariant="icon-only"` instead.** `ScOnlyIcon` is a
19
+ > Figma-generated stub with no consumers anywhere — not in the four host
20
+ > dashboards, and not inside `@streamoid/ui` itself. It cannot render any icon
21
+ > other than the gear, has no keyboard or `aria` semantics, and has no disabled
22
+ > state.
23
+
24
+ ## TL;DR for agents
25
+
26
+ - **Reach for it when:** essentially never. The only honest use is a bare
27
+ settings-gear affordance where you also don't need keyboard access.
28
+ - **Don't reach for it when:** you need *any* other icon, a11y, a disabled state,
29
+ variants or sizes → `ScButton` (`styleVariant="icon-only"`).
30
+ - **Three things that will bite you:**
31
+ 1. `icon` **does not exist**. Passing one is a type error and would be ignored.
32
+ 2. `variant` accepts only `"default"` and maps to a class that isn't in the
33
+ stylesheet, so it does nothing.
34
+ 3. It is a `<div>` — no `role`, no `tabIndex`, no Enter/Space, no focus ring.
35
+
36
+ ---
37
+
38
+ ## 1. How to use it
39
+
40
+ ### Import
41
+
42
+ ```tsx
43
+ import { ScOnlyIcon } from "@streamoid/ui";
44
+ import "@streamoid/ui/dist/index.css"; // once, at your app root
45
+ ```
46
+
47
+ ### Minimal usage
48
+
49
+ ```tsx
50
+ <ScOnlyIcon onClick={openSettings} />
51
+ ```
52
+
53
+ ### Props
54
+
55
+ Extends `React.HTMLAttributes<HTMLDivElement>`; unlisted props (`onClick`,
56
+ `style`, `title`, `aria-*`, `data-*`) are spread onto the root div.
57
+
58
+ | Prop | Type | Default | Notes |
59
+ |---|---|---|---|
60
+ | `variant` | `"default"` | `"default"` | Dead prop — resolves to a class (`variant-default`) that the stylesheet does not define. |
61
+ | `className` | `string` | – | Appended to the root class list. The only real styling hook. |
62
+
63
+ There is **no** `icon`, `size`, `state`, `disabled`, `active` or `label` prop.
64
+
65
+ #### What actually renders
66
+
67
+ | Part | Value |
68
+ |---|---|
69
+ | Root | `div`, `padding: 0.5rem`, `border-radius: var(--radius-3xl, 1rem)`, flex row |
70
+ | Icon | `<SiconSettings />` at its default `size={24}`, `stroke: currentColor` |
71
+ | Total box | **40 × 40 px** — derived (24 px icon + 2 × 8 px padding); the stylesheet sets no `width`/`height` |
72
+ | Hover | background `--alias-fill-neutral-neutralhover` |
73
+ | Icon colour | inherited `currentColor` from the parent — set `color` on an ancestor to change it |
74
+
75
+ ### Recipes
76
+
77
+ ```tsx
78
+ // The only sane call: a gear that opens settings, with semantics bolted on
79
+ <ScOnlyIcon
80
+ role="button"
81
+ tabIndex={0}
82
+ aria-label="Settings"
83
+ onClick={openSettings}
84
+ onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") openSettings(); }}
85
+ />
86
+
87
+ // Recolour the gear (it inherits currentColor)
88
+ <span style={{ color: "var(--alias-text-and-icons-tertiary)" }}>
89
+ <ScOnlyIcon onClick={openSettings} />
90
+ </span>
91
+
92
+ // What you almost certainly want instead
93
+ <ScButton
94
+ styleVariant="icon-only"
95
+ icon={<SiconSettings size={24} />}
96
+ variant="mono"
97
+ type="tertiary"
98
+ size="md"
99
+ aria-label="Settings"
100
+ onClick={openSettings}
101
+ />
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 2. Where to use it
107
+
108
+ Nowhere, currently. Grepping CXO, Catalogix, Photogenix and Artifax — and
109
+ `packages/ui/src` itself — finds no render site. Its intended home was clearly a
110
+ toolbar or panel-header gear.
111
+
112
+ The surfaces that *look* like its job are already served by other components:
113
+
114
+ | Surface | What actually renders there |
115
+ |---|---|
116
+ | Sidebar rail icons | `ScSidebarIcons` / `StreamoidSidebar` |
117
+ | Header / toolbar icon actions | `ScButton styleVariant="icon-only"` |
118
+ | Composer toolbar actions | `ScFieldButton type="only-icon"` |
119
+ | Row overflow menus | `ScPopUpMenu` + `ScMenuOptions` |
120
+
121
+ ---
122
+
123
+ ## 3. When to use it
124
+
125
+ ### Use it when
126
+
127
+ - You want a bare gear icon with the DS hover square and you are fine adding
128
+ `role`/`tabIndex`/`aria-label` yourself.
129
+
130
+ That is the complete list.
131
+
132
+ ### Don't use it — reach for this instead
133
+
134
+ | Situation | Use instead |
135
+ |---|---|
136
+ | Any icon other than the settings gear | `ScButton styleVariant="icon-only"` with `icon={…}` |
137
+ | The icon button needs keyboard access, a focus ring, `aria-disabled` | `ScButton` |
138
+ | A disabled/loading state | `ScButton` (`state="disabled"`, `loading`) |
139
+ | A compact icon affordance inside a composer or beside a field | `ScFieldButton type="only-icon"` (which *does* take an `icon`) |
140
+ | A sidebar rail icon with active state | `ScSidebarIcons` / `StreamoidSidebar` |
141
+ | An icon that opens a menu | `ScPopUpMenu` |
142
+
143
+ ### Don't confuse with
144
+
145
+ | You may actually want | Not this |
146
+ |---|---|
147
+ | **`ScOnlyField`** — a text **input** in a pill. One character apart from this name and a completely different component. | `ScOnlyIcon` renders no input |
148
+ | `ScFieldButton` with `type="only-icon"` — a 36 px chip that accepts **your** icon | `ScOnlyIcon`'s icon is hardcoded |
149
+ | `ScButton` with `styleVariant="icon-only"` — the supported icon button | `ScOnlyIcon` has no variants, states or semantics |
150
+
151
+ ---
152
+
153
+ ## 4. Why to use it
154
+
155
+ Honestly: there is little reason. What it does give you is the 8 px / 16 px-radius
156
+ hover square that matches other icon affordances, in ~20 lines with no variant
157
+ logic. Everything else — icon choice, colour normalisation, keyboard access,
158
+ disabled handling, Figma variant parity — you get from `ScButton` and not from
159
+ here.
160
+
161
+ If you keep it, keep it for the gear only, and add the semantics yourself.
162
+
163
+ ---
164
+
165
+ ## Gotchas
166
+
167
+ **1. You cannot change the icon.**
168
+
169
+ ```tsx
170
+ // WRONG — type error, and there is no code path that would render it
171
+ <ScOnlyIcon icon={<SiconClose />} />
172
+
173
+ // RIGHT
174
+ <ScButton styleVariant="icon-only" icon={<SiconClose size={24} />} aria-label="Close" />
175
+ ```
176
+
177
+ **2. `variant` does nothing.** The component computes `styles["variant-default"]`,
178
+ which is not defined in `ScOnlyIcon.module.css`, so the literal string `undefined`
179
+ lands in the class attribute (raw concatenation also adds `undefined` when
180
+ `className` is omitted). Don't write CSS or tests against this class list.
181
+
182
+ **3. `.hover-true` is unreachable.** The stylesheet has a forced-hover class for
183
+ Figma parity, but no prop sets it. Only real `:hover` works — you cannot
184
+ screenshot the hover state via props the way `ScButton state="hover"` allows.
185
+
186
+ **4. No semantics at all.** `div` with a spread `onClick`. Add
187
+ `role="button" tabIndex={0} aria-label="…"` and an `onKeyDown`, or use `ScButton`.
188
+
189
+ **5. No size control.** There is no `size` prop: the box is whatever the icon plus
190
+ `0.5rem` of padding comes to — 40 × 40 today, because the stylesheet gives
191
+ `.siconSettingsInstance` no sizing rule and `Sicon*` defaults to `size={24}`. The
192
+ CSS itself declares no `width`/`height`, so the only lever is a `className` on the
193
+ root plus a descendant rule.
194
+
195
+ ---
196
+
197
+ ## In the wild
198
+
199
+ _No host render site found — used by the agent runtime / composed internally._
200
+
201
+ To be precise: not used by the agent runtime either — this one is a genuine
202
+ orphan. If a gear affordance is needed, it belongs in a header/toolbar row beside
203
+ an `ScHeader`, and should be built with `ScButton styleVariant="icon-only"`.
204
+
205
+ ---
206
+
207
+ ## Related
208
+
209
+ - `ScButton` — `styleVariant="icon-only"`; the supported way to render an icon button.
210
+ - `ScFieldButton` — `type="only-icon"`; compact 36 px chip that accepts your icon.
211
+ - `ScOnlyField` — the near-identical *name* that is actually a text input.
212
+ - `ScSidebarIcons` / `StreamoidSidebar` — sidebar rail icons with active states.
213
+ - `@streamoid/icons` — `SiconSettings` and every other icon; see `packages/icons/ICONS.md`.