@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,319 @@
|
|
|
1
|
+
# RadialBarChart
|
|
2
|
+
|
|
3
|
+
> A typed radial-bar-chart composition over the shared `Chart` primitives (a polar/radial type). Plots each data row as a concentric arc sized by `dataKey` and colored per `nameKey` — or, with `dataKeys`, one arc per metric — inside a `ChartContainer` with an optional background track, tooltip, and legend. No variant axes: the sweep (start/end angle), radii and centre are plain props. `valueDomain` scales the arcs against a known range, which is what turns a single value into a readable gauge; `segments` draws such a gauge's ring as notched pieces and `centerLabel` puts the reading in the hole. Ported from the apps/demo `RadialChartPlayground`.
|
|
4
|
+
|
|
5
|
+
**Status:** draft · **Category:** data-display · **Since:** v0.58.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { RadialBarChart } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<RadialBarChart
|
|
17
|
+
config={config}
|
|
18
|
+
data={data}
|
|
19
|
+
dataKey="value"
|
|
20
|
+
nameKey="browser"
|
|
21
|
+
className="h-[360px] w-[360px]"
|
|
22
|
+
/>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
A typed radial-bar-chart built on the shared `Chart` primitives. Give it `data`,
|
|
26
|
+
a per-arc `config`, the value field (`dataKey`), and the label field (`nameKey`);
|
|
27
|
+
it renders a themed recharts `RadialBarChart` — concentric arcs, an optional
|
|
28
|
+
background track, tooltip, and legend included — so you don't hand-compose
|
|
29
|
+
recharts children.
|
|
30
|
+
|
|
31
|
+
Arc colors come from the `palette` prop — a dataviz palette resolving to the
|
|
32
|
+
`--ui-dataviz-*` tokens, `categorical` by default — not from `config`.
|
|
33
|
+
|
|
34
|
+
> **Design-pending v1.** Ported from the apps/demo `RadialChartPlayground`. The
|
|
35
|
+
> chrome is reconciled with Figma later; Code Connect is deferred.
|
|
36
|
+
|
|
37
|
+
## When to use
|
|
38
|
+
|
|
39
|
+
- A compact, decorative comparison of a few categories (device/browser share).
|
|
40
|
+
- A gauge-style progress readout — one value against a known range. This needs
|
|
41
|
+
**`valueDomain`**, not just a half sweep: without a domain every arc is scaled
|
|
42
|
+
against the largest value in the data, so a lone value always fills whatever
|
|
43
|
+
sweep it is given. Pair it with `centerLabel` for the reading, and `segments`
|
|
44
|
+
for the notched-ring look.
|
|
45
|
+
- When the circular form is worth more than precise value comparison.
|
|
46
|
+
|
|
47
|
+
## When not to use
|
|
48
|
+
|
|
49
|
+
- Accurate magnitude comparison — a bar chart is far easier to read (arc length
|
|
50
|
+
on a curve distorts).
|
|
51
|
+
- Part-to-whole of a single total — a pie/donut reads more directly.
|
|
52
|
+
- A trend over time — use a line or area chart.
|
|
53
|
+
|
|
54
|
+
## Variants
|
|
55
|
+
|
|
56
|
+
None. RadialBarChart has no CVA variant axes — its sweep (`startAngle` /
|
|
57
|
+
`endAngle`), radii (`innerRadius` / `outerRadius`) and centre (`cx` / `cy`) are
|
|
58
|
+
plain geometry props, so a caller can build a full ring or a half circle;
|
|
59
|
+
`showBackground` toggles the muted track.
|
|
60
|
+
|
|
61
|
+
What the chart _reads as_ is driven by the data mapping rather than a variant:
|
|
62
|
+
one arc per row (the default), one arc per metric (`dataKeys`), or a single-value
|
|
63
|
+
gauge scaled by `valueDomain` — optionally with its ring notched into `segments`.
|
|
64
|
+
|
|
65
|
+
## Example
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { RadialBarChart } from '@acronis-platform/ui-react';
|
|
69
|
+
import type { ChartConfig } from '@acronis-platform/ui-react';
|
|
70
|
+
|
|
71
|
+
const data = [
|
|
72
|
+
{ browser: 'Chrome', value: 65 },
|
|
73
|
+
{ browser: 'Safari', value: 50 },
|
|
74
|
+
{ browser: 'Firefox', value: 35 },
|
|
75
|
+
{ browser: 'Edge', value: 25 },
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
const config = {
|
|
79
|
+
Chrome: { label: 'Chrome', color: 'var(--ui-background-brand-secondary)' },
|
|
80
|
+
Safari: {
|
|
81
|
+
label: 'Safari',
|
|
82
|
+
color: 'var(--ui-background-status-strong-danger)',
|
|
83
|
+
},
|
|
84
|
+
Firefox: {
|
|
85
|
+
label: 'Firefox',
|
|
86
|
+
color: 'var(--ui-background-status-strong-success)',
|
|
87
|
+
},
|
|
88
|
+
Edge: { label: 'Edge', color: 'var(--ui-background-status-strong-warning)' },
|
|
89
|
+
} satisfies ChartConfig;
|
|
90
|
+
|
|
91
|
+
<RadialBarChart
|
|
92
|
+
config={config}
|
|
93
|
+
data={data}
|
|
94
|
+
dataKey="value"
|
|
95
|
+
nameKey="browser"
|
|
96
|
+
className="h-[360px] w-[360px]"
|
|
97
|
+
/>;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Arc colors reference existing semantic `--ui-*` tokens, keyed by each arc's
|
|
101
|
+
`nameKey` value. `--ui-background-status-strong-*` is chromatic in every brand;
|
|
102
|
+
`--ui-background-brand-secondary` is brand-dependent (blue in `default`, neutral
|
|
103
|
+
in some white-label brands), so it is not color-stable across brands until the
|
|
104
|
+
real data-viz palette lands.
|
|
105
|
+
|
|
106
|
+
## Props
|
|
107
|
+
|
|
108
|
+
| Prop | Type | Default | Required | Description |
|
|
109
|
+
|------|------|---------|----------|-------------|
|
|
110
|
+
| `data` | `ReadonlyArray<Record<string, string | number>>` | — | yes | Row-per-arc data — each row holds a `nameKey` label and a `dataKey` numeric value. |
|
|
111
|
+
| `config` | `ChartConfig` | — | yes | Arcs take their colour from the container's `palette`; each entry, keyed by the arc's `nameKey` value, maps that arc to a `label` and an optional `tone`. Resolved into the `--color-<name>` custom properties the arcs fill from. |
|
|
112
|
+
| `dataKey` | `string` | — | yes | The numeric field that sizes each arc. Ignored when dataKeys is set. |
|
|
113
|
+
| `dataKeys` | `string[]` | — | no | Multi-metric mode: one arc per key instead of one per row, colored and named from config keyed by the KEY (the cartesian-chart convention). Every metric shares one angular scale, so pair it with valueDomain. |
|
|
114
|
+
| `nameKey` | `string` | — | yes | The label field that names each arc (drives legend, tooltip, and the `--color-<name>` lookup). Values should be unique per chart — arcs sharing a name share one config/color entry. |
|
|
115
|
+
| `innerRadius` | `number` | `20` | no | Inner radius of the innermost arc. |
|
|
116
|
+
| `outerRadius` | `number` | `60` | no | Outer radius of the outermost arc. |
|
|
117
|
+
| `startAngle` | `number` | `90` | no | Angle (degrees) the arcs sweep from. |
|
|
118
|
+
| `endAngle` | `number` | `-270` | no | Angle (degrees) the arcs sweep to (default is a full clockwise circle). |
|
|
119
|
+
| `valueDomain` | `[number, number]` | — | no | The value range the sweep represents. Without it every arc is drawn relative to the largest value in the data, so a single value always fills the sweep — which is never what a gauge means. |
|
|
120
|
+
| `cornerRadius` | `number` | `4` | no | Corner radius on each arc's ends. |
|
|
121
|
+
| `cx` | `number | string` | `'50%'` | no | Horizontal center of the arcs, in px or a percentage of the width. |
|
|
122
|
+
| `cy` | `number | string` | `'50%'` | no | Vertical center of the arcs, in px or a percentage of the height. Worth moving for a half-circle gauge, whose drawn half otherwise sits in the upper half of the surface. |
|
|
123
|
+
| `barSize` | `number` | — | no | Thickness of each arc, in px. Omit to let the radii and gaps size it. |
|
|
124
|
+
| `barGap` | `number | string` | — | no | Gap between the arcs of different metrics in one band, in px. |
|
|
125
|
+
| `barCategoryGap` | `number | string` | — | no | Gap between bands, in px or a percentage string. |
|
|
126
|
+
| `minAngle` | `number` | — | no | Smallest angle a non-zero arc may occupy, in degrees, so a tiny value stays visible. The floor also applies to a 0, which then reads as a small positive — leave unset when a metric can legitimately be zero. |
|
|
127
|
+
| `margin` | `{ top?: number; right?: number; bottom?: number; left?: number }` | — | no | Plot-area margin, in px. Omit for recharts' default (5 a side). |
|
|
128
|
+
| `segments` | `number` | — | no | Draw a single-value gauge's ring as this many equal segments, notched apart. Needs valueDomain, and applies only to a single-value gauge: anything else — more than one row, dataKeys set, fewer than two segments, or a dataKey value that is not a number — falls back to the normal concentric arcs (legend included) rather than erroring. The ring is then synthetic geometry, so the arc labels and the legend are suppressed and showBackground is redundant (the unreached segments are the track); the tooltip reads the metric wherever the ring is hovered. |
|
|
129
|
+
| `segmentGap` | `number` | `3` | no | Gap between a segmented gauge's segments, in degrees. Clamped so the segments always keep at least half the sweep. |
|
|
130
|
+
| `centerLabel` | `{ value?: string | number; label?: string | number }` | — | no | The readout in the hole — a headline value and/or a caption, stacked and centered. Needs an innerRadius big enough to hold the text; it is not clipped to the hole. |
|
|
131
|
+
| `showPolarGrid` | `boolean` | `false` | no | Draw the concentric polar grid behind the arcs. |
|
|
132
|
+
| `showBackground` | `boolean` | `true` | no | Render a muted background track behind each arc. |
|
|
133
|
+
| `showTooltip` | `boolean` | `true` | no | Render the hover tooltip. |
|
|
134
|
+
| `showLegend` | `boolean` | `true` | no | Render the legend. |
|
|
135
|
+
| `legendValueFormatter` | `(value: string | number) => string` | — | no | Format each arc's value in the list legend. Ignored in multi-metric mode (values are per-row, not per-series). |
|
|
136
|
+
| `tooltipContent` | `ReactElement | ((props) => ReactNode)` | — | no | Replace the default tooltip. Pass a configured ChartTooltipContent (from this library) — e.g. with a formatter / labelFormatter — to customize the tooltip content without composing recharts. Ignored when showTooltip is false. |
|
|
137
|
+
| `animate` | `boolean` | `false` | no | Enable entrance animation. Off by default so output/baselines are unchanged. |
|
|
138
|
+
| `animationDuration` | `number` | — | no | Animation duration in ms. |
|
|
139
|
+
| `animationBegin` | `number` | — | no | Delay before the animation starts, in ms. |
|
|
140
|
+
| `animationEasing` | `'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear'` | — | no | Easing curve. |
|
|
141
|
+
| `showLabels` | `boolean` | `false` | no | Render a value label on each data point/segment. |
|
|
142
|
+
| `labelPosition` | `'outside' | 'center' | 'centerTop' | 'centerBottom' | 'insideStart' | 'insideEnd' | 'end'` | `'insideStart'` | no | Where the value labels sit on the arc. Polar positions only — the cartesian ones collapse to the same mid-radius placement. Inside placements switch the label to the on-fill token. |
|
|
143
|
+
| `labelFormat` | `'value' | 'name-value'` | `'value'` | no | What each data label reads — the value alone, or the arc's name and its value. The name is the row's nameKey value, or the metric's config label in multi-metric mode. |
|
|
144
|
+
| `labelFormatter` | `(value) => string` | — | no | Format each label value (reuses the tick formatters). Formats only the numeric part, so a label and its tooltip stay in the same units. |
|
|
145
|
+
|
|
146
|
+
## Behavior
|
|
147
|
+
|
|
148
|
+
`RadialBarChart` is a typed [recharts](https://recharts.org) composition over the
|
|
149
|
+
shared `Chart` primitives. It plots each data row as a concentric arc sized by
|
|
150
|
+
`dataKey` and colored per `nameKey`, inside a `ChartContainer`.
|
|
151
|
+
|
|
152
|
+
```gherkin
|
|
153
|
+
Scenario: Render arcs from data and config
|
|
154
|
+
Given data rows and a config mapping each arc name to a label and color
|
|
155
|
+
And dataKey "value" and nameKey "browser"
|
|
156
|
+
Then one concentric arc renders per row, sized by its dataKey value
|
|
157
|
+
And each arc fills from its injected --color-<name> custom property
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
```gherkin
|
|
161
|
+
Scenario: Full circle (default)
|
|
162
|
+
Given startAngle 90 and endAngle -270
|
|
163
|
+
Then the arcs sweep a full clockwise circle
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```gherkin
|
|
167
|
+
Scenario: Gauge
|
|
168
|
+
Given startAngle 180 and endAngle 0
|
|
169
|
+
Then the arcs sweep a half circle (a gauge)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The sweep's **direction** is the order of its two angles — `90 → -270` runs
|
|
173
|
+
clockwise, `-270 → 90` counter-clockwise. There is no separate `clockWise` prop:
|
|
174
|
+
recharts 3 exposes none for a radial bar, and the angles already say it.
|
|
175
|
+
|
|
176
|
+
```gherkin
|
|
177
|
+
Scenario: A single value needs a scale to read as a gauge
|
|
178
|
+
Given one data row and no valueDomain
|
|
179
|
+
Then its arc fills the whole sweep, because the row is its own maximum
|
|
180
|
+
But given valueDomain [0, 100] and a value of 65
|
|
181
|
+
Then the arc covers 65% of the sweep over the background track
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```gherkin
|
|
185
|
+
Scenario: Center readout
|
|
186
|
+
Given centerLabel { value, label }
|
|
187
|
+
Then the value renders large and the caption under it, centered in the hole
|
|
188
|
+
And the block is centered as a whole when both lines are present
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```gherkin
|
|
192
|
+
Scenario: Multi-metric
|
|
193
|
+
Given dataKeys ["used", "quota"]
|
|
194
|
+
Then one arc renders per metric, not one per row
|
|
195
|
+
And each takes its color and legend label from config keyed by that metric
|
|
196
|
+
And nameKey names the band the metrics share
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Segment gaps are **decorative on a pie (`paddingAngle`) but structural here**: a
|
|
200
|
+
radial arc has no padding of its own, so a notched ring is built by laying the
|
|
201
|
+
pieces out as one stack of synthetic series measured in degrees. That is what
|
|
202
|
+
`segments` does — and it is deliberately scoped to a single-value gauge, where the
|
|
203
|
+
pieces mean something; concentric rows keep the clean single-arc rendering.
|
|
204
|
+
|
|
205
|
+
```gherkin
|
|
206
|
+
Scenario: Segmented gauge
|
|
207
|
+
Given one data row, valueDomain [0, 38], a value of 29 and segments 8
|
|
208
|
+
Then the ring renders as 8 equal segments separated by transparent notches
|
|
209
|
+
And the segments up to 29/38 of the drawn ring take the arc's color
|
|
210
|
+
And the rest take the track's muted surface
|
|
211
|
+
And the notches never eat into the value's proportion
|
|
212
|
+
And the arc labels and the legend are suppressed (the pieces are not data rows)
|
|
213
|
+
And hovering anywhere on the ring reads the metric and its maximum
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```gherkin
|
|
217
|
+
Scenario: Segments only apply to a single-value gauge
|
|
218
|
+
Given segments is set
|
|
219
|
+
But data holds more than one row, or dataKeys is set,
|
|
220
|
+
or segments is fewer than two, or the dataKey value is not a number
|
|
221
|
+
Then the chart renders its normal concentric arcs, legend included,
|
|
222
|
+
and ignores segments
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```gherkin
|
|
226
|
+
Scenario: A domain that cannot place a value
|
|
227
|
+
Given segments and a valueDomain with no span ([n, n]) or an inverted one
|
|
228
|
+
Then the ring renders as all track and no value is claimed
|
|
229
|
+
Because a gauge that cannot read its scale must not report progress
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```gherkin
|
|
233
|
+
Scenario: A tiny value stays visible
|
|
234
|
+
Given minAngle 12
|
|
235
|
+
Then a non-zero arc smaller than 12 degrees is grown to 12 degrees
|
|
236
|
+
And it grows along the sweep's own direction, not against it
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
```gherkin
|
|
240
|
+
Scenario: Background track
|
|
241
|
+
Given showBackground is true
|
|
242
|
+
Then a muted track renders behind each arc
|
|
243
|
+
But when false only the value arcs render
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
```gherkin
|
|
247
|
+
Scenario: Tooltip on hover
|
|
248
|
+
Given showTooltip is true
|
|
249
|
+
When the user hovers an arc
|
|
250
|
+
Then a card shows that arc's name and value
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
```gherkin
|
|
254
|
+
Scenario: Legend
|
|
255
|
+
Given showLegend is true
|
|
256
|
+
Then a swatch + label renders for each arc (from nameKey / config)
|
|
257
|
+
And in multi-metric mode one renders per metric instead (from dataKeys / config)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```gherkin
|
|
261
|
+
Scenario: Data labels
|
|
262
|
+
Given showLabels is true
|
|
263
|
+
Then each arc carries its value, following the arc from labelPosition
|
|
264
|
+
And labelFormat "name-value" prefixes the arc's name
|
|
265
|
+
And an inside placement switches the label to the on-fill token
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```gherkin
|
|
269
|
+
Scenario: Empty data
|
|
270
|
+
Given data is an empty array
|
|
271
|
+
Then the chart renders with no arcs and does not throw
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```gherkin
|
|
275
|
+
Scenario: Entrance animation is opt-in
|
|
276
|
+
Given animate is unset
|
|
277
|
+
Then the series render at their final geometry with no entrance animation
|
|
278
|
+
And the committed visual baselines are unaffected
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```gherkin
|
|
282
|
+
Scenario: Reduced motion
|
|
283
|
+
Given animate is true
|
|
284
|
+
And a user with prefers-reduced-motion
|
|
285
|
+
Then the entrance animation does not play and the series render at their final geometry
|
|
286
|
+
And the same applies when rendering on the server
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Accessibility
|
|
290
|
+
|
|
291
|
+
- recharts' `accessibilityLayer` is **on by default** (recharts v3), giving the
|
|
292
|
+
chart keyboard focus and an accessible description of the plotted arcs.
|
|
293
|
+
- A radial bar chart is inherently visual and hard to read precisely (arc length
|
|
294
|
+
on a curve is a poor quantitative encoding). **Pair it with a text
|
|
295
|
+
alternative** — a caption, a summary, or an adjacent data table carrying the
|
|
296
|
+
same numbers — and give the chart an accessible name (`aria-label` /
|
|
297
|
+
`aria-labelledby` referencing a visible heading). The wrapper forwards native
|
|
298
|
+
`div` attributes, so `aria-*` pass through.
|
|
299
|
+
- Do **not** rely on color alone to distinguish arcs. Keep `showLegend` (or
|
|
300
|
+
`showLabels`) on so each color is paired with a text label — the radial arcs
|
|
301
|
+
carry none of their own. The tooltip does **not** count as that pairing: it is
|
|
302
|
+
hover/focus-only, so it can't be the only place a value exists.
|
|
303
|
+
- A **segmented gauge** (`segments`) suppresses both the legend and the arc
|
|
304
|
+
labels unconditionally — its ring is geometry, not data rows. `centerLabel` is
|
|
305
|
+
therefore not decorative there but the chart's only always-visible reading;
|
|
306
|
+
give it the value and its scale (`29`, `/ 38 criteria met`).
|
|
307
|
+
- The chrome (tooltip, legend) and the muted background track resolve to semantic
|
|
308
|
+
`--ui-*` tokens that meet contrast in light and dark. **Arc colors are
|
|
309
|
+
caller-supplied** via `config` — pick values that meet 3:1 against the surface
|
|
310
|
+
and are distinguishable for color-vision deficiencies. The borrowed semantic
|
|
311
|
+
tokens are a design-pending stopgap until the `--ui-chart-*` palette lands.
|
|
312
|
+
- Watch recharts issue [#4809](https://github.com/recharts/recharts/issues/4809)
|
|
313
|
+
on the a11y layer for heavily-customized charts.
|
|
314
|
+
|
|
315
|
+
## Contrast
|
|
316
|
+
|
|
317
|
+
Chart chrome and the background track meet contrast in both themes via the
|
|
318
|
+
semantic tokens. Arc fills come from `config` and are the caller's
|
|
319
|
+
responsibility — keep adjacent arcs distinguishable from each other.
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# RadioGroup
|
|
2
|
+
|
|
3
|
+
> A group of mutually exclusive options where exactly one can be selected. Selecting an option deselects the previously selected one. Composed from a RadioGroup container and Radio items.
|
|
4
|
+
|
|
5
|
+
**Status:** ready · **Category:** forms · **Since:** v0.7.0
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { RadioGroup, Radio } from '@acronis-platform/ui-react'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<RadioGroup value={plan} onValueChange={setPlan} aria-label="Plan">
|
|
17
|
+
<label>
|
|
18
|
+
<Radio value="free" /> Free
|
|
19
|
+
</label>
|
|
20
|
+
<label>
|
|
21
|
+
<Radio value="standard" /> Standard
|
|
22
|
+
</label>
|
|
23
|
+
</RadioGroup>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A group of mutually exclusive options where the user selects exactly one.
|
|
27
|
+
Selecting an option deselects the previous one. Built from a `RadioGroup`
|
|
28
|
+
container (owns the selected value) and `Radio` items.
|
|
29
|
+
|
|
30
|
+
## When to Use
|
|
31
|
+
|
|
32
|
+
- Choose exactly one option from a small, visible set (2–7 options).
|
|
33
|
+
- The options are mutually exclusive.
|
|
34
|
+
|
|
35
|
+
## When NOT to Use
|
|
36
|
+
|
|
37
|
+
- **Multiple selections** (or none) — use checkboxes.
|
|
38
|
+
- **Many options** / long lists — use a select / combobox.
|
|
39
|
+
- **On/off for a single setting** — use a switch.
|
|
40
|
+
|
|
41
|
+
## Parts
|
|
42
|
+
|
|
43
|
+
| Part | Element | Role |
|
|
44
|
+
| ------------ | ---------------------------- | ----------------------------------------- |
|
|
45
|
+
| `RadioGroup` | `<div role="radiogroup">` | Owns the selected value; groups the items |
|
|
46
|
+
| `Radio` | `<span role="radio">` (16px) | One option; takes a `value` |
|
|
47
|
+
| (indicator) | 8px inner dot | Shown on the selected item |
|
|
48
|
+
|
|
49
|
+
## States
|
|
50
|
+
|
|
51
|
+
| State | How | Visual |
|
|
52
|
+
| ---------- | ---------------------------- | --------------------------------------------- |
|
|
53
|
+
| Unselected | default | Idle border, white fill, no dot |
|
|
54
|
+
| Hover | pointer hover | `--ui-radio-unchecked-box-border-color-hover` |
|
|
55
|
+
| Focus | focus | 3px `--ui-focus-primary` ring |
|
|
56
|
+
| Selected | group `value` === item value | Active fill + border + dot |
|
|
57
|
+
| Disabled | `disabled` (group or item) | Faint fill/border, muted dot, not selectable |
|
|
58
|
+
|
|
59
|
+
## Quick Example
|
|
60
|
+
|
|
61
|
+
### React
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { RadioGroup, Radio } from '@acronis-platform/ui-react';
|
|
65
|
+
|
|
66
|
+
function PlanPicker() {
|
|
67
|
+
const [plan, setPlan] = useState('standard');
|
|
68
|
+
return (
|
|
69
|
+
<RadioGroup value={plan} onValueChange={setPlan} aria-label="Plan">
|
|
70
|
+
<label className="inline-flex items-center gap-2">
|
|
71
|
+
<Radio value="free" /> Free
|
|
72
|
+
</label>
|
|
73
|
+
<label className="inline-flex items-center gap-2">
|
|
74
|
+
<Radio value="standard" /> Standard
|
|
75
|
+
</label>
|
|
76
|
+
<label className="inline-flex items-center gap-2">
|
|
77
|
+
<Radio value="premium" /> Premium
|
|
78
|
+
</label>
|
|
79
|
+
</RadioGroup>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> Each `Radio` is composed with its label by the consumer today; a `Field`
|
|
85
|
+
> component that wires label/description is planned.
|
|
86
|
+
|
|
87
|
+
## Spec Files
|
|
88
|
+
|
|
89
|
+
| File | Contents |
|
|
90
|
+
| ------------------ | ----------------------------------------------------------- |
|
|
91
|
+
| `index.yaml` | Identity, status, category, Figma link |
|
|
92
|
+
| `anatomy.yaml` | Root, item + indicator parts, internal value state, states |
|
|
93
|
+
| `api.yaml` | Framework-agnostic contract + framework adapters |
|
|
94
|
+
| `tokens.yaml` | `--ui-radio-*` + focus-ring token references |
|
|
95
|
+
| `behavior.md` | Given/When/Then behavior scenarios |
|
|
96
|
+
| `accessibility.md` | ARIA, keyboard map, screen-reader and contrast requirements |
|
|
97
|
+
|
|
98
|
+
## Props
|
|
99
|
+
|
|
100
|
+
| Prop | Type | Default | Required | Description |
|
|
101
|
+
|------|------|---------|----------|-------------|
|
|
102
|
+
| `value` | `string` | — | no | Controlled selected value. Pair with the change event. |
|
|
103
|
+
| `default-value` | `string` | — | no | Initially selected value when uncontrolled. |
|
|
104
|
+
| `disabled` | `boolean` | `false` | no | Disables every item in the group. |
|
|
105
|
+
| `name` | `string` | — | no | Form field name submitted with the selected value. |
|
|
106
|
+
| `required` | `boolean` | `false` | no | Requires a selection before the form can submit. |
|
|
107
|
+
|
|
108
|
+
## Events
|
|
109
|
+
|
|
110
|
+
| Event | Payload | Description |
|
|
111
|
+
|-------|---------|-------------|
|
|
112
|
+
| `value-change` | `string` | Fired when the selection changes (React: `onValueChange`). Payload is the newly selected item's value. |
|
|
113
|
+
|
|
114
|
+
## Content slots
|
|
115
|
+
|
|
116
|
+
| Slot | Description |
|
|
117
|
+
|------|-------------|
|
|
118
|
+
| `default` | Radio items. Each takes a `value` (and optional `disabled`); compose each with its label (e.g. wrap both in a `<label>`). |
|
|
119
|
+
|
|
120
|
+
## Behavior
|
|
121
|
+
|
|
122
|
+
### Rendering
|
|
123
|
+
|
|
124
|
+
#### Renders a radio group
|
|
125
|
+
|
|
126
|
+
**Given** a RadioGroup with several Radio items
|
|
127
|
+
**When** it renders
|
|
128
|
+
**Then** the container exposes `role="radiogroup"`
|
|
129
|
+
**And** each item exposes `role="radio"` with `aria-checked` reflecting selection
|
|
130
|
+
|
|
131
|
+
#### Reflects the selected value
|
|
132
|
+
|
|
133
|
+
**Given** a RadioGroup with `default-value` matching one item
|
|
134
|
+
**When** it renders
|
|
135
|
+
**Then** that item has `aria-checked="true"` and shows the inner dot
|
|
136
|
+
**And** all other items have `aria-checked="false"`
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### Interaction
|
|
141
|
+
|
|
142
|
+
#### Selecting deselects the previous option
|
|
143
|
+
|
|
144
|
+
**Given** a RadioGroup with item A selected
|
|
145
|
+
**When** the user clicks item B
|
|
146
|
+
**Then** B becomes selected (`aria-checked="true"`)
|
|
147
|
+
**And** A is deselected
|
|
148
|
+
**And** `value-change` fires with B's value
|
|
149
|
+
|
|
150
|
+
#### Keyboard navigation
|
|
151
|
+
|
|
152
|
+
**Given** focus is inside the group
|
|
153
|
+
**When** the user presses Arrow keys
|
|
154
|
+
**Then** focus moves to the adjacent item and selects it (roving tab index)
|
|
155
|
+
|
|
156
|
+
#### Disabled item is not selectable
|
|
157
|
+
|
|
158
|
+
**Given** a Radio item with `disabled` (or a disabled group)
|
|
159
|
+
**When** the user clicks it
|
|
160
|
+
**Then** the selection does not change
|
|
161
|
+
**And** `value-change` does not fire
|
|
162
|
+
**And** the disabled form tokens apply
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### States
|
|
167
|
+
|
|
168
|
+
#### Hover
|
|
169
|
+
|
|
170
|
+
**Given** an enabled, unselected item
|
|
171
|
+
**When** the pointer hovers it
|
|
172
|
+
**Then** the border uses `--ui-radio-unchecked-box-border-color-hover`
|
|
173
|
+
|
|
174
|
+
#### Focus
|
|
175
|
+
|
|
176
|
+
**Given** an item
|
|
177
|
+
**When** it receives keyboard focus
|
|
178
|
+
**Then** a 3px `--ui-focus-primary` ring is shown
|
|
179
|
+
|
|
180
|
+
#### Selected fill
|
|
181
|
+
|
|
182
|
+
**Given** a selected item
|
|
183
|
+
**When** it renders
|
|
184
|
+
**Then** the circle fills with `--ui-radio-checked-box-color-idle`
|
|
185
|
+
**And** the dot uses `--ui-radio-checked-icon-color-idle`
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Edge Cases
|
|
190
|
+
|
|
191
|
+
#### Controlled vs uncontrolled
|
|
192
|
+
|
|
193
|
+
**Given** a controlled RadioGroup (`value` + change handler)
|
|
194
|
+
**When** the user clicks an item
|
|
195
|
+
**Then** the selection changes only when the consumer updates `value`.
|
|
196
|
+
|
|
197
|
+
#### Single selection invariant
|
|
198
|
+
|
|
199
|
+
**Given** any RadioGroup
|
|
200
|
+
**When** rendered
|
|
201
|
+
**Then** at most one item is selected at a time.
|
|
202
|
+
|
|
203
|
+
## Accessibility
|
|
204
|
+
|
|
205
|
+
Implements the [WAI-ARIA Radio Group pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/)
|
|
206
|
+
via Base UI's RadioGroup / Radio primitives.
|
|
207
|
+
|
|
208
|
+
## ARIA Roles and Attributes
|
|
209
|
+
|
|
210
|
+
| Element / Attribute | Value | Reason |
|
|
211
|
+
| -------------------- | --------------------- | --------------------------------------- |
|
|
212
|
+
| group `role` | `"radiogroup"` | Groups the options for assistive tech |
|
|
213
|
+
| item `role` | `"radio"` | Identifies each option |
|
|
214
|
+
| item `aria-checked` | `"true"/"false"` | Reflects whether the option is selected |
|
|
215
|
+
| item `aria-disabled` | present when disabled | Disabled items are skipped |
|
|
216
|
+
|
|
217
|
+
Give the group an accessible name (`aria-label` / `aria-labelledby`), and give
|
|
218
|
+
each item an accessible name via its associated `<label>`.
|
|
219
|
+
|
|
220
|
+
## Keyboard Navigation
|
|
221
|
+
|
|
222
|
+
| Key | Action |
|
|
223
|
+
| ---------------- | --------------------------------------------------------- |
|
|
224
|
+
| Tab | Moves focus into the group (to the selected / first item) |
|
|
225
|
+
| Arrow Up/Left | Selects and focuses the previous item |
|
|
226
|
+
| Arrow Down/Right | Selects and focuses the next item |
|
|
227
|
+
| Space | Selects the focused item |
|
|
228
|
+
|
|
229
|
+
The group is a single tab stop (roving tab index): Tab enters/leaves it; Arrow
|
|
230
|
+
keys move between items.
|
|
231
|
+
|
|
232
|
+
## Screen Reader Requirements
|
|
233
|
+
|
|
234
|
+
1. The group is announced with its label and the count/position of options.
|
|
235
|
+
2. Each item announces its label and selected state.
|
|
236
|
+
3. Disabled items announce as disabled and are skipped by Arrow navigation.
|
|
237
|
+
|
|
238
|
+
## Color and Contrast
|
|
239
|
+
|
|
240
|
+
| Element | Minimum Ratio | Standard |
|
|
241
|
+
| --------------------------- | ------------- | ---------------------- |
|
|
242
|
+
| Circle border vs background | 3:1 | WCAG 1.4.11 (non-text) |
|
|
243
|
+
| Dot vs selected fill | 3:1 | WCAG 1.4.11 (non-text) |
|
|
244
|
+
| Focus indicator | 3:1 | WCAG 1.4.11 |
|
|
245
|
+
|
|
246
|
+
Selection is not signalled by color alone — the inner dot and `aria-checked`
|
|
247
|
+
distinguish selected from unselected.
|
|
248
|
+
|
|
249
|
+
## Testing Checklist
|
|
250
|
+
|
|
251
|
+
- [ ] Group has `role="radiogroup"` + an accessible name
|
|
252
|
+
- [ ] Items are `role="radio"` with `aria-checked`
|
|
253
|
+
- [ ] Arrow keys move + select; group is a single tab stop
|
|
254
|
+
- [ ] Disabled items are not selectable and are skipped
|
|
255
|
+
- [ ] Border / dot / focus ring meet 3:1
|