@acronis-platform/ui-react 3.0.0 → 4.0.0
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/dist/components/ui/accordion-container/accordion-container.js +14 -14
- package/dist/components/ui/accordion-container/accordion-container.js.map +1 -1
- package/dist/components/ui/app-shell-chat/app-shell-chat.js.map +1 -1
- package/dist/components/ui/area-chart/area-chart.js +141 -139
- package/dist/components/ui/area-chart/area-chart.js.map +1 -1
- package/dist/components/ui/bar-chart/bar-chart.js +295 -293
- package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
- package/dist/components/ui/category-bar/category-bar.js +109 -93
- package/dist/components/ui/category-bar/category-bar.js.map +1 -1
- package/dist/components/ui/chart/chart-palette.js +113 -0
- package/dist/components/ui/chart/chart-palette.js.map +1 -0
- package/dist/components/ui/chart/chart.js +176 -129
- package/dist/components/ui/chart/chart.js.map +1 -1
- package/dist/components/ui/chart-state/chart-state-illustrations.js +310 -0
- package/dist/components/ui/chart-state/chart-state-illustrations.js.map +1 -0
- package/dist/components/ui/chart-state/chart-state.js +48 -34
- package/dist/components/ui/chart-state/chart-state.js.map +1 -1
- package/dist/components/ui/chart-widget/chart-widget.js +87 -0
- package/dist/components/ui/chart-widget/chart-widget.js.map +1 -0
- package/dist/components/ui/composed-chart/composed-chart.js +117 -115
- package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
- package/dist/components/ui/confidence-cone/confidence-cone.js +166 -158
- package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
- package/dist/components/ui/funnel-chart/funnel-chart.js +162 -161
- package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
- package/dist/components/ui/histogram/histogram.js +94 -92
- package/dist/components/ui/histogram/histogram.js.map +1 -1
- package/dist/components/ui/input/input.js.map +1 -1
- package/dist/components/ui/label/label.js +2 -9
- package/dist/components/ui/label/label.js.map +1 -1
- package/dist/components/ui/line-chart/line-chart.js +143 -141
- package/dist/components/ui/line-chart/line-chart.js.map +1 -1
- package/dist/components/ui/metric/metric.js +74 -185
- package/dist/components/ui/metric/metric.js.map +1 -1
- package/dist/components/ui/page-content/page-content.js.map +1 -1
- package/dist/components/ui/pie-chart/pie-chart.js +201 -195
- package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
- package/dist/components/ui/radar-chart/radar-chart.js +133 -131
- package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +297 -265
- package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
- package/dist/components/ui/sankey-chart/sankey-chart.js +123 -101
- package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -1
- package/dist/components/ui/scatter-chart/scatter-chart.js +76 -74
- package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
- package/dist/components/ui/section/section.js +157 -31
- package/dist/components/ui/section/section.js.map +1 -1
- package/dist/components/ui/stepper/stepper.js +24 -24
- package/dist/components/ui/stepper/stepper.js.map +1 -1
- package/dist/components/ui/stepper-item/stepper-item.js +43 -24
- package/dist/components/ui/stepper-item/stepper-item.js.map +1 -1
- package/dist/components/ui/treemap/treemap.js +133 -124
- package/dist/components/ui/treemap/treemap.js.map +1 -1
- package/dist/components/ui/trend-indicator/trend-indicator.js +34 -69
- package/dist/components/ui/trend-indicator/trend-indicator.js.map +1 -1
- package/dist/components/ui/wizard/wizard.js +59 -0
- package/dist/components/ui/wizard/wizard.js.map +1 -0
- package/dist/hooks/use-wizard.js +75 -0
- package/dist/hooks/use-wizard.js.map +1 -0
- package/dist/index.js +502 -497
- package/dist/index.js.map +1 -1
- package/dist/llms/accordion-container.md +181 -0
- package/dist/llms/accordion.md +124 -0
- package/dist/llms/alert.md +225 -0
- package/dist/llms/app-shell-chat.md +415 -0
- package/dist/llms/area-chart.md +355 -0
- package/dist/llms/avatar.md +208 -0
- package/dist/llms/bar-chart.md +406 -0
- package/dist/llms/breadcrumb.md +326 -0
- package/dist/llms/button-group.md +298 -0
- package/dist/llms/button-icon-input.md +142 -0
- package/dist/llms/button-icon-menu.md +209 -0
- package/dist/llms/button-icon.md +128 -0
- package/dist/llms/button-menu.md +172 -0
- package/dist/llms/button.md +185 -0
- package/dist/llms/calendar-panel.md +733 -0
- package/dist/llms/calendar.md +188 -0
- package/dist/llms/card-filter.md +214 -0
- package/dist/llms/card-section.md +293 -0
- package/dist/llms/card.md +447 -0
- package/dist/llms/carousel-dialog.md +156 -0
- package/dist/llms/category-bar.md +193 -0
- package/dist/llms/chart-state.md +190 -0
- package/dist/llms/chart-widget.md +209 -0
- package/dist/llms/chart.md +182 -0
- package/dist/llms/checkbox.md +257 -0
- package/dist/llms/chip.md +195 -0
- package/dist/llms/combobox.md +164 -0
- package/dist/llms/composed-chart.md +508 -0
- package/dist/llms/confidence-cone.md +277 -0
- package/dist/llms/data-table.md +474 -0
- package/dist/llms/date-range-picker.md +272 -0
- package/dist/llms/description-list.md +131 -0
- package/dist/llms/dialog-footer-carousel.md +147 -0
- package/dist/llms/dialog-footer-default.md +142 -0
- package/dist/llms/dialog-root.md +246 -0
- package/dist/llms/dialog-welcome.md +223 -0
- package/dist/llms/dialog.md +403 -0
- package/dist/llms/dropdown-menu.md +193 -0
- package/dist/llms/empty-overlay.md +146 -0
- package/dist/llms/empty.md +156 -0
- package/dist/llms/field.md +185 -0
- package/dist/llms/filter-cards.md +157 -0
- package/dist/llms/filter-chips.md +323 -0
- package/dist/llms/filter-search.md +512 -0
- package/dist/llms/form.md +154 -0
- package/dist/llms/funnel-chart.md +333 -0
- package/dist/llms/grid.md +80 -0
- package/dist/llms/histogram.md +190 -0
- package/dist/llms/input-date-picker.md +203 -0
- package/dist/llms/input-otp.md +173 -0
- package/dist/llms/input-password.md +197 -0
- package/dist/llms/input-search.md +170 -0
- package/dist/llms/input-select.md +278 -0
- package/dist/llms/input-text-area.md +271 -0
- package/dist/llms/input-text.md +192 -0
- package/dist/llms/line-chart.md +369 -0
- package/dist/llms/link.md +209 -0
- package/dist/llms/loading.md +130 -0
- package/dist/llms/meter.md +177 -0
- package/dist/llms/metric.md +204 -0
- package/dist/llms/number-field.md +122 -0
- package/dist/llms/page-content.md +69 -0
- package/dist/llms/page-header.md +182 -0
- package/dist/llms/pagination.md +133 -0
- package/dist/llms/pie-chart.md +307 -0
- package/dist/llms/popover.md +252 -0
- package/dist/llms/progress-circle.md +126 -0
- package/dist/llms/progress.md +111 -0
- package/dist/llms/radar-chart.md +316 -0
- package/dist/llms/radial-bar-chart.md +319 -0
- package/dist/llms/radio.md +255 -0
- package/dist/llms/resizable.md +195 -0
- package/dist/llms/sankey-chart.md +208 -0
- package/dist/llms/scatter-chart.md +239 -0
- package/dist/llms/scroll-area.md +183 -0
- package/dist/llms/section.md +401 -0
- package/dist/llms/select.md +210 -0
- package/dist/llms/separator.md +87 -0
- package/dist/llms/sheet.md +202 -0
- package/dist/llms/sidebar-primary.md +360 -0
- package/dist/llms/sidebar-secondary.md +417 -0
- package/dist/llms/skeleton.md +81 -0
- package/dist/llms/slider.md +97 -0
- package/dist/llms/spinner.md +100 -0
- package/dist/llms/stack.md +80 -0
- package/dist/llms/stepper-item.md +309 -0
- package/dist/llms/stepper.md +251 -0
- package/dist/llms/switch.md +140 -0
- package/dist/llms/table.md +436 -0
- package/dist/llms/tabs.md +197 -0
- package/dist/llms/tag.md +139 -0
- package/dist/llms/timeline.md +361 -0
- package/dist/llms/timer.md +259 -0
- package/dist/llms/toast.md +241 -0
- package/dist/llms/toggle-group.md +121 -0
- package/dist/llms/toolbar.md +453 -0
- package/dist/llms/tooltip.md +164 -0
- package/dist/llms/treemap.md +254 -0
- package/dist/llms/trend-indicator.md +132 -0
- package/dist/llms/widget-placeholder.md +169 -0
- package/dist/llms/wizard.md +412 -0
- package/dist/llms.txt +142 -0
- package/dist/react.js +502 -497
- package/dist/react.js.map +1 -1
- package/dist/src/components/ui/area-chart/area-chart.d.ts +9 -4
- package/dist/src/components/ui/avatar/avatar.d.ts +1 -1
- package/dist/src/components/ui/bar-chart/bar-chart.d.ts +9 -4
- package/dist/src/components/ui/category-bar/category-bar.d.ts +10 -4
- package/dist/src/components/ui/chart/__stories__/palette-control.d.ts +48 -0
- package/dist/src/components/ui/chart/__tests__/chart-palette.test.d.ts +1 -0
- package/dist/src/components/ui/chart/chart-palette.d.ts +128 -0
- package/dist/src/components/ui/chart/chart.d.ts +66 -15
- package/dist/src/components/ui/chart/index.d.ts +4 -2
- package/dist/src/components/ui/chart-state/chart-state-illustrations.d.ts +6 -0
- package/dist/src/components/ui/chart-state/chart-state.d.ts +13 -2
- package/dist/src/components/ui/chart-state/index.d.ts +1 -0
- package/dist/src/components/ui/chart-widget/chart-widget.d.ts +64 -0
- package/dist/src/components/ui/chart-widget/index.d.ts +1 -0
- package/dist/src/components/ui/composed-chart/composed-chart.d.ts +12 -7
- package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +10 -5
- package/dist/src/components/ui/empty-overlay/empty-overlay.d.ts +1 -1
- package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +11 -5
- package/dist/src/components/ui/histogram/histogram.d.ts +10 -4
- package/dist/src/components/ui/label/index.d.ts +1 -1
- package/dist/src/components/ui/label/label.d.ts +1 -5
- package/dist/src/components/ui/line-chart/line-chart.d.ts +9 -4
- package/dist/src/components/ui/metric/metric.d.ts +13 -14
- package/dist/src/components/ui/pie-chart/pie-chart.d.ts +17 -8
- package/dist/src/components/ui/radar-chart/radar-chart.d.ts +10 -5
- package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +17 -6
- package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +10 -5
- package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +10 -5
- package/dist/src/components/ui/section/index.d.ts +1 -1
- package/dist/src/components/ui/section/section.d.ts +75 -6
- package/dist/src/components/ui/stepper-item/stepper-item.d.ts +6 -5
- package/dist/src/components/ui/tag/tag.d.ts +1 -1
- package/dist/src/components/ui/treemap/treemap.d.ts +11 -5
- package/dist/src/components/ui/trend-indicator/trend-indicator.d.ts +3 -7
- package/dist/src/components/ui/wizard/index.d.ts +1 -0
- package/dist/src/components/ui/wizard/wizard.d.ts +6 -0
- package/dist/src/hooks/index.d.ts +1 -0
- package/dist/src/hooks/use-wizard.d.ts +80 -0
- package/dist/src/index.d.ts +2 -3
- package/dist/ui-react.css +1 -1
- package/package.json +9 -3
- package/dist/components/ui/app-shell/app-shell.js +0 -75
- package/dist/components/ui/app-shell/app-shell.js.map +0 -1
- package/dist/components/ui/auth-layout/auth-layout.js +0 -56
- package/dist/components/ui/auth-layout/auth-layout.js.map +0 -1
- package/dist/components/ui/collapsible/collapsible.js +0 -22
- package/dist/components/ui/collapsible/collapsible.js.map +0 -1
- package/dist/src/components/ui/app-shell/app-shell.d.ts +0 -8
- package/dist/src/components/ui/app-shell/index.d.ts +0 -1
- package/dist/src/components/ui/auth-layout/auth-layout.d.ts +0 -6
- package/dist/src/components/ui/auth-layout/index.d.ts +0 -1
- package/dist/src/components/ui/collapsible/collapsible.d.ts +0 -5
- package/dist/src/components/ui/collapsible/index.d.ts +0 -1
- package/dist/src/components/ui/label/label.docs.d.ts +0 -10
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# Card
|
|
2
|
+
|
|
3
|
+
> A surface that groups related content and actions. A set of composable parts (header, content, footer) on a bordered, rounded container. The header carries the interactive surface: an optional drag handle, toggle switch, avatar, rename button, extras, end-aligned actions, and an optional collapse trigger. Collapsibility is composed by wrapping the header and content/footer in `AccordionContainer`.
|
|
4
|
+
|
|
5
|
+
**Status:** ready · **Category:** layout · **Since:** v0.8.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Card, CardHeader, CardContent, CardFooter } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<Card>
|
|
17
|
+
<CardHeader title="Backup status" description="Last run 5 minutes ago" hasDescription />
|
|
18
|
+
<CardContent>All workloads protected.</CardContent>
|
|
19
|
+
<CardFooter>
|
|
20
|
+
<Button>View report</Button>
|
|
21
|
+
</CardFooter>
|
|
22
|
+
</Card>
|
|
23
|
+
|
|
24
|
+
// Collapsible: compose with AccordionContainer, and set
|
|
25
|
+
// CardHeader's isCollapsible to render the trigger.
|
|
26
|
+
<Card>
|
|
27
|
+
<AccordionContainer collapsible defaultOpen>
|
|
28
|
+
<CardHeader title="Backup policy" isCollapsible />
|
|
29
|
+
<AccordionContainer.Content>
|
|
30
|
+
<CardContent>Applies to 12 workloads.</CardContent>
|
|
31
|
+
<CardFooter>
|
|
32
|
+
<Button>Save</Button>
|
|
33
|
+
</CardFooter>
|
|
34
|
+
</AccordionContainer.Content>
|
|
35
|
+
</AccordionContainer>
|
|
36
|
+
</Card>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
A surface that groups related content and actions into a bordered, rounded
|
|
40
|
+
container. Composable from parts (`Card`, `CardHeader`, `CardContent`,
|
|
41
|
+
`CardFooter`); the header carries a rich, Figma-driven feature set.
|
|
42
|
+
|
|
43
|
+
> Figma node: `10012-195993`. The design's `isCollapsable` variant
|
|
44
|
+
> (expanded/collapsed) is implemented by composing `Card` with
|
|
45
|
+
> `AccordionContainer` — see "Collapsible" below.
|
|
46
|
+
|
|
47
|
+
## When to use
|
|
48
|
+
|
|
49
|
+
- Grouping related information into a self-contained block (a stat, a
|
|
50
|
+
summary, a settings group, a reorderable list item).
|
|
51
|
+
- A header that needs any combination of: a drag handle (reorderable lists), a
|
|
52
|
+
toggle switch, an avatar, a title with an optional rename affordance, extra
|
|
53
|
+
inline content (tags/badges), and end-aligned actions (e.g. a menu button).
|
|
54
|
+
- Nesting cards (a "main" card containing one or more "secondary" cards as
|
|
55
|
+
content) — `Card` is the same component in both roles; there is no separate
|
|
56
|
+
primary/secondary variant.
|
|
57
|
+
|
|
58
|
+
## When not to use
|
|
59
|
+
|
|
60
|
+
- For a compact single-stat tile with built-in variants, use **`CardFilter`**
|
|
61
|
+
instead.
|
|
62
|
+
- As a generic layout `<div>` with no visual surface — just use a styled
|
|
63
|
+
element.
|
|
64
|
+
- For modal/overlay surfaces — use the dialog/popover components.
|
|
65
|
+
|
|
66
|
+
## Parts
|
|
67
|
+
|
|
68
|
+
| Part | Element (default) | Purpose |
|
|
69
|
+
| ------------- | ----------------- | ---------------------------------------------------------------------------------- |
|
|
70
|
+
| `Card` | `div` | The card surface (border, radius); `hasError` swaps the border to the error token. |
|
|
71
|
+
| `CardHeader` | `div` | Title/description + drag handle, switch, avatar, rename, extras, actions. |
|
|
72
|
+
| `CardContent` | `div` | Primary body region for arbitrary children. |
|
|
73
|
+
| `CardFooter` | `div` | Bottom region; horizontal action row. |
|
|
74
|
+
|
|
75
|
+
`Card` and `CardContent` accept a `render` prop for polymorphic composition.
|
|
76
|
+
|
|
77
|
+
## Example
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import {
|
|
81
|
+
Button,
|
|
82
|
+
Card,
|
|
83
|
+
CardContent,
|
|
84
|
+
CardFooter,
|
|
85
|
+
CardHeader,
|
|
86
|
+
} from '@acronis-platform/ui-react';
|
|
87
|
+
|
|
88
|
+
<Card className="w-[350px]">
|
|
89
|
+
<CardHeader
|
|
90
|
+
title="Backup status"
|
|
91
|
+
description="Last successful run 5 minutes ago."
|
|
92
|
+
hasDescription
|
|
93
|
+
/>
|
|
94
|
+
<CardContent>All 24 workloads are protected.</CardContent>
|
|
95
|
+
<CardFooter className="gap-2">
|
|
96
|
+
<Button>View report</Button>
|
|
97
|
+
<Button variant="secondary">Run now</Button>
|
|
98
|
+
</CardFooter>
|
|
99
|
+
</Card>;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Header features
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<CardHeader
|
|
106
|
+
title="Backup policy"
|
|
107
|
+
isDraggable
|
|
108
|
+
isSwitchable
|
|
109
|
+
defaultSwitchChecked
|
|
110
|
+
hasAvatar
|
|
111
|
+
avatarLabel="SB"
|
|
112
|
+
hasRename
|
|
113
|
+
onRename={() => setRenaming(true)}
|
|
114
|
+
extras={<Badge>Beta</Badge>}
|
|
115
|
+
actions={
|
|
116
|
+
<ButtonIcon aria-label="More actions">
|
|
117
|
+
<EllipsisIcon size={24} />
|
|
118
|
+
</ButtonIcon>
|
|
119
|
+
}
|
|
120
|
+
/>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- `isDraggable` shows a grip handle for reorderable lists — wire your own
|
|
124
|
+
drag library (e.g. `@dnd-kit/sortable`) onto the header or handle.
|
|
125
|
+
- `isSwitchable` renders a real `Switch`; control it with `switchChecked` /
|
|
126
|
+
`defaultSwitchChecked` / `onSwitchCheckedChange`.
|
|
127
|
+
- `hasAvatar` defaults to an initials avatar (`avatarLabel`); pass `avatar`
|
|
128
|
+
to render a custom node (e.g. an image avatar) instead.
|
|
129
|
+
- `hasRename` renders a pencil icon button; wire `onRename` to open your own
|
|
130
|
+
rename UI (an inline input, a dialog, …) — Card does not manage rename
|
|
131
|
+
state itself.
|
|
132
|
+
- `hasError` (on `Card`, not `CardHeader`) only swaps the root border color.
|
|
133
|
+
|
|
134
|
+
## Collapsible
|
|
135
|
+
|
|
136
|
+
Compose `Card` with `AccordionContainer` (the shared disclosure primitive):
|
|
137
|
+
wrap `CardContent`/`CardFooter` in `AccordionContainer.Content` and set
|
|
138
|
+
`CardHeader`'s `isCollapsible` to render the trigger — restyled to match the
|
|
139
|
+
Figma design's ghost `ButtonIcon` chrome rather than `AccordionContainer`'s
|
|
140
|
+
own neutral default.
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
import {
|
|
144
|
+
AccordionContainer,
|
|
145
|
+
Card,
|
|
146
|
+
CardContent,
|
|
147
|
+
CardFooter,
|
|
148
|
+
CardHeader,
|
|
149
|
+
} from '@acronis-platform/ui-react';
|
|
150
|
+
|
|
151
|
+
<Card className="w-[420px]">
|
|
152
|
+
<AccordionContainer collapsible defaultOpen>
|
|
153
|
+
<CardHeader
|
|
154
|
+
title="Backup policy"
|
|
155
|
+
description="Applies to 12 workloads."
|
|
156
|
+
hasDescription
|
|
157
|
+
isCollapsible
|
|
158
|
+
collapseLabel="Toggle backup policy"
|
|
159
|
+
/>
|
|
160
|
+
<AccordionContainer.Content>
|
|
161
|
+
<CardContent>All 24 workloads are protected and up to date.</CardContent>
|
|
162
|
+
<CardFooter className="gap-2">
|
|
163
|
+
<Button>Save</Button>
|
|
164
|
+
<Button variant="secondary">Cancel</Button>
|
|
165
|
+
</CardFooter>
|
|
166
|
+
</AccordionContainer.Content>
|
|
167
|
+
</AccordionContainer>
|
|
168
|
+
</Card>;
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- `isCollapsible` on `CardHeader` only has an effect when the header renders
|
|
172
|
+
inside a collapsible `AccordionContainer` — it's a no-op otherwise.
|
|
173
|
+
- The header itself (title, drag handle, switch, avatar, actions, …) stays
|
|
174
|
+
visible in both the open and closed state; only content wrapped in
|
|
175
|
+
`AccordionContainer.Content` is hidden when closed.
|
|
176
|
+
|
|
177
|
+
## Props
|
|
178
|
+
|
|
179
|
+
| Prop | Type | Default | Required | Description |
|
|
180
|
+
|------|------|---------|----------|-------------|
|
|
181
|
+
| `hasError` | `boolean` | `false` | no | Switches the root border to the error token. Set on the root (`Card`), not the header. |
|
|
182
|
+
| `render` | `RenderProp` | `undefined` | no | Base UI composition prop available on the root and every part — replaces the rendered element with another component (e.g. render the root as `<article>`) while merging props and classes. React-only; other frameworks use their own polymorphism. |
|
|
183
|
+
| `header.title` | `string` | `undefined` | no | The card's title text. Renders nothing when omitted. |
|
|
184
|
+
| `header.description` | `string` | `undefined` | no | Helper text shown under the title; only rendered when `header.hasDescription` is set. |
|
|
185
|
+
| `header.hasDescription` | `boolean` | `false` | no | Shows `header.description` below the title. |
|
|
186
|
+
| `header.isDraggable` | `boolean` | `false` | no | Shows a drag handle at the start of the header, for reorderable lists. |
|
|
187
|
+
| `header.dragHandleLabel` | `string` | `Reorder` | no | Accessible label for the drag handle. |
|
|
188
|
+
| `header.isSwitchable` | `boolean` | `false` | no | Shows a toggle switch at the start of the header. |
|
|
189
|
+
| `header.switchChecked` | `boolean` | `undefined` | no | Controlled checked state of the header switch. |
|
|
190
|
+
| `header.defaultSwitchChecked` | `boolean` | `undefined` | no | Uncontrolled initial checked state of the header switch. |
|
|
191
|
+
| `header.switchDisabled` | `boolean` | `undefined` | no | Disables the header switch. |
|
|
192
|
+
| `header.switchLabel` | `string` | `Toggle card` | no | Accessible label for the header switch. |
|
|
193
|
+
| `header.hasAvatar` | `boolean` | `false` | no | Shows an avatar before the title. |
|
|
194
|
+
| `header.avatarLabel` | `string` | `` | no | Initials shown in the default avatar; ignored if `header.avatar` is provided. |
|
|
195
|
+
| `header.avatar` | `ReactNode` | `undefined` | no | Replaces the default initials avatar with custom content. |
|
|
196
|
+
| `header.hasRename` | `boolean` | `false` | no | Shows a rename button next to the title. |
|
|
197
|
+
| `header.renameLabel` | `string` | `Rename` | no | Accessible label for the rename button. |
|
|
198
|
+
| `header.extras` | `ReactNode` | `undefined` | no | Extra content rendered inline next to the title (e.g. a tag or badge). |
|
|
199
|
+
| `header.actions` | `ReactNode` | `undefined` | no | Actions rendered at the end of the header (e.g. a menu button). |
|
|
200
|
+
| `header.isCollapsible` | `boolean` | `false` | no | Shows a disclosure trigger at the end of the header. Only has an effect when the header renders inside a collapsible `AccordionContainer` — see the collapsible composition example. |
|
|
201
|
+
| `header.collapseLabel` | `string` | `Collapse card` | no | Accessible label for the collapse trigger. |
|
|
202
|
+
|
|
203
|
+
## Events
|
|
204
|
+
|
|
205
|
+
| Event | Payload | Description |
|
|
206
|
+
|-------|---------|-------------|
|
|
207
|
+
| `header.onSwitchCheckedChange` | `undefined` | Fires when the header switch is toggled. |
|
|
208
|
+
| `header.onRename` | `undefined` | Fires when the rename button is activated. |
|
|
209
|
+
|
|
210
|
+
## Content slots
|
|
211
|
+
|
|
212
|
+
| Slot | Description |
|
|
213
|
+
|------|-------------|
|
|
214
|
+
| `default` | The composed card. Author it from the parts: an optional header (title, description, drag handle, switch, avatar, rename, extras, actions), a content region, and an optional footer for actions. All parts are optional and may be used in any combination. |
|
|
215
|
+
|
|
216
|
+
## Behavior
|
|
217
|
+
|
|
218
|
+
Card is a compound component: `Card` (root) + `CardHeader` + `CardContent` +
|
|
219
|
+
`CardFooter`. Any part may be omitted; the root has no minimum composition.
|
|
220
|
+
`CardHeader` owns most of the interactive surface described below.
|
|
221
|
+
|
|
222
|
+
### Composition
|
|
223
|
+
|
|
224
|
+
```gherkin
|
|
225
|
+
Scenario: A fully composed card
|
|
226
|
+
Given a Card wrapping a CardHeader, a CardContent, and a CardFooter
|
|
227
|
+
When the card renders
|
|
228
|
+
Then the header, content, and footer appear in source order
|
|
229
|
+
And the root carries the rounded border and surface background
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```gherkin
|
|
233
|
+
Scenario: Parts are optional
|
|
234
|
+
Given a Card wrapping only a CardContent
|
|
235
|
+
When the card renders
|
|
236
|
+
Then the card surface renders with just the content region
|
|
237
|
+
And no header or footer spacing is reserved
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Root — hasError
|
|
241
|
+
|
|
242
|
+
```gherkin
|
|
243
|
+
Scenario: Default border
|
|
244
|
+
Given a Card with hasError unset (or false)
|
|
245
|
+
When the card renders
|
|
246
|
+
Then the root border uses the on-surface-border token
|
|
247
|
+
|
|
248
|
+
Scenario: Error border
|
|
249
|
+
Given a Card with hasError set to true
|
|
250
|
+
When the card renders
|
|
251
|
+
Then the root border uses the on-surface-border-error token
|
|
252
|
+
And the header divider and text colors are unchanged
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Header — title & description
|
|
256
|
+
|
|
257
|
+
```gherkin
|
|
258
|
+
Scenario: Default title
|
|
259
|
+
Given a CardHeader with no title prop
|
|
260
|
+
When the header renders
|
|
261
|
+
Then the title reads "Title"
|
|
262
|
+
|
|
263
|
+
Scenario: Description hidden by default
|
|
264
|
+
Given a CardHeader with a description prop but hasDescription unset
|
|
265
|
+
When the header renders
|
|
266
|
+
Then the description text does not appear
|
|
267
|
+
|
|
268
|
+
Scenario: Description shown
|
|
269
|
+
Given a CardHeader with a description prop and hasDescription set to true
|
|
270
|
+
When the header renders
|
|
271
|
+
Then the description appears below the title
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Header — drag handle
|
|
275
|
+
|
|
276
|
+
```gherkin
|
|
277
|
+
Scenario: Drag handle hidden by default
|
|
278
|
+
Given a CardHeader with isDraggable unset
|
|
279
|
+
When the header renders
|
|
280
|
+
Then no drag handle appears
|
|
281
|
+
|
|
282
|
+
Scenario: Drag handle shown
|
|
283
|
+
Given a CardHeader with isDraggable set to true
|
|
284
|
+
When the header renders
|
|
285
|
+
Then a grip icon appears at the start of the header
|
|
286
|
+
And it carries the accessible name from dragHandleLabel (default "Reorder")
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Header — switch
|
|
290
|
+
|
|
291
|
+
```gherkin
|
|
292
|
+
Scenario: Switch shown and toggled
|
|
293
|
+
Given a CardHeader with isSwitchable set to true
|
|
294
|
+
When the user activates the switch
|
|
295
|
+
Then onSwitchCheckedChange fires with the new checked value
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Header — avatar
|
|
299
|
+
|
|
300
|
+
```gherkin
|
|
301
|
+
Scenario: Default avatar
|
|
302
|
+
Given a CardHeader with hasAvatar set to true and no avatar override
|
|
303
|
+
When the header renders
|
|
304
|
+
Then an avatar with avatarLabel's initials appears before the title
|
|
305
|
+
|
|
306
|
+
Scenario: Custom avatar
|
|
307
|
+
Given a CardHeader with hasAvatar set to true and an avatar override
|
|
308
|
+
When the header renders
|
|
309
|
+
Then the provided avatar node renders instead of the default initials avatar
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Header — rename
|
|
313
|
+
|
|
314
|
+
```gherkin
|
|
315
|
+
Scenario: Rename button shown and activated
|
|
316
|
+
Given a CardHeader with hasRename set to true and an onRename handler
|
|
317
|
+
When the user activates the rename button
|
|
318
|
+
Then onRename fires
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Header — extras & actions
|
|
322
|
+
|
|
323
|
+
```gherkin
|
|
324
|
+
Scenario: Extras render next to the title
|
|
325
|
+
Given a CardHeader with an extras node
|
|
326
|
+
When the header renders
|
|
327
|
+
Then the extras node appears immediately after the title (and rename button, if shown)
|
|
328
|
+
|
|
329
|
+
Scenario: Actions render at the end of the header
|
|
330
|
+
Given a CardHeader with an actions node
|
|
331
|
+
When the header renders
|
|
332
|
+
Then the actions node appears at the end of the header row
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Header — collapsible
|
|
336
|
+
|
|
337
|
+
```gherkin
|
|
338
|
+
Scenario: Collapse trigger hidden by default
|
|
339
|
+
Given a CardHeader with isCollapsible unset
|
|
340
|
+
When the header renders
|
|
341
|
+
Then no collapse trigger appears
|
|
342
|
+
|
|
343
|
+
Scenario: Collapse trigger has no effect outside a collapsible AccordionContainer
|
|
344
|
+
Given a CardHeader with isCollapsible set to true, rendered with no
|
|
345
|
+
ancestor AccordionContainer
|
|
346
|
+
When the header renders
|
|
347
|
+
Then no collapse trigger appears
|
|
348
|
+
|
|
349
|
+
Scenario: Collapse trigger shown and operated inside a collapsible AccordionContainer
|
|
350
|
+
Given a Card composed as: AccordionContainer(collapsible) wrapping a
|
|
351
|
+
CardHeader with isCollapsible set to true, and an AccordionContainer.Content
|
|
352
|
+
wrapping CardContent/CardFooter
|
|
353
|
+
When the user activates the collapse trigger
|
|
354
|
+
Then the AccordionContainer's onOpenChange fires with the new open value
|
|
355
|
+
And AccordionContainer.Content's children (CardContent, CardFooter) are
|
|
356
|
+
hidden when closed and shown when open
|
|
357
|
+
And the header itself remains visible in both states
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Pass-through
|
|
361
|
+
|
|
362
|
+
```gherkin
|
|
363
|
+
Scenario: Native attributes pass through
|
|
364
|
+
Given a Card with an id, data-* attribute, and aria-label
|
|
365
|
+
When the card renders
|
|
366
|
+
Then those attributes appear on the root element
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
```gherkin
|
|
370
|
+
Scenario: A custom className is merged, not replaced
|
|
371
|
+
Given a Card with className="w-[350px]"
|
|
372
|
+
When the card renders
|
|
373
|
+
Then the root carries both "w-[350px]" and the card's base classes
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Polymorphism
|
|
377
|
+
|
|
378
|
+
```gherkin
|
|
379
|
+
Scenario: Rendering the root as a semantic element
|
|
380
|
+
Given a Card with render={<article />}
|
|
381
|
+
When the card renders
|
|
382
|
+
Then it renders as an <article> element
|
|
383
|
+
And it keeps the card's surface classes
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Accessibility
|
|
387
|
+
|
|
388
|
+
Card is a presentational grouping container plus a header that composes real
|
|
389
|
+
interactive controls (switch, rename button). Accessibility is partly a
|
|
390
|
+
function of how the card is composed and partly built into `CardHeader`'s
|
|
391
|
+
own controls.
|
|
392
|
+
|
|
393
|
+
## Roles & semantics
|
|
394
|
+
|
|
395
|
+
- The root is a generic `<div>` with no role by default. If the card
|
|
396
|
+
represents a meaningful standalone region, render it as a landmark/section
|
|
397
|
+
via the `render` prop (e.g. `render={<section aria-labelledby="…" />}`) so
|
|
398
|
+
assistive tech can navigate to it.
|
|
399
|
+
- `CardHeader`'s title renders as a `<p>` by default, which has **no heading
|
|
400
|
+
semantics**. When the title is the heading of a content region, wrap the
|
|
401
|
+
card in a landmark and label it via `aria-labelledby` pointing at an
|
|
402
|
+
external heading, or render the root itself with an appropriate
|
|
403
|
+
`aria-label`.
|
|
404
|
+
- The drag handle icon is decorative artwork with an accessible name (via the
|
|
405
|
+
icon's `title` prop, driven by `dragHandleLabel`) — it is not itself
|
|
406
|
+
operable; drag-and-drop keyboard/pointer behavior is the consumer's
|
|
407
|
+
responsibility (e.g. wiring `dnd-kit`/`@dnd-kit/sortable`'s listeners onto
|
|
408
|
+
the header or handle).
|
|
409
|
+
|
|
410
|
+
## Keyboard
|
|
411
|
+
|
|
412
|
+
- Card itself is not interactive and is not in the tab order.
|
|
413
|
+
- The header switch (`isSwitchable`) is a real Base UI `Switch` — reachable by
|
|
414
|
+
Tab and toggled with Space, per its own component contract.
|
|
415
|
+
- The rename button (`hasRename`) is a real `ButtonIconInput` — reachable by
|
|
416
|
+
Tab and activated with Enter/Space.
|
|
417
|
+
- The collapse trigger (`isCollapsible`, composed with `AccordionContainer`)
|
|
418
|
+
is a real Base UI `Collapsible.Trigger` — reachable by Tab and activated
|
|
419
|
+
with Enter/Space; ARIA `aria-expanded`/`aria-controls` wiring is owned by
|
|
420
|
+
`AccordionContainer`, not Card.
|
|
421
|
+
- Interactive children placed in `content` or `footer` retain their own
|
|
422
|
+
keyboard behavior and focus order — Card does not trap, reorder, or
|
|
423
|
+
intercept focus.
|
|
424
|
+
|
|
425
|
+
## Screen reader
|
|
426
|
+
|
|
427
|
+
- The switch, rename button, and collapse trigger each require an accessible
|
|
428
|
+
name: `switchLabel` (default `"Toggle card"`), `renameLabel` (default
|
|
429
|
+
`"Rename"`), and `collapseLabel` (default `"Collapse card"`) — override all
|
|
430
|
+
three with copy specific to what the card represents (e.g. `"Enable
|
|
431
|
+
policy"`, `"Rename policy"`, `"Toggle backup policy"`) so they read
|
|
432
|
+
distinctly when more than one appears in the same header.
|
|
433
|
+
- The default avatar (`hasAvatar`) renders initials as visible text
|
|
434
|
+
(`avatarLabel`); provide a full-word label via a wrapping `aria-label` if
|
|
435
|
+
the initials alone aren't a sufficient description.
|
|
436
|
+
- With no landmark role on the root, the card's children are announced inline
|
|
437
|
+
in reading order.
|
|
438
|
+
|
|
439
|
+
## Contrast
|
|
440
|
+
|
|
441
|
+
- Title and body text use `--ui-text-on-surface-primary`; the description
|
|
442
|
+
uses `--ui-text-on-surface-secondary` — both against
|
|
443
|
+
`--ui-background-surface-primary`. These token pairings meet WCAG AA in
|
|
444
|
+
both light and dark themes.
|
|
445
|
+
- The 1px border uses `--ui-border-on-surface-border` (or
|
|
446
|
+
`--ui-border-on-surface-border-error` when `hasError` is set) — border
|
|
447
|
+
contrast is decorative, not a text-contrast requirement.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# CarouselDialog
|
|
2
|
+
|
|
3
|
+
> The control row inside a `DialogFooterCarousel`: a `Back` button (hidden on the first slide), a dot slide indicator, and a `Next`/call-to-action button. Pure controls — no Embla import; the slide count/index/callbacks are threaded down from `DialogWelcome`, which owns the carousel engine. Deliberately NOT exported from `@acronis-platform/ui-react`'s public entry point — it is an internal primitive consumed only by `DialogFooterCarousel`. Apps building a welcome/onboarding carousel dialog should use `DialogWelcome` instead.
|
|
4
|
+
|
|
5
|
+
**Status:** draft · **Category:** layout · **Since:** v0.58.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { CarouselDialog } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<CarouselDialog
|
|
17
|
+
variant="middle"
|
|
18
|
+
slideCount={3}
|
|
19
|
+
selectedIndex={1}
|
|
20
|
+
onSelectIndex={setSelectedIndex}
|
|
21
|
+
onBack={() => embla.scrollPrev()}
|
|
22
|
+
onNext={() => embla.scrollNext()}
|
|
23
|
+
/>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The control row inside a `DialogFooterCarousel`: a `Back` button, a dot slide
|
|
27
|
+
indicator, and a `Next`/call-to-action button. Pure controls with no Embla
|
|
28
|
+
import of its own; the slide count/index/callbacks are threaded down from
|
|
29
|
+
`DialogWelcome`, which owns the carousel engine.
|
|
30
|
+
|
|
31
|
+
## When to use
|
|
32
|
+
|
|
33
|
+
- Inside `DialogFooterCarousel`, which supplies the themed footer bar around
|
|
34
|
+
this row. Not meant to be used standalone.
|
|
35
|
+
|
|
36
|
+
## When not to use
|
|
37
|
+
|
|
38
|
+
- A standalone content carousel with no dialog footer chrome.
|
|
39
|
+
- A dialog's ordinary action row (Cancel/Save) — use `DialogFooterDefault`.
|
|
40
|
+
|
|
41
|
+
## Parts
|
|
42
|
+
|
|
43
|
+
| Part | Description |
|
|
44
|
+
| ------------- | --------------------------------------------------------------------- |
|
|
45
|
+
| boxLeft | `Back` button. Hidden on the first slide (`variant="first"`). |
|
|
46
|
+
| listIndicator | One dot per slide; clicking a dot jumps to that slide. |
|
|
47
|
+
| boxRight | `Next` (first/middle slide) or the call-to-action label (last slide). |
|
|
48
|
+
|
|
49
|
+
## Example
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { CarouselDialog } from '@acronis-platform/ui-react';
|
|
53
|
+
|
|
54
|
+
<CarouselDialog
|
|
55
|
+
variant="middle"
|
|
56
|
+
slideCount={3}
|
|
57
|
+
selectedIndex={1}
|
|
58
|
+
onSelectIndex={setSelectedIndex}
|
|
59
|
+
onBack={() => embla.scrollPrev()}
|
|
60
|
+
onNext={() => embla.scrollNext()}
|
|
61
|
+
/>;
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Props
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Default | Required | Description |
|
|
67
|
+
|------|------|---------|----------|-------------|
|
|
68
|
+
| `variant` | `'first' | 'middle' | 'last'` | `'first'` | no | Which slide position this renders for. |
|
|
69
|
+
| `slideCount` | `number` | `1` | no | Total number of slides, used to render the dot indicator. |
|
|
70
|
+
| `selectedIndex` | `number` | `0` | no | The currently active slide index (0-based). |
|
|
71
|
+
| `backLabel` | `string` | `'Back'` | no | `Back` button label. |
|
|
72
|
+
| `nextLabel` | `string` | `'Next'` | no | `Next` button label (`variant="first" | "middle"`). |
|
|
73
|
+
| `primaryLabel` | `string` | `'Call to action'` | no | Call-to-action button label (`variant="last"`). |
|
|
74
|
+
| `goToSlideLabel` | `(index: number, count: number) => string` | — | no | Builds each dot's accessible name from its 0-based index and the slide count. |
|
|
75
|
+
|
|
76
|
+
## Events
|
|
77
|
+
|
|
78
|
+
| Event | Payload | Description |
|
|
79
|
+
|-------|---------|-------------|
|
|
80
|
+
| `select-index` | `number` | Fired when a dot is activated, with its slide index (React `onSelectIndex`). |
|
|
81
|
+
| `back` | `undefined` | Fired when `Back` (hidden on `variant="first"`) is activated (React `onBack`). |
|
|
82
|
+
| `next` | `undefined` | Fired when `Next` (`variant="first" | "middle"`) is activated (React `onNext`). |
|
|
83
|
+
| `primary-action` | `undefined` | Fired when the call-to-action button (`variant="last"`) is activated (React `onPrimaryAction`). |
|
|
84
|
+
|
|
85
|
+
## Behavior
|
|
86
|
+
|
|
87
|
+
CarouselDialog is a pure function of its props — no internal state. The
|
|
88
|
+
carousel engine (which slide is active, how to move between slides) lives in
|
|
89
|
+
the caller — typically `DialogWelcome`'s Embla instance, threaded through
|
|
90
|
+
`DialogFooterCarousel` — which passes `slideCount`/`selectedIndex` in and
|
|
91
|
+
receives `onSelectIndex`/`onBack`/`onNext`/`onPrimaryAction` back out.
|
|
92
|
+
|
|
93
|
+
```gherkin
|
|
94
|
+
Scenario: First slide (variant="first")
|
|
95
|
+
Given a CarouselDialog with variant="first"
|
|
96
|
+
Then `Back` is not rendered
|
|
97
|
+
And `Next` is rendered in boxRight
|
|
98
|
+
And the dot indicator marks the first dot active
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```gherkin
|
|
102
|
+
Scenario: A middle slide (variant="middle")
|
|
103
|
+
Given a CarouselDialog with variant="middle"
|
|
104
|
+
Then `Back` is rendered in boxLeft
|
|
105
|
+
And `Next` is rendered in boxRight
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```gherkin
|
|
109
|
+
Scenario: The last slide (variant="last")
|
|
110
|
+
Given a CarouselDialog with variant="last"
|
|
111
|
+
Then `Back` is rendered in boxLeft
|
|
112
|
+
And the call-to-action label (default "Call to action") replaces `Next` in boxRight
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```gherkin
|
|
116
|
+
Scenario: Jumping to an arbitrary slide
|
|
117
|
+
Given a CarouselDialog with slideCount=3
|
|
118
|
+
When a dot other than the active one is activated
|
|
119
|
+
Then onSelectIndex fires with that dot's 0-based index
|
|
120
|
+
And the caller is responsible for actually moving the carousel and passing
|
|
121
|
+
back an updated `variant`/`selectedIndex`
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```gherkin
|
|
125
|
+
Scenario: A single-slide carousel
|
|
126
|
+
Given a CarouselDialog with slideCount=1
|
|
127
|
+
Then only one dot renders, always active
|
|
128
|
+
And the caller is responsible for choosing variant="last" for that single
|
|
129
|
+
slide (it is both the first and the last), so the call-to-action button
|
|
130
|
+
is reachable
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Accessibility
|
|
134
|
+
|
|
135
|
+
- `Back`, `Next`, and the call-to-action control render as real `Button`
|
|
136
|
+
elements — native focus, keyboard activation (Enter/Space), and the
|
|
137
|
+
Button's own accessible name (its label) come for free.
|
|
138
|
+
- Each dot in the indicator is a real `<button>` with an explicit
|
|
139
|
+
`aria-label` (default `"Go to slide N of M"`, overridable via
|
|
140
|
+
`goToSlideLabel`) — dots are never bare, unlabeled `<div>`s. The active dot
|
|
141
|
+
carries `aria-current="true"`. Dots have their own `focus-visible` ring
|
|
142
|
+
(`--ui-focus-primary`), matching the kit's other raw-`<button>` controls
|
|
143
|
+
(e.g. `Pagination`, `Tabs`).
|
|
144
|
+
- CarouselDialog is a plain layout container — no landmark role of its own.
|
|
145
|
+
It's meant to live inside `DialogFooterCarousel` inside a dialog (e.g.
|
|
146
|
+
`DialogWelcome`), which owns the `role="dialog"` / focus-trap semantics.
|
|
147
|
+
- Focus order follows DOM order: `Back` (when present) → dots → `Next`/
|
|
148
|
+
call-to-action.
|
|
149
|
+
|
|
150
|
+
## Contrast
|
|
151
|
+
|
|
152
|
+
The active dot uses `--ui-glyph-on-surface-primary`; inactive dots use
|
|
153
|
+
`--ui-glyph-on-surface-disabled`. Both are guaranteed to meet contrast against
|
|
154
|
+
the footer's own background in both light and dark (shared semantic
|
|
155
|
+
glyph/surface pairing) — the same tokens `Breadcrumb`'s separator icon and
|
|
156
|
+
`Switch`'s track use for the equivalent idle/disabled distinction.
|