@acronis-platform/ui-react 2.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 +144 -0
- package/dist/components/ui/accordion-container/accordion-container.js.map +1 -0
- 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/avatar/avatar.js +33 -22
- package/dist/components/ui/avatar/avatar.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/card/card.js +150 -74
- package/dist/components/ui/card/card.js.map +1 -1
- package/dist/components/ui/card-section/card-section.js +111 -0
- package/dist/components/ui/card-section/card-section.js.map +1 -0
- 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/data-table/data-table.js +4 -2
- package/dist/components/ui/data-table/data-table.js.map +1 -1
- package/dist/components/ui/empty-overlay/empty-overlay.js +49 -0
- package/dist/components/ui/empty-overlay/empty-overlay.js.map +1 -0
- 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/table/table.js +27 -27
- package/dist/components/ui/table/table.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 +540 -525
- 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 +540 -525
- package/dist/react.js.map +1 -1
- package/dist/src/components/ui/accordion-container/accordion-container.d.ts +44 -0
- package/dist/src/components/ui/accordion-container/index.d.ts +1 -0
- package/dist/src/components/ui/area-chart/area-chart.d.ts +9 -4
- package/dist/src/components/ui/avatar/avatar.d.ts +27 -8
- package/dist/src/components/ui/bar-chart/bar-chart.d.ts +9 -4
- package/dist/src/components/ui/button/button.d.ts +1 -1
- package/dist/src/components/ui/card/card.d.ts +69 -8
- package/dist/src/components/ui/card/index.d.ts +1 -1
- package/dist/src/components/ui/card-section/card-section.d.ts +50 -0
- package/dist/src/components/ui/card-section/index.d.ts +1 -0
- 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/dialog/dialog.d.ts +1 -1
- package/dist/src/components/ui/empty-overlay/empty-overlay.d.ts +20 -0
- package/dist/src/components/ui/empty-overlay/index.d.ts +2 -0
- package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +11 -5
- package/dist/src/components/ui/grid/grid.d.ts +1 -1
- 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/sheet/sheet.d.ts +1 -1
- package/dist/src/components/ui/stack/stack.d.ts +1 -1
- 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 +5 -3
- package/dist/ui-react.css +1 -1
- package/package.json +12 -6
- 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,142 @@
|
|
|
1
|
+
# DialogFooterDefault
|
|
2
|
+
|
|
3
|
+
> A bottom action bar (panel/dialog/sheet footer) — end-aligned actions plus an optional start slot: a truncated description, or a link. The Figma `variant` (default / withDescription / withLink) is structural, following from which slot is passed, not a separate prop.
|
|
4
|
+
|
|
5
|
+
**Status:** ready · **Category:** layout · **Since:** v0.58.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { DialogFooterDefault } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<DialogFooterDefault>
|
|
17
|
+
<Button variant="secondary">Cancel</Button>
|
|
18
|
+
<Button>Save</Button>
|
|
19
|
+
</DialogFooterDefault>
|
|
20
|
+
|
|
21
|
+
<DialogFooterDefault description="Changes are saved automatically as you type.">
|
|
22
|
+
<Button variant="secondary">Cancel</Button>
|
|
23
|
+
<Button>Save</Button>
|
|
24
|
+
</DialogFooterDefault>
|
|
25
|
+
|
|
26
|
+
<DialogFooterDefault link={<Link href="/docs">Learn more</Link>}>
|
|
27
|
+
<Button variant="secondary">Cancel</Button>
|
|
28
|
+
<Button>Save</Button>
|
|
29
|
+
</DialogFooterDefault>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
A bottom action bar for panels, dialogs, and sheets — end-aligned actions
|
|
33
|
+
plus an optional start slot: a truncated description, or a link.
|
|
34
|
+
|
|
35
|
+
## When to use
|
|
36
|
+
|
|
37
|
+
- The bottom action row of a panel/dialog/sheet — e.g. Cancel + Save.
|
|
38
|
+
- When the actions need brief accompanying context (a description) or a
|
|
39
|
+
related link (e.g. "Learn more").
|
|
40
|
+
|
|
41
|
+
## When not to use
|
|
42
|
+
|
|
43
|
+
- For a bulk-action/selection bar above a list or table — use `Toolbar`.
|
|
44
|
+
- For a full app-level bottom bar — compose the layout directly.
|
|
45
|
+
|
|
46
|
+
## Parts
|
|
47
|
+
|
|
48
|
+
| Part | Description |
|
|
49
|
+
| ----------- | ---------------------------------------------------------------------- |
|
|
50
|
+
| description | Optional truncated text next to the actions. |
|
|
51
|
+
| link | Optional `Link` (or similar) element next to the actions. |
|
|
52
|
+
| actions | End-aligned action content — typically a secondary + primary `Button`. |
|
|
53
|
+
|
|
54
|
+
`description` and `link` are mutually exclusive — pass at most one.
|
|
55
|
+
|
|
56
|
+
## Example
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { Button, DialogFooterDefault, Link } from '@acronis-platform/ui-react';
|
|
60
|
+
|
|
61
|
+
<DialogFooterDefault>
|
|
62
|
+
<Button variant="secondary">Cancel</Button>
|
|
63
|
+
<Button>Save</Button>
|
|
64
|
+
</DialogFooterDefault>
|
|
65
|
+
|
|
66
|
+
<DialogFooterDefault description="Changes are saved automatically as you type.">
|
|
67
|
+
<Button variant="secondary">Cancel</Button>
|
|
68
|
+
<Button>Save</Button>
|
|
69
|
+
</DialogFooterDefault>
|
|
70
|
+
|
|
71
|
+
<DialogFooterDefault link={<Link href="/docs">Learn more</Link>}>
|
|
72
|
+
<Button variant="secondary">Cancel</Button>
|
|
73
|
+
<Button>Save</Button>
|
|
74
|
+
</DialogFooterDefault>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Props
|
|
78
|
+
|
|
79
|
+
| Prop | Type | Default | Required | Description |
|
|
80
|
+
|------|------|---------|----------|-------------|
|
|
81
|
+
| `description` | `string` | — | no | Truncated description text next to the actions. Mutually exclusive with `link` — set at most one. |
|
|
82
|
+
| `link` | `ReactNode` | — | no | A `Link` (or similar) element next to the actions. Mutually exclusive with `description` — set at most one. |
|
|
83
|
+
|
|
84
|
+
## Content slots
|
|
85
|
+
|
|
86
|
+
| Slot | Description |
|
|
87
|
+
|------|-------------|
|
|
88
|
+
| `default` | End-aligned actions — typically a secondary and a primary `Button`. DialogFooterDefault imposes no button count or order. |
|
|
89
|
+
|
|
90
|
+
## Behavior
|
|
91
|
+
|
|
92
|
+
DialogFooterDefault is a pure function of its props — no internal state, no
|
|
93
|
+
interaction of its own (interactivity lives on the composed `Button`/`Link`
|
|
94
|
+
children).
|
|
95
|
+
|
|
96
|
+
```gherkin
|
|
97
|
+
Scenario: Actions only
|
|
98
|
+
Given a DialogFooterDefault with no `description` or `link`
|
|
99
|
+
Then its children render end-aligned (root falls back to justify-end)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```gherkin
|
|
103
|
+
Scenario: With a description
|
|
104
|
+
Given a DialogFooterDefault with description="Changes are saved automatically as you type."
|
|
105
|
+
Then the description renders truncated (single line, ellipsis) next to the actions
|
|
106
|
+
And the actions no longer need the justify-end fallback (the description's
|
|
107
|
+
flex-1 pushes them to the end)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```gherkin
|
|
111
|
+
Scenario: With a link
|
|
112
|
+
Given a DialogFooterDefault with link={<Link href="/docs">Learn more</Link>}
|
|
113
|
+
Then the link renders in a 32px-tall row next to the actions, untruncated
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```gherkin
|
|
117
|
+
Scenario: description and link are mutually exclusive
|
|
118
|
+
Given a DialogFooterDefault with both `description` and `link` set
|
|
119
|
+
Then both slots render (the component does not validate mutual exclusivity) —
|
|
120
|
+
callers should pass at most one, matching the single Figma `variant`
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Accessibility
|
|
124
|
+
|
|
125
|
+
- DialogFooterDefault is a plain layout container — no landmark role of its
|
|
126
|
+
own. If a DialogFooterDefault's actions form the primary controls for an
|
|
127
|
+
enclosing dialog/sheet, that ancestor (e.g. `Dialog`, `Sheet`) owns the
|
|
128
|
+
relevant ARIA (e.g. `role="dialog"`, focus trapping); DialogFooterDefault
|
|
129
|
+
does not duplicate it.
|
|
130
|
+
- All interactive semantics (focus order, keyboard activation, accessible
|
|
131
|
+
names) come from the composed `Button`/`Link` children — DialogFooterDefault
|
|
132
|
+
does not wrap or override them.
|
|
133
|
+
- The `description` text is plain, truncated text — `title`/`aria-label` is
|
|
134
|
+
the caller's responsibility if the full (untruncated) text should also be
|
|
135
|
+
available to assistive tech or as a hover tooltip.
|
|
136
|
+
|
|
137
|
+
## Contrast
|
|
138
|
+
|
|
139
|
+
`description` uses the shared `text-foreground` token
|
|
140
|
+
(`--ui-text-on-surface-primary`), guaranteed to meet contrast against
|
|
141
|
+
DialogFooterDefault's own `--ui-footer-default-color` background in both
|
|
142
|
+
light and dark (both come from the same semantic surface/text pairing).
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# DialogRoot
|
|
2
|
+
|
|
3
|
+
> A modal overlay that interrupts the user to show focused content or request a decision. A set of composable parts (trigger, overlay, content, header, title, close, body, description, footer) built on the Base UI Dialog primitive. Initial version ported from the legacy shadcn-uikit `Dialog`; design reconciliation against Figma is pending. Internal-only as of the Dialog (recipe) merge — not exported from the package root. `Dialog` (sourceDir: dialog, see the `dialog` spec) is the sole public entry point; it composes these parts internally.
|
|
4
|
+
|
|
5
|
+
**Status:** draft · **Category:** overlays · **Since:** v0.9.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
Internal-only — NOT exported from '@acronis-platform/ui-react'. `Dialog` (the recipe) is the sole public entry point; these parts are an implementation detail it composes internally (src/components/ui/dialog/dialog.tsx).
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
// Internal usage only (e.g. inside Dialog or its tests):
|
|
17
|
+
<DialogRoot>
|
|
18
|
+
<DialogTrigger render={<Button variant="secondary">Open</Button>} />
|
|
19
|
+
<DialogContent>
|
|
20
|
+
<DialogHeaderRoot>
|
|
21
|
+
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
|
22
|
+
<DialogCloseButton />
|
|
23
|
+
</DialogHeaderRoot>
|
|
24
|
+
<DialogBodyRoot>
|
|
25
|
+
<DialogDescription>This action cannot be undone.</DialogDescription>
|
|
26
|
+
</DialogBodyRoot>
|
|
27
|
+
<DialogFooterRoot>
|
|
28
|
+
<DialogClose render={<Button variant="ghost">Cancel</Button>} />
|
|
29
|
+
<Button variant="destructive">Delete</Button>
|
|
30
|
+
</DialogFooterRoot>
|
|
31
|
+
</DialogContent>
|
|
32
|
+
</DialogRoot>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> **Internal-only.** Not exported from `@acronis-platform/ui-react`. This is
|
|
36
|
+
> the composable primitive `Dialog` (the recipe) is built on — use
|
|
37
|
+
> [`Dialog`](../dialog/README.md) instead. Documented here because its source
|
|
38
|
+
> lives alongside `Dialog`'s (`packages/ui-react/src/components/ui/dialog/`)
|
|
39
|
+
> and other internal code (tests, Storybook VR coverage) still references it
|
|
40
|
+
> directly.
|
|
41
|
+
|
|
42
|
+
A modal overlay that interrupts the user to show focused content or request a
|
|
43
|
+
decision. Composable from parts; built on the Base UI Dialog primitive.
|
|
44
|
+
|
|
45
|
+
> **Status: draft (design-pending v1).** Ported from the legacy
|
|
46
|
+
> `@acronis-platform/shadcn-uikit` `Dialog`. There is no `--ui-dialog-*` token
|
|
47
|
+
> tier yet, so colors resolve to the shared semantic tokens. Enter/exit
|
|
48
|
+
> animations use `tw-animate-css` (overlay fade, popup fade + zoom), keyed to
|
|
49
|
+
> Base UI's open/closed state. Reconcile against Figma with
|
|
50
|
+
> `/figma-component Dialog <url> --update` once a mockup lands.
|
|
51
|
+
|
|
52
|
+
## When to use
|
|
53
|
+
|
|
54
|
+
- Never directly — it has no public export. Use `Dialog`; if none of its
|
|
55
|
+
seven canned use-cases (or the `wide` escape hatch) fit, that's a gap to
|
|
56
|
+
raise with the design system team (a new variant), not a reason to reach
|
|
57
|
+
for this primitive.
|
|
58
|
+
|
|
59
|
+
## Parts
|
|
60
|
+
|
|
61
|
+
| Part | Element (default) | Purpose |
|
|
62
|
+
| -------------------------------- | ------------------ | ------------------------------------------------- |
|
|
63
|
+
| `DialogRoot` | — | Root; owns the open state (Base UI `Root`). |
|
|
64
|
+
| `DialogTrigger` | `button` | Opens the dialog. |
|
|
65
|
+
| `DialogContent` | `div[role=dialog]` | The portaled, centered popup (+ overlay). |
|
|
66
|
+
| `DialogHeaderRoot` | `div` | Top bar; holds the title and close button. |
|
|
67
|
+
| `DialogTitle` | `h2` | Accessible dialog name (`aria-labelledby`). |
|
|
68
|
+
| `DialogCloseButton` | `button` | Icon button that dismisses the dialog. |
|
|
69
|
+
| `DialogBodyRoot` | `div` | Scrollable content region. |
|
|
70
|
+
| `DialogDescription` | `p` | Supporting copy (`aria-describedby`). |
|
|
71
|
+
| `DialogFooterRoot` | `div` | Right-aligned action bar. |
|
|
72
|
+
| `DialogClose` | `button` | Closes the dialog; wrap a Button via `render`. |
|
|
73
|
+
| `DialogOverlay` / `DialogPortal` | — | Lower-level parts (`DialogContent` renders them). |
|
|
74
|
+
|
|
75
|
+
## Sizes
|
|
76
|
+
|
|
77
|
+
`DialogContent` takes a `size` prop controlling the popup max-width. `sm`
|
|
78
|
+
(512px, default) has a Figma-defined token (`--ui-dialog-container-size-sm`);
|
|
79
|
+
`large` (832px) is a legacy backward-compatibility size with no design token,
|
|
80
|
+
kept for existing call sites (see the public `Dialog` recipe's `wide` variant).
|
|
81
|
+
|
|
82
|
+
## Example (internal usage only)
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// NOT a public import — './dialog' is an internal module path, shown here
|
|
86
|
+
// only to document what Dialog (the recipe) composes internally.
|
|
87
|
+
import {
|
|
88
|
+
DialogRoot,
|
|
89
|
+
DialogTrigger,
|
|
90
|
+
DialogContent,
|
|
91
|
+
DialogHeaderRoot,
|
|
92
|
+
DialogTitle,
|
|
93
|
+
DialogCloseButton,
|
|
94
|
+
DialogBodyRoot,
|
|
95
|
+
DialogDescription,
|
|
96
|
+
DialogFooterRoot,
|
|
97
|
+
DialogClose,
|
|
98
|
+
} from './dialog';
|
|
99
|
+
import { Button } from '../button';
|
|
100
|
+
|
|
101
|
+
<DialogRoot>
|
|
102
|
+
<DialogTrigger render={<Button variant="secondary">Open dialog</Button>} />
|
|
103
|
+
<DialogContent>
|
|
104
|
+
<DialogHeaderRoot>
|
|
105
|
+
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
|
106
|
+
<DialogCloseButton />
|
|
107
|
+
</DialogHeaderRoot>
|
|
108
|
+
<DialogBodyRoot>
|
|
109
|
+
<DialogDescription>This action cannot be undone.</DialogDescription>
|
|
110
|
+
</DialogBodyRoot>
|
|
111
|
+
<DialogFooterRoot>
|
|
112
|
+
<DialogClose render={<Button variant="ghost">Cancel</Button>} />
|
|
113
|
+
<Button variant="destructive">Delete account</Button>
|
|
114
|
+
</DialogFooterRoot>
|
|
115
|
+
</DialogContent>
|
|
116
|
+
</DialogRoot>;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Props
|
|
120
|
+
|
|
121
|
+
| Prop | Type | Default | Required | Description |
|
|
122
|
+
|------|------|---------|----------|-------------|
|
|
123
|
+
| `open` | `boolean` | — | no | Controlled open state. Pair with the change event. |
|
|
124
|
+
| `default-open` | `boolean` | `false` | no | Initial open state when uncontrolled. |
|
|
125
|
+
| `modal` | `boolean | 'trap-focus'` | `true` | no | Modal behavior — traps focus and locks background scroll while open. `'trap-focus'` keeps the focus trap but allows background interaction. |
|
|
126
|
+
| `size` | `'sm' | 'large'` | `'sm'` | no | Popup max-width (on the content part). `sm` (512px) has a Figma-defined token (`--ui-dialog-container-size-sm`); `large` (832px) is a legacy backward-compatibility size with no design token, kept for existing call sites (see the public `Dialog` recipe's `wide` variant). |
|
|
127
|
+
| `portal` | `boolean` | `true` | no | Render the content inside a portal (the content part). Required by the underlying primitive for correct stacking; disable only when supplying your own portal ancestor. |
|
|
128
|
+
| `render` | `RenderProp` | `undefined` | no | Composition prop available on the trigger, close, title, description, and other primitive parts — replaces the rendered element with another component (e.g. render the trigger as a Button) while merging props. React-only; other frameworks use their own polymorphism. |
|
|
129
|
+
|
|
130
|
+
## Events
|
|
131
|
+
|
|
132
|
+
| Event | Payload | Description |
|
|
133
|
+
|-------|---------|-------------|
|
|
134
|
+
| `open-change` | `boolean` | Fired when the dialog opens or closes (React: `onOpenChange`). Payload is the new open value. |
|
|
135
|
+
|
|
136
|
+
## Content slots
|
|
137
|
+
|
|
138
|
+
| Slot | Description |
|
|
139
|
+
|------|-------------|
|
|
140
|
+
| `default` | The composed dialog. Author it from the parts: an optional trigger, plus the content (popup) wrapping an optional header (title + close), a body (with a description), and an optional footer for actions. |
|
|
141
|
+
|
|
142
|
+
## Behavior
|
|
143
|
+
|
|
144
|
+
DialogRoot is a modal overlay assembled from composable parts. It owns one
|
|
145
|
+
piece of state — `open` — and the focus/scroll management that comes with
|
|
146
|
+
being modal.
|
|
147
|
+
|
|
148
|
+
### Opening & closing
|
|
149
|
+
|
|
150
|
+
```gherkin
|
|
151
|
+
Scenario: Opening from the trigger
|
|
152
|
+
Given a closed DialogRoot with a DialogTrigger
|
|
153
|
+
When the user activates the trigger
|
|
154
|
+
Then the overlay and popup appear
|
|
155
|
+
And focus moves into the dialog
|
|
156
|
+
And open-change(true) fires
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```gherkin
|
|
160
|
+
Scenario: Closing via the close button
|
|
161
|
+
Given an open DialogRoot with a DialogCloseButton
|
|
162
|
+
When the user activates the close button
|
|
163
|
+
Then the dialog closes
|
|
164
|
+
And open-change(false) fires
|
|
165
|
+
And focus returns to the trigger
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```gherkin
|
|
169
|
+
Scenario: Dismissing with the keyboard
|
|
170
|
+
Given an open modal DialogRoot
|
|
171
|
+
When the user presses Escape
|
|
172
|
+
Then the dialog closes and open-change(false) fires
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```gherkin
|
|
176
|
+
Scenario: Dismissing by clicking outside
|
|
177
|
+
Given an open DialogRoot
|
|
178
|
+
When the user presses on the overlay outside the popup
|
|
179
|
+
Then the dialog closes and open-change(false) fires
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Controlled vs uncontrolled
|
|
183
|
+
|
|
184
|
+
```gherkin
|
|
185
|
+
Scenario: Uncontrolled with default-open
|
|
186
|
+
Given a DialogRoot with default-open = true and no open prop
|
|
187
|
+
When it mounts
|
|
188
|
+
Then it renders open, and the user can dismiss it without consumer code
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```gherkin
|
|
192
|
+
Scenario: Controlled
|
|
193
|
+
Given a DialogRoot with a fixed open prop
|
|
194
|
+
When the user attempts to dismiss it
|
|
195
|
+
Then internal state does NOT change on its own
|
|
196
|
+
And open-change fires so the consumer can update the open prop
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Modality
|
|
200
|
+
|
|
201
|
+
```gherkin
|
|
202
|
+
Scenario: Modal locks the background (default)
|
|
203
|
+
Given an open DialogRoot with modal = true
|
|
204
|
+
Then background content is inert, scroll is locked, and focus is trapped
|
|
205
|
+
inside the dialog until it closes
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Accessibility
|
|
209
|
+
|
|
210
|
+
DialogRoot leans on the Base UI Dialog primitive for its modal semantics,
|
|
211
|
+
focus management, and keyboard handling. The author's job is to provide an
|
|
212
|
+
accessible name and description and to use the parts as intended.
|
|
213
|
+
|
|
214
|
+
## Roles & semantics
|
|
215
|
+
|
|
216
|
+
- The popup (`root`) has `role="dialog"` and `aria-modal="true"` when modal.
|
|
217
|
+
- **Name the dialog.** Render a `DialogTitle` — it is wired to the popup via
|
|
218
|
+
`aria-labelledby`. Without a title the dialog has no accessible name.
|
|
219
|
+
- **Describe it when useful.** A `DialogDescription` is wired via
|
|
220
|
+
`aria-describedby`, so supporting copy is announced after the name.
|
|
221
|
+
- The close button exposes an accessible name ("Close") via an `sr-only` label
|
|
222
|
+
alongside the icon.
|
|
223
|
+
|
|
224
|
+
## Keyboard
|
|
225
|
+
|
|
226
|
+
- **Tab / Shift+Tab** — focus cycles **within** the dialog only; the focus trap
|
|
227
|
+
prevents reaching background content while modal.
|
|
228
|
+
- **Escape** — closes the dialog (fires the change event).
|
|
229
|
+
- On open, focus moves into the dialog (the first focusable element, or the
|
|
230
|
+
popup); on close, focus returns to the element that opened it (the trigger).
|
|
231
|
+
|
|
232
|
+
## Screen reader
|
|
233
|
+
|
|
234
|
+
- Entering the dialog announces its role, name (title), and description.
|
|
235
|
+
- While modal, background content is marked inert, so assistive tech stays
|
|
236
|
+
within the dialog.
|
|
237
|
+
|
|
238
|
+
## Contrast
|
|
239
|
+
|
|
240
|
+
- Title/body text use `--ui-text-on-surface-primary`; the description and idle
|
|
241
|
+
close icon use `--ui-text-on-surface-secondary`; both meet WCAG AA against the
|
|
242
|
+
`--ui-background-surface-secondary` popup and `--ui-background-surface-primary`
|
|
243
|
+
header/footer in light and dark themes. The close button shows a 2px
|
|
244
|
+
`--ui-focus-primary` ring on keyboard focus.
|
|
245
|
+
- This is a design-pending v1 on semantic tokens — re-verify contrast against the
|
|
246
|
+
final palette once a `--ui-dialog-*` tier and Figma reference exist.
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# DialogWelcome
|
|
2
|
+
|
|
3
|
+
> An onboarding dialog with two layouts: `carousel` (a multi-slide feature tour driven by a real Embla carousel engine, with a `DialogFooterCarousel` footer) and `single` (one image/title/description body with a primary action and a `Close` link). Built from scratch — does not reuse any existing carousel implementation in this repo.
|
|
4
|
+
|
|
5
|
+
**Status:** draft · **Category:** overlay · **Since:** v0.58.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { DialogWelcome } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<DialogWelcome
|
|
17
|
+
variant="carousel"
|
|
18
|
+
slides={[
|
|
19
|
+
{ title: 'Automated backups', description: 'Your data is backed up on a schedule you control.' },
|
|
20
|
+
{ title: 'Instant recovery', description: 'Restore a full workload in minutes, not hours.' },
|
|
21
|
+
]}
|
|
22
|
+
open={open}
|
|
23
|
+
onOpenChange={setOpen}
|
|
24
|
+
onPrimaryAction={() => setOpen(false)}
|
|
25
|
+
/>
|
|
26
|
+
|
|
27
|
+
<DialogWelcome
|
|
28
|
+
variant="single"
|
|
29
|
+
title="You're all set"
|
|
30
|
+
description="Your workspace is ready to go."
|
|
31
|
+
primaryLabel="Get started"
|
|
32
|
+
open={open}
|
|
33
|
+
onOpenChange={setOpen}
|
|
34
|
+
/>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
An onboarding dialog with two layouts: `carousel` (a multi-slide feature tour
|
|
38
|
+
driven by a real Embla carousel engine, with a `DialogFooterCarousel` footer)
|
|
39
|
+
and `single` (one image/title/description body with a primary action and a
|
|
40
|
+
`Close` link). Built from scratch; does not reuse any existing carousel
|
|
41
|
+
implementation in this repo.
|
|
42
|
+
|
|
43
|
+
## When to use
|
|
44
|
+
|
|
45
|
+
- A first-run or feature-announcement dialog that walks through several
|
|
46
|
+
screenshots/highlights one at a time — use `variant="carousel"`.
|
|
47
|
+
- A single-screen announcement or confirmation with one image and one
|
|
48
|
+
call-to-action — use `variant="single"`.
|
|
49
|
+
|
|
50
|
+
## When not to use
|
|
51
|
+
|
|
52
|
+
- An ordinary confirmation/action dialog — use `Dialog`.
|
|
53
|
+
- A content carousel with no dialog chrome — compose `DialogFooterCarousel`
|
|
54
|
+
(or a plain Embla instance) directly into your own layout.
|
|
55
|
+
|
|
56
|
+
## Parts
|
|
57
|
+
|
|
58
|
+
| Part | Description |
|
|
59
|
+
| ------------- | ------------------------------------------------------------------------- |
|
|
60
|
+
| container | The popup card — reuses `Dialog`'s own chrome. |
|
|
61
|
+
| image | Illustration/media for the active slide (or the single body). |
|
|
62
|
+
| title | The active slide's title; also the dialog's accessible name. |
|
|
63
|
+
| description | The active slide's description; also the dialog's accessible description. |
|
|
64
|
+
| footer | `DialogFooterCarousel` (`variant="carousel"` only). |
|
|
65
|
+
| primaryAction | Call-to-action `Button` (`variant="single"` only). |
|
|
66
|
+
| close | Ghost `Button` that dismisses the dialog (`variant="single"` only). |
|
|
67
|
+
|
|
68
|
+
## Example
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { DialogWelcome } from '@acronis-platform/ui-react';
|
|
72
|
+
|
|
73
|
+
<DialogWelcome
|
|
74
|
+
variant="carousel"
|
|
75
|
+
slides={[
|
|
76
|
+
{ title: 'Automated backups', description: 'Your data is backed up on a schedule you control.' },
|
|
77
|
+
{ title: 'Instant recovery', description: 'Restore a full workload in minutes, not hours.' },
|
|
78
|
+
]}
|
|
79
|
+
open={open}
|
|
80
|
+
onOpenChange={setOpen}
|
|
81
|
+
onPrimaryAction={() => setOpen(false)}
|
|
82
|
+
/>
|
|
83
|
+
|
|
84
|
+
<DialogWelcome
|
|
85
|
+
variant="single"
|
|
86
|
+
title="You're all set"
|
|
87
|
+
description="Your workspace is ready to go."
|
|
88
|
+
primaryLabel="Get started"
|
|
89
|
+
open={open}
|
|
90
|
+
onOpenChange={setOpen}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Props
|
|
95
|
+
|
|
96
|
+
| Prop | Type | Default | Required | Description |
|
|
97
|
+
|------|------|---------|----------|-------------|
|
|
98
|
+
| `variant` | `'carousel' | 'single'` | `'carousel'` | no | Selects the Figma-defined layout. |
|
|
99
|
+
| `slides` | `Array<{ image?: ReactNode; title: string; description: string }>` | `3-item placeholder ('Title' / 'Feature description.')` | no | Slides shown one at a time (`variant="carousel"`). |
|
|
100
|
+
| `selected-index` | `number` | — | no | Controls the active slide (`variant="carousel"`). Uncontrolled (starting at `0`) when omitted. |
|
|
101
|
+
| `back-label` | `string` | `'Back'` | no | `Back` button label (`variant="carousel"`). |
|
|
102
|
+
| `next-label` | `string` | `'Next'` | no | `Next` button label (`variant="carousel"`). |
|
|
103
|
+
| `go-to-slide-label` | `(index: number, count: number) => string` | — | no | Builds each carousel dot's accessible name (`variant="carousel"`). |
|
|
104
|
+
| `image` | `ReactNode` | — | no | Illustration/media (`variant="single"`). |
|
|
105
|
+
| `title` | `string` | `'Title'` | no | `variant="single"` title. |
|
|
106
|
+
| `description` | `string` | `'Feature description.'` | no | `variant="single"` description. |
|
|
107
|
+
| `close-label` | `string` | `'Close'` | no | `Close` link label (`variant="single"`). |
|
|
108
|
+
| `primary-label` | `string` | `'Call to action'` | no | Call-to-action button label. |
|
|
109
|
+
| `open` | `boolean` | — | no | Controlled open state. Pair with the change event. |
|
|
110
|
+
| `default-open` | `boolean` | `false` | no | Initial open state when uncontrolled (React `defaultOpen`). |
|
|
111
|
+
| `modal` | `boolean | 'trap-focus'` | `true` | no | Modal behavior — traps focus and locks background scroll while open. |
|
|
112
|
+
| `portal` | `boolean` | `true` | no | Render the popup inside a portal (forwarded to `DialogContent`). |
|
|
113
|
+
| `keep-mounted` | `boolean` | — | no | Keep the popup mounted while closed (forwarded to `DialogContent`). |
|
|
114
|
+
|
|
115
|
+
## Events
|
|
116
|
+
|
|
117
|
+
| Event | Payload | Description |
|
|
118
|
+
|-------|---------|-------------|
|
|
119
|
+
| `open-change` | `boolean` | Fired when the dialog opens or closes (React `onOpenChange`). |
|
|
120
|
+
| `selected-index-change` | `number` | Fired whenever the active slide changes (React `onSelectedIndexChange`, `variant="carousel"`). |
|
|
121
|
+
| `close-action` | `undefined` | Fired when `Close` is activated, before the dialog closes (React `onCloseAction`, `variant="single"`). |
|
|
122
|
+
| `primary-action` | `undefined` | Fired when the call-to-action button is activated (React `onPrimaryAction`). |
|
|
123
|
+
|
|
124
|
+
## Behavior
|
|
125
|
+
|
|
126
|
+
```gherkin
|
|
127
|
+
Scenario: Opening the carousel variant
|
|
128
|
+
Given a DialogWelcome with variant="carousel" and 3 slides
|
|
129
|
+
When it opens
|
|
130
|
+
Then the first slide's image/title/description render
|
|
131
|
+
And the footer renders with variant="start" (no Back, Next visible)
|
|
132
|
+
And the dot indicator marks the first dot active
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```gherkin
|
|
136
|
+
Scenario: Advancing through the carousel
|
|
137
|
+
Given an open DialogWelcome carousel on a middle slide
|
|
138
|
+
When Next is activated
|
|
139
|
+
Then the carousel scrolls to the next slide
|
|
140
|
+
And onSelectedIndexChange fires with the new index
|
|
141
|
+
And the footer's variant updates (start/middle/end) to match the new position
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```gherkin
|
|
145
|
+
Scenario: Reaching the last slide
|
|
146
|
+
Given an open DialogWelcome carousel on the last slide
|
|
147
|
+
Then the footer renders with variant="end"
|
|
148
|
+
And its call-to-action button (default "Call to action") replaces Next
|
|
149
|
+
When the call-to-action button is activated
|
|
150
|
+
Then onPrimaryAction fires — the dialog does not close automatically
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```gherkin
|
|
154
|
+
Scenario: Jumping directly to a slide
|
|
155
|
+
Given an open DialogWelcome carousel
|
|
156
|
+
When a dot other than the active one is activated
|
|
157
|
+
Then the carousel scrolls directly to that slide
|
|
158
|
+
And onSelectedIndexChange fires with its index
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```gherkin
|
|
162
|
+
Scenario: Controlled without a change handler
|
|
163
|
+
Given an open DialogWelcome carousel with a controlled `selectedIndex`
|
|
164
|
+
and no `onSelectedIndexChange` wired
|
|
165
|
+
When Back, Next, or a dot is activated
|
|
166
|
+
Then nothing happens — these controls only ever call
|
|
167
|
+
`onSelectedIndexChange`, which is absent, so the carousel cannot move
|
|
168
|
+
When a drag gesture moves the carousel's physical position directly
|
|
169
|
+
Then it snaps back to the controlled `selectedIndex` instead of leaving
|
|
170
|
+
the visible slide out of sync with the slide carrying the dialog's
|
|
171
|
+
accessible name
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```gherkin
|
|
175
|
+
Scenario: Non-active slides are inert
|
|
176
|
+
Given an open DialogWelcome carousel with more than one slide
|
|
177
|
+
Then every slide except the active one is `aria-hidden` and `inert` —
|
|
178
|
+
unreachable by keyboard/screen reader until it becomes active
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```gherkin
|
|
182
|
+
Scenario: Opening the single variant
|
|
183
|
+
Given a DialogWelcome with variant="single"
|
|
184
|
+
When it opens
|
|
185
|
+
Then the image/title/description render once, with no footer
|
|
186
|
+
And a primary call-to-action button and a "Close" link render below it
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```gherkin
|
|
190
|
+
Scenario: Closing from the single variant
|
|
191
|
+
Given an open DialogWelcome with variant="single"
|
|
192
|
+
When Close is activated
|
|
193
|
+
Then onCloseAction fires
|
|
194
|
+
And the dialog closes (Dialog.Close's default behavior)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Accessibility
|
|
198
|
+
|
|
199
|
+
- Reuses Base UI `Dialog.Root`/`Dialog.Popup` (via `DialogContent`) for focus
|
|
200
|
+
trapping, scroll locking, `role="dialog"`/`aria-modal`, and Escape/
|
|
201
|
+
outside-press dismissal — the same primitive `Dialog` builds on.
|
|
202
|
+
- Exactly one `Dialog.Title`/`Dialog.Description` pair is mounted at a time —
|
|
203
|
+
the active slide's (`variant="carousel"`) or the single body's
|
|
204
|
+
(`variant="single"`). This keeps `aria-labelledby`/`aria-describedby`
|
|
205
|
+
pointed at real, visible content instead of an off-screen duplicate.
|
|
206
|
+
- **Non-active carousel slides are hidden from assistive tech and the
|
|
207
|
+
keyboard** (`aria-hidden` + `inert`) — a screen reader or Tab press cannot
|
|
208
|
+
land on a slide that isn't currently shown, which a naive "just clip it
|
|
209
|
+
visually" carousel would get wrong.
|
|
210
|
+
- The footer's `Back`/`Next`/call-to-action controls and dot indicators
|
|
211
|
+
inherit `DialogFooterCarousel`'s accessibility contract (see its own
|
|
212
|
+
`accessibility.md`) — real `<button>`s, explicit dot labels, `aria-current`
|
|
213
|
+
on the active dot.
|
|
214
|
+
- `variant="single"`'s primary action and `Close` are both real `Button`s;
|
|
215
|
+
`Close` is wrapped in `Dialog.Close` so Escape and the button both dismiss
|
|
216
|
+
the same way.
|
|
217
|
+
|
|
218
|
+
## Contrast
|
|
219
|
+
|
|
220
|
+
`image`'s placeholder surface (`--ui-background-surface-active`) and
|
|
221
|
+
`title`/`description`'s text (`--ui-text-on-surface-primary`, bridged via
|
|
222
|
+
`text-foreground`) are the same semantic surface/text pairing used across the
|
|
223
|
+
kit — contrast-checked in both light and dark by construction.
|