@acronis-platform/ui-react 5.5.9 → 6.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.
Files changed (29) hide show
  1. package/dist/components/ui/chart/chart.js +14 -11
  2. package/dist/components/ui/chart/chart.js.map +1 -1
  3. package/dist/components/ui/chart-state/chart-state.js +47 -37
  4. package/dist/components/ui/chart-state/chart-state.js.map +1 -1
  5. package/dist/components/ui/chart-widget/chart-widget.js +21 -23
  6. package/dist/components/ui/chart-widget/chart-widget.js.map +1 -1
  7. package/dist/components/ui/dialog/dialog.js +45 -32
  8. package/dist/components/ui/dialog/dialog.js.map +1 -1
  9. package/dist/components/ui/pie-chart/pie-chart.js +88 -84
  10. package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
  11. package/dist/index.js +86 -87
  12. package/dist/llms/chart-state.md +81 -164
  13. package/dist/llms/chart-widget.md +27 -25
  14. package/dist/llms/dialog-root.md +40 -13
  15. package/dist/llms/dialog.md +26 -1
  16. package/dist/llms.txt +3 -3
  17. package/dist/react.js +86 -87
  18. package/dist/src/components/ui/chart/chart.d.ts +3 -3
  19. package/dist/src/components/ui/chart-state/chart-state.d.ts +5 -14
  20. package/dist/src/components/ui/chart-state/index.d.ts +0 -1
  21. package/dist/src/components/ui/chart-widget/chart-widget.d.ts +10 -15
  22. package/dist/src/components/ui/dialog/dialog.d.ts +9 -0
  23. package/dist/src/components/ui/dialog/dialog.docs.d.ts +5 -1
  24. package/dist/src/components/ui/pie-chart/pie-chart.d.ts +1 -1
  25. package/dist/ui-react.css +1 -1
  26. package/package.json +13 -13
  27. package/dist/components/ui/chart-state/chart-state-illustrations.js +0 -412
  28. package/dist/components/ui/chart-state/chart-state-illustrations.js.map +0 -1
  29. package/dist/src/components/ui/chart-state/chart-state-illustrations.d.ts +0 -6
@@ -1,6 +1,6 @@
1
1
  # ChartState
2
2
 
3
- > A shared loading / empty / error placeholder for the chart types, rendered in place of the chart inside the same sized slot. A compact status block — a leading glyph over a centered label, with an optional retry action for the error state. The `empty` state draws the silhouette the design defines for each chart type (`variant`), plus an optional "Widget description" line; `loading` and `error` share one treatment. Distinct from `WidgetPlaceholder`, which is the composable skeleton for a widget that isn't a chart — see behavior.md.
3
+ > Shared loading / empty / warning / error / number visuals for a chart slot. Empty, warning, and error use the Breakpoints visual treatment: a 64px status circle with a 24px glyph and centered message. Number shows a centered KPI value; loading uses the shared spinner. Consumers select the state and may localize its content through `description`. Distinct from `WidgetPlaceholder`, which is the composable skeleton for a non-chart widget.
4
4
 
5
5
  **Status:** draft · **Category:** data-display · **Since:** v0.58.0
6
6
 
@@ -14,190 +14,107 @@ import { ChartState } from '@acronis-platform/ui-react'
14
14
 
15
15
  ```tsx
16
16
  <ChartState state="loading" />
17
- <ChartState state="empty" variant="bar" description="No results for the selected range" />
18
- <ChartState
19
- state="error"
20
- action={<Button variant="ghost" onClick={refetch}>Try again</Button>}
21
- />
17
+ <ChartState state="empty" description={t('chart.noData')} />
18
+ <ChartState state="warning" description={t('chart.partialData')} />
19
+ <ChartState state="error" description={t('chart.loadError')} />
20
+ <ChartState state="number" description="0 GB" />
22
21
  ```
23
22
 
24
- A shared loading / empty / error placeholder for the chart types. Render it in
25
- place of a chart — inside the same sized slot — while data is loading, when
26
- there is nothing to plot, or when the fetch failed.
23
+ A shared visual state for one chart slot. Use it while chart data is loading,
24
+ missing, incomplete, or has failed, or when a KPI should show its numeric empty
25
+ value. Empty, warning, and error share the Breakpoints state circles; number
26
+ uses the centered disabled-style KPI value; loading uses the shared spinner.
27
27
 
28
- > **Design-pending v1.** Ported from the Figma InputSelect dropdown states (the
29
- > reference node for this task) and kept visually in step with the shipped
30
- > `InputSelectStatus`. There is no `--ui-chart-*` token tier yet, so it themes
31
- > from existing semantic tokens directly.
32
-
33
- ## When to use
34
-
35
- - A chart cannot render yet (data in flight), has no data to plot, or failed to
36
- load — swap the chart for the matching `ChartState`.
37
- - You want the same placeholder across every chart type, rather than each chart
38
- hand-rolling its own.
39
-
40
- ## When not to use
41
-
42
- - A full-page empty state (illustration, title, description, primary action) —
43
- use the larger `Empty` component instead.
44
- - A bare loading indicator with no surrounding message — use `Spinner` directly.
45
-
46
- ## Example
28
+ Consumers select the semantic state and pass localized or context-specific
29
+ content through `description`. `ChartState` does not infer the state from data.
47
30
 
48
31
  ```tsx
49
- import { ChartState, ChartContainer, Button } from '@acronis-platform/ui-react';
50
-
51
- function Sales({ status, data, config, refetch }) {
52
- if (status === 'loading') return <ChartState state="loading" />;
53
- if (status === 'error')
54
- return (
55
- <ChartState
56
- state="error"
57
- action={
58
- <Button variant="ghost" onClick={refetch}>
59
- Try again
60
- </Button>
61
- }
62
- />
63
- );
64
- if (!data.length) return <ChartState state="empty" />;
65
-
66
- return (
67
- <ChartContainer config={config} className="h-[300px] w-[500px]">
68
- {/* …the chart… */}
69
- </ChartContainer>
70
- );
71
- }
32
+ import { ChartState } from '@acronis-platform/ui-react';
33
+
34
+ if (status === 'loading') return <ChartState state="loading" />;
35
+ if (status === 'warning')
36
+ return <ChartState state="warning" description={t('chart.partialData')} />;
37
+ if (status === 'error')
38
+ return <ChartState state="error" description={t('chart.loadError')} />;
39
+ if (isEmptyKpi) return <ChartState state="number" description="0 GB" />;
40
+ if (!data.length)
41
+ return <ChartState state="empty" description={t('chart.noData')} />;
72
42
  ```
73
43
 
74
- The three states share one compact layout: a leading glyph (spinner / inbox /
75
- warning) over a centered label. Pass `description` to override a state's default
76
- label, and `action` to add a retry affordance to the error state. Long unbroken
77
- error descriptions (CTI paths, API URLs) wrap at word boundaries and scroll
78
- vertically when they exceed the slot height.
44
+ `ChartState` fills the chart's slot. It does not own the containing widget card
45
+ or dashboard composition; see `ChartWidget` for a single chart card.
79
46
 
80
47
  ## Props
81
48
 
82
49
  | Prop | Type | Default | Required | Description |
83
50
  |------|------|---------|----------|-------------|
84
- | `state` | `'loading' | 'empty' | 'error'` | — | yes | Which placeholder to show. Drives the leading artwork and the default label (loading → spinner + "Data is loading…"; empty → variant silhouette or no artwork + "No data found"; error → warning glyph + "Something went wrong"). |
85
- | `variant` | `'area' | 'bar' | 'line' | 'donut' | 'radial' | 'funnel' | 'radar' | 'sankey' | 'scatter' | 'treemap' | 'table' | 'text'` | — | no | Which chart the slot holds. The `empty` state then draws that type's silhouette instead of the generic inbox glyph — the design defines one per chart type. `donut` and `radial` share a ring. Ignored by `loading` and `error`, which share one treatment. |
86
- | `description` | `ReactNode` | — | no | Text shown below the illustration or glyph. Defaults to `"Data is loading…"` / `"No data found"` / `"Something went wrong"` based on `state`. Pass a value to override for any state. |
87
- | `action` | `ReactNode` | — | no | Trailing action rendered for the `error` state only (e.g. a "Try again" button). |
51
+ | `state` | `'loading' | 'empty' | 'warning' | 'error' | 'number'` | — | yes | Which state to show. Loading uses the shared spinner; empty, warning, and error use the shared circular status icon; number shows a centered disabled-style KPI value. Error is an assertive alert; other states are polite status messages. |
52
+ | `description` | `ReactNode` | — | no | Localized or context-specific content. For `number`, this is the numeric readout. Defaults to "Data is loading…", "No data found", "Data may be incomplete", "Something went wrong", or "0". |
88
53
 
89
54
  ## Behavior
90
55
 
91
56
  ### Rendering per state
92
57
 
93
58
  - **Given** `state="loading"`, **when** rendered, **then** it shows the shared
94
- `Spinner` (lg) above the label "Data is loading…" and announces the label via
95
- its `role="status"` live region (no `aria-busy`, which could defer that
96
- announcement).
97
- - **Given** `state="empty"`, **when** rendered, **then** it shows the label
98
- "No data found" (no artwork unless a `variant` is passed).
99
- - **Given** `state="error"`, **when** rendered, **then** it shows the warning
100
- glyph above the label "Something went wrong" and announces as an alert.
101
-
102
- ### Label override
103
-
104
- - **Given** a `description` prop, **when** rendered in any state, **then** the
105
- supplied text replaces that state's default label.
106
-
107
- ### Action
108
-
109
- - **Given** an `action` node, **when** `state="error"`, **then** the action is
110
- rendered after the label (e.g. a "Try again" button).
111
- - **Given** an `action` node, **when** `state` is `loading` or `empty`, **then**
112
- the action is **not** rendered.
113
-
114
- ### Layout
115
-
116
- - **Given** any state, **when** placed in a sized slot (the same box a chart
117
- would occupy), **then** the block fills it (`size-full`) with a `min-h-32`
118
- floor so it stays legible in an unsized parent.
119
- - **Given** `state="loading"` or `state="empty"`, **when** rendered, **then**
120
- the content is vertically centered in the slot (`justify-center`).
121
- - **Given** `state="error"`, **when** the description is short enough to fit,
122
- **then** the content is vertically centered via auto margins (`my-auto`).
123
- - **Given** `state="error"` with a long unbroken `description` (e.g. CTI error
124
- paths, API URLs), **when** the text overflows the slot height, **then** the
125
- auto margins collapse and the icon stays anchored at the top, with vertical
126
- scroll (`overflow-y: auto`) so the full diagnostic text is accessible. Long
127
- unbroken strings wrap at word boundaries (`overflow-wrap: break-word`),
128
- breaking mid-word only when a single token cannot fit on one line.
129
- `overflow-x: hidden` prevents any horizontal scrollbar.
130
-
131
- ### Per-type empty states
132
-
133
- `empty` is the one state the design draws per chart type: an area silhouette for
134
- an area chart, a ring for a donut, a funnel for a funnel. An empty widget then
135
- still says what it _would_ have shown, which a single generic glyph can't.
136
-
137
- `variant` selects it. `donut` and `radial` share one ring — a radial-bar widget
138
- with no data has nothing to tell it apart. Without a `variant` the empty state
139
- shows no artwork — just the text.
140
-
141
- The geometry is exported from the Figma instances rather than redrawn, and every
142
- path is `currentColor`: the tone is set once on the container, so brand and theme
143
- overrides reach the artwork. Two of the eleven silhouettes use a second, fainter
144
- tone (the table and metric-list ones tint their header row darker than the body
145
- rows); that hierarchy is kept as `fill-opacity` on the same colour rather than a
146
- second token.
147
-
148
- The caption is **one line, in one style**. Figma styles it `body/default` on
149
- `text/onSurface/primary` — 14/24, centred, _not_ muted — which is what the root
150
- already applies, so the description and the fallback status label read
151
- identically. For a per-type empty state that line is the `description`: the mockups draw the silhouette over "Widget description" with no
152
- status label, because the artwork already says "no data" and the sentence worth
153
- the space is what the widget _would_ show. With no `description` it falls back to
154
- the status label, so a caller that only sets `variant` still reads sensibly.
155
-
156
- `loading` and `error` deliberately keep one shared treatment — the design only
157
- redesigned `empty`.
158
-
159
- ### Not `WidgetPlaceholder`
160
-
161
- Two components, two jobs, and they are not interchangeable:
162
-
163
- - **`ChartState`** is the placeholder _inside_ a chart's slot. It fills whatever
164
- gives the slot its height, renders one of three states, and is what a chart
165
- widget swaps in for its plot.
166
- - **`WidgetPlaceholder`** is a composable skeleton with its own header, footer
167
- and action parts, plus an `interactive` affordance — for a dashboard widget
168
- that isn't a chart, or a whole tile that is still being set up.
169
-
170
- `WidgetPlaceholder` predates the per-type empty states and is used by consuming
171
- MFEs, so it stays.
59
+ large `Spinner` and the default message "Data is loading…".
60
+ - **Given** `state="empty"`, **when** rendered, **then** it shows the neutral
61
+ circle with the `CircleMinusGray` glyph and the default message "No data
62
+ found".
63
+ - **Given** `state="warning"`, **when** rendered, **then** it shows the warning
64
+ circle with the `TriangleWarningYellow` glyph and the default message "Data
65
+ may be incomplete".
66
+ - **Given** `state="error"`, **when** rendered, **then** it shows the critical
67
+ circle with the `DiamondWarningRed` glyph and the default message "Something
68
+ went wrong".
69
+ - **Given** `state="number"`, **when** rendered, **then** it shows the centered
70
+ disabled-style numeric value "0" without a state icon.
71
+ - **Given** empty, warning, or error, **when** rendered, **then** the group is
72
+ centered and uses a 64px state circle, a 24px glyph, 12px separation, and
73
+ centered 14px / 24px text.
74
+
75
+ ### Copy
76
+
77
+ - **Given** a `description`, **when** rendered in any state, **then** the supplied
78
+ content replaces that state's fallback message. Consumers provide localized
79
+ or context-specific copy.
80
+
81
+ ### Layout and overflow
82
+
83
+ - **Given** any state, **when** placed in a chart slot, **then** the block fills
84
+ the slot without forcing a minimum height beyond its content.
85
+ - **Given** loading, empty, or warning, **when** rendered, **then** the content
86
+ is centered in the slot.
87
+ - **Given** `state="error"` with a short message, **when** rendered, **then**
88
+ the icon and message are vertically centered.
89
+ - **Given** an error with a long message, **when** it exceeds the slot height,
90
+ **then** the icon remains fully visible, the state scrolls vertically, and
91
+ unbroken strings wrap within the available width.
92
+
93
+ ### Composition boundary
94
+
95
+ `ChartState` controls the state visuals inside one chart slot. It does not set
96
+ the chart-widget card border or arrange a group of widgets; those belong to
97
+ their respective component or consuming application.
172
98
 
173
99
  ## Accessibility
174
100
 
175
- - The root is a **live region** so a screen reader announces the state change
176
- when a chart swaps its content in:
177
- - `loading` / `empty` → `role="status"` with `aria-live="polite"`.
178
- - `error` → `role="alert"` with `aria-live="assertive"`.
179
- - On `loading` the shared `Spinner` is rendered `aria-hidden` so the root's own
180
- live region (with the label) announces once, rather than the Spinner's
181
- `role="status"` + sr-only "Loading…" nesting inside it and double-announcing.
182
- - The root does **not** carry `aria-busy`. It is itself the live region, and some
183
- screen readers defer announcing a busy region's content until `aria-busy`
184
- clears; because this placeholder is unmounted (swapped for the chart) rather
185
- than un-busied, a busy flag would risk swallowing the "Data is loading…"
186
- announcement. Put `aria-busy` on the chart-slot **container** instead if a busy
187
- signal is needed (same guidance as `Skeleton`).
188
- - The live-region attributes (`role` / `aria-live`) are applied after the prop
189
- spread, so the state's a11y contract is not clobbered by a consumer-passed
190
- attribute.
191
- - The label text is a real `<p>`, so the state message is always in the
192
- accessible tree — the glyph is decorative and does not need its own label.
193
- - **Do not rely on the glyph color alone** to convey the state — the label
194
- carries the meaning. Icon colors (`--ui-glyph-on-status-info` /
195
- `--ui-glyph-on-status-warning`) and the label (`--ui-text-on-surface-primary`)
196
- resolve to semantic tokens that meet contrast in both themes.
197
- - If the error state offers a retry, pass an actual interactive control as
198
- `action` (a `Button`) so it is focusable and keyboard-operable.
101
+ - The root is the live region: loading, empty, warning, and number use
102
+ `role="status"` with `aria-live="polite"`; error uses `role="alert"` with
103
+ `aria-live="assertive"`.
104
+ - The root live-region attributes are applied after the prop spread, so the
105
+ selected state's announcement semantics cannot be overwritten by consumer
106
+ props.
107
+ - The loading Spinner and state glyphs are decorative. The displayed content
108
+ supplies the state meaning independently of icon color.
109
+ - The root does not carry `aria-busy`. This placeholder is unmounted when the
110
+ chart replaces it, and some screen readers defer announcements inside a busy
111
+ region. Put `aria-busy` on the chart-slot container if a busy signal is needed.
112
+ - Long error text can scroll vertically, and long unbroken strings wrap within
113
+ the available width.
199
114
 
200
115
  ## Contrast
201
116
 
202
- Label and glyph colors resolve to semantic `--ui-*` tokens that meet contrast on
203
- the surface in both light and dark themes.
117
+ Message text uses `--ui-text-on-surface-primary`. The state glyphs are the
118
+ multi-color design assets, placed on semantic neutral, warning, and critical
119
+ background tokens. The textual message communicates meaning without relying on
120
+ color.
@@ -1,6 +1,6 @@
1
1
  # ChartWidget
2
2
 
3
- > The dashboard card a chart sits in: a `Card` with the standard widget header (title, optional filter chip and the ⋯ actions menu) and an optional metric readout above the plot. Adds the one thing a `Card` doesn't know about — the body's loading / empty / error placeholder — and re-implements nothing else: its `header` is `CardHeaderProps`, spread. It declares no size: the grid sizes the card and the widget passes that height down, so a `size-full` chart fills whatever the header leaves. The per-type chart components stay card-less, so a chart is still usable outside a widget.
3
+ > The dashboard card a chart sits in: a `Card` with the standard widget header (title, optional filter chip and the ⋯ actions menu) and an optional metric readout above the plot. Adds the one thing a `Card` doesn't know about — the body's loading / empty / warning / error / number state — and re-implements nothing else. The consumer selects the state explicitly; the widget does not infer it from chart data. its `header` is `CardHeaderProps`, spread. It declares no size: the grid sizes the card and the widget passes that height down, so a `size-full` chart fills whatever the header leaves. The per-type chart components stay card-less, so a chart is still usable outside a widget.
4
4
 
5
5
  **Status:** draft · **Category:** data-display · **Since:** v2.1.0
6
6
 
@@ -35,10 +35,11 @@ readout, then the plot. `ChartWidget` is that composition — and only that.
35
35
 
36
36
  ## What it adds
37
37
 
38
- One thing a `Card` legitimately doesn't know about: **what the body shows while
39
- there is no plot.** `state="loading" | "empty" | "error"` renders `ChartState` in
40
- place of the chart, and `error` also gives the Card its error border — one prop,
41
- not two.
38
+ One thing a `Card` legitimately doesn't know about: **what the body shows for
39
+ an explicitly selected state.** `state="loading" | "empty" | "warning" |
40
+ "error" | "number"` renders `ChartState` in place of the metric and chart. The
41
+ consumer chooses the state; the widget does not infer it from data. Card chrome
42
+ remains consistent for each state.
42
43
 
43
44
  ## What it doesn't add
44
45
 
@@ -63,7 +64,7 @@ the rest of the card. See `behavior.md`.
63
64
  | ------------------ | ------------------------------------------------------------------ |
64
65
  | `index.yaml` | Identity, category, status, `since`. |
65
66
  | `api.yaml` | The prop contract and the per-framework adapters. |
66
- | `anatomy.yaml` | Parts, the schematic, and the four body states. |
67
+ | `anatomy.yaml` | Parts, the schematic, and the five widget states. |
67
68
  | `behavior.md` | Composition, how the height reaches the plot, state, localization. |
68
69
  | `accessibility.md` | Roles, the placeholder's live region, header controls. |
69
70
  | `tokens.yaml` | The `--ui-*` tokens the widget references. |
@@ -87,12 +88,10 @@ chart.
87
88
  | `header` | `CardHeaderProps` | — | no | The card header, forwarded verbatim to `CardHeader` — `title`, `description`, `extras` (a filter chip), `actions` (the ⋯ menu), `isDraggable`, `isSwitchable`, `hasAvatar`, `hasRename`, `isCollapsible`. Omit for a header-less widget. |
88
89
  | `orientation` | `'vertical' | 'horizontal'` | `vertical` | no | How the `metric` and plot are arranged inside the card body. `vertical` (default) — metric above the plot, full width; the metric takes its natural height and the plot fills the rest. `horizontal` — metric and plot side by side, each `flex-1`; use for compact (sm/288px) widgets where vertical space is at a premium. |
89
90
  | `metric` | `ReactNode` | — | no | The readout beside or above the plot (depending on `orientation`), typically a `Metric`. |
90
- | `variant` | `'area' | 'bar' | 'line' | 'donut' | 'radial' | 'funnel' | 'radar' | 'sankey' | 'scatter' | 'treemap' | 'table' | 'text'` | — | no | Which chart the widget holds. Only used while `state="empty"`, to pick the silhouette for that chart type. Forwarded to `ChartState`. |
91
- | `state` | `'loading' | 'empty' | 'error'` | — | no | Renders `ChartState` in place of the plot, keeping the header. `error` additionally gives the Card its error border. |
92
- | `stateDescription` | `ReactNode` | — | no | Text below the placeholder illustration or glyph. Forwarded to `ChartState` as `description`. Defaults to the per-state built-in ("Data is loading…" / "No data found" / "Something went wrong"). |
93
- | `stateAction` | `ReactNode` | — | no | Trailing action on the `error` placeholder — e.g. a retry button. |
91
+ | `state` | `'loading' | 'empty' | 'warning' | 'error' | 'number'` | — | no | Renders `ChartState` in place of the metric and plot, keeping the header. The consumer selects the state; no state is inferred from the data. Card chrome remains consistent for all states. |
92
+ | `stateDescription` | `ReactNode` | — | no | Localized or context-specific content shown by `ChartState`. For `number`, pass the numeric value and unit. Defaults to per-state fallback content, including `0` for `number`. |
94
93
  | `bodyClassName` | `string` | — | no | Class for the card body. Rarely needed — the body already fills the card. For the case where neither the grid nor the content gives a height, e.g. a placeholder-only widget outside a sized cell. |
95
- | `children` | `ReactNode` | — | no | The chart. Replaced by the placeholder while `state` is set. |
94
+ | `children` | `ReactNode` | — | no | The selected state replaces this chart and the metric while `state` is set. |
96
95
  | `render` | `useRender.RenderProp` | — | no | Replace the rendered `<div>` with another element or component (Base UI composition), forwarded to `Card`. How a dashboard gives each widget a landmark role — `render={<section aria-label="Sessions" />}` — which is the one thing the widget can't infer for itself. |
97
96
 
98
97
  ## Behavior
@@ -142,21 +141,23 @@ design constraint, and hard-coding them would have fought the grid.
142
141
 
143
142
  ### State
144
143
 
145
- `state` renders `ChartState` **instead of** `children`. The header stays.
144
+ The consumer selects `state` explicitly; the widget does not infer it from chart
145
+ data. When set, `ChartState` replaces both the `metric` and `children`. The
146
+ header stays. The `number` state shows a centered numeric KPI value.
146
147
 
147
- `state="error"` also maps to `Card`'s `hasError`, so the error border and the
148
- error placeholder come from one prop. A caller can't get one without the other,
149
- which is what the mockups draw.
148
+ The card surface and border remain the same for loading, empty, warning, error,
149
+ and number. State-specific visuals are contained within `ChartState` in the
150
+ body.
150
151
 
151
- `ChartState` owns the live-region contract (`role="status"` for loading/empty,
152
- `role="alert"` for error), so the announcement follows the placeholder rather
153
- than being re-declared on the widget.
152
+ `ChartState` owns the live-region contract (`role="status"` for loading, empty,
153
+ warning, and number; `role="alert"` for error), so the announcement follows
154
+ the state rather than being re-declared on the widget.
154
155
 
155
156
  ### Localization
156
157
 
157
- Every string is the caller's: the header's `title` / `description`, the metric's
158
- own labels, `stateDescription`, and the label inside `stateAction`. The only
159
- literals are `ChartState`'s per-state defaults, which `stateDescription` overrides.
158
+ The header's `title` / `description`, the metric's labels, and
159
+ `stateDescription` can be supplied by the consumer. The `stateDescription`
160
+ prop lets applications localize or contextualize the state content.
160
161
 
161
162
  ## Accessibility
162
163
 
@@ -187,7 +188,7 @@ name, so a chart inside should not repeat it in its own accessible name.
187
188
  ## The placeholder is the live region
188
189
 
189
190
  While `state` is set, `ChartState` is the live region — `role="status"`
190
- (`aria-live="polite"`) for loading and empty, `role="alert"`
191
+ (`aria-live="polite"`) for loading, empty, warning, and number; `role="alert"`
191
192
  (`aria-live="assertive"`) for error. The widget deliberately does **not** add
192
193
  `aria-busy` around it: the placeholder is unmounted and replaced by the plot
193
194
  rather than un-busied, and some assistive tech defers announcing a busy region's
@@ -203,7 +204,8 @@ switch, rename button and collapse trigger each take a label prop with a
203
204
  default, and the `actions` slot is the caller's own control (an icon button
204
205
  needs its own `aria-label` — the mockups' ⋯ menu has no visible text).
205
206
 
206
- ## Colour is not the only signal
207
+ ## State meaning
207
208
 
208
- `state="error"` changes the card's border colour, but the placeholder also
209
- carries an icon and a message, so the error is not conveyed by colour alone.
209
+ The widget card border stays consistent across states. `ChartState` supplies a
210
+ state icon and message (or the numeric KPI value), so meaning does not rely on
211
+ color alone.
@@ -58,19 +58,19 @@ decision. Composable from parts; built on the Base UI Dialog primitive.
58
58
 
59
59
  ## Parts
60
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). |
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 popup (+ overlay); centered by default, or top-aligned via `verticalAlign`. |
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
74
 
75
75
  ## Sizes
76
76
 
@@ -79,6 +79,12 @@ decision. Composable from parts; built on the Base UI Dialog primitive.
79
79
  `large` (832px) is a legacy backward-compatibility size with no design token,
80
80
  kept for existing call sites (see the public `Dialog` recipe's `wide` variant).
81
81
 
82
+ ## Placement
83
+
84
+ `DialogContent` takes a `verticalAlign` prop: `center` (default) centers the
85
+ popup in the viewport; `top` pins it 48px from the top edge, horizontally
86
+ centered, keeping its content height (still capped at `100dvh - 96px`).
87
+
82
88
  ## Example (internal usage only)
83
89
 
84
90
  ```tsx
@@ -124,6 +130,7 @@ import { Button } from '../button';
124
130
  | `default-open` | `boolean` | `false` | no | Initial open state when uncontrolled. |
125
131
  | `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
132
  | `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). |
133
+ | `verticalAlign` | `'center' | 'top'` | `'center'` | no | Vertical placement of the popup (on the content part). `center` (the default) centers it in the viewport; `top` pins it 48px from the top edge of the viewport instead, keeping its content height. A ui-react-only extension beyond the Figma contract, like `size="large"`. |
127
134
  | `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
135
  | `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
136
 
@@ -205,6 +212,26 @@ Scenario: Modal locks the background (default)
205
212
  inside the dialog until it closes
206
213
  ```
207
214
 
215
+ ### Placement
216
+
217
+ ```gherkin
218
+ Scenario: The popup is centered by default
219
+ Given a DialogRoot whose DialogContent has no verticalAlign (or
220
+ verticalAlign = "center")
221
+ When it opens
222
+ Then the popup is centered in the viewport, horizontally and vertically
223
+ ```
224
+
225
+ ```gherkin
226
+ Scenario: verticalAlign = "top" pins the popup near the top edge
227
+ Given a DialogRoot whose DialogContent has verticalAlign = "top"
228
+ When it opens
229
+ Then the popup's top edge sits 48px below the top of the viewport
230
+ And it stays horizontally centered
231
+ And it keeps its content height (still capped at 100dvh - 96px), leaving
232
+ the viewport below it empty
233
+ ```
234
+
208
235
  ## Accessibility
209
236
 
210
237
  DialogRoot leans on the Base UI Dialog primitive for its modal semantics,
@@ -97,7 +97,7 @@ name is `Dialog`.
97
97
 
98
98
  | Part | Element (default) | Purpose |
99
99
  | ----------------- | ------------------ | ---------------------------------------------------- |
100
- | `container` | `div[role=dialog]` | The portaled, centered popup card. |
100
+ | `container` | `div[role=dialog]` | The portaled popup card; centered (or top-aligned). |
101
101
  | `header` | `div` | Top bar; title + close button. |
102
102
  | `title` | `h2` | Accessible dialog name (`aria-labelledby`). |
103
103
  | `close-button` | `button` | Icon button that dismisses the dialog. |
@@ -146,6 +146,11 @@ import { Dialog } from '@acronis-platform/ui-react';
146
146
  <p>Body-only content — no title bar, no close button.</p>
147
147
  </Dialog>;
148
148
 
149
+ // Pin the popup 48px from the top of the viewport instead of centering it
150
+ <Dialog variant="default" verticalAlign="top" open>
151
+ <p>Any custom body content.</p>
152
+ </Dialog>;
153
+
149
154
  // Legacy wide variant — free-form footer, kept for backward compatibility
150
155
  import { Button, DialogClose } from '@acronis-platform/ui-react';
151
156
 
@@ -185,6 +190,7 @@ import { Button, DialogClose } from '@acronis-platform/ui-react';
185
190
  | `default-open` | `boolean` | `false` | no | Initial open state when uncontrolled (React `defaultOpen`). |
186
191
  | `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. |
187
192
  | `size` | `'sm' | 'large'` | `'sm'` | no | Popup max-width (forwarded to the underlying content). Defaults to `sm` (512px, the Figma-defined size), or to `large` (832px) when `variant` is `wide`. `large` predates the Figma node and has no design token — a legacy backward-compatibility size, not a design-system width scale. |
193
+ | `verticalAlign` | `'center' | 'top'` | `'center'` | no | Vertical placement of the popup (forwarded to the underlying content). `center` (the default) centers it in the viewport; `top` pins it 48px from the top edge of the viewport instead, keeping its content height. A ui-react-only extension beyond the Figma contract, like `size="large"`. |
188
194
  | `portal` | `boolean` | `true` | no | Render the content inside a portal (forwarded to the underlying content). Required for correct stacking; disable only when supplying your own portal ancestor. |
189
195
  | `keepMounted` | `boolean` | — | no | Keep the content mounted while closed (forwarded to the underlying content's portal). |
190
196
 
@@ -241,6 +247,25 @@ Scenario: The wide variant is a free-form escape hatch
241
247
  secondary/primary pair
242
248
  ```
243
249
 
250
+ ### Placement
251
+
252
+ ```gherkin
253
+ Scenario: The popup is centered by default
254
+ Given a Dialog with no verticalAlign (or verticalAlign = "center")
255
+ When it opens
256
+ Then the popup is centered in the viewport, horizontally and vertically
257
+ ```
258
+
259
+ ```gherkin
260
+ Scenario: verticalAlign = "top" pins the popup near the top edge
261
+ Given a Dialog with verticalAlign = "top"
262
+ When it opens
263
+ Then the popup's top edge sits 48px below the top of the viewport
264
+ And it stays horizontally centered
265
+ And it keeps its content height (still capped at 100dvh - 96px), leaving
266
+ the viewport below it empty
267
+ ```
268
+
244
269
  ### Body slot
245
270
 
246
271
  ```gherkin
package/dist/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # Acronis UI Kit for React — LLM Reference
2
2
 
3
- > `@acronis-platform/ui-react` v5.5.9
3
+ > `@acronis-platform/ui-react` v6.0.0
4
4
 
5
5
  Machine-readable component reference compiled from framework-agnostic specs.
6
6
  Each entry links to a self-contained markdown file with props, behavior,
@@ -34,8 +34,8 @@ accessibility notes, and usage examples.
34
34
  - [CardWidgetCarousel](./llms/card-widget-carousel.md): A horizontal scroll carousel that holds a row of action-widget cards and exposes floating Previous/Next chevron buttons to navigate the view. The carousel shell manages scroll; the individual cards are passed as `children`. Ships with a companion `CardWidget` component (same barrel) — a status-colored card with icon box, optional skeleton, and footer slot.
35
35
  - [CategoryBar](./llms/category-bar.md): A single horizontal bar split into proportional colored segments — one part-to-whole across a handful of categories in one row (onboarding stages, certification status, a pass/fail split). Each segment's width is its value over the sum of all values; segment colors are caller-supplied via `config`. A plain flex composition (not a recharts chart) with one CVA axis (`size`), an optional count/% legend, and per-segment hover tooltips. Design-pending v1 — no chart token tier exists yet.
36
36
  - [Chart](./llms/chart.md): A theming layer over recharts — a `ChartContainer` that supplies series colors and recharts class overrides, plus tooltip and legend chrome (`ChartTooltipContent`, `ChartLegendContent`). The chart type (bar / line / area / pie / …) is composed from recharts primitives by the caller. Ported from the legacy shadcn-uikit `chart`.
37
- - [ChartState](./llms/chart-state.md): A shared loading / empty / error placeholder for the chart types, rendered in place of the chart inside the same sized slot. A compact status block — a leading glyph over a centered label, with an optional retry action for the error state. The `empty` state draws the silhouette the design defines for each chart type (`variant`), plus an optional "Widget description" line; `loading` and `error` share one treatment. Distinct from `WidgetPlaceholder`, which is the composable skeleton for a widget that isn't a chart — see behavior.md.
38
- - [ChartWidget](./llms/chart-widget.md): The dashboard card a chart sits in: a `Card` with the standard widget header (title, optional filter chip and the ⋯ actions menu) and an optional metric readout above the plot. Adds the one thing a `Card` doesn't know about — the body's loading / empty / error placeholder — and re-implements nothing else: its `header` is `CardHeaderProps`, spread. It declares no size: the grid sizes the card and the widget passes that height down, so a `size-full` chart fills whatever the header leaves. The per-type chart components stay card-less, so a chart is still usable outside a widget.
37
+ - [ChartState](./llms/chart-state.md): Shared loading / empty / warning / error / number visuals for a chart slot. Empty, warning, and error use the Breakpoints visual treatment: a 64px status circle with a 24px glyph and centered message. Number shows a centered KPI value; loading uses the shared spinner. Consumers select the state and may localize its content through `description`. Distinct from `WidgetPlaceholder`, which is the composable skeleton for a non-chart widget.
38
+ - [ChartWidget](./llms/chart-widget.md): The dashboard card a chart sits in: a `Card` with the standard widget header (title, optional filter chip and the ⋯ actions menu) and an optional metric readout above the plot. Adds the one thing a `Card` doesn't know about — the body's loading / empty / warning / error / number state — and re-implements nothing else. The consumer selects the state explicitly; the widget does not infer it from chart data. its `header` is `CardHeaderProps`, spread. It declares no size: the grid sizes the card and the widget passes that height down, so a `size-full` chart fills whatever the header leaves. The per-type chart components stay card-less, so a chart is still usable outside a widget.
39
39
  - [Chip](./llms/chip.md): A compact, interactive label for a selection, a removable token, or an inline action. The `removable` variant carries a trailing × button; `selectable` is a toggle that shows an active style when selected; `operational` is a plain action chip with a strong-link label. All three accept an optional leading icon.
40
40
  - [ComposedChart](./llms/composed-chart.md): A typed composed (mixed) chart over the shared `Chart` primitives. Plots a `series` list over one shared category axis, where each entry picks its own render `type` (bar / line / area), inside a `ChartContainer` with tooltip and legend chrome. No variant axes — the mix is data-driven via `series[].type`. Series render in the caller's `series` order (later entries paint on top). Ported from the apps/demo `ComposedChartPlayground`.
41
41
  - [ConfidenceCone](./llms/confidence-cone.md): A forecast confidence-cone over the shared `Chart` primitives: a solid line for the known/actual period, a dashed line for the forecast, and a shaded band (the "cone") between a lower and upper bound that typically widens with the horizon, visualizing growing uncertainty. Distinct from the conversion `FunnelChart`. Design-pending v1 (no `--ui-chart-*` palette, no `apps/demo` playground — built net-new).