@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.
Files changed (219) hide show
  1. package/dist/components/ui/accordion-container/accordion-container.js +14 -14
  2. package/dist/components/ui/accordion-container/accordion-container.js.map +1 -1
  3. package/dist/components/ui/app-shell-chat/app-shell-chat.js.map +1 -1
  4. package/dist/components/ui/area-chart/area-chart.js +141 -139
  5. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  6. package/dist/components/ui/bar-chart/bar-chart.js +295 -293
  7. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  8. package/dist/components/ui/category-bar/category-bar.js +109 -93
  9. package/dist/components/ui/category-bar/category-bar.js.map +1 -1
  10. package/dist/components/ui/chart/chart-palette.js +113 -0
  11. package/dist/components/ui/chart/chart-palette.js.map +1 -0
  12. package/dist/components/ui/chart/chart.js +176 -129
  13. package/dist/components/ui/chart/chart.js.map +1 -1
  14. package/dist/components/ui/chart-state/chart-state-illustrations.js +310 -0
  15. package/dist/components/ui/chart-state/chart-state-illustrations.js.map +1 -0
  16. package/dist/components/ui/chart-state/chart-state.js +48 -34
  17. package/dist/components/ui/chart-state/chart-state.js.map +1 -1
  18. package/dist/components/ui/chart-widget/chart-widget.js +87 -0
  19. package/dist/components/ui/chart-widget/chart-widget.js.map +1 -0
  20. package/dist/components/ui/composed-chart/composed-chart.js +117 -115
  21. package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
  22. package/dist/components/ui/confidence-cone/confidence-cone.js +166 -158
  23. package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
  24. package/dist/components/ui/funnel-chart/funnel-chart.js +162 -161
  25. package/dist/components/ui/funnel-chart/funnel-chart.js.map +1 -1
  26. package/dist/components/ui/histogram/histogram.js +94 -92
  27. package/dist/components/ui/histogram/histogram.js.map +1 -1
  28. package/dist/components/ui/input/input.js.map +1 -1
  29. package/dist/components/ui/label/label.js +2 -9
  30. package/dist/components/ui/label/label.js.map +1 -1
  31. package/dist/components/ui/line-chart/line-chart.js +143 -141
  32. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  33. package/dist/components/ui/metric/metric.js +74 -185
  34. package/dist/components/ui/metric/metric.js.map +1 -1
  35. package/dist/components/ui/page-content/page-content.js.map +1 -1
  36. package/dist/components/ui/pie-chart/pie-chart.js +201 -195
  37. package/dist/components/ui/pie-chart/pie-chart.js.map +1 -1
  38. package/dist/components/ui/radar-chart/radar-chart.js +133 -131
  39. package/dist/components/ui/radar-chart/radar-chart.js.map +1 -1
  40. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js +297 -265
  41. package/dist/components/ui/radial-bar-chart/radial-bar-chart.js.map +1 -1
  42. package/dist/components/ui/sankey-chart/sankey-chart.js +123 -101
  43. package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -1
  44. package/dist/components/ui/scatter-chart/scatter-chart.js +76 -74
  45. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  46. package/dist/components/ui/section/section.js +157 -31
  47. package/dist/components/ui/section/section.js.map +1 -1
  48. package/dist/components/ui/stepper/stepper.js +24 -24
  49. package/dist/components/ui/stepper/stepper.js.map +1 -1
  50. package/dist/components/ui/stepper-item/stepper-item.js +43 -24
  51. package/dist/components/ui/stepper-item/stepper-item.js.map +1 -1
  52. package/dist/components/ui/treemap/treemap.js +133 -124
  53. package/dist/components/ui/treemap/treemap.js.map +1 -1
  54. package/dist/components/ui/trend-indicator/trend-indicator.js +34 -69
  55. package/dist/components/ui/trend-indicator/trend-indicator.js.map +1 -1
  56. package/dist/components/ui/wizard/wizard.js +59 -0
  57. package/dist/components/ui/wizard/wizard.js.map +1 -0
  58. package/dist/hooks/use-wizard.js +75 -0
  59. package/dist/hooks/use-wizard.js.map +1 -0
  60. package/dist/index.js +502 -497
  61. package/dist/index.js.map +1 -1
  62. package/dist/llms/accordion-container.md +181 -0
  63. package/dist/llms/accordion.md +124 -0
  64. package/dist/llms/alert.md +225 -0
  65. package/dist/llms/app-shell-chat.md +415 -0
  66. package/dist/llms/area-chart.md +355 -0
  67. package/dist/llms/avatar.md +208 -0
  68. package/dist/llms/bar-chart.md +406 -0
  69. package/dist/llms/breadcrumb.md +326 -0
  70. package/dist/llms/button-group.md +298 -0
  71. package/dist/llms/button-icon-input.md +142 -0
  72. package/dist/llms/button-icon-menu.md +209 -0
  73. package/dist/llms/button-icon.md +128 -0
  74. package/dist/llms/button-menu.md +172 -0
  75. package/dist/llms/button.md +185 -0
  76. package/dist/llms/calendar-panel.md +733 -0
  77. package/dist/llms/calendar.md +188 -0
  78. package/dist/llms/card-filter.md +214 -0
  79. package/dist/llms/card-section.md +293 -0
  80. package/dist/llms/card.md +447 -0
  81. package/dist/llms/carousel-dialog.md +156 -0
  82. package/dist/llms/category-bar.md +193 -0
  83. package/dist/llms/chart-state.md +190 -0
  84. package/dist/llms/chart-widget.md +209 -0
  85. package/dist/llms/chart.md +182 -0
  86. package/dist/llms/checkbox.md +257 -0
  87. package/dist/llms/chip.md +195 -0
  88. package/dist/llms/combobox.md +164 -0
  89. package/dist/llms/composed-chart.md +508 -0
  90. package/dist/llms/confidence-cone.md +277 -0
  91. package/dist/llms/data-table.md +474 -0
  92. package/dist/llms/date-range-picker.md +272 -0
  93. package/dist/llms/description-list.md +131 -0
  94. package/dist/llms/dialog-footer-carousel.md +147 -0
  95. package/dist/llms/dialog-footer-default.md +142 -0
  96. package/dist/llms/dialog-root.md +246 -0
  97. package/dist/llms/dialog-welcome.md +223 -0
  98. package/dist/llms/dialog.md +403 -0
  99. package/dist/llms/dropdown-menu.md +193 -0
  100. package/dist/llms/empty-overlay.md +146 -0
  101. package/dist/llms/empty.md +156 -0
  102. package/dist/llms/field.md +185 -0
  103. package/dist/llms/filter-cards.md +157 -0
  104. package/dist/llms/filter-chips.md +323 -0
  105. package/dist/llms/filter-search.md +512 -0
  106. package/dist/llms/form.md +154 -0
  107. package/dist/llms/funnel-chart.md +333 -0
  108. package/dist/llms/grid.md +80 -0
  109. package/dist/llms/histogram.md +190 -0
  110. package/dist/llms/input-date-picker.md +203 -0
  111. package/dist/llms/input-otp.md +173 -0
  112. package/dist/llms/input-password.md +197 -0
  113. package/dist/llms/input-search.md +170 -0
  114. package/dist/llms/input-select.md +278 -0
  115. package/dist/llms/input-text-area.md +271 -0
  116. package/dist/llms/input-text.md +192 -0
  117. package/dist/llms/line-chart.md +369 -0
  118. package/dist/llms/link.md +209 -0
  119. package/dist/llms/loading.md +130 -0
  120. package/dist/llms/meter.md +177 -0
  121. package/dist/llms/metric.md +204 -0
  122. package/dist/llms/number-field.md +122 -0
  123. package/dist/llms/page-content.md +69 -0
  124. package/dist/llms/page-header.md +182 -0
  125. package/dist/llms/pagination.md +133 -0
  126. package/dist/llms/pie-chart.md +307 -0
  127. package/dist/llms/popover.md +252 -0
  128. package/dist/llms/progress-circle.md +126 -0
  129. package/dist/llms/progress.md +111 -0
  130. package/dist/llms/radar-chart.md +316 -0
  131. package/dist/llms/radial-bar-chart.md +319 -0
  132. package/dist/llms/radio.md +255 -0
  133. package/dist/llms/resizable.md +195 -0
  134. package/dist/llms/sankey-chart.md +208 -0
  135. package/dist/llms/scatter-chart.md +239 -0
  136. package/dist/llms/scroll-area.md +183 -0
  137. package/dist/llms/section.md +401 -0
  138. package/dist/llms/select.md +210 -0
  139. package/dist/llms/separator.md +87 -0
  140. package/dist/llms/sheet.md +202 -0
  141. package/dist/llms/sidebar-primary.md +360 -0
  142. package/dist/llms/sidebar-secondary.md +417 -0
  143. package/dist/llms/skeleton.md +81 -0
  144. package/dist/llms/slider.md +97 -0
  145. package/dist/llms/spinner.md +100 -0
  146. package/dist/llms/stack.md +80 -0
  147. package/dist/llms/stepper-item.md +309 -0
  148. package/dist/llms/stepper.md +251 -0
  149. package/dist/llms/switch.md +140 -0
  150. package/dist/llms/table.md +436 -0
  151. package/dist/llms/tabs.md +197 -0
  152. package/dist/llms/tag.md +139 -0
  153. package/dist/llms/timeline.md +361 -0
  154. package/dist/llms/timer.md +259 -0
  155. package/dist/llms/toast.md +241 -0
  156. package/dist/llms/toggle-group.md +121 -0
  157. package/dist/llms/toolbar.md +453 -0
  158. package/dist/llms/tooltip.md +164 -0
  159. package/dist/llms/treemap.md +254 -0
  160. package/dist/llms/trend-indicator.md +132 -0
  161. package/dist/llms/widget-placeholder.md +169 -0
  162. package/dist/llms/wizard.md +412 -0
  163. package/dist/llms.txt +142 -0
  164. package/dist/react.js +502 -497
  165. package/dist/react.js.map +1 -1
  166. package/dist/src/components/ui/area-chart/area-chart.d.ts +9 -4
  167. package/dist/src/components/ui/avatar/avatar.d.ts +1 -1
  168. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +9 -4
  169. package/dist/src/components/ui/category-bar/category-bar.d.ts +10 -4
  170. package/dist/src/components/ui/chart/__stories__/palette-control.d.ts +48 -0
  171. package/dist/src/components/ui/chart/__tests__/chart-palette.test.d.ts +1 -0
  172. package/dist/src/components/ui/chart/chart-palette.d.ts +128 -0
  173. package/dist/src/components/ui/chart/chart.d.ts +66 -15
  174. package/dist/src/components/ui/chart/index.d.ts +4 -2
  175. package/dist/src/components/ui/chart-state/chart-state-illustrations.d.ts +6 -0
  176. package/dist/src/components/ui/chart-state/chart-state.d.ts +13 -2
  177. package/dist/src/components/ui/chart-state/index.d.ts +1 -0
  178. package/dist/src/components/ui/chart-widget/chart-widget.d.ts +64 -0
  179. package/dist/src/components/ui/chart-widget/index.d.ts +1 -0
  180. package/dist/src/components/ui/composed-chart/composed-chart.d.ts +12 -7
  181. package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +10 -5
  182. package/dist/src/components/ui/empty-overlay/empty-overlay.d.ts +1 -1
  183. package/dist/src/components/ui/funnel-chart/funnel-chart.d.ts +11 -5
  184. package/dist/src/components/ui/histogram/histogram.d.ts +10 -4
  185. package/dist/src/components/ui/label/index.d.ts +1 -1
  186. package/dist/src/components/ui/label/label.d.ts +1 -5
  187. package/dist/src/components/ui/line-chart/line-chart.d.ts +9 -4
  188. package/dist/src/components/ui/metric/metric.d.ts +13 -14
  189. package/dist/src/components/ui/pie-chart/pie-chart.d.ts +17 -8
  190. package/dist/src/components/ui/radar-chart/radar-chart.d.ts +10 -5
  191. package/dist/src/components/ui/radial-bar-chart/radial-bar-chart.d.ts +17 -6
  192. package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +10 -5
  193. package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +10 -5
  194. package/dist/src/components/ui/section/index.d.ts +1 -1
  195. package/dist/src/components/ui/section/section.d.ts +75 -6
  196. package/dist/src/components/ui/stepper-item/stepper-item.d.ts +6 -5
  197. package/dist/src/components/ui/tag/tag.d.ts +1 -1
  198. package/dist/src/components/ui/treemap/treemap.d.ts +11 -5
  199. package/dist/src/components/ui/trend-indicator/trend-indicator.d.ts +3 -7
  200. package/dist/src/components/ui/wizard/index.d.ts +1 -0
  201. package/dist/src/components/ui/wizard/wizard.d.ts +6 -0
  202. package/dist/src/hooks/index.d.ts +1 -0
  203. package/dist/src/hooks/use-wizard.d.ts +80 -0
  204. package/dist/src/index.d.ts +2 -3
  205. package/dist/ui-react.css +1 -1
  206. package/package.json +9 -3
  207. package/dist/components/ui/app-shell/app-shell.js +0 -75
  208. package/dist/components/ui/app-shell/app-shell.js.map +0 -1
  209. package/dist/components/ui/auth-layout/auth-layout.js +0 -56
  210. package/dist/components/ui/auth-layout/auth-layout.js.map +0 -1
  211. package/dist/components/ui/collapsible/collapsible.js +0 -22
  212. package/dist/components/ui/collapsible/collapsible.js.map +0 -1
  213. package/dist/src/components/ui/app-shell/app-shell.d.ts +0 -8
  214. package/dist/src/components/ui/app-shell/index.d.ts +0 -1
  215. package/dist/src/components/ui/auth-layout/auth-layout.d.ts +0 -6
  216. package/dist/src/components/ui/auth-layout/index.d.ts +0 -1
  217. package/dist/src/components/ui/collapsible/collapsible.d.ts +0 -5
  218. package/dist/src/components/ui/collapsible/index.d.ts +0 -1
  219. package/dist/src/components/ui/label/label.docs.d.ts +0 -10
@@ -0,0 +1,333 @@
1
+ # FunnelChart
2
+
3
+ > A typed funnel-chart composition over the shared `Chart` primitives. Plots a single series of stages (rows) as stacked, narrowing segments inside a `ChartContainer`, with a tooltip and on-chart stage labels (no legend — the inline labels name every stage). One variant axis: `lastShape` (the funnel narrows to a `triangle` point or ends `rectangle` flat). Ported from the apps/demo `FunnelChartPlayground`.
4
+
5
+ **Status:** draft · **Category:** data-display · **Since:** v0.58.0
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { FunnelChart } from '@acronis-platform/ui-react'
11
+ ```
12
+
13
+ ## Quick example
14
+
15
+ ```tsx
16
+ <FunnelChart
17
+ config={config}
18
+ data={data}
19
+ dataKey="value"
20
+ nameKey="stage"
21
+ lastShape="triangle"
22
+ className="h-[380px] w-[460px]"
23
+ />
24
+ ```
25
+
26
+ A typed funnel-chart built on the shared `Chart` primitives. Give it `data`, a
27
+ per-stage `config`, the value field (`dataKey`), and the label field (`nameKey`);
28
+ it renders a themed recharts `FunnelChart` — on-chart stage labels and a tooltip
29
+ included — so you don't hand-compose recharts children. (There's no legend: the
30
+ inline labels already name every stage.)
31
+
32
+ Stage colors come from the `palette` prop — a dataviz palette resolving to the
33
+ `--ui-dataviz-*` tokens — not from `config`. Stages are an ordered progression,
34
+ so `{ type: 'sequential', ramp }` usually reads better than the default
35
+ `categorical`.
36
+
37
+ > **Design-pending v1.** Ported from the apps/demo `FunnelChartPlayground`. The
38
+ > chrome is reconciled with Figma later; Code Connect is deferred.
39
+
40
+ ## When to use
41
+
42
+ - Showing progression (and drop-off) through the ordered stages of a process —
43
+ a conversion funnel, a recruitment pipeline, an onboarding flow.
44
+ - A handful of monotonically decreasing stages read best.
45
+
46
+ ## When not to use
47
+
48
+ - Unordered categories or part-to-whole of a single total — use a pie/donut or
49
+ bar chart.
50
+ - A trend over time — use a line or area chart.
51
+ - Values that don't decrease stage to stage — the funnel metaphor misleads.
52
+
53
+ ## Variants
54
+
55
+ | Axis | Values | Effect |
56
+ | ----------- | ------------------------ | ---------------------------------------------- |
57
+ | `lastShape` | `triangle` · `rectangle` | Final segment narrows to a point vs ends flat. |
58
+
59
+ ## Example
60
+
61
+ ```tsx
62
+ import { FunnelChart } from '@acronis-platform/ui-react';
63
+ import type { ChartConfig } from '@acronis-platform/ui-react';
64
+
65
+ const data = [
66
+ { stage: 'Visits', value: 5000 },
67
+ { stage: 'Signups', value: 2600 },
68
+ { stage: 'Trials', value: 1400 },
69
+ { stage: 'Purchases', value: 620 },
70
+ ];
71
+
72
+ const config = {
73
+ Visits: { label: 'Visits', color: 'var(--ui-background-brand-secondary)' },
74
+ Signups: {
75
+ label: 'Signups',
76
+ color: 'var(--ui-background-status-strong-success)',
77
+ },
78
+ Trials: {
79
+ label: 'Trials',
80
+ color: 'var(--ui-background-status-strong-warning)',
81
+ },
82
+ Purchases: {
83
+ label: 'Purchases',
84
+ color: 'var(--ui-background-status-strong-danger)',
85
+ },
86
+ } satisfies ChartConfig;
87
+
88
+ <FunnelChart
89
+ config={config}
90
+ data={data}
91
+ dataKey="value"
92
+ nameKey="stage"
93
+ className="h-[380px] w-[460px]"
94
+ />;
95
+ ```
96
+
97
+ Stage colors reference existing semantic `--ui-*` tokens, keyed by each stage's
98
+ `nameKey` value. `--ui-background-status-strong-*` is chromatic in every brand;
99
+ `--ui-background-brand-secondary` is brand-dependent (blue in `default`, neutral
100
+ in some white-label brands), so it is not color-stable across brands until the
101
+ real data-viz palette lands.
102
+
103
+ ## Props
104
+
105
+ | Prop | Type | Default | Required | Description |
106
+ |------|------|---------|----------|-------------|
107
+ | `lastShape` | `'triangle' | 'rectangle'` | `'triangle'` | no | How the funnel ends. `triangle` narrows the final segment to a point; `rectangle` ends it flat (a stack of trapezoids). |
108
+ | `data` | `ReadonlyArray<Record<string, string | number>>` | — | yes | Row-per-stage data — each row holds a `nameKey` label and a `dataKey` numeric value. |
109
+ | `config` | `ChartConfig` | — | yes | Stages take their colour from the container's `palette`; each entry, keyed by the stage's `nameKey` value, maps that stage to a `label` and an optional `tone`. Resolved into the `--color-<name>` custom properties the segments fill from. |
110
+ | `dataKey` | `string` | — | yes | The numeric field that sizes each stage. |
111
+ | `nameKey` | `string` | — | yes | The label field that names each stage (drives the tooltip, on-chart labels, and the `--color-<name>` lookup). Values should be unique per chart — stages sharing a name share one config/color entry. |
112
+ | `reversed` | `boolean` | `false` | no | Flip the funnel so it widens toward the bottom instead of narrowing. |
113
+ | `showLabels` | `boolean` | `true` | no | Render a label for each stage — see labelFormat and labelPosition. |
114
+ | `labelFormat` | `'name' | 'value' | 'percent' | 'name-value' | 'name-percent' | 'value-percent'` | `'name'` | no | What each stage's label says. A percentage is the stage's share of the widest stage — its conversion from the top of the funnel, not a share of the sum, because a funnel's stages are nested subsets rather than parts of a whole. The value is formatted by labelFormatter and the share by percentFormatter. A composite format (a pair) narrows the funnel to leave itself room, unless funnelWidth says otherwise. |
115
+ | `labelPosition` | `'right' | 'left' | 'inside'` | `'right'` | no | Where each stage's label sits. `right`/`left` place it beside the segment on the chart surface; `inside` centres it on the segment, which switches the label to the on-fill color so it keeps contrast over a saturated fill. `inside` only works while every stage is wide enough to hold the text — a funnel narrows, so its last stages often are not; keep the text short there (`percent`) or leave the labels beside the funnel. |
116
+ | `showValueLabels` | `boolean` | `false` | no | Render a second label carrying the stage's value, so the name and the number can sit on opposite sides of the funnel. |
117
+ | `valuePosition` | `'right' | 'left' | 'inside'` | `the side opposite labelPosition` | no | Where the value label sits. Defaults to the side opposite labelPosition, where every stage has room — so it follows the names rather than pinning itself to one edge, which would overprint them when the names move. See labelPosition before choosing inside. |
118
+ | `labelFill` | `string` | — | no | Color for both label lists, overriding the contrast-matched default. Pass a --ui-* token; only needed when the default doesn't work on the surface. |
119
+ | `labelFormatter` | `(value: number | string, index?: number) => string` | — | no | Format the numeric part of a label. |
120
+ | `percentFormatter` | `(value: number | string, index?: number) => string` | — | no | Format the conversion share behind the percent formats. Receives the share as a fraction (0.52); defaults to a one-decimal bare percentage ("52.0%"). Replace it for a locale that doesn't write a bare percent sign. |
121
+ | `showLegend` | `boolean` | `false` | no | Render the legend — one entry per visible stage. Off by default because a funnel labels its stages on the chart. |
122
+ | `legendPos` | `'top' | 'bottom'` | `'bottom'` | no | Which edge the legend sits on. |
123
+ | `colorMode` | `'palette' | 'gradient'` | `'palette'` | no | How the stages are colored. `palette` gives each stage its own config color; `gradient` ramps one hue from the widest stage down to the narrowest, mixing it toward the surface so every segment stays opaque. |
124
+ | `gradientColor` | `string` | — | no | The hue gradient mode ramps. Defaults to the first visible stage's own color — including a stageSettings color set on it, since that is what the stage actually paints with. Ignored when colorMode is palette. |
125
+ | `stageSettings` | `Record<string, { color?: string; hidden?: boolean }>` | — | no | Per-stage overrides keyed by the stage's nameKey value. `color` wins over both config and colorMode; `hidden` drops the stage from the funnel, its labels, the legend, and the conversion percentages. |
126
+ | `showActiveShape` | `boolean` | `false` | no | Outline the hovered segment, rather than changing its fill, so it keeps the color that ties it to its legend entry and label. |
127
+ | `stroke` | `string` | — | no | Segment border color — reference an existing --ui-* token. Defaults to the border token when strokeWidth is set on its own, because the renderer's own default is a hardcoded white the container neutralizes. |
128
+ | `strokeWidth` | `number` | — | no | Segment border width, in px. Implies a default stroke when given alone. |
129
+ | `funnelWidth` | `number | string` | — | no | Funnel width — px, or a percentage of the plot area ('70%'). Defaults to the full plot area, except that a composite labelFormat beside the funnel narrows it: the renderer word-wraps a label against the gap between its segment and the plot-area edge, so narrowing the funnel is what creates label room. A margin cannot — it moves that edge inward with the funnel. |
130
+ | `margin` | `{ top?: number; right?: number; bottom?: number; left?: number }` | — | no | Plot-area margin, in px, merged over the defaults per side so passing one side keeps the others. It reserves the side a label list sits on so unwrappable text isn't clipped at the SVG edge — see funnelWidth for the label's wrap room. |
131
+ | `showTooltip` | `boolean` | `true` | no | Render the hover tooltip. |
132
+ | `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. |
133
+ | `animate` | `boolean` | `false` | no | Enable entrance animation. Off by default so output/baselines are unchanged. |
134
+ | `animationDuration` | `number` | — | no | Animation duration in ms. |
135
+ | `animationBegin` | `number` | — | no | Delay before the animation starts, in ms. |
136
+ | `animationEasing` | `'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear'` | — | no | Easing curve. |
137
+
138
+ ## Behavior
139
+
140
+ `FunnelChart` is a typed [recharts](https://recharts.org) composition over the
141
+ shared `Chart` primitives. It plots a single series of stages (`data` rows) as
142
+ stacked, narrowing segments inside a `ChartContainer`.
143
+
144
+ ```gherkin
145
+ Scenario: Render stages from data and config
146
+ Given data rows and a config mapping each stage name to a label and color
147
+ And dataKey "value" and nameKey "stage"
148
+ Then one segment renders per row, sized by its dataKey value
149
+ And each segment fills from its injected --color-<name> custom property
150
+ ```
151
+
152
+ ```gherkin
153
+ Scenario: Triangle last shape (default)
154
+ Given lastShape is "triangle"
155
+ Then the final segment narrows to a point
156
+ ```
157
+
158
+ ```gherkin
159
+ Scenario: Rectangle last shape
160
+ Given lastShape is "rectangle"
161
+ Then the final segment ends flat (a stack of trapezoids)
162
+ ```
163
+
164
+ ```gherkin
165
+ Scenario: Reversed
166
+ Given reversed is true
167
+ Then the funnel widens toward the bottom instead of narrowing
168
+ ```
169
+
170
+ ```gherkin
171
+ Scenario: Stage labels
172
+ Given showLabels is true
173
+ Then each stage's name renders beside its segment
174
+ ```
175
+
176
+ ```gherkin
177
+ Scenario: Label format
178
+ Given showLabels is true
179
+ And labelFormat is "name-percent"
180
+ Then each label pairs the stage's name with its conversion from the widest stage
181
+ And the widest stage reads 100.0%, whatever order the stages arrive in
182
+ And the share is formatted by percentFormatter, so a locale that doesn't write a
183
+ bare percent sign can replace it
184
+ ```
185
+
186
+ ```gherkin
187
+ Scenario: Label position drives the label color
188
+ Given labelPosition is "inside"
189
+ Then each label is centred on its segment
190
+ And it uses the on-fill color, which holds its contrast over a saturated fill
191
+ ```
192
+
193
+ ```gherkin
194
+ Scenario: An on-segment label needs a segment wide enough to hold it
195
+ Given labelPosition is "inside"
196
+ And a stage too narrow for its label text
197
+ Then the text runs past that segment onto the surface, where the on-fill color
198
+ has nothing to sit on
199
+ And the readable options are a short labelFormat or a position beside the funnel
200
+ ```
201
+
202
+ ```gherkin
203
+ Scenario: Separate value labels
204
+ Given showValueLabels is true
205
+ Then each stage carries its name on one side of the funnel and its value on the
206
+ other — the values default to the side opposite the names
207
+ And both read against the surface, so the narrow tail stages stay legible
208
+ ```
209
+
210
+ ```gherkin
211
+ Scenario: The value labels follow the names to the other side
212
+ Given showValueLabels is true
213
+ And labelPosition is "left"
214
+ And no valuePosition is given
215
+ Then the values render to the right of the funnel, not on top of the names
216
+ ```
217
+
218
+ ```gherkin
219
+ Scenario: A composite label gets room by narrowing the funnel
220
+ Given showLabels is true
221
+ And labelFormat is a pair, sitting to the right of the funnel
222
+ And no funnelWidth is given
223
+ Then the funnel is narrowed within the plot area so the label has room to wrap
224
+ into, because a label wraps against the gap between its segment and the plot
225
+ area's edge — an inset moves that edge inward with the funnel and so gives it
226
+ less room, not more
227
+ And a caller-supplied funnelWidth replaces the reserve
228
+ ```
229
+
230
+ ```gherkin
231
+ Scenario: A partial margin keeps the other sides
232
+ Given a margin that sets only one side
233
+ Then the remaining sides keep their default insets rather than collapsing to zero
234
+ ```
235
+
236
+ ```gherkin
237
+ Scenario: Legend is opt-in
238
+ Given showLegend is unset
239
+ Then no legend renders
240
+ ```
241
+
242
+ ```gherkin
243
+ Scenario: Legend entries come from the visible stages
244
+ Given showLegend is true
245
+ Then one entry renders per distinct visible stage name, labelled and colored
246
+ from config
247
+ And two stages sharing a name share the single entry they share a color with
248
+ And it sits on the edge given by legendPos (bottom by default)
249
+ ```
250
+
251
+ ```gherkin
252
+ Scenario: Gradient color mode
253
+ Given colorMode is "gradient"
254
+ Then every stage fills from one hue — gradientColor, or the first visible stage's
255
+ own color, including a stageSettings color set on it
256
+ And the hue is mixed further toward the surface at each stage down the funnel
257
+ ```
258
+
259
+ ```gherkin
260
+ Scenario: Per-stage color override
261
+ Given a stageSettings entry keyed by a stage's nameKey value carries a color
262
+ Then that stage fills with it, whatever config and colorMode say
263
+ ```
264
+
265
+ ```gherkin
266
+ Scenario: Hidden stage
267
+ Given a stageSettings entry hides its stage
268
+ Then the stage has no segment, no label and no legend entry
269
+ And the remaining conversions are measured over the visible stages only
270
+ ```
271
+
272
+ ```gherkin
273
+ Scenario: Active segment
274
+ Given showActiveShape is true
275
+ When the user hovers a stage
276
+ Then that segment is outlined and keeps its fill
277
+ ```
278
+
279
+ ```gherkin
280
+ Scenario: Tooltip on hover
281
+ Given showTooltip is true
282
+ When the user hovers a stage
283
+ Then a card shows that stage's name and value
284
+ ```
285
+
286
+ ```gherkin
287
+ Scenario: Empty data
288
+ Given data is an empty array
289
+ Then the chart renders with no segments and does not throw
290
+ ```
291
+
292
+ ```gherkin
293
+ Scenario: Entrance animation is opt-in
294
+ Given animate is unset
295
+ Then the series render at their final geometry with no entrance animation
296
+ And the committed visual baselines are unaffected
297
+ ```
298
+
299
+ ```gherkin
300
+ Scenario: Reduced motion
301
+ Given animate is true
302
+ And a user with prefers-reduced-motion
303
+ Then the entrance animation does not play and the series render at their final geometry
304
+ And the same applies when rendering on the server
305
+ ```
306
+
307
+ ## Accessibility
308
+
309
+ - recharts' `accessibilityLayer` is **on by default** (recharts v3), giving the
310
+ chart keyboard focus and an accessible description of the plotted stages.
311
+ - A funnel chart is inherently visual. **Pair it with a text alternative** — a
312
+ caption, a summary sentence, or an adjacent data table carrying the same
313
+ numbers (including the drop-off between stages, which the funnel only implies) —
314
+ and give the chart an accessible name (`aria-label` / `aria-labelledby`
315
+ referencing a visible heading). The wrapper forwards native `div` attributes,
316
+ so `aria-*` pass through.
317
+ - Do **not** rely on color alone to distinguish stages. Keep `showLabels` (or the
318
+ tooltip) visible so each color is paired with a text label — the on-chart labels
319
+ are the funnel's naming channel (there is no legend).
320
+ - The tooltip chrome resolves to semantic `--ui-*` tokens, and on-chart labels use
321
+ the foreground text token — both meet contrast in light and dark.
322
+ **Stage colors are caller-supplied** via `config` — pick values that meet 3:1
323
+ against the surface and are distinguishable for color-vision deficiencies. The
324
+ borrowed semantic tokens are a design-pending stopgap until the `--ui-chart-*`
325
+ palette lands.
326
+ - Watch recharts issue [#4809](https://github.com/recharts/recharts/issues/4809)
327
+ on the a11y layer for heavily-customized charts.
328
+
329
+ ## Contrast
330
+
331
+ Chart chrome and the on-chart stage labels meet contrast in both themes via the
332
+ semantic tokens. Segment fills come from `config` and are the caller's
333
+ responsibility — keep adjacent segments distinguishable from each other.
@@ -0,0 +1,80 @@
1
+ # Grid
2
+
3
+ > A responsive CSS-grid layout primitive — lay children into a column count that steps down at smaller breakpoints, with a configurable gap. Ported 1:1 from the legacy shadcn-uikit `grid`.
4
+
5
+ **Status:** draft · **Category:** layout · **Since:** v0.51.0
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { Grid } from '@acronis-platform/ui-react'
11
+ ```
12
+
13
+ ## Quick example
14
+
15
+ ```tsx
16
+ <Grid cols={4} gap="lg">{cells}</Grid>
17
+ ```
18
+
19
+ A responsive CSS-grid layout primitive — lay children into a column count that
20
+ steps down at smaller breakpoints, with a configurable gap.
21
+
22
+ > Design-pending v1, ported 1:1 from the legacy shadcn-uikit `grid`.
23
+
24
+ ## When to use
25
+
26
+ - Card galleries, dashboards, and other two-dimensional layouts.
27
+
28
+ ## When not to use
29
+
30
+ - One-dimensional rows/columns — use `Stack`.
31
+ - Tabular data — use `Table` / `DataTable`.
32
+
33
+ ## Parts
34
+
35
+ `Grid` is a single component.
36
+
37
+ ## Example
38
+
39
+ ```tsx
40
+ import { Grid } from '@acronis-platform/ui-react';
41
+
42
+ <Grid cols={3} gap="md">
43
+ {items.map((i) => (
44
+ <Card key={i.id} {...i} />
45
+ ))}
46
+ </Grid>;
47
+ ```
48
+
49
+ ## Props
50
+
51
+ | Prop | Type | Default | Required | Description |
52
+ |------|------|---------|----------|-------------|
53
+ | `cols` | `1 | 2 | 3 | 4 | 6 | 12` | `3` | no | Target column count at the largest breakpoint (steps down responsively). |
54
+ | `gap` | `'none' | 'sm' | 'md' | 'lg' | 'xl'` | `'md'` | no | Space between grid cells. |
55
+ | `container` | `boolean` | `false` | no | Size columns by the grid's own width (container queries) instead of the viewport — wraps the grid in a `@container/grid`. Use for grids inside a variable-width area (e.g. App Shell main). |
56
+
57
+ ## Behavior
58
+
59
+ ```gherkin
60
+ Scenario: Responsive columns
61
+ Given a Grid with cols={4}
62
+ Then cells lay out in up to 4 columns at large widths, stepping down to fewer
63
+ columns at smaller breakpoints
64
+ ```
65
+
66
+ ```gherkin
67
+ Scenario: Gap
68
+ Given a gap value
69
+ Then a consistent gap is applied between rows and columns
70
+ ```
71
+
72
+ ## Accessibility
73
+
74
+ Grid is a presentational layout `<div>` with no semantics of its own; children
75
+ follow source order. It uses CSS grid only for visual layout — don't rely on it to
76
+ convey relationships that need real table/list semantics.
77
+
78
+ ## Contrast
79
+
80
+ No color; nothing to evaluate.
@@ -0,0 +1,190 @@
1
+ # Histogram
2
+
3
+ > A frequency histogram — bins a set of continuous samples (`values`) into equal-width ranges and plots the count of each as contiguous bars. Distinct from `BarChart`, which plots pre-categorized rows: the binning is the component's own job (a pure helper). Built on the shared `Chart` primitives; design-pending v1 (no `--ui-chart-*` palette yet, no `apps/demo` playground).
4
+
5
+ **Status:** draft · **Category:** data-display · **Since:** v0.58.0
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { Histogram } from '@acronis-platform/ui-react'
11
+ ```
12
+
13
+ ## Quick example
14
+
15
+ ```tsx
16
+ <Histogram
17
+ config={{ count: { label: 'Frequency', color: 'var(--ui-background-brand-secondary)' } }}
18
+ values={[12, 15, 18, 20, 22, 25, 30, 42]}
19
+ binCount={10}
20
+ className="h-[320px] w-[560px]"
21
+ />
22
+ ```
23
+
24
+ A frequency histogram built on the shared `Chart` primitives. Give it raw
25
+ `values` and a per-series `config`; it bins the samples into equal-width ranges
26
+ and plots the count of each as contiguous bars — you don't pre-aggregate.
27
+
28
+ The bar color comes from the `palette` prop — a dataviz palette resolving to the
29
+ `--ui-dataviz-*` tokens, `categorical` by default — not from `config`.
30
+
31
+ > **Design-pending v1.** No `apps/demo` playground — built net-new. Code Connect
32
+ > is deferred.
33
+
34
+ ## When to use
35
+
36
+ - Showing the **distribution** of a single continuous variable — how many
37
+ samples fall in each value range (response times, scores, sizes).
38
+ - Spotting shape: skew, spread, modality, outliers.
39
+
40
+ ## When not to use
41
+
42
+ - Comparing named categories — that's a [`BarChart`](/components/bar-chart)
43
+ (pre-categorized rows), not a histogram (binned continuous data).
44
+ - Part-to-whole — use a pie/donut.
45
+ - Two-variable relationships — use a scatter chart.
46
+
47
+ ## Example
48
+
49
+ ```tsx
50
+ import { Histogram } from '@acronis-platform/ui-react';
51
+ import type { ChartConfig } from '@acronis-platform/ui-react';
52
+
53
+ const values = [12, 15, 18, 20, 22, 22, 25, 28, 30, 35, 42, 48, 60];
54
+
55
+ const config = {
56
+ count: { label: 'Frequency', color: 'var(--ui-background-brand-secondary)' },
57
+ } satisfies ChartConfig;
58
+
59
+ <Histogram
60
+ config={config}
61
+ values={values}
62
+ binCount={10}
63
+ className="h-[320px] w-[560px]"
64
+ />;
65
+ ```
66
+
67
+ Tune the resolution with `binCount`, or fix the range with `domain={[0, 100]}`
68
+ (samples outside the domain are dropped). The bar color references an existing
69
+ semantic `--ui-*` token; `--ui-background-brand-secondary` is brand-dependent, so
70
+ it is not color-stable across brands until the real data-viz palette lands.
71
+
72
+ ## Props
73
+
74
+ | Prop | Type | Default | Required | Description |
75
+ |------|------|---------|----------|-------------|
76
+ | `values` | `ReadonlyArray<number>` | — | yes | Raw continuous samples to bin. Non-finite values are ignored. |
77
+ | `config` | `ChartConfig` | — | yes | The single series takes its colour from the container's `palette`; the entry, keyed by `dataKey`, maps it to a `label` and an optional `tone`. Resolved into the `--color-<dataKey>` custom property the bars fill from. |
78
+ | `dataKey` | `string` | `'count'` | no | The `config` key that colors + labels the frequency bars. |
79
+ | `binCount` | `number` | `10` | no | Number of equal-width bins to split the range into. |
80
+ | `domain` | `[number, number]` | — | no | Fix the binning range instead of deriving it from the data's min/max; samples outside the domain are dropped. |
81
+ | `xAxisLabel` | `string` | — | no | Title rendered beneath the horizontal (X) axis. |
82
+ | `yAxisLabel` | `string` | — | no | Title rendered beside the vertical (Y) axis (rotated). |
83
+ | `yUnit` | `string` | — | no | Unit suffix appended to Y-axis tick values (recharts `unit`); the X axis is the bin label. |
84
+ | `barRadius` | `number` | `0` | no | Corner radius on the top of each bar (0 = square, the histogram default). |
85
+ | `showGrid` | `boolean` | `true` | no | Render the CartesianGrid. |
86
+ | `showTooltip` | `boolean` | `true` | no | Render the hover tooltip. |
87
+ | `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. |
88
+ | `showXAxis` | `boolean` | `true` | no | Render the X axis (its ticks and title). Set false to hide it. |
89
+ | `showYAxis` | `boolean` | `true` | no | Render the Y axis (its ticks and title). Set false to hide it. |
90
+ | `xTickFormatter` | `(value: number | string, index?: number) => string` | — | no | Format each X-axis tick value. Unlike the `unit` suffix (append-only), a formatter transforms the value — abbreviate, prefix a symbol, or map to a label. Use formatCompactNumber / formatPercent / createTickFormatter from the shared Chart primitives, or any function. |
91
+ | `yTickFormatter` | `(value: number | string, index?: number) => string` | — | no | Format each Y-axis tick value (see xTickFormatter). |
92
+ | `xAxisAngle` | `number` | — | no | Rotate the X-axis tick labels by this many degrees (a negative angle tilts them up toward the right); the tick anchor + axis height adjust. |
93
+ | `xAxisInterval` | `number | 'preserveStart' | 'preserveEnd' | 'preserveStartEnd' | 'equidistantPreserveStart'` | — | no | X-axis tick density — a recharts placement strategy, or a fixed number of ticks to skip between two rendered ones (recharts interval: 0 shows every tick, 1 every other one, 2 every third). |
94
+ | `yAxisTickCount` | `number` | — | no | Desired number of ticks on the value axis (recharts tickCount; a hint, not exact). Applies to whichever axis holds the values — Y for most charts, X for BarChart with orientation="horizontal". |
95
+ | `yAxisDomain` | `'auto' | 'dataMin-dataMax' | 'zero'` | — | no | Value-axis domain preset — auto (fit the data at both ends; the axis need not include 0), zero (anchor the axis at 0, which is also recharts' behaviour when the prop is omitted), or dataMin-dataMax (tight to the data, no padding). Applies to whichever axis holds the values — Y for most charts, X for BarChart with orientation="horizontal". |
96
+ | `gridDashed` | `boolean` | — | no | Draw grid lines dashed instead of solid. |
97
+ | `gridHorizontal` | `boolean` | — | no | Show horizontal grid lines (defaults to the chart's own default when unset). |
98
+ | `gridVertical` | `boolean` | — | no | Show vertical grid lines (defaults to the chart's own default when unset). |
99
+ | `animate` | `boolean` | `false` | no | Enable entrance animation. Off by default so output/baselines are unchanged. |
100
+ | `animationDuration` | `number` | — | no | Animation duration in ms. |
101
+ | `animationBegin` | `number` | — | no | Delay before the animation starts, in ms. |
102
+ | `animationEasing` | `'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear'` | — | no | Easing curve. |
103
+
104
+ ## Behavior
105
+
106
+ `Histogram` bins a set of continuous samples (`values`) into equal-width ranges
107
+ and renders their frequencies as contiguous bars, built on the shared `Chart`
108
+ primitives.
109
+
110
+ ```gherkin
111
+ Scenario: Bin and render a distribution
112
+ Given values and a binCount
113
+ Then the [min, max] range is split into binCount equal-width bins
114
+ And each bar's height is the number of samples in that bin
115
+ And the bars are contiguous (no category gap), reading as a distribution
116
+ ```
117
+
118
+ ```gherkin
119
+ Scenario: Max value placement
120
+ Given a sample equal to the range maximum
121
+ Then it falls in the last bin (whose upper edge is inclusive), not dropped
122
+ ```
123
+
124
+ ```gherkin
125
+ Scenario: Explicit domain
126
+ Given a domain [lo, hi]
127
+ Then bins span [lo, hi] instead of the data's own min/max
128
+ And samples outside [lo, hi] are dropped
129
+ ```
130
+
131
+ ```gherkin
132
+ Scenario: Degenerate range
133
+ Given all values are equal (a zero-width range)
134
+ Then the range is widened so a single bin still has extent and counts them
135
+ ```
136
+
137
+ ```gherkin
138
+ Scenario: Non-finite samples
139
+ Given values containing NaN / Infinity
140
+ Then those are ignored and only finite samples are binned
141
+ ```
142
+
143
+ ```gherkin
144
+ Scenario: Tooltip on hover
145
+ Given showTooltip is true
146
+ When the user hovers a bar
147
+ Then a card shows the bin range label and its count
148
+ ```
149
+
150
+ ```gherkin
151
+ Scenario: Empty data
152
+ Given values is empty (or has no finite samples)
153
+ Then no bars render and the chart does not throw
154
+ ```
155
+
156
+ ```gherkin
157
+ Scenario: Entrance animation is opt-in
158
+ Given animate is unset
159
+ Then the series render at their final geometry with no entrance animation
160
+ And the committed visual baselines are unaffected
161
+ ```
162
+
163
+ ```gherkin
164
+ Scenario: Reduced motion
165
+ Given animate is true
166
+ And a user with prefers-reduced-motion
167
+ Then the entrance animation does not play and the series render at their final geometry
168
+ And the same applies when rendering on the server
169
+ ```
170
+
171
+ ## Accessibility
172
+
173
+ - recharts' `accessibilityLayer` is **on by default** (recharts v3), giving the
174
+ chart keyboard focus and an accessible description of the plotted bins.
175
+ - A histogram is inherently visual. **Pair it with a text alternative** — a
176
+ caption, a summary, or an adjacent data table carrying the same counts — and
177
+ give the chart an accessible name (`aria-label` / `aria-labelledby` referencing
178
+ a visible heading). The wrapper forwards native `div` attributes, so `aria-*`
179
+ pass through.
180
+ - Do **not** rely on the bar color alone — the x-axis bin labels and the tooltip
181
+ (kept on via `showTooltip`) carry the range and count. Keep enough bins for the
182
+ distribution to be legible, but not so many that labels collide.
183
+ - Watch recharts issue [#4809](https://github.com/recharts/recharts/issues/4809)
184
+ on the a11y layer for heavily-customized charts.
185
+
186
+ ## Contrast
187
+
188
+ Tooltip chrome, axis labels, and the grid meet contrast in both themes via the
189
+ semantic tokens. The bar fill comes from `config` and is the caller's
190
+ responsibility — pick a token with sufficient contrast on the surface.