@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,251 @@
|
|
|
1
|
+
# Stepper
|
|
2
|
+
|
|
3
|
+
> The root of a step sequence. It renders the sequence two ways and lets CSS pick one: on wide viewports a start-aligned, wrapping row of `StepperItem` children; on narrow ones a two-line text summary — "Step 3 of 5: <current step>" and "Next: <next step>" — with no items at all. The switch is a real viewport media query (Tailwind's `lg:`, `min-width: 1024px`), not a JS measurement, so both subtrees are always in the DOM and only one is ever displayed. It owns that layout switch and the summary copy only: the steps, their order, which one is current, and all navigation belong to the application.
|
|
4
|
+
|
|
5
|
+
**Status:** ready · **Category:** navigation · **Since:** v0.63.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Stepper } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<Stepper
|
|
17
|
+
currentStep={2}
|
|
18
|
+
totalSteps={3}
|
|
19
|
+
current="Choose a plan"
|
|
20
|
+
next="Confirm and pay"
|
|
21
|
+
>
|
|
22
|
+
<StepperItem variant="completed" label="Create an account" avatar={…} />
|
|
23
|
+
<StepperItem variant="current" label="Choose a plan" avatar={…} />
|
|
24
|
+
<StepperItem variant="future" label="Confirm and pay" avatar={…} />
|
|
25
|
+
</Stepper>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The root of a step sequence. It renders the sequence **two ways** and lets CSS
|
|
29
|
+
pick one:
|
|
30
|
+
|
|
31
|
+
- **At 1024px and above** — the `StepperItem` children you pass, in a
|
|
32
|
+
start-aligned row that wraps.
|
|
33
|
+
- **Below 1024px** — a two-line text summary instead: "Step 3 of 5: Choose a
|
|
34
|
+
plan" and "Next: Confirm and pay". No step items at all.
|
|
35
|
+
|
|
36
|
+
Both subtrees are always in the DOM; a real viewport media query (Tailwind's
|
|
37
|
+
`lg:`) displays one and hides the other. So you supply **both** the children and
|
|
38
|
+
the summary props — the component cannot derive one from the other.
|
|
39
|
+
|
|
40
|
+
## When to use
|
|
41
|
+
|
|
42
|
+
- Any wizard / checkout / onboarding flow that has to stay usable on a narrow
|
|
43
|
+
viewport, where a row of steps would not fit.
|
|
44
|
+
- Whenever you would otherwise lay `StepperItem`s out by hand: this is that row,
|
|
45
|
+
plus the compact fallback.
|
|
46
|
+
|
|
47
|
+
## When not to use
|
|
48
|
+
|
|
49
|
+
- For a single step in isolation — that is `StepperItem`.
|
|
50
|
+
- To show progress as one quantity — use `Progress` or `ProgressCircle`.
|
|
51
|
+
- For a chronological log of things that already happened — use `Timeline`.
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<Stepper
|
|
57
|
+
currentStep={2}
|
|
58
|
+
totalSteps={3}
|
|
59
|
+
current="Choose a plan"
|
|
60
|
+
next="Confirm and pay"
|
|
61
|
+
>
|
|
62
|
+
<StepperItem
|
|
63
|
+
variant="completed"
|
|
64
|
+
label="Create an account"
|
|
65
|
+
avatar={
|
|
66
|
+
<Avatar color="green" className="[box-shadow:none]">
|
|
67
|
+
<CheckIcon size={16} />
|
|
68
|
+
</Avatar>
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
71
|
+
<StepperItem
|
|
72
|
+
variant="current"
|
|
73
|
+
label="Choose a plan"
|
|
74
|
+
avatar={
|
|
75
|
+
<Avatar color="blue" className="[box-shadow:none]">
|
|
76
|
+
<AvatarFallback>2</AvatarFallback>
|
|
77
|
+
</Avatar>
|
|
78
|
+
}
|
|
79
|
+
/>
|
|
80
|
+
<StepperItem
|
|
81
|
+
variant="future"
|
|
82
|
+
label="Confirm and pay"
|
|
83
|
+
avatar={
|
|
84
|
+
<Avatar color="gray" className="[box-shadow:none]">
|
|
85
|
+
<AvatarFallback>3</AvatarFallback>
|
|
86
|
+
</Avatar>
|
|
87
|
+
}
|
|
88
|
+
/>
|
|
89
|
+
</Stepper>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`Avatar`'s 2px outset ring (meant to separate overlapping avatars in an
|
|
93
|
+
`AvatarGroup`) is switched off with `className="[box-shadow:none]"` on each
|
|
94
|
+
composed avatar — Figma's Stepper avatars carry no stroke, and left on, the
|
|
95
|
+
ring shows as an unwanted halo on a filled step container. See `StepperItem`'s
|
|
96
|
+
own spec `README.md` for the full note.
|
|
97
|
+
|
|
98
|
+
On the **last** step, omit `next` — the whole "Next: …" line is then left out
|
|
99
|
+
rather than rendered empty.
|
|
100
|
+
|
|
101
|
+
Every string the component generates itself is a prop so it can be translated —
|
|
102
|
+
`stepLabel` ("Step"), `ofLabel` ("of"), `nextLabel` ("Next:"), and
|
|
103
|
+
`separatorLabel` (": ", the punctuation before the step's name). Everything else
|
|
104
|
+
it renders is yours.
|
|
105
|
+
|
|
106
|
+
## Parts
|
|
107
|
+
|
|
108
|
+
| Part | Element | Notes |
|
|
109
|
+
| -------------- | ------- | ------------------------------------------------------ |
|
|
110
|
+
| root | `div` | Full width; holds both layouts |
|
|
111
|
+
| `summary` | `div` | The compact layout, displayed below 1024px |
|
|
112
|
+
| `current-line` | `p` | "Step N of M: {current}", two-tone |
|
|
113
|
+
| `next-line` | `p` | "Next: {next}"; absent when `next` is omitted |
|
|
114
|
+
| `items-row` | `div` | The `StepperItem` children, displayed at 1024px and up |
|
|
115
|
+
|
|
116
|
+
## Breakpoint boundary
|
|
117
|
+
|
|
118
|
+
Figma names the two variants `0-1024` and `>1025`, which leaves 1024px itself
|
|
119
|
+
ambiguous. The implementation uses the kit's pinned `lg` breakpoint — exactly
|
|
120
|
+
1024px (64rem) — so **1024px renders the wide row**, one pixel lower than the
|
|
121
|
+
Figma label implies. That is a deliberate choice to stay on the shared
|
|
122
|
+
breakpoint scale rather than mint a bespoke `1025px` query for one component;
|
|
123
|
+
the repo documents equivalent roundings elsewhere (see
|
|
124
|
+
`src/stories/breakpoints-demo.stories.tsx`).
|
|
125
|
+
|
|
126
|
+
## Design status
|
|
127
|
+
|
|
128
|
+
As of the 2026-08-24 Figma sync, this component consumes a dedicated
|
|
129
|
+
`--ui-stepper-breakpoint-*` token tier (see `tokens.yaml`) — the summary's line
|
|
130
|
+
gap, the item row's gap, and both summary text colors are Stepper-owned
|
|
131
|
+
tokens rather than borrowed from the semantic scale, the same treatment
|
|
132
|
+
`StepperItem` already carries.
|
|
133
|
+
|
|
134
|
+
## Props
|
|
135
|
+
|
|
136
|
+
| Prop | Type | Default | Required | Description |
|
|
137
|
+
|------|------|---------|----------|-------------|
|
|
138
|
+
| `currentStep` | `ReactNode` | — | yes | 1-based index of the step the user is on, e.g. `3`. Appears in the compact summary only; above the breakpoint the highlighted `StepperItem` carries the same information. |
|
|
139
|
+
| `totalSteps` | `ReactNode` | — | yes | How many steps the sequence has, e.g. `5`. Compact summary only. |
|
|
140
|
+
| `current` | `ReactNode` | — | yes | The current step's name. Compact summary only. |
|
|
141
|
+
| `next` | `ReactNode` | — | no | The next step's name. Omit it — on the last step — and the whole "Next: …" line is left out rather than rendered empty. Compact summary only. |
|
|
142
|
+
| `stepLabel` | `string` | `Step` | no | The word introducing the step counter. A prop rather than an inlined literal so the component ships no untranslatable copy; the default is English, and a localized application overrides it. |
|
|
143
|
+
| `ofLabel` | `string` | `of` | no | The word joining the current step number to the total. Translatable — see `stepLabel`. |
|
|
144
|
+
| `nextLabel` | `string` | `Next:` | no | The label introducing the next step's name. Translatable — see `stepLabel`. |
|
|
145
|
+
| `separatorLabel` | `string` | `: ` | no | The punctuation joining the step counter to the current step's name. Translatable — see `stepLabel`; not every locale writes it as `": "` (French spaces before the colon, CJK uses a full-width one). |
|
|
146
|
+
|
|
147
|
+
## Content slots
|
|
148
|
+
|
|
149
|
+
| Slot | Description |
|
|
150
|
+
|------|-------------|
|
|
151
|
+
| `default` | The `StepperItem` elements making up the sequence, laid out in the wide row. They are not rendered in the compact summary, which replaces the row with text. |
|
|
152
|
+
|
|
153
|
+
## Behavior
|
|
154
|
+
|
|
155
|
+
### Two layouts, chosen by the viewport
|
|
156
|
+
|
|
157
|
+
- **Given** a viewport **at or above 1024px**
|
|
158
|
+
**Then** the `StepperItem` children render as a start-aligned row that wraps, and
|
|
159
|
+
the compact summary is `display: none`.
|
|
160
|
+
- **Given** a viewport **below 1024px**
|
|
161
|
+
**Then** the two-line text summary renders, and the item row is
|
|
162
|
+
`display: none` — no step items are shown at all.
|
|
163
|
+
- **Given** any viewport
|
|
164
|
+
**Then** _both_ subtrees are in the DOM. The switch is a CSS media query
|
|
165
|
+
(Tailwind's `lg:`, i.e. `@media (min-width: 1024px)`), not a JS measurement,
|
|
166
|
+
so nothing is mounted or unmounted as the window resizes and there is no
|
|
167
|
+
hydration mismatch, no `ResizeObserver`, and no measuring pass.
|
|
168
|
+
- **Given** a viewport of exactly **1024px**
|
|
169
|
+
**Then** the wide row renders. Figma names the variants `0-1024` and `>1025`,
|
|
170
|
+
which makes 1024 itself ambiguous; the implementation follows the kit's pinned
|
|
171
|
+
`lg` breakpoint (1024px = 64rem) rather than inventing a one-off `1025px`
|
|
172
|
+
query, so the boundary sits one pixel lower than the Figma label suggests.
|
|
173
|
+
- **Given** a `dir="rtl"` document
|
|
174
|
+
**Then** both layouts mirror without extra work: neither uses a physical
|
|
175
|
+
directional utility.
|
|
176
|
+
|
|
177
|
+
### The compact summary
|
|
178
|
+
|
|
179
|
+
- **Given** `currentStep`, `totalSteps`, and `current`
|
|
180
|
+
**Then** the first line reads "Step {currentStep} of {totalSteps}: {current}",
|
|
181
|
+
with the generated prefix in `--ui-stepper-breakpoint-default-label-color` and
|
|
182
|
+
the step's name in `--ui-stepper-breakpoint-default-value-color`.
|
|
183
|
+
- **Given** a `next` step name
|
|
184
|
+
**Then** a second line reads "Next: {next}", with the same two-tone treatment.
|
|
185
|
+
- **Given** no `next`
|
|
186
|
+
**Then** the second line is **not rendered at all** — no empty paragraph, no
|
|
187
|
+
dangling "Next:". This is how the last step in a sequence renders.
|
|
188
|
+
- **Given** `stepLabel`, `ofLabel`, `nextLabel`, or `separatorLabel`
|
|
189
|
+
**Then** the corresponding generated string is replaced. The component ships
|
|
190
|
+
English defaults and no other copy of its own, so a localized application
|
|
191
|
+
overrides exactly these four. `separatorLabel` (default `": "`) is the
|
|
192
|
+
punctuation joining the counter to the step name — a prop rather than an inlined
|
|
193
|
+
literal because not every locale writes it that way.
|
|
194
|
+
|
|
195
|
+
### The wide row
|
|
196
|
+
|
|
197
|
+
- **Given** `children`
|
|
198
|
+
**Then** they are laid out in a flex row, start-aligned, wrapping onto further
|
|
199
|
+
lines when the sequence is too wide. Each wrapped line packs to the start
|
|
200
|
+
(left in LTR) rather than centering independently, so a lone trailing item on
|
|
201
|
+
the last line stays visually connected to the row above it instead of
|
|
202
|
+
floating under the container's midpoint.
|
|
203
|
+
- **Given** more steps than fit
|
|
204
|
+
**Then** the row wraps rather than scrolling or truncating; below the
|
|
205
|
+
breakpoint the summary takes over instead.
|
|
206
|
+
|
|
207
|
+
### Not owned here
|
|
208
|
+
|
|
209
|
+
- The steps themselves — their number, order, labels, markers, and which one is
|
|
210
|
+
`current` are the application's, passed as `StepperItem` children.
|
|
211
|
+
- Navigation: the component has no events. A completed step becomes clickable by
|
|
212
|
+
composing that `StepperItem` with its own `render` prop.
|
|
213
|
+
- Keeping `currentStep` / `current` / `next` consistent with the children. The
|
|
214
|
+
compact summary and the wide row are two renderings of the same state, but the
|
|
215
|
+
component cannot inspect its children to derive one from the other — the
|
|
216
|
+
caller supplies both.
|
|
217
|
+
|
|
218
|
+
## Accessibility
|
|
219
|
+
|
|
220
|
+
- **Only one layout is ever announced.** Both subtrees are in the DOM at all
|
|
221
|
+
times, but the inactive one is `display: none`, which removes it from the
|
|
222
|
+
accessibility tree. A screen-reader user below 1024px hears the text summary;
|
|
223
|
+
above it, the step items. Nothing is duplicated. Do not "fix" this with
|
|
224
|
+
`aria-hidden` — which layout is live is a CSS decision the component cannot
|
|
225
|
+
observe, so any JS-set flag would be wrong half the time.
|
|
226
|
+
- **The compact summary is the accessible progress statement.** "Step 3 of 5:
|
|
227
|
+
Choose a plan" is plain text in a `<p>`, so it is read verbatim, in order,
|
|
228
|
+
with no ARIA required. That is deliberately the same sentence a sighted user
|
|
229
|
+
reads.
|
|
230
|
+
- **The wide row is not itself a list.** The root is a plain `<div>` with no
|
|
231
|
+
`role`. If the sequence should announce as an ordered list, or the current
|
|
232
|
+
step as `aria-current="step"`, the application composes that on the
|
|
233
|
+
`StepperItem` children — which are polymorphic via their own `render` prop.
|
|
234
|
+
- **No tab stops of its own.** The root and both layouts are non-interactive.
|
|
235
|
+
Focusability comes only from whatever a `StepperItem` child is rendered as.
|
|
236
|
+
- **Ships four English strings** — `stepLabel`, `ofLabel`, `nextLabel`,
|
|
237
|
+
`separatorLabel` — and nothing else. They are props, so a localized application replaces them; the
|
|
238
|
+
step names themselves are always consumer-supplied.
|
|
239
|
+
- **RTL**: the summary is a plain block flow and the row uses logical flex
|
|
240
|
+
layout with a gap, so both mirror under `dir="rtl"` with no extra work and no
|
|
241
|
+
physical directional utility to correct.
|
|
242
|
+
|
|
243
|
+
## Contrast
|
|
244
|
+
|
|
245
|
+
The generated prefix uses `--ui-stepper-breakpoint-default-label-color` and the
|
|
246
|
+
step names use `--ui-stepper-breakpoint-default-value-color` (see
|
|
247
|
+
`tokens.yaml`) — both Stepper-owned tokens as of the 2026-08-24 tier sync.
|
|
248
|
+
Contrast has been verified against the tier's resolved values in light and
|
|
249
|
+
dark; the label-color/prefix pairing is the one to re-check first if a brand
|
|
250
|
+
later defines a distinct value for it, as it is the lowest-contrast text the
|
|
251
|
+
component renders.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Switch
|
|
2
|
+
|
|
3
|
+
> A binary on/off toggle. Wraps the Base UI Switch primitive; the change takes effect immediately (no separate submit).
|
|
4
|
+
|
|
5
|
+
**Status:** ready · **Category:** forms · **Since:** v0.4.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Switch } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<Switch
|
|
17
|
+
aria-label="Wireless"
|
|
18
|
+
checked={enabled}
|
|
19
|
+
onCheckedChange={setEnabled}
|
|
20
|
+
/>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A binary on/off toggle whose change takes effect immediately.
|
|
24
|
+
|
|
25
|
+
## When to use
|
|
26
|
+
|
|
27
|
+
- Toggling a single setting that applies instantly (e.g. "Enable notifications").
|
|
28
|
+
|
|
29
|
+
## When not to use
|
|
30
|
+
|
|
31
|
+
- A choice that only applies after submitting a form — use a checkbox.
|
|
32
|
+
- Selecting one of several options — use radios or a segmented control.
|
|
33
|
+
|
|
34
|
+
## Example (React — implemented)
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { Switch } from '@acronis-platform/ui-react';
|
|
38
|
+
|
|
39
|
+
const [enabled, setEnabled] = useState(false);
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
/* Bare toggle — name it with aria-label */
|
|
43
|
+
}
|
|
44
|
+
<Switch aria-label="Wireless" checked={enabled} onCheckedChange={setEnabled} />;
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
/* With a label — the whole row toggles */
|
|
48
|
+
}
|
|
49
|
+
<Switch
|
|
50
|
+
label="Enable notifications"
|
|
51
|
+
checked={enabled}
|
|
52
|
+
onCheckedChange={setEnabled}
|
|
53
|
+
/>;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Pass `label` to compose the full field (the row becomes clickable and the toggle
|
|
57
|
+
is named via aria-labelledby); omit it for a bare toggle named with `aria-label`.
|
|
58
|
+
Vue and Web Component implementations are planned against the same contract.
|
|
59
|
+
|
|
60
|
+
## Parts
|
|
61
|
+
|
|
62
|
+
| Part | Element | Notes |
|
|
63
|
+
| ----------- | -------- | ------------------------------------------------------- |
|
|
64
|
+
| `root` | `button` | The track (role `switch`); fill per off/on state |
|
|
65
|
+
| `thumb` | `span` | The sliding knob |
|
|
66
|
+
| `container` | `label` | Wraps toggle + label, forwards clicks (only with label) |
|
|
67
|
+
| `label` | `span` | Label text, names the control |
|
|
68
|
+
|
|
69
|
+
## Props
|
|
70
|
+
|
|
71
|
+
| Prop | Type | Default | Required | Description |
|
|
72
|
+
|------|------|---------|----------|-------------|
|
|
73
|
+
| `checked` | `boolean` | — | no | Controlled checked state. Pair with the change event. |
|
|
74
|
+
| `default-checked` | `boolean` | `false` | no | Initial checked state when uncontrolled. |
|
|
75
|
+
| `disabled` | `boolean` | `false` | no | Disables interaction. |
|
|
76
|
+
| `required` | `boolean` | `false` | no | Marks the control as required in a form. |
|
|
77
|
+
| `name` | `string` | — | no | Form field name submitted with the form. |
|
|
78
|
+
| `value` | `string` | — | no | Form field value when checked. |
|
|
79
|
+
| `label` | `ReactNode` | — | no | Optional label rendered beside the toggle. When provided, the whole row becomes a clickable `<label>` and the toggle is named via aria-labelledby. |
|
|
80
|
+
|
|
81
|
+
## Events
|
|
82
|
+
|
|
83
|
+
| Event | Payload | Description |
|
|
84
|
+
|-------|---------|-------------|
|
|
85
|
+
| `checked-change` | `boolean` | Fired when the checked state changes (React: `onCheckedChange`). Payload is the new checked value. |
|
|
86
|
+
|
|
87
|
+
## Behavior
|
|
88
|
+
|
|
89
|
+
### Toggling
|
|
90
|
+
|
|
91
|
+
#### Toggles on activation
|
|
92
|
+
|
|
93
|
+
**Given** an enabled Switch
|
|
94
|
+
**When** the user clicks it or presses Space/Enter while focused
|
|
95
|
+
**Then** the checked state flips
|
|
96
|
+
**And** a `checked-change` event fires with the new boolean value
|
|
97
|
+
**And** the thumb slides to the new position.
|
|
98
|
+
|
|
99
|
+
### Controlled vs uncontrolled
|
|
100
|
+
|
|
101
|
+
#### Uncontrolled
|
|
102
|
+
|
|
103
|
+
**Given** a Switch with `default-checked` and no `checked`
|
|
104
|
+
**When** it renders
|
|
105
|
+
**Then** it manages its own state, starting from `default-checked`.
|
|
106
|
+
|
|
107
|
+
#### Controlled
|
|
108
|
+
|
|
109
|
+
**Given** a Switch with `checked`
|
|
110
|
+
**When** the user toggles it
|
|
111
|
+
**Then** it emits `checked-change` but does not change visually until the owner
|
|
112
|
+
updates `checked`.
|
|
113
|
+
|
|
114
|
+
### Disabled
|
|
115
|
+
|
|
116
|
+
**Given** a Switch with `disabled`
|
|
117
|
+
**When** the user attempts to toggle it
|
|
118
|
+
**Then** the state does not change and no event fires.
|
|
119
|
+
|
|
120
|
+
### Known gap
|
|
121
|
+
|
|
122
|
+
The current React implementation renders correctly but is **not yet wired to the
|
|
123
|
+
`--ui-switch-*` tokens** (see `tokens.yaml`). It uses the shared semantic bridge
|
|
124
|
+
and `opacity-50` for disabled. This spec is the target contract; aligning the
|
|
125
|
+
implementation is tracked follow-up.
|
|
126
|
+
|
|
127
|
+
## Accessibility
|
|
128
|
+
|
|
129
|
+
- **Role:** `switch` (Base UI Switch.Root), with `aria-checked` reflecting the
|
|
130
|
+
on/off state.
|
|
131
|
+
- **Accessible name:** associate a visible label (e.g. wrap with a `<label>` or
|
|
132
|
+
use `aria-labelledby`); when there is no visible label, provide `aria-label`.
|
|
133
|
+
- **Keyboard:** Space (and Enter) toggle the switch while focused; Tab moves
|
|
134
|
+
focus. A `disabled` switch is not focusable.
|
|
135
|
+
- **Focus visible:** 2px `--ui-focus-brand` ring with 2px offset via
|
|
136
|
+
`:focus-visible`.
|
|
137
|
+
- **State, not color alone:** the on/off state is exposed via `aria-checked` and
|
|
138
|
+
the thumb position, not color alone.
|
|
139
|
+
- **WCAG:** 2.1.1 (keyboard), 2.4.7 (focus visible), 4.1.2 (name/role/value),
|
|
140
|
+
1.4.11 (non-text contrast).
|