@optilogic/charts 1.3.11 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +353 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -1
- package/dist/index.d.ts +49 -1
- package/dist/index.js +355 -31
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/cartesian/area-chart.tsx +11 -0
- package/src/cartesian/bar-chart.tsx +109 -12
- package/src/cartesian/composed-chart.tsx +11 -0
- package/src/cartesian/line-chart.tsx +12 -2
- package/src/cartesian/scatter-chart.tsx +22 -0
- package/src/cartesian/waterfall-chart.tsx +11 -0
- package/src/dashboard/chart-builder.tsx +47 -5
- package/src/dashboard/chart-renderer.tsx +1 -1
- package/src/index.ts +5 -1
- package/src/radial/donut-chart.tsx +6 -0
- package/src/radial/pie-chart.tsx +6 -0
- package/src/radial/radar-chart.tsx +11 -0
- package/src/radial/radial-bar-chart.tsx +6 -0
- package/src/shared/chart-container.tsx +133 -6
- package/src/shared/formatters.ts +20 -0
- package/src/specialized/funnel-chart.tsx +6 -0
- package/src/specialized/gantt-chart.tsx +25 -0
- package/src/specialized/heatmap-chart.tsx +40 -5
- package/src/specialized/sankey-chart.tsx +17 -0
- package/src/specialized/treemap-chart.tsx +31 -1
package/dist/index.cjs
CHANGED
|
@@ -232,6 +232,13 @@ function resolveLegendConfig(legend) {
|
|
|
232
232
|
if (legend === true) return { position: "top", align: "right" };
|
|
233
233
|
return legend;
|
|
234
234
|
}
|
|
235
|
+
function formatCell(value) {
|
|
236
|
+
if (value == null) return "";
|
|
237
|
+
if (typeof value === "number") return value.toLocaleString();
|
|
238
|
+
if (value instanceof Date) return value.toLocaleString();
|
|
239
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
240
|
+
return String(value);
|
|
241
|
+
}
|
|
235
242
|
var ChartContainer = React17__namespace.forwardRef(function ChartContainer2({
|
|
236
243
|
children,
|
|
237
244
|
className,
|
|
@@ -240,8 +247,18 @@ var ChartContainer = React17__namespace.forwardRef(function ChartContainer2({
|
|
|
240
247
|
empty,
|
|
241
248
|
emptyMessage = "No data available",
|
|
242
249
|
title,
|
|
243
|
-
description
|
|
250
|
+
description,
|
|
251
|
+
ariaLabel,
|
|
252
|
+
ariaDescription,
|
|
253
|
+
tableData,
|
|
254
|
+
tableColumns,
|
|
255
|
+
onRowActivate,
|
|
256
|
+
rowActionLabel
|
|
244
257
|
}, ref) {
|
|
258
|
+
const descriptionId = React17__namespace.useId();
|
|
259
|
+
const accessibleName = ariaLabel ?? title;
|
|
260
|
+
const accessibleDescription = ariaDescription ?? description;
|
|
261
|
+
const hasTable = !loading && !empty && !!tableData && tableData.length > 0 && !!tableColumns && tableColumns.length > 0;
|
|
245
262
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: core.cn("w-full", className), style: { height }, children: [
|
|
246
263
|
(title || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
|
|
247
264
|
title && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -304,12 +321,51 @@ var ChartContainer = React17__namespace.forwardRef(function ChartContainer2({
|
|
|
304
321
|
},
|
|
305
322
|
children: emptyMessage
|
|
306
323
|
}
|
|
307
|
-
) : /* @__PURE__ */ jsxRuntime.
|
|
308
|
-
|
|
324
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
325
|
+
"div",
|
|
309
326
|
{
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
327
|
+
role: "img",
|
|
328
|
+
"aria-label": accessibleName,
|
|
329
|
+
"aria-describedby": accessibleDescription ? descriptionId : void 0,
|
|
330
|
+
className: "relative",
|
|
331
|
+
style: {
|
|
332
|
+
width: "100%",
|
|
333
|
+
height: title || description ? "calc(100% - 40px)" : "100%"
|
|
334
|
+
},
|
|
335
|
+
children: [
|
|
336
|
+
accessibleDescription && /* @__PURE__ */ jsxRuntime.jsx(core.VisuallyHidden, { as: "span", id: descriptionId, children: accessibleDescription }),
|
|
337
|
+
/* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children }),
|
|
338
|
+
hasTable && /* @__PURE__ */ jsxRuntime.jsx(core.VisuallyHidden, { as: "div", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { children: [
|
|
339
|
+
accessibleName && /* @__PURE__ */ jsxRuntime.jsx("caption", { children: accessibleName }),
|
|
340
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: tableColumns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: col.label }, col.key)) }) }),
|
|
341
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: tableData.map((row, rowIndex) => {
|
|
342
|
+
const record = row;
|
|
343
|
+
return /* @__PURE__ */ jsxRuntime.jsx("tr", { children: tableColumns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: formatCell(record[col.key]) }, col.key)) }, rowIndex);
|
|
344
|
+
}) })
|
|
345
|
+
] }) }),
|
|
346
|
+
hasTable && onRowActivate && /* @__PURE__ */ jsxRuntime.jsx(
|
|
347
|
+
"nav",
|
|
348
|
+
{
|
|
349
|
+
"aria-label": `${accessibleName ?? "Chart"} data point links`,
|
|
350
|
+
className: "sr-only focus-within:not-sr-only focus-within:absolute focus-within:z-20 focus-within:top-1 focus-within:left-1 focus-within:flex focus-within:max-h-[calc(100%-0.5rem)] focus-within:flex-col focus-within:gap-1 focus-within:overflow-auto focus-within:rounded-md focus-within:border focus-within:border-border focus-within:bg-popover focus-within:p-2 focus-within:shadow-md",
|
|
351
|
+
children: tableData.map((row, rowIndex) => {
|
|
352
|
+
const record = row;
|
|
353
|
+
const firstKey = tableColumns[0]?.key;
|
|
354
|
+
const label = rowActionLabel?.(row, rowIndex) ?? (firstKey ? formatCell(record[firstKey]) : `Row ${rowIndex + 1}`);
|
|
355
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
356
|
+
"button",
|
|
357
|
+
{
|
|
358
|
+
type: "button",
|
|
359
|
+
onClick: () => onRowActivate(row, rowIndex),
|
|
360
|
+
className: "rounded px-1 py-0.5 text-left text-sm text-foreground underline focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
361
|
+
children: label
|
|
362
|
+
},
|
|
363
|
+
rowIndex
|
|
364
|
+
);
|
|
365
|
+
})
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
]
|
|
313
369
|
}
|
|
314
370
|
)
|
|
315
371
|
] });
|
|
@@ -362,6 +418,14 @@ function useLiveData(config = {}) {
|
|
|
362
418
|
}
|
|
363
419
|
|
|
364
420
|
// src/shared/formatters.ts
|
|
421
|
+
function toCellValue(value) {
|
|
422
|
+
if (value == null) return null;
|
|
423
|
+
if (typeof value === "number" || typeof value === "string" || typeof value === "boolean") {
|
|
424
|
+
return value;
|
|
425
|
+
}
|
|
426
|
+
if (value instanceof Date) return value;
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
365
429
|
var compactThresholds = [
|
|
366
430
|
[1e9, "B"],
|
|
367
431
|
[1e6, "M"],
|
|
@@ -428,6 +492,13 @@ var LineChart = React17__namespace.forwardRef(
|
|
|
428
492
|
const legendConfig = resolveLegendConfig(legend);
|
|
429
493
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
430
494
|
const isAnimated = live ? false : animate;
|
|
495
|
+
const tableColumns = React17__namespace.useMemo(
|
|
496
|
+
() => [
|
|
497
|
+
{ key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
|
|
498
|
+
...series.map((s) => ({ key: s.dataKey, label: s.name }))
|
|
499
|
+
],
|
|
500
|
+
[xAxis.dataKey, xAxis.label, series]
|
|
501
|
+
);
|
|
431
502
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
432
503
|
ChartContainer,
|
|
433
504
|
{
|
|
@@ -436,6 +507,9 @@ var LineChart = React17__namespace.forwardRef(
|
|
|
436
507
|
height,
|
|
437
508
|
loading,
|
|
438
509
|
empty: !data?.length,
|
|
510
|
+
ariaLabel: "Line chart",
|
|
511
|
+
tableData: data,
|
|
512
|
+
tableColumns,
|
|
439
513
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, margin, children: [
|
|
440
514
|
gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
|
|
441
515
|
recharts.CartesianGrid,
|
|
@@ -530,7 +604,8 @@ var BarChart = React17__namespace.forwardRef(
|
|
|
530
604
|
className,
|
|
531
605
|
height = "100%",
|
|
532
606
|
margin = { top: 8, right: 12, left: 0, bottom: 4 },
|
|
533
|
-
loading
|
|
607
|
+
loading,
|
|
608
|
+
onDataPointClick
|
|
534
609
|
}, ref) => {
|
|
535
610
|
const gridConfig = React17__namespace.useMemo(() => {
|
|
536
611
|
if (grid === false) return null;
|
|
@@ -541,6 +616,36 @@ var BarChart = React17__namespace.forwardRef(
|
|
|
541
616
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
542
617
|
const isAnimated = live ? false : animate;
|
|
543
618
|
const isHorizontal = layout === "horizontal";
|
|
619
|
+
const tableColumns = React17__namespace.useMemo(
|
|
620
|
+
() => [
|
|
621
|
+
{ key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
|
|
622
|
+
...series.map((s) => ({ key: s.dataKey, label: s.name }))
|
|
623
|
+
],
|
|
624
|
+
[xAxis.dataKey, xAxis.label, series]
|
|
625
|
+
);
|
|
626
|
+
const seriesScaleDomains = React17__namespace.useMemo(() => {
|
|
627
|
+
const domains = {};
|
|
628
|
+
for (const s of series) {
|
|
629
|
+
const cf = s.conditionalFormat;
|
|
630
|
+
if (cf?.type === "colorScale" && !cf.domain) {
|
|
631
|
+
domains[s.dataKey] = core.computeScaleDomain(
|
|
632
|
+
data.map((d) => toCellValue(d[s.dataKey]))
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
return domains;
|
|
637
|
+
}, [series, data]);
|
|
638
|
+
const resolveBarFill = (s, datum, fallback) => {
|
|
639
|
+
if (!s.conditionalFormat) return fallback;
|
|
640
|
+
const fmt = core.resolveCellFormat(
|
|
641
|
+
s.conditionalFormat,
|
|
642
|
+
toCellValue(datum[s.dataKey]),
|
|
643
|
+
datum,
|
|
644
|
+
seriesScaleDomains[s.dataKey]
|
|
645
|
+
);
|
|
646
|
+
const color = fmt?.background ?? fmt?.color;
|
|
647
|
+
return color ? core.resolveFormatColor(color) : fallback;
|
|
648
|
+
};
|
|
544
649
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
545
650
|
ChartContainer,
|
|
546
651
|
{
|
|
@@ -549,6 +654,13 @@ var BarChart = React17__namespace.forwardRef(
|
|
|
549
654
|
height,
|
|
550
655
|
loading,
|
|
551
656
|
empty: !data?.length,
|
|
657
|
+
ariaLabel: "Bar chart",
|
|
658
|
+
tableData: data,
|
|
659
|
+
tableColumns,
|
|
660
|
+
onRowActivate: onDataPointClick ? (_row, index) => {
|
|
661
|
+
const datum = data[index];
|
|
662
|
+
if (datum) onDataPointClick(datum, index);
|
|
663
|
+
} : void 0,
|
|
552
664
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
553
665
|
recharts.BarChart,
|
|
554
666
|
{
|
|
@@ -647,19 +759,36 @@ var BarChart = React17__namespace.forwardRef(
|
|
|
647
759
|
content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
|
|
648
760
|
}
|
|
649
761
|
),
|
|
650
|
-
series.map((s, index) =>
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
762
|
+
series.map((s, index) => {
|
|
763
|
+
const baseFill = getChartColor(index, s.color);
|
|
764
|
+
const interactive = !!onDataPointClick;
|
|
765
|
+
const perDatum = !!s.conditionalFormat || interactive;
|
|
766
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
767
|
+
recharts.Bar,
|
|
768
|
+
{
|
|
769
|
+
dataKey: s.dataKey,
|
|
770
|
+
name: s.name,
|
|
771
|
+
fill: baseFill,
|
|
772
|
+
stackId: s.stackId,
|
|
773
|
+
radius: s.radius ?? 0,
|
|
774
|
+
isAnimationActive: isAnimated,
|
|
775
|
+
animationDuration: isAnimated ? 300 : 0,
|
|
776
|
+
onClick: interactive ? (_data, i) => {
|
|
777
|
+
const datum = data[i];
|
|
778
|
+
if (datum) onDataPointClick?.(datum, i);
|
|
779
|
+
} : void 0,
|
|
780
|
+
children: perDatum ? data.map((d, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
781
|
+
recharts.Cell,
|
|
782
|
+
{
|
|
783
|
+
fill: resolveBarFill(s, d, baseFill),
|
|
784
|
+
cursor: interactive ? "pointer" : void 0
|
|
785
|
+
},
|
|
786
|
+
`${s.dataKey}-${i}`
|
|
787
|
+
)) : null
|
|
788
|
+
},
|
|
789
|
+
s.dataKey
|
|
790
|
+
);
|
|
791
|
+
})
|
|
663
792
|
]
|
|
664
793
|
}
|
|
665
794
|
)
|
|
@@ -692,6 +821,13 @@ var AreaChart = React17__namespace.forwardRef(
|
|
|
692
821
|
const legendConfig = resolveLegendConfig(legend);
|
|
693
822
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
694
823
|
const isAnimated = live ? false : animate;
|
|
824
|
+
const tableColumns = React17__namespace.useMemo(
|
|
825
|
+
() => [
|
|
826
|
+
{ key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
|
|
827
|
+
...series.map((s) => ({ key: s.dataKey, label: s.name }))
|
|
828
|
+
],
|
|
829
|
+
[xAxis.dataKey, xAxis.label, series]
|
|
830
|
+
);
|
|
695
831
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
696
832
|
ChartContainer,
|
|
697
833
|
{
|
|
@@ -700,6 +836,9 @@ var AreaChart = React17__namespace.forwardRef(
|
|
|
700
836
|
height,
|
|
701
837
|
loading,
|
|
702
838
|
empty: !data?.length,
|
|
839
|
+
ariaLabel: "Area chart",
|
|
840
|
+
tableData: data,
|
|
841
|
+
tableColumns,
|
|
703
842
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.AreaChart, { data, margin, children: [
|
|
704
843
|
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: series.map((s, index) => {
|
|
705
844
|
const color = getChartColor(index, s.color);
|
|
@@ -820,6 +959,22 @@ var ScatterChart = React17__namespace.forwardRef(
|
|
|
820
959
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
821
960
|
const isAnimated = live ? false : animate;
|
|
822
961
|
const hasZ = series.some((s) => s.zDataKey);
|
|
962
|
+
const zDataKey = series.find((s) => s.zDataKey)?.zDataKey;
|
|
963
|
+
const tableColumns = React17__namespace.useMemo(() => {
|
|
964
|
+
const cols = [
|
|
965
|
+
{ key: "__series", label: "Series" },
|
|
966
|
+
{ key: xAxis.dataKey, label: xAxis.name ?? xAxis.label ?? xAxis.dataKey },
|
|
967
|
+
{ key: "y", label: yAxis?.name ?? yAxis?.label ?? "y" }
|
|
968
|
+
];
|
|
969
|
+
if (zDataKey) cols.push({ key: zDataKey, label: zDataKey });
|
|
970
|
+
return cols;
|
|
971
|
+
}, [xAxis.dataKey, xAxis.name, xAxis.label, yAxis?.name, yAxis?.label, zDataKey]);
|
|
972
|
+
const tableData = React17__namespace.useMemo(
|
|
973
|
+
() => series.flatMap(
|
|
974
|
+
(s) => (s.data ?? []).map((point) => ({ __series: s.name, ...point }))
|
|
975
|
+
),
|
|
976
|
+
[series]
|
|
977
|
+
);
|
|
823
978
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
824
979
|
ChartContainer,
|
|
825
980
|
{
|
|
@@ -828,6 +983,9 @@ var ScatterChart = React17__namespace.forwardRef(
|
|
|
828
983
|
height,
|
|
829
984
|
loading,
|
|
830
985
|
empty: !series.some((s) => s.data?.length),
|
|
986
|
+
ariaLabel: "Scatter chart",
|
|
987
|
+
tableData,
|
|
988
|
+
tableColumns,
|
|
831
989
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.ScatterChart, { margin, children: [
|
|
832
990
|
gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
|
|
833
991
|
recharts.CartesianGrid,
|
|
@@ -929,6 +1087,13 @@ var ComposedChart = React17__namespace.forwardRef(
|
|
|
929
1087
|
const legendConfig = resolveLegendConfig(legend);
|
|
930
1088
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
931
1089
|
const isAnimated = live ? false : animate;
|
|
1090
|
+
const tableColumns = React17__namespace.useMemo(
|
|
1091
|
+
() => [
|
|
1092
|
+
{ key: xAxis.dataKey, label: xAxis.label ?? xAxis.dataKey },
|
|
1093
|
+
...series.map((s) => ({ key: s.dataKey, label: s.name }))
|
|
1094
|
+
],
|
|
1095
|
+
[xAxis.dataKey, xAxis.label, series]
|
|
1096
|
+
);
|
|
932
1097
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
933
1098
|
ChartContainer,
|
|
934
1099
|
{
|
|
@@ -937,6 +1102,9 @@ var ComposedChart = React17__namespace.forwardRef(
|
|
|
937
1102
|
height,
|
|
938
1103
|
loading,
|
|
939
1104
|
empty: !data?.length,
|
|
1105
|
+
ariaLabel: "Composed chart",
|
|
1106
|
+
tableData: data,
|
|
1107
|
+
tableColumns,
|
|
940
1108
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.ComposedChart, { data, margin, children: [
|
|
941
1109
|
gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
|
|
942
1110
|
recharts.CartesianGrid,
|
|
@@ -1115,6 +1283,13 @@ var WaterfallChart = React17__namespace.forwardRef(
|
|
|
1115
1283
|
const posColor = positiveColor ?? getSemanticColor("positive");
|
|
1116
1284
|
const negColor = negativeColor ?? getSemanticColor("negative");
|
|
1117
1285
|
const totColor = totalColor ?? "hsl(var(--chart-3))";
|
|
1286
|
+
const tableColumns = React17__namespace.useMemo(
|
|
1287
|
+
() => [
|
|
1288
|
+
{ key: "name", label: xAxis?.label ?? "Name" },
|
|
1289
|
+
{ key: "value", label: yAxis?.label ?? "Value" }
|
|
1290
|
+
],
|
|
1291
|
+
[xAxis?.label, yAxis?.label]
|
|
1292
|
+
);
|
|
1118
1293
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1119
1294
|
ChartContainer,
|
|
1120
1295
|
{
|
|
@@ -1123,6 +1298,9 @@ var WaterfallChart = React17__namespace.forwardRef(
|
|
|
1123
1298
|
height,
|
|
1124
1299
|
loading,
|
|
1125
1300
|
empty: !data?.length,
|
|
1301
|
+
ariaLabel: "Waterfall chart",
|
|
1302
|
+
tableData: data,
|
|
1303
|
+
tableColumns,
|
|
1126
1304
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data: rows, margin, children: [
|
|
1127
1305
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1128
1306
|
recharts.CartesianGrid,
|
|
@@ -1251,6 +1429,12 @@ var PieChart = React17__namespace.forwardRef(
|
|
|
1251
1429
|
height,
|
|
1252
1430
|
loading,
|
|
1253
1431
|
empty: !data?.length,
|
|
1432
|
+
ariaLabel: "Pie chart",
|
|
1433
|
+
tableData: data,
|
|
1434
|
+
tableColumns: [
|
|
1435
|
+
{ key: "name", label: "Name" },
|
|
1436
|
+
{ key: "value", label: "Value" }
|
|
1437
|
+
],
|
|
1254
1438
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { margin, children: [
|
|
1255
1439
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1256
1440
|
recharts.Pie,
|
|
@@ -1323,6 +1507,12 @@ var DonutChart = React17__namespace.forwardRef(
|
|
|
1323
1507
|
height,
|
|
1324
1508
|
loading,
|
|
1325
1509
|
empty: !data?.length,
|
|
1510
|
+
ariaLabel: centerLabel ?? "Donut chart",
|
|
1511
|
+
tableData: data,
|
|
1512
|
+
tableColumns: [
|
|
1513
|
+
{ key: "name", label: "Name" },
|
|
1514
|
+
{ key: "value", label: "Value" }
|
|
1515
|
+
],
|
|
1326
1516
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { margin, children: [
|
|
1327
1517
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1328
1518
|
recharts.Pie,
|
|
@@ -1415,6 +1605,13 @@ var RadarChart = React17__namespace.forwardRef(
|
|
|
1415
1605
|
const legendConfig = resolveLegendConfig(legend);
|
|
1416
1606
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
1417
1607
|
const isAnimated = live ? false : animate;
|
|
1608
|
+
const tableColumns = React17__namespace.useMemo(
|
|
1609
|
+
() => [
|
|
1610
|
+
{ key: categoryKey, label: categoryKey },
|
|
1611
|
+
...series.map((s) => ({ key: s.dataKey, label: s.name }))
|
|
1612
|
+
],
|
|
1613
|
+
[categoryKey, series]
|
|
1614
|
+
);
|
|
1418
1615
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1419
1616
|
ChartContainer,
|
|
1420
1617
|
{
|
|
@@ -1423,6 +1620,9 @@ var RadarChart = React17__namespace.forwardRef(
|
|
|
1423
1620
|
height,
|
|
1424
1621
|
loading,
|
|
1425
1622
|
empty: !data?.length,
|
|
1623
|
+
ariaLabel: "Radar chart",
|
|
1624
|
+
tableData: data,
|
|
1625
|
+
tableColumns,
|
|
1426
1626
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.RadarChart, { data, margin, cx: "50%", cy: "50%", children: [
|
|
1427
1627
|
/* @__PURE__ */ jsxRuntime.jsx(recharts.PolarGrid, { stroke: "hsl(var(--divider))" }),
|
|
1428
1628
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1508,6 +1708,12 @@ var RadialBarChart = React17__namespace.forwardRef(
|
|
|
1508
1708
|
height,
|
|
1509
1709
|
loading,
|
|
1510
1710
|
empty: !data?.length,
|
|
1711
|
+
ariaLabel: "Radial bar chart",
|
|
1712
|
+
tableData: data,
|
|
1713
|
+
tableColumns: [
|
|
1714
|
+
{ key: "name", label: "Name" },
|
|
1715
|
+
{ key: "value", label: "Value" }
|
|
1716
|
+
],
|
|
1511
1717
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1512
1718
|
recharts.RadialBarChart,
|
|
1513
1719
|
{
|
|
@@ -1625,6 +1831,14 @@ var SankeyChart = React17__namespace.forwardRef(
|
|
|
1625
1831
|
loading
|
|
1626
1832
|
}, ref) => {
|
|
1627
1833
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
1834
|
+
const tableData = React17__namespace.useMemo(
|
|
1835
|
+
() => (data?.links ?? []).map((link) => ({
|
|
1836
|
+
source: data.nodes[link.source]?.name ?? String(link.source),
|
|
1837
|
+
target: data.nodes[link.target]?.name ?? String(link.target),
|
|
1838
|
+
value: link.value
|
|
1839
|
+
})),
|
|
1840
|
+
[data]
|
|
1841
|
+
);
|
|
1628
1842
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1629
1843
|
ChartContainer,
|
|
1630
1844
|
{
|
|
@@ -1633,6 +1847,13 @@ var SankeyChart = React17__namespace.forwardRef(
|
|
|
1633
1847
|
height,
|
|
1634
1848
|
loading,
|
|
1635
1849
|
empty: !data?.nodes?.length,
|
|
1850
|
+
ariaLabel: "Sankey diagram",
|
|
1851
|
+
tableData,
|
|
1852
|
+
tableColumns: [
|
|
1853
|
+
{ key: "source", label: "Source" },
|
|
1854
|
+
{ key: "target", label: "Target" },
|
|
1855
|
+
{ key: "value", label: "Value" }
|
|
1856
|
+
],
|
|
1636
1857
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1637
1858
|
recharts.Sankey,
|
|
1638
1859
|
{
|
|
@@ -1650,6 +1871,20 @@ var SankeyChart = React17__namespace.forwardRef(
|
|
|
1650
1871
|
}
|
|
1651
1872
|
);
|
|
1652
1873
|
SankeyChart.displayName = "SankeyChart";
|
|
1874
|
+
function flattenTreemap(nodes) {
|
|
1875
|
+
const rows = [];
|
|
1876
|
+
const walk = (items) => {
|
|
1877
|
+
for (const item of items) {
|
|
1878
|
+
if (item.children && item.children.length > 0) {
|
|
1879
|
+
walk(item.children);
|
|
1880
|
+
} else {
|
|
1881
|
+
rows.push({ name: item.name, value: item.value ?? null });
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
};
|
|
1885
|
+
walk(nodes);
|
|
1886
|
+
return rows;
|
|
1887
|
+
}
|
|
1653
1888
|
function TreemapContent({
|
|
1654
1889
|
x,
|
|
1655
1890
|
y,
|
|
@@ -1663,6 +1898,7 @@ function TreemapContent({
|
|
|
1663
1898
|
const fill = color ?? getChartColor(index);
|
|
1664
1899
|
const showLabel = width > 40 && height > 20;
|
|
1665
1900
|
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
1901
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("title", { children: name }),
|
|
1666
1902
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1667
1903
|
"rect",
|
|
1668
1904
|
{
|
|
@@ -1703,11 +1939,11 @@ var TreemapChart = React17__namespace.forwardRef(
|
|
|
1703
1939
|
live = false,
|
|
1704
1940
|
className,
|
|
1705
1941
|
height = "100%",
|
|
1706
|
-
margin,
|
|
1707
1942
|
loading
|
|
1708
1943
|
}, ref) => {
|
|
1709
1944
|
const tooltipProps = resolveTooltipProps(tooltip);
|
|
1710
1945
|
const isAnimated = live ? false : animate;
|
|
1946
|
+
const tableData = React17__namespace.useMemo(() => flattenTreemap(data), [data]);
|
|
1711
1947
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1712
1948
|
ChartContainer,
|
|
1713
1949
|
{
|
|
@@ -1716,6 +1952,12 @@ var TreemapChart = React17__namespace.forwardRef(
|
|
|
1716
1952
|
height,
|
|
1717
1953
|
loading,
|
|
1718
1954
|
empty: !data?.length,
|
|
1955
|
+
ariaLabel: "Treemap chart",
|
|
1956
|
+
tableData,
|
|
1957
|
+
tableColumns: [
|
|
1958
|
+
{ key: "name", label: "Name" },
|
|
1959
|
+
{ key: "value", label: "Value" }
|
|
1960
|
+
],
|
|
1719
1961
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1720
1962
|
recharts.Treemap,
|
|
1721
1963
|
{
|
|
@@ -1755,6 +1997,12 @@ var FunnelChart = React17__namespace.forwardRef(
|
|
|
1755
1997
|
height,
|
|
1756
1998
|
loading,
|
|
1757
1999
|
empty: !data?.length,
|
|
2000
|
+
ariaLabel: "Funnel chart",
|
|
2001
|
+
tableData: data,
|
|
2002
|
+
tableColumns: [
|
|
2003
|
+
{ key: "name", label: "Stage" },
|
|
2004
|
+
{ key: "value", label: "Value" }
|
|
2005
|
+
],
|
|
1758
2006
|
children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.FunnelChart, { margin, children: [
|
|
1759
2007
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1760
2008
|
recharts.Funnel,
|
|
@@ -1995,9 +2243,13 @@ var GanttChart = React17__namespace.forwardRef(
|
|
|
1995
2243
|
const color = task.color ?? getChartColor(i);
|
|
1996
2244
|
const isHovered = hoveredId === task.id;
|
|
1997
2245
|
const progress = task.progress ?? 0;
|
|
2246
|
+
const taskLabel = `${task.name}, ${task.start.toLocaleDateString()} to ${task.end.toLocaleDateString()}${task.progress != null ? `, ${Math.round((task.progress ?? 0) * 100)}% complete` : ""}`;
|
|
1998
2247
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1999
2248
|
"g",
|
|
2000
2249
|
{
|
|
2250
|
+
tabIndex: 0,
|
|
2251
|
+
role: onTaskClick ? "button" : "img",
|
|
2252
|
+
"aria-label": taskLabel,
|
|
2001
2253
|
onMouseEnter: (e) => {
|
|
2002
2254
|
setHoveredId(task.id);
|
|
2003
2255
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
@@ -2011,7 +2263,22 @@ var GanttChart = React17__namespace.forwardRef(
|
|
|
2011
2263
|
setHoveredId(null);
|
|
2012
2264
|
setTooltipInfo(null);
|
|
2013
2265
|
},
|
|
2266
|
+
onFocus: () => {
|
|
2267
|
+
setHoveredId(task.id);
|
|
2268
|
+
setTooltipInfo({ task, x: barX, y: barY });
|
|
2269
|
+
},
|
|
2270
|
+
onBlur: () => {
|
|
2271
|
+
setHoveredId(null);
|
|
2272
|
+
setTooltipInfo(null);
|
|
2273
|
+
},
|
|
2274
|
+
onKeyDown: (e) => {
|
|
2275
|
+
if (onTaskClick && (e.key === "Enter" || e.key === " ")) {
|
|
2276
|
+
e.preventDefault();
|
|
2277
|
+
onTaskClick(task);
|
|
2278
|
+
}
|
|
2279
|
+
},
|
|
2014
2280
|
onClick: () => onTaskClick?.(task),
|
|
2281
|
+
className: "focus:outline-none focus-visible:[outline:2px_solid_hsl(var(--ring))]",
|
|
2015
2282
|
style: { cursor: onTaskClick ? "pointer" : "default" },
|
|
2016
2283
|
children: [
|
|
2017
2284
|
i % 2 === 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2220,6 +2487,7 @@ var HeatmapChart = React17__namespace.forwardRef(
|
|
|
2220
2487
|
}, ref) {
|
|
2221
2488
|
const containerRef = React17__namespace.useRef(null);
|
|
2222
2489
|
const [hoveredCell, setHoveredCell] = React17__namespace.useState(null);
|
|
2490
|
+
const [focusedKey, setFocusedKey] = React17__namespace.useState(null);
|
|
2223
2491
|
const [tooltipPos, setTooltipPos] = React17__namespace.useState({ x: 0, y: 0 });
|
|
2224
2492
|
const { valueMap, minVal, maxVal } = React17__namespace.useMemo(() => {
|
|
2225
2493
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -2302,9 +2570,15 @@ var HeatmapChart = React17__namespace.forwardRef(
|
|
|
2302
2570
|
const cx = labelColWidth + xi * cellSize;
|
|
2303
2571
|
const cy = 28 + yi * cellSize;
|
|
2304
2572
|
const cellData = { x: xLabel, y: yLabel, value: val ?? 0 };
|
|
2573
|
+
const isInteractive = !!onCellClick;
|
|
2574
|
+
const valueText = val != null ? valueFormatter ? valueFormatter(val) : val.toLocaleString() : "no value";
|
|
2575
|
+
const cellLabel = `${yLabel}, ${xLabel}: ${valueText}`;
|
|
2305
2576
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2306
2577
|
"g",
|
|
2307
2578
|
{
|
|
2579
|
+
role: isInteractive ? "button" : "img",
|
|
2580
|
+
tabIndex: 0,
|
|
2581
|
+
"aria-label": cellLabel,
|
|
2308
2582
|
onMouseEnter: (e) => {
|
|
2309
2583
|
setHoveredCell(cellData);
|
|
2310
2584
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
@@ -2314,8 +2588,26 @@ var HeatmapChart = React17__namespace.forwardRef(
|
|
|
2314
2588
|
});
|
|
2315
2589
|
},
|
|
2316
2590
|
onMouseLeave: () => setHoveredCell(null),
|
|
2591
|
+
onFocus: () => {
|
|
2592
|
+
setHoveredCell(cellData);
|
|
2593
|
+
setFocusedKey(key);
|
|
2594
|
+
setTooltipPos({
|
|
2595
|
+
x: cx + cellSize / 2,
|
|
2596
|
+
y: cy
|
|
2597
|
+
});
|
|
2598
|
+
},
|
|
2599
|
+
onBlur: () => {
|
|
2600
|
+
setHoveredCell(null);
|
|
2601
|
+
setFocusedKey(null);
|
|
2602
|
+
},
|
|
2317
2603
|
onClick: () => onCellClick?.(cellData),
|
|
2318
|
-
|
|
2604
|
+
onKeyDown: (e) => {
|
|
2605
|
+
if (isInteractive && (e.key === "Enter" || e.key === " ")) {
|
|
2606
|
+
e.preventDefault();
|
|
2607
|
+
onCellClick?.(cellData);
|
|
2608
|
+
}
|
|
2609
|
+
},
|
|
2610
|
+
style: { cursor: onCellClick ? "pointer" : "default", outline: "none" },
|
|
2319
2611
|
children: [
|
|
2320
2612
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2321
2613
|
"rect",
|
|
@@ -2327,8 +2619,8 @@ var HeatmapChart = React17__namespace.forwardRef(
|
|
|
2327
2619
|
rx: 3,
|
|
2328
2620
|
fill: val != null ? interpolateColor(t, colorScale) : "hsl(var(--muted))",
|
|
2329
2621
|
fillOpacity: val != null ? 0.85 : 0.3,
|
|
2330
|
-
stroke: hoveredCell?.x === xLabel && hoveredCell?.y === yLabel ? "hsl(var(--foreground))" : "none",
|
|
2331
|
-
strokeWidth: 1.5
|
|
2622
|
+
stroke: focusedKey === key ? "hsl(var(--ring))" : hoveredCell?.x === xLabel && hoveredCell?.y === yLabel ? "hsl(var(--foreground))" : "none",
|
|
2623
|
+
strokeWidth: focusedKey === key ? 2.5 : 1.5
|
|
2332
2624
|
}
|
|
2333
2625
|
),
|
|
2334
2626
|
showValues && val != null && cellSize >= 32 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2958,6 +3250,18 @@ var labelStyle = {
|
|
|
2958
3250
|
marginBottom: 3,
|
|
2959
3251
|
display: "block"
|
|
2960
3252
|
};
|
|
3253
|
+
var FOCUS_STYLE_ID = "opti-chart-builder-focus";
|
|
3254
|
+
var focusStyles = `
|
|
3255
|
+
.opti-chart-builder-control:focus-visible {
|
|
3256
|
+
outline: 2px solid hsl(var(--ring));
|
|
3257
|
+
outline-offset: 1px;
|
|
3258
|
+
border-radius: 4px;
|
|
3259
|
+
}
|
|
3260
|
+
`;
|
|
3261
|
+
function FocusStyles() {
|
|
3262
|
+
return /* @__PURE__ */ jsxRuntime.jsx("style", { id: FOCUS_STYLE_ID, children: focusStyles });
|
|
3263
|
+
}
|
|
3264
|
+
var FOCUS_CLASS = "opti-chart-builder-control";
|
|
2961
3265
|
var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
2962
3266
|
columns,
|
|
2963
3267
|
data,
|
|
@@ -3000,6 +3304,7 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3000
3304
|
className: core.cn("flex gap-4", className),
|
|
3001
3305
|
style: { minHeight: 400 },
|
|
3002
3306
|
children: [
|
|
3307
|
+
/* @__PURE__ */ jsxRuntime.jsx(FocusStyles, {}),
|
|
3003
3308
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3004
3309
|
"div",
|
|
3005
3310
|
{
|
|
@@ -3014,10 +3319,12 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3014
3319
|
children: [
|
|
3015
3320
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, fontWeight: 600, color: "hsl(var(--foreground))" }, children: "Chart Builder" }),
|
|
3016
3321
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3017
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { style: labelStyle, children: "Chart Type" }),
|
|
3322
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "cb-chart-type", style: labelStyle, children: "Chart Type" }),
|
|
3018
3323
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3019
3324
|
"select",
|
|
3020
3325
|
{
|
|
3326
|
+
id: "cb-chart-type",
|
|
3327
|
+
className: FOCUS_CLASS,
|
|
3021
3328
|
style: selectStyle,
|
|
3022
3329
|
value: config.type,
|
|
3023
3330
|
onChange: (e) => setConfig((prev) => ({ ...prev, type: e.target.value })),
|
|
@@ -3026,10 +3333,12 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3026
3333
|
)
|
|
3027
3334
|
] }),
|
|
3028
3335
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3029
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { style: labelStyle, children: "Category Axis" }),
|
|
3336
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "cb-category-axis", style: labelStyle, children: "Category Axis" }),
|
|
3030
3337
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3031
3338
|
"select",
|
|
3032
3339
|
{
|
|
3340
|
+
id: "cb-category-axis",
|
|
3341
|
+
className: FOCUS_CLASS,
|
|
3033
3342
|
style: selectStyle,
|
|
3034
3343
|
value: config.categoryKey,
|
|
3035
3344
|
onChange: (e) => setConfig((prev) => ({ ...prev, categoryKey: e.target.value })),
|
|
@@ -3037,8 +3346,8 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3037
3346
|
}
|
|
3038
3347
|
)
|
|
3039
3348
|
] }),
|
|
3040
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3041
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
3349
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": "Series", children: [
|
|
3350
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle, children: "Series" }),
|
|
3042
3351
|
config.series.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3043
3352
|
"div",
|
|
3044
3353
|
{
|
|
@@ -3048,6 +3357,8 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3048
3357
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3049
3358
|
"select",
|
|
3050
3359
|
{
|
|
3360
|
+
className: FOCUS_CLASS,
|
|
3361
|
+
"aria-label": `Series ${i + 1} data column`,
|
|
3051
3362
|
style: { ...selectStyle, flex: 1 },
|
|
3052
3363
|
value: s.dataKey,
|
|
3053
3364
|
onChange: (e) => updateSeries(i, "dataKey", e.target.value),
|
|
@@ -3057,6 +3368,9 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3057
3368
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3058
3369
|
"button",
|
|
3059
3370
|
{
|
|
3371
|
+
type: "button",
|
|
3372
|
+
"aria-label": `Remove series ${i + 1}`,
|
|
3373
|
+
className: FOCUS_CLASS,
|
|
3060
3374
|
onClick: () => removeSeries(i),
|
|
3061
3375
|
style: {
|
|
3062
3376
|
padding: "2px 6px",
|
|
@@ -3078,6 +3392,8 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3078
3392
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3079
3393
|
"button",
|
|
3080
3394
|
{
|
|
3395
|
+
type: "button",
|
|
3396
|
+
className: FOCUS_CLASS,
|
|
3081
3397
|
onClick: addSeries,
|
|
3082
3398
|
style: {
|
|
3083
3399
|
width: "100%",
|
|
@@ -3095,10 +3411,12 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3095
3411
|
)
|
|
3096
3412
|
] }),
|
|
3097
3413
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3098
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { style: labelStyle, children: "Legend" }),
|
|
3414
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "cb-legend", style: labelStyle, children: "Legend" }),
|
|
3099
3415
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3100
3416
|
"select",
|
|
3101
3417
|
{
|
|
3418
|
+
id: "cb-legend",
|
|
3419
|
+
className: FOCUS_CLASS,
|
|
3102
3420
|
style: selectStyle,
|
|
3103
3421
|
value: config.legend,
|
|
3104
3422
|
onChange: (e) => setConfig((prev) => ({ ...prev, legend: e.target.value })),
|
|
@@ -3112,6 +3430,8 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3112
3430
|
{
|
|
3113
3431
|
type: "checkbox",
|
|
3114
3432
|
id: "grid-toggle",
|
|
3433
|
+
"aria-label": "Show Grid",
|
|
3434
|
+
className: FOCUS_CLASS,
|
|
3115
3435
|
checked: config.grid,
|
|
3116
3436
|
onChange: (e) => setConfig((prev) => ({ ...prev, grid: e.target.checked }))
|
|
3117
3437
|
}
|
|
@@ -3124,6 +3444,8 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3124
3444
|
{
|
|
3125
3445
|
type: "checkbox",
|
|
3126
3446
|
id: "animate-toggle",
|
|
3447
|
+
"aria-label": "Animate",
|
|
3448
|
+
className: FOCUS_CLASS,
|
|
3127
3449
|
checked: config.animate,
|
|
3128
3450
|
onChange: (e) => setConfig((prev) => ({ ...prev, animate: e.target.checked }))
|
|
3129
3451
|
}
|
|
@@ -3133,6 +3455,8 @@ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
|
|
|
3133
3455
|
onSave && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3134
3456
|
"button",
|
|
3135
3457
|
{
|
|
3458
|
+
type: "button",
|
|
3459
|
+
className: FOCUS_CLASS,
|
|
3136
3460
|
onClick: () => onSave(config),
|
|
3137
3461
|
style: {
|
|
3138
3462
|
marginTop: 8,
|