@spark-web/design-system 5.1.7 → 5.1.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spark-web/design-system",
3
- "version": "5.1.7",
3
+ "version": "5.1.9",
4
4
  "license": "MIT",
5
5
  "main": "dist/spark-web-design-system.cjs.js",
6
6
  "module": "dist/spark-web-design-system.esm.js",
@@ -17,10 +17,10 @@
17
17
  "@spark-web/analytics": "5.1.0",
18
18
  "@spark-web/badge": "^5.1.1",
19
19
  "@spark-web/box": "6.0.1",
20
- "@spark-web/button": "5.6.1",
20
+ "@spark-web/button": "5.7.0",
21
21
  "@spark-web/checkbox": "5.1.2",
22
22
  "@spark-web/columns": "5.1.1",
23
- "@spark-web/combobox": "6.1.0",
23
+ "@spark-web/combobox": "6.2.0",
24
24
  "@spark-web/container": "5.1.1",
25
25
  "@spark-web/control-label": "5.1.0",
26
26
  "@spark-web/core": "5.2.0",
@@ -44,9 +44,9 @@
44
44
  "@spark-web/multi-select": "6.0.2",
45
45
  "@spark-web/nav-link": "5.1.0",
46
46
  "@spark-web/next-utils": "5.1.0",
47
- "@spark-web/page-header": "1.0.0",
47
+ "@spark-web/page-header": "2.0.0",
48
48
  "@spark-web/password-input": "6.0.0",
49
- "@spark-web/portal-table": "^1.0.1",
49
+ "@spark-web/portal-table": "^2.0.0",
50
50
  "@spark-web/radio": "5.3.1",
51
51
  "@spark-web/row": "5.1.1",
52
52
  "@spark-web/section-card": "0.1.0",
@@ -105,6 +105,35 @@ Spark Web theme.
105
105
 
106
106
  ---
107
107
 
108
+ ## Destructive-action caution alert
109
+
110
+ When a form control triggers a destructive or irreversible side-effect (e.g.
111
+ toggling off an authority contact, revoking access), show an
112
+ `Alert tone="caution"` **below** the control that caused the change — not above
113
+ it. The alert appears only while the destructive state is active, and disappears
114
+ when the user reverses the action (e.g. re-toggles the item back on).
115
+
116
+ Place the alert after the controls so the user sees the change they made before
117
+ the warning. Showing it above shifts the layout downward and pushes the controls
118
+ away from where the user just clicked.
119
+
120
+ ---
121
+
122
+ ## Button size
123
+
124
+ Internal-admin surfaces are dense, so the compact `size="small"` button (32px
125
+ tall) is permitted here — use it for inline row actions, table toolbars, and
126
+ other tightly-packed action clusters where the default `medium` button would
127
+ crowd the layout.
128
+
129
+ Use `size="small"` only where density genuinely requires it. Page-level primary
130
+ actions (page headers, form submit/cancel) stay at the default `medium`. Never
131
+ mix `small` and `medium` buttons within the same action group — pick one size
132
+ per cluster. The `small` size is scoped to internal-admin; do not use it on
133
+ vendor-admin or public surfaces.
134
+
135
+ ---
136
+
108
137
  ## Rules that update as the system grows
109
138
 
110
139
  When a new pattern or component is added to the internal admin surface, update
@@ -191,29 +191,111 @@ Two parts:
191
191
 
192
192
  Each row is a bordered card wrapping a space-between flex row, with the Switch's
193
193
  accessible name supplied via `aria-label` (so the name isn't rendered twice;
194
- target a row with `getByRole('switch', { name })`):
194
+ target a row with `getByRole('switch', { name })`).
195
+
196
+ ### Row content
197
+
198
+ Each row's children follow a consistent layout: a label stack on the left and an
199
+ optional `Switch` on the right. The label stack contains the item name and an
200
+ optional description line (`Text size="small" tone="muted"`) providing context
201
+ such as the item's current status or effective date:
202
+
203
+ ```tsx
204
+ <ToggleRow variant="active">
205
+ <Stack gap="small">
206
+ <Text>{item.name}</Text>
207
+ <Text size="small" tone="muted">
208
+ Current authority contact
209
+ </Text>
210
+ </Stack>
211
+ <Switch
212
+ aria-label={item.name}
213
+ checked
214
+ onCheckedChange={() => toggle(item.id)}
215
+ >
216
+ {''}
217
+ </Switch>
218
+ </ToggleRow>
219
+ ```
220
+
221
+ The description is optional — when no secondary line is needed, drop the `Stack`
222
+ wrapper and render a single `<Text>{item.name}</Text>` directly as the left-side
223
+ child of `ToggleRow`.
224
+
225
+ ### Row variants
226
+
227
+ A toggle row has three visual variants. Use a reusable `ToggleRow` component
228
+ (see Reference implementation below) to encapsulate these — never hand-write the
229
+ border/background per call site.
230
+
231
+ **Default** — standard field border, surface background. Used when the switch is
232
+ off (item not currently active):
195
233
 
196
234
  ```tsx
197
- <Box border="field" borderRadius="medium" padding="medium">
235
+ <Box border="field" borderRadius="medium" padding="medium" background="surface">
198
236
  <Box
199
237
  display="flex"
200
238
  alignItems="center"
201
239
  justifyContent="spaceBetween"
202
240
  gap="medium"
203
241
  >
204
- <Text>{item.name}</Text>
205
- <Switch
206
- aria-label={item.name}
207
- checked={value.includes(item.id)}
208
- onCheckedChange={() => toggle(item.id)}
209
- >
210
- {''}
211
- </Switch>
242
+ {children}
212
243
  </Box>
213
244
  </Box>
214
245
  ```
215
246
 
216
- Keep the toggle field consistent with the selection:
247
+ **Active** primary border with a green tint background. Used when the switch
248
+ is on (item currently active):
249
+
250
+ ```tsx
251
+ <Box
252
+ border="primary"
253
+ borderRadius="medium"
254
+ padding="medium"
255
+ background="primaryLow"
256
+ >
257
+ <Box
258
+ display="flex"
259
+ alignItems="center"
260
+ justifyContent="spaceBetween"
261
+ gap="medium"
262
+ >
263
+ {children}
264
+ </Box>
265
+ </Box>
266
+ ```
267
+
268
+ **Ended** — field border, reduced opacity, no switch. Used for historical items
269
+ that can no longer be changed (e.g. an authority contact whose term has ended).
270
+ Show these as read-only rows alongside active toggles when the modal displays
271
+ history for context:
272
+
273
+ ```tsx
274
+ <Box
275
+ border="field"
276
+ borderRadius="medium"
277
+ padding="medium"
278
+ background="surface"
279
+ opacity={0.6}
280
+ >
281
+ <Box
282
+ display="flex"
283
+ alignItems="center"
284
+ justifyContent="spaceBetween"
285
+ gap="medium"
286
+ >
287
+ {children}
288
+ </Box>
289
+ </Box>
290
+ ```
291
+
292
+ **Important:** always provide a `background` value (even `"surface"` for
293
+ non-active variants) so the Box's internal `BackgroundProvider` stays mounted
294
+ across variant changes — toggling between `background={undefined}` and a value
295
+ unmounts the provider and recreates the subtree, which breaks Switch state in
296
+ tests and can cause flicker.
297
+
298
+ ### Keeping the toggle field consistent
217
299
 
218
300
  - **Prune on change** — when an item is deselected (or an upstream condition
219
301
  turns the section off), drop its id from the toggle field. Do this in the
@@ -222,10 +304,25 @@ Keep the toggle field consistent with the selection:
222
304
  `[{ id, <flag>: onIds.includes(id) }]` in a single helper so the field's wire
223
305
  shape lives in one spot.
224
306
 
225
- Reference implementation — Authority Contacts on the Create/Edit vendor-user
226
- flows:
307
+ ### Reference implementation
308
+
309
+ > **Note:** paths below are in the **portal-hub** consumer repo
310
+ > (`brighte-labs/portal-hub`), not this repository.
311
+
312
+ `ToggleRow` — a reusable row container at
313
+ `apps/admin-portal/src/components/ToggleRow/ToggleRow.tsx` that accepts a
314
+ `variant` prop (`'default' | 'active' | 'ended'`) and renders the correct
315
+ border/background/opacity combination using only Spark Box tokens. Children are
316
+ placed inside the inner flex Box.
227
317
 
228
- - `apps/admin-portal/src/components/AuthorityContactToggleList` the row list
318
+ Usage in Authority Contacts flows (portal-hub):
319
+
320
+ - **Edit AC modal** (vendor Overview) —
321
+ `apps/admin-portal/src/pages/Vendors/VendorDetail/Overview/EditAuthorityContactsModal.tsx`
322
+ — active contacts get `variant="active"` with a Switch, ended contacts get
323
+ `variant="ended"` with no Switch.
324
+ - **Create/Edit vendor-user** —
325
+ `apps/admin-portal/src/components/AuthorityContactToggleList` — the row list
229
326
  (props: `name`, `control`, `vendors: { id; name }[]`, optional
230
327
  `label`/`description`/`rules`).
231
328
  - `apps/admin-portal/src/utils/authorityContact` → `buildVendorAcPayload` —
@@ -233,14 +330,14 @@ flows:
233
330
  - `apps/admin-portal/src/hooks/useAuthorityContactSync` — prunes the field on
234
331
  role/selection change.
235
332
 
236
- Do NOTs (portal-hub):
333
+ ### Do NOTs (portal-hub)
237
334
 
238
335
  - NEVER pass raw CSS to Spark `Box` layout props — they take token KEYS:
239
336
  `justifyContent="spaceBetween"` (NOT `"space-between"`),
240
337
  `alignItems`=`start|center|end|stretch`. An unrecognised value is silently
241
338
  dropped and the row falls back to `flex-start` (the switch clumps next to the
242
339
  label instead of aligning right).
243
- - NEVER render a toggle row for an item that can't be changed in the current
244
- flow show those as read-only `Badge`s instead.
340
+ - NEVER hand-write border/background per toggle row use the `ToggleRow`
341
+ component with the appropriate `variant`.
245
342
  - NEVER put visibility/eligibility logic inside the row list — the consumer
246
343
  gates it and owns pruning the field.