@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,146 @@
|
|
|
1
|
+
# EmptyOverlay
|
|
2
|
+
|
|
3
|
+
> A full-bleed empty-state overlay — a colored icon badge over a centered title/description, on a fade-to-solid backdrop. Meant to sit over other content (e.g. a frozen/blurred widget preview); the developer sizes it (typically `absolute inset-0` over a positioned parent).
|
|
4
|
+
|
|
5
|
+
**Status:** ready · **Category:** data-display · **Since:** v2.1.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { EmptyOverlay } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<div className="relative h-96">
|
|
17
|
+
<EmptyOverlay
|
|
18
|
+
icon={<InboxIcon />}
|
|
19
|
+
title="No object yet"
|
|
20
|
+
description="Short description."
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
A full-bleed empty-state overlay: a colored icon badge over a centered
|
|
26
|
+
title/description, on a fade-to-solid backdrop.
|
|
27
|
+
|
|
28
|
+
## When to use
|
|
29
|
+
|
|
30
|
+
- Overlay a "no data yet" message on top of other content — e.g. a
|
|
31
|
+
frozen/blurred widget preview behind the message.
|
|
32
|
+
- As a standalone empty state that should fill its container edge-to-edge.
|
|
33
|
+
|
|
34
|
+
## When not to use
|
|
35
|
+
|
|
36
|
+
- For a plain, non-overlay empty state with no background treatment — use
|
|
37
|
+
`Empty`'s composable parts instead.
|
|
38
|
+
- For a bordered dashboard-widget card with a header/footer — use
|
|
39
|
+
`WidgetPlaceholder`.
|
|
40
|
+
|
|
41
|
+
## Sizing
|
|
42
|
+
|
|
43
|
+
`EmptyOverlay` always fills its parent (`size-full`) — the developer is
|
|
44
|
+
responsible for sizing and positioning the parent, typically
|
|
45
|
+
`relative` + `absolute inset-0`.
|
|
46
|
+
|
|
47
|
+
## Examples
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { EmptyOverlay } from '@acronis-platform/ui-react';
|
|
51
|
+
import { InboxIcon } from '@acronis-platform/icons-react/stroke-mono';
|
|
52
|
+
|
|
53
|
+
<div className="relative h-96">
|
|
54
|
+
<EmptyOverlay
|
|
55
|
+
icon={<InboxIcon />}
|
|
56
|
+
title="No object yet"
|
|
57
|
+
description="Short description."
|
|
58
|
+
/>
|
|
59
|
+
</div>;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Parts
|
|
63
|
+
|
|
64
|
+
| Part | Element | Purpose |
|
|
65
|
+
| ------------- | ------- | -------------------------------------------- |
|
|
66
|
+
| root | `div` | Fills the parent; fade-to-solid backdrop. |
|
|
67
|
+
| `icon` | `div` | Optional 24px glyph in a 64px colored badge. |
|
|
68
|
+
| `title` | `h3` | The empty-state headline. |
|
|
69
|
+
| `description` | `p` | Optional supporting copy under the title. |
|
|
70
|
+
|
|
71
|
+
## Props
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Default | Required | Description |
|
|
74
|
+
|------|------|---------|----------|-------------|
|
|
75
|
+
| `icon` | `ReactNode` | — | no | Icon rendered in the colored badge (e.g. an `icons-react` glyph at 24px). Omitting it omits the badge entirely. |
|
|
76
|
+
| `title` | `ReactNode` | — | yes | The empty-state headline, rendered as an `<h3>`. |
|
|
77
|
+
| `description` | `ReactNode` | — | no | Optional supporting copy shown under the title. |
|
|
78
|
+
| `color` | `'teal' | 'violet' | 'red' | 'yellow' | 'orange' | 'blue' | 'gray' | 'green'` | `green` | no | Icon badge color scheme, from the shared avatar palette. Maps to `--ui-avatar-color-<scheme>` (badge fill) and `--ui-avatar-label-color-<scheme>` (icon color). |
|
|
79
|
+
|
|
80
|
+
## Behavior
|
|
81
|
+
|
|
82
|
+
### Fills its container
|
|
83
|
+
|
|
84
|
+
**Given** an `EmptyOverlay`
|
|
85
|
+
**When** it renders
|
|
86
|
+
**Then** it fills the width and height of its parent (`size-full`) and centers
|
|
87
|
+
its content — the developer is responsible for sizing/positioning the parent
|
|
88
|
+
(e.g. `relative` + `absolute inset-0` to overlay other content).
|
|
89
|
+
|
|
90
|
+
### Icon badge
|
|
91
|
+
|
|
92
|
+
**Given** an `icon`
|
|
93
|
+
**When** it renders
|
|
94
|
+
**Then** a 64px circular badge shows above the title, holding the icon at
|
|
95
|
+
24px; the badge's fill/icon color come from the `color` prop (default
|
|
96
|
+
`green`).
|
|
97
|
+
**Given** no `icon`
|
|
98
|
+
**Then** the badge is omitted entirely — only the title/description center.
|
|
99
|
+
|
|
100
|
+
### Color
|
|
101
|
+
|
|
102
|
+
**Given** `color` set to one of the eight avatar palette values (`teal`,
|
|
103
|
+
`violet`, `red`, `yellow`, `orange`, `blue`, `gray`, `green`)
|
|
104
|
+
**When** it renders
|
|
105
|
+
**Then** the badge's fill and icon color resolve from that color's
|
|
106
|
+
`--ui-avatar-color-<color>` / `--ui-avatar-label-color-<color>` tokens
|
|
107
|
+
**And** with no `color` it defaults to `green`.
|
|
108
|
+
|
|
109
|
+
### Title / description
|
|
110
|
+
|
|
111
|
+
**Given** a `title`
|
|
112
|
+
**When** it renders
|
|
113
|
+
**Then** it shows as an `<h3>` headline below the badge.
|
|
114
|
+
**Given** a `description`
|
|
115
|
+
**When** it renders
|
|
116
|
+
**Then** it shows as supporting copy below the title.
|
|
117
|
+
**Given** no `description`
|
|
118
|
+
**Then** only the title renders.
|
|
119
|
+
|
|
120
|
+
### Non-interactive
|
|
121
|
+
|
|
122
|
+
**Given** an `EmptyOverlay`
|
|
123
|
+
**When** the user hovers or clicks it
|
|
124
|
+
**Then** nothing happens — it is a presentational placeholder, not a control.
|
|
125
|
+
|
|
126
|
+
## Accessibility
|
|
127
|
+
|
|
128
|
+
## Semantics
|
|
129
|
+
|
|
130
|
+
- The root is a plain, non-interactive `<div>` — no role, not a live region.
|
|
131
|
+
If the overlay replaces content that a screen reader user was tracking
|
|
132
|
+
(e.g. it appears after a failed load), the consumer is responsible for any
|
|
133
|
+
live-region announcement at the point where the overlay is mounted.
|
|
134
|
+
- `title` renders as an `<h3>`, so it participates in the page's heading
|
|
135
|
+
outline — pick a container level that keeps that hierarchy sensible.
|
|
136
|
+
- The icon badge is decorative (the title/description already carry the
|
|
137
|
+
meaning); it needs no accessible name of its own.
|
|
138
|
+
|
|
139
|
+
## Keyboard & focus
|
|
140
|
+
|
|
141
|
+
- Not focusable and not in the tab order — there is nothing to activate.
|
|
142
|
+
|
|
143
|
+
## Contrast
|
|
144
|
+
|
|
145
|
+
- Each badge color's fill/icon pair, and the title/description text colors,
|
|
146
|
+
resolve from tokens that meet contrast in both light and dark themes.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Empty
|
|
2
|
+
|
|
3
|
+
> A centered empty-state placeholder shown when there is no data or content. A set of composable parts (icon, header, title, description, actions, links). Ported from the legacy shadcn-uikit `Empty`; themed by the shared semantic text tokens.
|
|
4
|
+
|
|
5
|
+
**Status:** draft · **Category:** data-display · **Since:** v0.13.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Empty, EmptyIcon, EmptyHeader, EmptyTitle, EmptyDescription, EmptyActions, EmptyLinks } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<Empty>
|
|
17
|
+
<EmptyIcon>
|
|
18
|
+
<InboxIcon />
|
|
19
|
+
</EmptyIcon>
|
|
20
|
+
<EmptyHeader>
|
|
21
|
+
<EmptyTitle>No backups found</EmptyTitle>
|
|
22
|
+
<EmptyDescription>Create your first backup plan.</EmptyDescription>
|
|
23
|
+
</EmptyHeader>
|
|
24
|
+
<EmptyActions>
|
|
25
|
+
<Button>Create backup plan</Button>
|
|
26
|
+
</EmptyActions>
|
|
27
|
+
</Empty>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
A centered empty-state placeholder shown when there is no data or content.
|
|
31
|
+
Composable from parts; no variants.
|
|
32
|
+
|
|
33
|
+
> **Status: draft (design-pending v1).** Ported from the legacy
|
|
34
|
+
> `@acronis-platform/shadcn-uikit` `Empty`. No `--ui-empty-*` token tier yet, so
|
|
35
|
+
> it themes from the shared semantic text tokens (title `text-foreground`,
|
|
36
|
+
> description/icon `text-muted-foreground`). Reconcile with
|
|
37
|
+
> `/figma-component Empty <url> --update` once a mockup lands.
|
|
38
|
+
|
|
39
|
+
## When to use
|
|
40
|
+
|
|
41
|
+
- A list, table, or panel that has no items yet (or none match a filter).
|
|
42
|
+
- A first-run state inviting the user to create the first item.
|
|
43
|
+
|
|
44
|
+
## When not to use
|
|
45
|
+
|
|
46
|
+
- For a loading state — use a spinner/skeleton, not Empty.
|
|
47
|
+
- For an error state — show an error with a retry, not a neutral empty.
|
|
48
|
+
- For a blocking message — use a Dialog.
|
|
49
|
+
|
|
50
|
+
## Parts
|
|
51
|
+
|
|
52
|
+
| Part | Element | Purpose |
|
|
53
|
+
| ------------------ | ------- | -------------------------------------- |
|
|
54
|
+
| `Empty` | `div` | Centered container (max 448px), muted. |
|
|
55
|
+
| `EmptyIcon` | `div` | Optional 72px illustration/glyph slot. |
|
|
56
|
+
| `EmptyHeader` | `div` | Groups the title + description. |
|
|
57
|
+
| `EmptyTitle` | `h3` | The heading (foreground color). |
|
|
58
|
+
| `EmptyDescription` | `p` | Supporting copy (muted). |
|
|
59
|
+
| `EmptyActions` | `div` | Primary action(s), e.g. a Button. |
|
|
60
|
+
| `EmptyLinks` | `div` | Secondary supporting link(s). |
|
|
61
|
+
|
|
62
|
+
## Example
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import {
|
|
66
|
+
Empty,
|
|
67
|
+
EmptyIcon,
|
|
68
|
+
EmptyHeader,
|
|
69
|
+
EmptyTitle,
|
|
70
|
+
EmptyDescription,
|
|
71
|
+
EmptyActions,
|
|
72
|
+
Button,
|
|
73
|
+
} from '@acronis-platform/ui-react';
|
|
74
|
+
import { InboxIcon } from '@acronis-platform/icons-react/stroke-mono';
|
|
75
|
+
|
|
76
|
+
<Empty>
|
|
77
|
+
<EmptyIcon>
|
|
78
|
+
<InboxIcon />
|
|
79
|
+
</EmptyIcon>
|
|
80
|
+
<EmptyHeader>
|
|
81
|
+
<EmptyTitle>No backups found</EmptyTitle>
|
|
82
|
+
<EmptyDescription>Create your first backup plan.</EmptyDescription>
|
|
83
|
+
</EmptyHeader>
|
|
84
|
+
<EmptyActions>
|
|
85
|
+
<Button>Create backup plan</Button>
|
|
86
|
+
</EmptyActions>
|
|
87
|
+
</Empty>;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Content slots
|
|
91
|
+
|
|
92
|
+
| Slot | Description |
|
|
93
|
+
|------|-------------|
|
|
94
|
+
| `default` | The composed empty state. Author it from the parts: an optional icon, a header (title + description), and optional actions / links. All parts are optional and may be combined as needed. |
|
|
95
|
+
|
|
96
|
+
## Behavior
|
|
97
|
+
|
|
98
|
+
Empty is a presentational placeholder assembled from composable parts. It has no
|
|
99
|
+
props, no variants, and no interaction state — it is a pure function of its
|
|
100
|
+
composition.
|
|
101
|
+
|
|
102
|
+
### Composition
|
|
103
|
+
|
|
104
|
+
```gherkin
|
|
105
|
+
Scenario: A full empty state
|
|
106
|
+
Given an Empty wrapping an EmptyIcon, an EmptyHeader (EmptyTitle +
|
|
107
|
+
EmptyDescription), and EmptyActions
|
|
108
|
+
When it renders
|
|
109
|
+
Then the icon, title, description, and actions stack centered in source order
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```gherkin
|
|
113
|
+
Scenario: Parts are optional
|
|
114
|
+
Given an Empty wrapping only an EmptyHeader with an EmptyTitle
|
|
115
|
+
When it renders
|
|
116
|
+
Then just the title shows, centered — no icon or actions space is reserved
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Usage
|
|
120
|
+
|
|
121
|
+
```gherkin
|
|
122
|
+
Scenario: Filling a region
|
|
123
|
+
Given a list or table with no rows
|
|
124
|
+
When the consumer renders an Empty in its place
|
|
125
|
+
Then the empty state is centered within that region (the consumer sizes it)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Accessibility
|
|
129
|
+
|
|
130
|
+
Empty is presentational; accessibility is mostly about the heading and the icon.
|
|
131
|
+
|
|
132
|
+
## Roles & semantics
|
|
133
|
+
|
|
134
|
+
- `EmptyTitle` renders an `<h3>`. Make sure that level fits the surrounding
|
|
135
|
+
document outline — if the empty state replaces a section whose heading was a
|
|
136
|
+
different level, set the heading appropriately (override via `className`/markup
|
|
137
|
+
as needed). Don't skip levels.
|
|
138
|
+
- `EmptyDescription` is a `<p>` associated with the title by proximity.
|
|
139
|
+
- The `EmptyIcon` is decorative — mark its SVG `aria-hidden="true"` so it isn't
|
|
140
|
+
announced (the title carries the meaning).
|
|
141
|
+
- When the empty state appears **in response to an async action** (e.g. a search
|
|
142
|
+
returned nothing, or data finished loading empty), wrap it (or a status region)
|
|
143
|
+
with `role="status"` / `aria-live="polite"` so screen-reader users are told the
|
|
144
|
+
result. Empty itself does not impose a role.
|
|
145
|
+
|
|
146
|
+
## Keyboard
|
|
147
|
+
|
|
148
|
+
- Empty has no interactive behavior. Any controls placed in `EmptyActions` /
|
|
149
|
+
`EmptyLinks` (Buttons, Links) keep their own focus and keyboard behavior.
|
|
150
|
+
|
|
151
|
+
## Contrast
|
|
152
|
+
|
|
153
|
+
- The title uses `--ui-text-on-surface-primary`; the description and icon use
|
|
154
|
+
`--ui-text-on-surface-secondary` — both meet WCAG AA against the page surface in
|
|
155
|
+
light and dark. Re-verify against the final palette once a `--ui-empty-*` tier
|
|
156
|
+
and Figma reference exist.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Field
|
|
2
|
+
|
|
3
|
+
> A form-field wrapper that ties a control to its label, description, and error, built on Base UI's Field primitive so those associations (and the validity state) are wired automatically. Ships structural parts (fieldset, legend, group, content, separator) for composing and grouping fields. Ported from the legacy shadcn-uikit `field`.
|
|
4
|
+
|
|
5
|
+
**Status:** draft · **Category:** forms · **Since:** v0.47.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Field, FieldLabel, FieldControl, FieldDescription, FieldError } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<Field>
|
|
17
|
+
<FieldLabel>Email</FieldLabel>
|
|
18
|
+
<FieldControl render={<InputBox />} />
|
|
19
|
+
<FieldDescription>We'll never share it.</FieldDescription>
|
|
20
|
+
</Field>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A form-field wrapper that ties a control to its label, description, and error.
|
|
24
|
+
Built on Base UI's Field primitive, so the `for` / `id` / `aria-describedby` /
|
|
25
|
+
`aria-invalid` associations and the validity state are wired automatically — no
|
|
26
|
+
manual plumbing. Structural parts (`FieldSet`, `FieldLegend`, `FieldGroup`,
|
|
27
|
+
`FieldContent`, `FieldSeparator`) compose and group fields.
|
|
28
|
+
|
|
29
|
+
> **Design-pending v1**, ported from the legacy shadcn-uikit `field` and rebuilt
|
|
30
|
+
> on Base UI Field. Reconcile with Figma later.
|
|
31
|
+
|
|
32
|
+
## When to use
|
|
33
|
+
|
|
34
|
+
- Labelling a **bare** control with a description and/or validation error — the
|
|
35
|
+
primary case is a text field via `FieldControl render={<InputBox />}`.
|
|
36
|
+
- Grouping related controls under a heading (`FieldSet` + `FieldLegend`).
|
|
37
|
+
|
|
38
|
+
## When not to use
|
|
39
|
+
|
|
40
|
+
- A standalone text field with built-in furniture — use `InputText` /
|
|
41
|
+
`InputSearch` / `InputSelect`, which already include label/description/error.
|
|
42
|
+
- Naming a single `Checkbox` / `Switch` — they self-label via their own `label`
|
|
43
|
+
prop. Use `Field`/`FieldSet` only to **group** them.
|
|
44
|
+
|
|
45
|
+
## Parts
|
|
46
|
+
|
|
47
|
+
| Export | Purpose |
|
|
48
|
+
| ------------------ | --------------------------------------------------------------------------------- |
|
|
49
|
+
| `Field` | The field wrapper (Base UI Field.Root). `orientation` lays out label vs. control. |
|
|
50
|
+
| `FieldLabel` | The caption — auto-associated with the control. |
|
|
51
|
+
| `FieldControl` | Wires a bare control; use its `render` prop (e.g. `render={<InputBox />}`). |
|
|
52
|
+
| `FieldDescription` | Helper text — auto-linked via `aria-describedby`. |
|
|
53
|
+
| `FieldError` | Validation message — shown by validity, or forced with `match`. |
|
|
54
|
+
| `FieldContent` | Stacks a label + description beside a control (e.g. a toggle row). |
|
|
55
|
+
| `FieldTitle` | A non-label heading for a field with no single associated control. |
|
|
56
|
+
| `FieldSet` | Native `<fieldset>` grouping related fields. |
|
|
57
|
+
| `FieldLegend` | The fieldset heading — `legend` (large) or `label` (small) `variant`. |
|
|
58
|
+
| `FieldGroup` | A vertical stack of fields / nested groups (container-query context). |
|
|
59
|
+
| `FieldSeparator` | A divider between fields, with an optional centered label. |
|
|
60
|
+
|
|
61
|
+
> `FieldLabel` / `FieldControl` / `FieldDescription` / `FieldError` are Base UI
|
|
62
|
+
> Field parts — they must be rendered **inside a `Field`** (they throw without the
|
|
63
|
+
> Field context). For a group-level heading use `FieldLegend` in a `FieldSet`.
|
|
64
|
+
|
|
65
|
+
## Example
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import {
|
|
69
|
+
Field,
|
|
70
|
+
FieldLabel,
|
|
71
|
+
FieldControl,
|
|
72
|
+
FieldDescription,
|
|
73
|
+
FieldError,
|
|
74
|
+
InputBox,
|
|
75
|
+
} from '@acronis-platform/ui-react';
|
|
76
|
+
|
|
77
|
+
<Field invalid={hasError}>
|
|
78
|
+
<FieldLabel>Email</FieldLabel>
|
|
79
|
+
<FieldControl render={<InputBox type="email" />} />
|
|
80
|
+
<FieldDescription>We'll never share your email.</FieldDescription>
|
|
81
|
+
<FieldError match>Please enter a valid email address.</FieldError>
|
|
82
|
+
</Field>;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Group self-labeling controls:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
<FieldSet>
|
|
89
|
+
<FieldLegend>Notifications</FieldLegend>
|
|
90
|
+
<FieldGroup>
|
|
91
|
+
<Checkbox label="Product updates" />
|
|
92
|
+
<Checkbox label="Security alerts" />
|
|
93
|
+
</FieldGroup>
|
|
94
|
+
</FieldSet>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Props
|
|
98
|
+
|
|
99
|
+
| Prop | Type | Default | Required | Description |
|
|
100
|
+
|------|------|---------|----------|-------------|
|
|
101
|
+
| `orientation` | `'vertical' | 'horizontal' | 'responsive'` | `'vertical'` | no | Label/control layout — stacked, inline, or stacked-then-inline at the @md container width. |
|
|
102
|
+
| `invalid` | `boolean` | — | no | Marks the field invalid (sets data-invalid + the control's aria-invalid). Useful when validation is controlled externally. |
|
|
103
|
+
| `disabled` | `boolean` | `false` | no | Disables the field and its control. |
|
|
104
|
+
| `name` | `string` | — | no | Identifies the field when a form is submitted. |
|
|
105
|
+
| `validate` | `(value, formValues) => string | string[] | null | Promise<…>` | — | no | Custom validation; returns error message(s) or null. |
|
|
106
|
+
| `validationMode` | `'onSubmit' | 'onBlur' | 'onChange'` | `'onSubmit'` | no | When the field validates. |
|
|
107
|
+
| `match` | `boolean | keyof ValidityState` | — | no | On FieldError — which ValidityState shows the message; `true` always shows it (for externally controlled validation). |
|
|
108
|
+
| `variant` | `'legend' | 'label'` | `'legend'` | no | On FieldLegend — large legend text or small label text. |
|
|
109
|
+
|
|
110
|
+
## Behavior
|
|
111
|
+
|
|
112
|
+
Field is built on Base UI's Field primitive. It wires a control to its label,
|
|
113
|
+
description, and error automatically, and pairs with the _bare_ controls
|
|
114
|
+
(`InputBox`, plus the self-labeling `Checkbox` / `Switch` / `RadioGroup` for
|
|
115
|
+
grouping) — not the self-contained `InputText` / `InputSearch` fields.
|
|
116
|
+
|
|
117
|
+
```gherkin
|
|
118
|
+
Scenario: Label associates with the control
|
|
119
|
+
Given a Field with a FieldLabel and a FieldControl render={<InputBox />}
|
|
120
|
+
Then the label's htmlFor matches the control's id (no manual wiring)
|
|
121
|
+
And clicking the label focuses the control
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```gherkin
|
|
125
|
+
Scenario: Description is announced
|
|
126
|
+
Given a Field with a FieldDescription
|
|
127
|
+
Then the control's aria-describedby references the description
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```gherkin
|
|
131
|
+
Scenario: Error on invalid
|
|
132
|
+
Given a Field marked invalid (or failing validation)
|
|
133
|
+
Then data-invalid is set, the control gets aria-invalid
|
|
134
|
+
And a FieldError message is shown (always, when match is forced on)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```gherkin
|
|
138
|
+
Scenario: Orientation
|
|
139
|
+
Given orientation="horizontal"
|
|
140
|
+
Then the label and control lay out in a row
|
|
141
|
+
And orientation="responsive" stacks until the @md container width, then rows
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```gherkin
|
|
145
|
+
Scenario: Group related fields
|
|
146
|
+
Given a FieldSet with a FieldLegend and a FieldGroup of fields
|
|
147
|
+
Then the legend names the group and the fields stack with consistent spacing
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```gherkin
|
|
151
|
+
Scenario: Group self-labeling controls
|
|
152
|
+
Given a FieldSet of Checkboxes that each carry their own label
|
|
153
|
+
Then the set provides the legend + spacing and each control names itself
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```gherkin
|
|
157
|
+
Scenario: Separate fields
|
|
158
|
+
Given a FieldSeparator with text between two fields
|
|
159
|
+
Then a divider renders with the text centered over the rule
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Accessibility
|
|
163
|
+
|
|
164
|
+
Field's purpose is accessibility: it removes the manual wiring that's easy to get
|
|
165
|
+
wrong.
|
|
166
|
+
|
|
167
|
+
- **Label association** is automatic — `FieldLabel` (Base UI `Field.Label`) links
|
|
168
|
+
to the control rendered through `FieldControl`, so no `htmlFor`/`id` plumbing.
|
|
169
|
+
- **Description** is exposed via `aria-describedby` on the control automatically.
|
|
170
|
+
- **Error / invalid:** an invalid field sets `data-invalid` and the control's
|
|
171
|
+
`aria-invalid`; `FieldError` carries `role="alert"` semantics so the message is
|
|
172
|
+
announced. Don't rely on color alone — the message text states the problem.
|
|
173
|
+
- **Grouping:** `FieldSet` is a native `<fieldset>` and `FieldLegend` a
|
|
174
|
+
`<legend>`, so a group of related fields (e.g. a set of checkboxes or radios)
|
|
175
|
+
is named for assistive tech. The field root carries `role="group"`.
|
|
176
|
+
- Pair Field with the **bare** controls. `Checkbox` / `Switch` already self-label
|
|
177
|
+
(their own `label` prop) — let them name themselves inside a `FieldSet`; don't
|
|
178
|
+
double-label them with a `FieldLabel`.
|
|
179
|
+
|
|
180
|
+
## Contrast
|
|
181
|
+
|
|
182
|
+
Error/invalid text uses `--ui-text-on-status-danger` (a readable red on the page
|
|
183
|
+
surface in both themes) — not the bridged `text-destructive`, which resolves to
|
|
184
|
+
the pale danger _surface_. Description text uses the muted
|
|
185
|
+
`--ui-text-on-surface-secondary`; both meet contrast in light and dark.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# FilterCards
|
|
2
|
+
|
|
3
|
+
> A horizontal row container (the Figma `FilterCards` component) that lays out a set of `CardFilter` items, stretching each to an equal share of the available width. Pure layout — it owns no visual styling of its own besides the inter-card gap. Figma's nested `ListCards` slot maps to `children`.
|
|
4
|
+
|
|
5
|
+
**Status:** ready · **Category:** data-display · **Since:** v0.62.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { FilterCards, CardFilter } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<FilterCards>
|
|
17
|
+
<CardFilter label="Total assets" value="125" />
|
|
18
|
+
<CardFilter label="Active filters" value="3" variant="clickable" />
|
|
19
|
+
<CardFilter label="Pending" variant="static-empty" />
|
|
20
|
+
</FilterCards>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A horizontal row container (the Figma `FilterCards` component) for
|
|
24
|
+
`CardFilter` items — Figma's nested `ListCards` slot maps to the `children`
|
|
25
|
+
you pass in. It stretches each child to an equal share of the available width
|
|
26
|
+
and owns the 16px gap between them — pure layout, no visual styling of its
|
|
27
|
+
own.
|
|
28
|
+
|
|
29
|
+
## When to use
|
|
30
|
+
|
|
31
|
+
- A row of stat/filter cards summarizing counts across a dashboard (e.g.
|
|
32
|
+
"Total assets", "Active filters", "Pending").
|
|
33
|
+
- Any number of `CardFilter` children — the row redistributes width evenly as
|
|
34
|
+
the count changes.
|
|
35
|
+
|
|
36
|
+
## When not to use
|
|
37
|
+
|
|
38
|
+
- For a single metric with no siblings — render a bare `CardFilter` instead.
|
|
39
|
+
- For a wrapping grid of cards — `FilterCards` is a single row, not a grid;
|
|
40
|
+
use `Grid`/`Stack` for a wrapping layout.
|
|
41
|
+
|
|
42
|
+
## Examples
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { FilterCards, CardFilter } from '@acronis-platform/ui-react';
|
|
46
|
+
import { SquareDashedIcon } from '@acronis-platform/icons-react/stroke-mono';
|
|
47
|
+
|
|
48
|
+
<FilterCards>
|
|
49
|
+
<CardFilter label="Total assets" value="125" icon={<SquareDashedIcon />} />
|
|
50
|
+
<CardFilter
|
|
51
|
+
variant="clickable"
|
|
52
|
+
label="Active filters"
|
|
53
|
+
value="3"
|
|
54
|
+
icon={<SquareDashedIcon />}
|
|
55
|
+
/>
|
|
56
|
+
<CardFilter variant="static-empty" label="Pending" />
|
|
57
|
+
</FilterCards>;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Overflow
|
|
61
|
+
|
|
62
|
+
Cards shrink to fill the row, but never below their own content's natural
|
|
63
|
+
width — a card's label/value is never clipped. If there are enough cards that
|
|
64
|
+
they no longer fit at that natural width, the row overflows its container.
|
|
65
|
+
`FilterCards` adds no scroll or wrap of its own — wrap the row in a
|
|
66
|
+
horizontally scrollable container if that's the desired behavior:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
<div className="overflow-x-auto">
|
|
70
|
+
<FilterCards>{/* many cards */}</FilterCards>
|
|
71
|
+
</div>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Parts
|
|
75
|
+
|
|
76
|
+
| Part | Element | Description |
|
|
77
|
+
| ------ | ------- | ------------------------------------------------------------------------------------------------- |
|
|
78
|
+
| `root` | `<div>` | The row itself — flex, 16px gap, equal-width children. |
|
|
79
|
+
| `card` | (any) | Consumer-supplied children (typically `CardFilter`), stretched to fill an equal share of the row. |
|
|
80
|
+
|
|
81
|
+
## Props
|
|
82
|
+
|
|
83
|
+
| Prop | Type | Default | Required | Description |
|
|
84
|
+
|------|------|---------|----------|-------------|
|
|
85
|
+
| `render` | `RenderProp` | `undefined` | no | Base UI composition prop on the root — replaces the rendered `<div>` with another element or component while merging props and classes. React-only; other frameworks use their own polymorphism. |
|
|
86
|
+
|
|
87
|
+
## Content slots
|
|
88
|
+
|
|
89
|
+
| Slot | Description |
|
|
90
|
+
|------|-------------|
|
|
91
|
+
| `default` | The cards to lay out in the row — typically a list of `CardFilter` elements. Each child is stretched to an equal share of the available width (flex-1), regardless of how many are passed in. |
|
|
92
|
+
|
|
93
|
+
## Behavior
|
|
94
|
+
|
|
95
|
+
### Layout
|
|
96
|
+
|
|
97
|
+
**Given** a `FilterCards` with two or more children
|
|
98
|
+
**When** it renders
|
|
99
|
+
**Then** the children lay out in a single horizontal row with a 16px gap
|
|
100
|
+
(`--ui-gap-16`) and each child stretches to an equal share of the row's
|
|
101
|
+
width via `flex: 1 1 0%` — except a child whose own content exceeds that
|
|
102
|
+
share, which takes more (see the min-content overflow scenario below).
|
|
103
|
+
|
|
104
|
+
**Given** a single `FilterCards` child
|
|
105
|
+
**When** it renders
|
|
106
|
+
**Then** that child fills the entire row width (equal share of one).
|
|
107
|
+
|
|
108
|
+
**Given** a `CardFilter` child with its own fixed 224px width
|
|
109
|
+
**When** it is composed inside `FilterCards`
|
|
110
|
+
**Then** the row's `flex-1` stretching overrides that fixed width — matching
|
|
111
|
+
the "fill container" sizing Figma applies to each `CardFilter` instance inside
|
|
112
|
+
this composition.
|
|
113
|
+
|
|
114
|
+
**Given** enough children that their combined natural (min-content) width
|
|
115
|
+
exceeds the row
|
|
116
|
+
**When** `FilterCards` renders
|
|
117
|
+
**Then** each card only shrinks down to its own content's natural width — no
|
|
118
|
+
card's label/value is ever clipped — and the row overflows its container
|
|
119
|
+
instead. `FilterCards` adds no scroll or wrap of its own; the consumer is
|
|
120
|
+
responsible for giving the row a scrollable container (e.g.
|
|
121
|
+
`overflow-x-auto`) when that degradation is undesired. There is no design
|
|
122
|
+
spec for this case — Figma only documents the exact-fit composition.
|
|
123
|
+
|
|
124
|
+
**Constraint:** `FilterCards` owns no state of its own — it is a pure function
|
|
125
|
+
of its `children`. Any interaction state (hover, selected, …) lives entirely
|
|
126
|
+
on the child (see `CardFilter`'s own spec).
|
|
127
|
+
|
|
128
|
+
### Composition
|
|
129
|
+
|
|
130
|
+
**Given** a `render` prop (e.g. `<section />`)
|
|
131
|
+
**When** `FilterCards` renders
|
|
132
|
+
**Then** it renders as that element with the row's classes and props merged
|
|
133
|
+
on.
|
|
134
|
+
|
|
135
|
+
**Given** children other than `CardFilter`
|
|
136
|
+
**When** `FilterCards` renders
|
|
137
|
+
**Then** they lay out identically — `FilterCards` does not constrain the
|
|
138
|
+
child type, only its layout.
|
|
139
|
+
|
|
140
|
+
## Accessibility
|
|
141
|
+
|
|
142
|
+
- **Role:** a plain `<div>` (`role="group"` is a reasonable authoring choice,
|
|
143
|
+
not enforced by the component) — pure layout, not a landmark or a list. The
|
|
144
|
+
`render` prop can swap the element.
|
|
145
|
+
- **No component-owned interaction:** `FilterCards` renders no interactive
|
|
146
|
+
element itself. All keyboard/focus/ARIA behavior belongs to its children
|
|
147
|
+
(e.g. `CardFilter`'s `clickable` variant) — see that component's own
|
|
148
|
+
accessibility spec.
|
|
149
|
+
- **Accessible name:** none required on the row itself; if the group of cards
|
|
150
|
+
needs an accessible label (e.g. "Filter summary"), pass `aria-label` — it
|
|
151
|
+
passes through as a native `<div>` attribute.
|
|
152
|
+
- **Reading order:** children read in DOM order, left-to-right in `ltr`,
|
|
153
|
+
mirrored in `rtl` via the browser's default flex-row bidi behavior — no
|
|
154
|
+
logical-vs-physical utility is involved since the row uses `flex` with no
|
|
155
|
+
directional margin/padding.
|
|
156
|
+
- **WCAG:** no component-specific requirements beyond what its children
|
|
157
|
+
contribute (1.3.1 structure is satisfied by DOM order).
|