@optilogic/charts 1.3.11 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optilogic/charts",
3
- "version": "1.3.11",
3
+ "version": "1.4.0",
4
4
  "description": "Chart components for Optilogic - LineChart and BarChart built on Recharts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -24,7 +24,7 @@
24
24
  "README.md"
25
25
  ],
26
26
  "dependencies": {
27
- "@optilogic/core": "^1.7.0"
27
+ "@optilogic/core": "^2.0.0"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "react": "^18.0.0 || ^19.0.0",
@@ -60,7 +60,7 @@
60
60
  "build": "tsup",
61
61
  "dev": "tsup --watch",
62
62
  "typecheck": "tsc --noEmit",
63
- "lint": "eslint src",
63
+ "lint": "eslint src --max-warnings 0",
64
64
  "clean": "rm -rf dist .turbo"
65
65
  }
66
66
  }
@@ -71,6 +71,14 @@ const AreaChart = React.forwardRef<HTMLDivElement, AreaChartProps>(
71
71
  const tooltipProps = resolveTooltipProps(tooltip);
72
72
  const isAnimated = live ? false : animate;
73
73
 
74
+ const tableColumns = React.useMemo(
75
+ () => [
76
+ { key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
77
+ ...series.map((s) => ({ key: s.dataKey, label: s.name })),
78
+ ],
79
+ [xAxis.dataKey, xAxis.label, series],
80
+ );
81
+
74
82
  return (
75
83
  <ChartContainer
76
84
  ref={ref}
@@ -78,6 +86,9 @@ const AreaChart = React.forwardRef<HTMLDivElement, AreaChartProps>(
78
86
  height={height}
79
87
  loading={loading}
80
88
  empty={!data?.length}
89
+ ariaLabel="Area chart"
90
+ tableData={data}
91
+ tableColumns={tableColumns}
81
92
  >
82
93
  <RechartsAreaChart data={data} margin={margin}>
83
94
  <defs>
@@ -2,16 +2,25 @@ import * as React from "react";
2
2
  import {
3
3
  BarChart as RechartsBarChart,
4
4
  Bar,
5
+ Cell,
5
6
  XAxis,
6
7
  YAxis,
7
8
  CartesianGrid,
8
9
  Tooltip,
9
10
  Legend,
10
11
  } from "recharts";
12
+ import {
13
+ resolveCellFormat,
14
+ resolveFormatColor,
15
+ computeScaleDomain,
16
+ type ConditionalFormat,
17
+ type ScaleDomain,
18
+ } from "@optilogic/core";
11
19
  import { getChartColor } from "../shared/colors";
12
20
  import { resolveTooltipProps } from "../shared/chart-tooltip";
13
21
  import { ChartLegendContent, resolveLegendConfig } from "../shared/chart-legend";
14
22
  import { ChartContainer } from "../shared/chart-container";
23
+ import { toCellValue } from "../shared/formatters";
15
24
  import type {
16
25
  BaseChartProps,
17
26
  ChartXAxis,
@@ -27,6 +36,14 @@ export interface BarChartSeries {
27
36
  color?: string;
28
37
  stackId?: string;
29
38
  radius?: number | [number, number, number, number];
39
+ /**
40
+ * Per-datum conditional formatting — a value-based color scale or ordered
41
+ * rules. The resolved `background` (or `color`) becomes each bar's fill, so
42
+ * bars follow the active theme. `className`-only formats do not apply to bars.
43
+ * Color is supplementary; the value stays available via the tooltip and the
44
+ * chart's accessible data table.
45
+ */
46
+ conditionalFormat?: ConditionalFormat<Record<string, unknown>>;
30
47
  }
31
48
 
32
49
  export interface BarChartProps extends BaseChartProps {
@@ -42,6 +59,12 @@ export interface BarChartProps extends BaseChartProps {
42
59
  barGap?: number;
43
60
  barCategoryGap?: number | string;
44
61
  loading?: boolean;
62
+ /**
63
+ * "Visualization link" — called when a data point is activated (a bar is
64
+ * clicked, or its keyboard/screen-reader link is triggered). Router-agnostic:
65
+ * navigate to a dashboard or open an external URL from your handler.
66
+ */
67
+ onDataPointClick?: (datum: Record<string, unknown>, index: number) => void;
45
68
  }
46
69
 
47
70
  const BarChart = React.forwardRef<HTMLDivElement, BarChartProps>(
@@ -64,6 +87,7 @@ const BarChart = React.forwardRef<HTMLDivElement, BarChartProps>(
64
87
  height = "100%",
65
88
  margin = { top: 8, right: 12, left: 0, bottom: 4 },
66
89
  loading,
90
+ onDataPointClick,
67
91
  },
68
92
  ref,
69
93
  ) => {
@@ -78,6 +102,45 @@ const BarChart = React.forwardRef<HTMLDivElement, BarChartProps>(
78
102
  const isAnimated = live ? false : animate;
79
103
  const isHorizontal = layout === "horizontal";
80
104
 
105
+ const tableColumns = React.useMemo(
106
+ () => [
107
+ { key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
108
+ ...series.map((s) => ({ key: s.dataKey, label: s.name })),
109
+ ],
110
+ [xAxis.dataKey, xAxis.label, series],
111
+ );
112
+
113
+ // Precompute numeric domains for auto-ranged color-scale series.
114
+ const seriesScaleDomains = React.useMemo(() => {
115
+ const domains: Record<string, ScaleDomain | undefined> = {};
116
+ for (const s of series) {
117
+ const cf = s.conditionalFormat;
118
+ if (cf?.type === "colorScale" && !cf.domain) {
119
+ domains[s.dataKey] = computeScaleDomain(
120
+ data.map((d) => toCellValue(d[s.dataKey])),
121
+ );
122
+ }
123
+ }
124
+ return domains;
125
+ }, [series, data]);
126
+
127
+ // Resolve a bar's fill from its series' conditional format (else the palette color).
128
+ const resolveBarFill = (
129
+ s: BarChartSeries,
130
+ datum: Record<string, unknown>,
131
+ fallback: string,
132
+ ): string => {
133
+ if (!s.conditionalFormat) return fallback;
134
+ const fmt = resolveCellFormat(
135
+ s.conditionalFormat,
136
+ toCellValue(datum[s.dataKey]),
137
+ datum,
138
+ seriesScaleDomains[s.dataKey],
139
+ );
140
+ const color = fmt?.background ?? fmt?.color;
141
+ return color ? resolveFormatColor(color) : fallback;
142
+ };
143
+
81
144
  return (
82
145
  <ChartContainer
83
146
  ref={ref}
@@ -85,6 +148,17 @@ const BarChart = React.forwardRef<HTMLDivElement, BarChartProps>(
85
148
  height={height}
86
149
  loading={loading}
87
150
  empty={!data?.length}
151
+ ariaLabel="Bar chart"
152
+ tableData={data}
153
+ tableColumns={tableColumns}
154
+ onRowActivate={
155
+ onDataPointClick
156
+ ? (_row, index) => {
157
+ const datum = data[index];
158
+ if (datum) onDataPointClick(datum, index);
159
+ }
160
+ : undefined
161
+ }
88
162
  >
89
163
  <RechartsBarChart
90
164
  data={data}
@@ -195,18 +269,41 @@ const BarChart = React.forwardRef<HTMLDivElement, BarChartProps>(
195
269
  content={<ChartLegendContent />}
196
270
  />
197
271
  )}
198
- {series.map((s, index) => (
199
- <Bar
200
- key={s.dataKey}
201
- dataKey={s.dataKey}
202
- name={s.name}
203
- fill={getChartColor(index, s.color)}
204
- stackId={s.stackId}
205
- radius={s.radius ?? 0}
206
- isAnimationActive={isAnimated}
207
- animationDuration={isAnimated ? 300 : 0}
208
- />
209
- ))}
272
+ {series.map((s, index) => {
273
+ const baseFill = getChartColor(index, s.color);
274
+ const interactive = !!onDataPointClick;
275
+ const perDatum = !!s.conditionalFormat || interactive;
276
+ return (
277
+ <Bar
278
+ key={s.dataKey}
279
+ dataKey={s.dataKey}
280
+ name={s.name}
281
+ fill={baseFill}
282
+ stackId={s.stackId}
283
+ radius={s.radius ?? 0}
284
+ isAnimationActive={isAnimated}
285
+ animationDuration={isAnimated ? 300 : 0}
286
+ onClick={
287
+ interactive
288
+ ? (_data: unknown, i: number) => {
289
+ const datum = data[i];
290
+ if (datum) onDataPointClick?.(datum, i);
291
+ }
292
+ : undefined
293
+ }
294
+ >
295
+ {perDatum
296
+ ? data.map((d, i) => (
297
+ <Cell
298
+ key={`${s.dataKey}-${i}`}
299
+ fill={resolveBarFill(s, d, baseFill)}
300
+ cursor={interactive ? "pointer" : undefined}
301
+ />
302
+ ))
303
+ : null}
304
+ </Bar>
305
+ );
306
+ })}
210
307
  </RechartsBarChart>
211
308
  </ChartContainer>
212
309
  );
@@ -79,6 +79,14 @@ const ComposedChart = React.forwardRef<HTMLDivElement, ComposedChartProps>(
79
79
  const tooltipProps = resolveTooltipProps(tooltip);
80
80
  const isAnimated = live ? false : animate;
81
81
 
82
+ const tableColumns = React.useMemo(
83
+ () => [
84
+ { key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
85
+ ...series.map((s) => ({ key: s.dataKey, label: s.name })),
86
+ ],
87
+ [xAxis.dataKey, xAxis.label, series],
88
+ );
89
+
82
90
  return (
83
91
  <ChartContainer
84
92
  ref={ref}
@@ -86,6 +94,9 @@ const ComposedChart = React.forwardRef<HTMLDivElement, ComposedChartProps>(
86
94
  height={height}
87
95
  loading={loading}
88
96
  empty={!data?.length}
97
+ ariaLabel="Composed chart"
98
+ tableData={data}
99
+ tableColumns={tableColumns}
89
100
  >
90
101
  <RechartsComposedChart data={data} margin={margin}>
91
102
  {gridConfig && (
@@ -8,9 +8,8 @@ import {
8
8
  Tooltip,
9
9
  Legend,
10
10
  } from "recharts";
11
- import { cn } from "@optilogic/core";
12
11
  import { getChartColor } from "../shared/colors";
13
- import { resolveTooltipProps, ChartTooltipContent } from "../shared/chart-tooltip";
12
+ import { resolveTooltipProps } from "../shared/chart-tooltip";
14
13
  import { ChartLegendContent, resolveLegendConfig } from "../shared/chart-legend";
15
14
  import { ChartContainer } from "../shared/chart-container";
16
15
  import type {
@@ -72,6 +71,14 @@ const LineChart = React.forwardRef<HTMLDivElement, LineChartProps>(
72
71
  const tooltipProps = resolveTooltipProps(tooltip);
73
72
  const isAnimated = live ? false : animate;
74
73
 
74
+ const tableColumns = React.useMemo(
75
+ () => [
76
+ { key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
77
+ ...series.map((s) => ({ key: s.dataKey, label: s.name })),
78
+ ],
79
+ [xAxis.dataKey, xAxis.label, series],
80
+ );
81
+
75
82
  return (
76
83
  <ChartContainer
77
84
  ref={ref}
@@ -79,6 +86,9 @@ const LineChart = React.forwardRef<HTMLDivElement, LineChartProps>(
79
86
  height={height}
80
87
  loading={loading}
81
88
  empty={!data?.length}
89
+ ariaLabel="Line chart"
90
+ tableData={data}
91
+ tableColumns={tableColumns}
82
92
  >
83
93
  <RechartsLineChart data={data} margin={margin}>
84
94
  {gridConfig && (
@@ -71,6 +71,25 @@ const ScatterChart = React.forwardRef<HTMLDivElement, ScatterChartProps>(
71
71
  const isAnimated = live ? false : animate;
72
72
  const hasZ = series.some((s) => s.zDataKey);
73
73
 
74
+ const zDataKey = series.find((s) => s.zDataKey)?.zDataKey;
75
+ const tableColumns = React.useMemo(() => {
76
+ const cols = [
77
+ { key: "__series", label: "Series" },
78
+ { key: xAxis.dataKey, label: xAxis.name ?? xAxis.label ?? xAxis.dataKey },
79
+ { key: "y", label: yAxis?.name ?? yAxis?.label ?? "y" },
80
+ ];
81
+ if (zDataKey) cols.push({ key: zDataKey, label: zDataKey });
82
+ return cols;
83
+ }, [xAxis.dataKey, xAxis.name, xAxis.label, yAxis?.name, yAxis?.label, zDataKey]);
84
+
85
+ const tableData = React.useMemo(
86
+ () =>
87
+ series.flatMap((s) =>
88
+ (s.data ?? []).map((point) => ({ __series: s.name, ...point })),
89
+ ),
90
+ [series],
91
+ );
92
+
74
93
  return (
75
94
  <ChartContainer
76
95
  ref={ref}
@@ -78,6 +97,9 @@ const ScatterChart = React.forwardRef<HTMLDivElement, ScatterChartProps>(
78
97
  height={height}
79
98
  loading={loading}
80
99
  empty={!series.some((s) => s.data?.length)}
100
+ ariaLabel="Scatter chart"
101
+ tableData={tableData}
102
+ tableColumns={tableColumns}
81
103
  >
82
104
  <RechartsScatterChart margin={margin}>
83
105
  {gridConfig && (
@@ -93,6 +93,14 @@ const WaterfallChart = React.forwardRef<HTMLDivElement, WaterfallChartProps>(
93
93
  const negColor = negativeColor ?? getSemanticColor("negative");
94
94
  const totColor = totalColor ?? "hsl(var(--chart-3))";
95
95
 
96
+ const tableColumns = React.useMemo(
97
+ () => [
98
+ { key: "name", label: xAxis?.label ?? "Name" },
99
+ { key: "value", label: yAxis?.label ?? "Value" },
100
+ ],
101
+ [xAxis?.label, yAxis?.label],
102
+ );
103
+
96
104
  return (
97
105
  <ChartContainer
98
106
  ref={ref}
@@ -100,6 +108,9 @@ const WaterfallChart = React.forwardRef<HTMLDivElement, WaterfallChartProps>(
100
108
  height={height}
101
109
  loading={loading}
102
110
  empty={!data?.length}
111
+ ariaLabel="Waterfall chart"
112
+ tableData={data}
113
+ tableColumns={tableColumns}
103
114
  >
104
115
  <RechartsBarChart data={rows} margin={margin}>
105
116
  <CartesianGrid
@@ -73,6 +73,22 @@ const labelStyle: React.CSSProperties = {
73
73
  display: "block",
74
74
  };
75
75
 
76
+ /** Visible keyboard focus indicator for the inline-styled controls (SC 2.4.7). */
77
+ const FOCUS_STYLE_ID = "opti-chart-builder-focus";
78
+ const focusStyles = `
79
+ .opti-chart-builder-control:focus-visible {
80
+ outline: 2px solid hsl(var(--ring));
81
+ outline-offset: 1px;
82
+ border-radius: 4px;
83
+ }
84
+ `;
85
+
86
+ function FocusStyles() {
87
+ return <style id={FOCUS_STYLE_ID}>{focusStyles}</style>;
88
+ }
89
+
90
+ const FOCUS_CLASS = "opti-chart-builder-control";
91
+
76
92
  const ChartBuilder = React.memo(function ChartBuilder({
77
93
  columns,
78
94
  data,
@@ -121,6 +137,7 @@ const ChartBuilder = React.memo(function ChartBuilder({
121
137
  className={cn("flex gap-4", className)}
122
138
  style={{ minHeight: 400 }}
123
139
  >
140
+ <FocusStyles />
124
141
  {/* Config panel */}
125
142
  <div
126
143
  className="flex flex-col gap-3 shrink-0 overflow-y-auto"
@@ -138,8 +155,12 @@ const ChartBuilder = React.memo(function ChartBuilder({
138
155
 
139
156
  {/* Chart type */}
140
157
  <div>
141
- <label style={labelStyle}>Chart Type</label>
158
+ <label htmlFor="cb-chart-type" style={labelStyle}>
159
+ Chart Type
160
+ </label>
142
161
  <select
162
+ id="cb-chart-type"
163
+ className={FOCUS_CLASS}
143
164
  style={selectStyle}
144
165
  value={config.type}
145
166
  onChange={(e) =>
@@ -154,8 +175,12 @@ const ChartBuilder = React.memo(function ChartBuilder({
154
175
 
155
176
  {/* Category axis */}
156
177
  <div>
157
- <label style={labelStyle}>Category Axis</label>
178
+ <label htmlFor="cb-category-axis" style={labelStyle}>
179
+ Category Axis
180
+ </label>
158
181
  <select
182
+ id="cb-category-axis"
183
+ className={FOCUS_CLASS}
159
184
  style={selectStyle}
160
185
  value={config.categoryKey}
161
186
  onChange={(e) =>
@@ -169,8 +194,8 @@ const ChartBuilder = React.memo(function ChartBuilder({
169
194
  </div>
170
195
 
171
196
  {/* Series */}
172
- <div>
173
- <label style={labelStyle}>Series</label>
197
+ <div role="group" aria-label="Series">
198
+ <div style={labelStyle}>Series</div>
174
199
  {config.series.map((s, i) => (
175
200
  <div
176
201
  key={i}
@@ -178,6 +203,8 @@ const ChartBuilder = React.memo(function ChartBuilder({
178
203
  style={{ marginBottom: 4 }}
179
204
  >
180
205
  <select
206
+ className={FOCUS_CLASS}
207
+ aria-label={`Series ${i + 1} data column`}
181
208
  style={{ ...selectStyle, flex: 1 }}
182
209
  value={s.dataKey}
183
210
  onChange={(e) => updateSeries(i, "dataKey", e.target.value)}
@@ -189,6 +216,9 @@ const ChartBuilder = React.memo(function ChartBuilder({
189
216
  ))}
190
217
  </select>
191
218
  <button
219
+ type="button"
220
+ aria-label={`Remove series ${i + 1}`}
221
+ className={FOCUS_CLASS}
192
222
  onClick={() => removeSeries(i)}
193
223
  style={{
194
224
  padding: "2px 6px",
@@ -206,6 +236,8 @@ const ChartBuilder = React.memo(function ChartBuilder({
206
236
  </div>
207
237
  ))}
208
238
  <button
239
+ type="button"
240
+ className={FOCUS_CLASS}
209
241
  onClick={addSeries}
210
242
  style={{
211
243
  width: "100%",
@@ -225,8 +257,12 @@ const ChartBuilder = React.memo(function ChartBuilder({
225
257
 
226
258
  {/* Legend */}
227
259
  <div>
228
- <label style={labelStyle}>Legend</label>
260
+ <label htmlFor="cb-legend" style={labelStyle}>
261
+ Legend
262
+ </label>
229
263
  <select
264
+ id="cb-legend"
265
+ className={FOCUS_CLASS}
230
266
  style={selectStyle}
231
267
  value={config.legend}
232
268
  onChange={(e) =>
@@ -244,6 +280,8 @@ const ChartBuilder = React.memo(function ChartBuilder({
244
280
  <input
245
281
  type="checkbox"
246
282
  id="grid-toggle"
283
+ aria-label="Show Grid"
284
+ className={FOCUS_CLASS}
247
285
  checked={config.grid}
248
286
  onChange={(e) =>
249
287
  setConfig((prev) => ({ ...prev, grid: e.target.checked }))
@@ -259,6 +297,8 @@ const ChartBuilder = React.memo(function ChartBuilder({
259
297
  <input
260
298
  type="checkbox"
261
299
  id="animate-toggle"
300
+ aria-label="Animate"
301
+ className={FOCUS_CLASS}
262
302
  checked={config.animate}
263
303
  onChange={(e) =>
264
304
  setConfig((prev) => ({ ...prev, animate: e.target.checked }))
@@ -271,6 +311,8 @@ const ChartBuilder = React.memo(function ChartBuilder({
271
311
 
272
312
  {onSave && (
273
313
  <button
314
+ type="button"
315
+ className={FOCUS_CLASS}
274
316
  onClick={() => onSave(config)}
275
317
  style={{
276
318
  marginTop: 8,
@@ -4,7 +4,7 @@ import { BarChart } from "../cartesian/bar-chart";
4
4
  import { AreaChart } from "../cartesian/area-chart";
5
5
  import { ScatterChart } from "../cartesian/scatter-chart";
6
6
  import { ComposedChart } from "../cartesian/composed-chart";
7
- import { WaterfallChart, type WaterfallItem } from "../cartesian/waterfall-chart";
7
+ import { WaterfallChart } from "../cartesian/waterfall-chart";
8
8
  import { PieChart } from "../radial/pie-chart";
9
9
  import { DonutChart } from "../radial/donut-chart";
10
10
  import { RadarChart } from "../radial/radar-chart";
package/src/index.ts CHANGED
@@ -2,7 +2,11 @@
2
2
  export { CHART_COLORS, getChartColor, getSemanticColor, type SemanticColorName } from "./shared/colors";
3
3
  export { ChartTooltipContent, resolveTooltipProps, type ChartTooltipContentProps } from "./shared/chart-tooltip";
4
4
  export { ChartLegendContent, resolveLegendConfig } from "./shared/chart-legend";
5
- export { ChartContainer, type ChartContainerProps } from "./shared/chart-container";
5
+ export {
6
+ ChartContainer,
7
+ type ChartContainerProps,
8
+ type ChartTableColumn,
9
+ } from "./shared/chart-container";
6
10
  export { useLiveData, type UseLiveDataConfig, type UseLiveDataReturn } from "./shared/use-live-data";
7
11
  export {
8
12
  formatCompact,
@@ -62,6 +62,12 @@ const DonutChart = React.forwardRef<HTMLDivElement, DonutChartProps>(
62
62
  height={height}
63
63
  loading={loading}
64
64
  empty={!data?.length}
65
+ ariaLabel={centerLabel ?? "Donut chart"}
66
+ tableData={data}
67
+ tableColumns={[
68
+ { key: "name", label: "Name" },
69
+ { key: "value", label: "Value" },
70
+ ]}
65
71
  >
66
72
  <RechartsPieChart margin={margin}>
67
73
  <Pie
@@ -108,6 +108,12 @@ const PieChart = React.forwardRef<HTMLDivElement, PieChartProps>(
108
108
  height={height}
109
109
  loading={loading}
110
110
  empty={!data?.length}
111
+ ariaLabel="Pie chart"
112
+ tableData={data}
113
+ tableColumns={[
114
+ { key: "name", label: "Name" },
115
+ { key: "value", label: "Value" },
116
+ ]}
111
117
  >
112
118
  <RechartsPieChart margin={margin}>
113
119
  <Pie
@@ -57,6 +57,14 @@ const RadarChart = React.forwardRef<HTMLDivElement, RadarChartProps>(
57
57
  const tooltipProps = resolveTooltipProps(tooltip);
58
58
  const isAnimated = live ? false : animate;
59
59
 
60
+ const tableColumns = React.useMemo(
61
+ () => [
62
+ { key: categoryKey, label: categoryKey },
63
+ ...series.map((s) => ({ key: s.dataKey, label: s.name })),
64
+ ],
65
+ [categoryKey, series],
66
+ );
67
+
60
68
  return (
61
69
  <ChartContainer
62
70
  ref={ref}
@@ -64,6 +72,9 @@ const RadarChart = React.forwardRef<HTMLDivElement, RadarChartProps>(
64
72
  height={height}
65
73
  loading={loading}
66
74
  empty={!data?.length}
75
+ ariaLabel="Radar chart"
76
+ tableData={data}
77
+ tableColumns={tableColumns}
67
78
  >
68
79
  <RechartsRadarChart data={data} margin={margin} cx="50%" cy="50%">
69
80
  <PolarGrid stroke="hsl(var(--divider))" />
@@ -70,6 +70,12 @@ const RadialBarChart = React.forwardRef<HTMLDivElement, RadialBarChartProps>(
70
70
  height={height}
71
71
  loading={loading}
72
72
  empty={!data?.length}
73
+ ariaLabel="Radial bar chart"
74
+ tableData={data}
75
+ tableColumns={[
76
+ { key: "name", label: "Name" },
77
+ { key: "value", label: "Value" },
78
+ ]}
73
79
  >
74
80
  <RechartsRadialBarChart
75
81
  data={coloredData}