@prismiq/react 0.1.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 (82) hide show
  1. package/README.md +88 -0
  2. package/dist/CustomSQLEditor-BXB4rf1q.d.cts +1297 -0
  3. package/dist/CustomSQLEditor-DYeId0Gp.d.ts +1297 -0
  4. package/dist/DashboardDialog-B3vYC5Gs.d.ts +1106 -0
  5. package/dist/DashboardDialog-LHmrtNQU.d.cts +1106 -0
  6. package/dist/accessibility-2yy5yqRR.d.cts +145 -0
  7. package/dist/accessibility-2yy5yqRR.d.ts +145 -0
  8. package/dist/charts/index.cjs +110 -0
  9. package/dist/charts/index.cjs.map +1 -0
  10. package/dist/charts/index.d.cts +2 -0
  11. package/dist/charts/index.d.ts +2 -0
  12. package/dist/charts/index.js +5 -0
  13. package/dist/charts/index.js.map +1 -0
  14. package/dist/chunk-2H5WTH4K.js +2409 -0
  15. package/dist/chunk-2H5WTH4K.js.map +1 -0
  16. package/dist/chunk-4AVL6GQK.cjs +470 -0
  17. package/dist/chunk-4AVL6GQK.cjs.map +1 -0
  18. package/dist/chunk-EX74SI67.js +455 -0
  19. package/dist/chunk-EX74SI67.js.map +1 -0
  20. package/dist/chunk-FEABEF3J.cjs +7543 -0
  21. package/dist/chunk-FEABEF3J.cjs.map +1 -0
  22. package/dist/chunk-JTCBZDHY.js +126 -0
  23. package/dist/chunk-JTCBZDHY.js.map +1 -0
  24. package/dist/chunk-LMTG3LRC.cjs +326 -0
  25. package/dist/chunk-LMTG3LRC.cjs.map +1 -0
  26. package/dist/chunk-MDXGGZSW.cjs +273 -0
  27. package/dist/chunk-MDXGGZSW.cjs.map +1 -0
  28. package/dist/chunk-MOAEEF5P.js +7510 -0
  29. package/dist/chunk-MOAEEF5P.js.map +1 -0
  30. package/dist/chunk-NK7HKX2J.cjs +2459 -0
  31. package/dist/chunk-NK7HKX2J.cjs.map +1 -0
  32. package/dist/chunk-NY6TZLST.cjs +8781 -0
  33. package/dist/chunk-NY6TZLST.cjs.map +1 -0
  34. package/dist/chunk-T6STUE7E.js +321 -0
  35. package/dist/chunk-T6STUE7E.js.map +1 -0
  36. package/dist/chunk-TRW7DKLP.cjs +141 -0
  37. package/dist/chunk-TRW7DKLP.cjs.map +1 -0
  38. package/dist/chunk-UPYINBZU.js +8706 -0
  39. package/dist/chunk-UPYINBZU.js.map +1 -0
  40. package/dist/chunk-WWTT2OJ5.js +246 -0
  41. package/dist/chunk-WWTT2OJ5.js.map +1 -0
  42. package/dist/components/index.cjs +222 -0
  43. package/dist/components/index.cjs.map +1 -0
  44. package/dist/components/index.d.cts +207 -0
  45. package/dist/components/index.d.ts +207 -0
  46. package/dist/components/index.js +5 -0
  47. package/dist/components/index.js.map +1 -0
  48. package/dist/dashboard/index.cjs +140 -0
  49. package/dist/dashboard/index.cjs.map +1 -0
  50. package/dist/dashboard/index.d.cts +302 -0
  51. package/dist/dashboard/index.d.ts +302 -0
  52. package/dist/dashboard/index.js +7 -0
  53. package/dist/dashboard/index.js.map +1 -0
  54. package/dist/export/index.cjs +32 -0
  55. package/dist/export/index.cjs.map +1 -0
  56. package/dist/export/index.d.cts +197 -0
  57. package/dist/export/index.d.ts +197 -0
  58. package/dist/export/index.js +3 -0
  59. package/dist/export/index.js.map +1 -0
  60. package/dist/index-C-Qcuu4Y.d.cts +821 -0
  61. package/dist/index-rPc7ijt8.d.ts +821 -0
  62. package/dist/index.cjs +1486 -0
  63. package/dist/index.cjs.map +1 -0
  64. package/dist/index.d.cts +1435 -0
  65. package/dist/index.d.ts +1435 -0
  66. package/dist/index.js +926 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/ssr/index.cjs +64 -0
  69. package/dist/ssr/index.cjs.map +1 -0
  70. package/dist/ssr/index.d.cts +213 -0
  71. package/dist/ssr/index.d.ts +213 -0
  72. package/dist/ssr/index.js +3 -0
  73. package/dist/ssr/index.js.map +1 -0
  74. package/dist/types-WrCbOeAV.d.cts +569 -0
  75. package/dist/types-WrCbOeAV.d.ts +569 -0
  76. package/dist/utils/index.cjs +64 -0
  77. package/dist/utils/index.cjs.map +1 -0
  78. package/dist/utils/index.d.cts +112 -0
  79. package/dist/utils/index.d.ts +112 -0
  80. package/dist/utils/index.js +3 -0
  81. package/dist/utils/index.js.map +1 -0
  82. package/package.json +110 -0
@@ -0,0 +1,2459 @@
1
+ 'use strict';
2
+
3
+ var chunkLMTG3LRC_cjs = require('./chunk-LMTG3LRC.cjs');
4
+ var chunk4AVL6GQK_cjs = require('./chunk-4AVL6GQK.cjs');
5
+ var react = require('react');
6
+ var ReactEChartsCore = require('echarts-for-react/esm/core');
7
+ var echarts = require('echarts/core');
8
+ var charts = require('echarts/charts');
9
+ var components = require('echarts/components');
10
+ var renderers = require('echarts/renderers');
11
+ var jsxRuntime = require('react/jsx-runtime');
12
+ var ReactEChartsCore2 = require('echarts-for-react/lib/core');
13
+
14
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
+
16
+ function _interopNamespace(e) {
17
+ if (e && e.__esModule) return e;
18
+ var n = Object.create(null);
19
+ if (e) {
20
+ Object.keys(e).forEach(function (k) {
21
+ if (k !== 'default') {
22
+ var d = Object.getOwnPropertyDescriptor(e, k);
23
+ Object.defineProperty(n, k, d.get ? d : {
24
+ enumerable: true,
25
+ get: function () { return e[k]; }
26
+ });
27
+ }
28
+ });
29
+ }
30
+ n.default = e;
31
+ return Object.freeze(n);
32
+ }
33
+
34
+ var ReactEChartsCore__default = /*#__PURE__*/_interopDefault(ReactEChartsCore);
35
+ var echarts__namespace = /*#__PURE__*/_interopNamespace(echarts);
36
+ var ReactEChartsCore2__default = /*#__PURE__*/_interopDefault(ReactEChartsCore2);
37
+
38
+ // src/charts/utils.ts
39
+ function queryResultToChartData(result, xColumn, yColumns, seriesColumn) {
40
+ const xIndex = result.columns.indexOf(xColumn);
41
+ if (xIndex === -1) {
42
+ return { categories: [], series: [] };
43
+ }
44
+ if (seriesColumn) {
45
+ const seriesIndex = result.columns.indexOf(seriesColumn);
46
+ if (seriesIndex === -1) {
47
+ return { categories: [], series: [] };
48
+ }
49
+ const xValuesSet = /* @__PURE__ */ new Set();
50
+ result.rows.forEach((row) => {
51
+ const xValue = row[xIndex];
52
+ xValuesSet.add(xValue === null ? "" : String(xValue));
53
+ });
54
+ const categories2 = Array.from(xValuesSet).sort();
55
+ const seriesNamesSet = /* @__PURE__ */ new Set();
56
+ result.rows.forEach((row) => {
57
+ const seriesValue = row[seriesIndex];
58
+ seriesNamesSet.add(seriesValue === null ? "" : String(seriesValue));
59
+ });
60
+ const seriesNames = Array.from(seriesNamesSet).sort();
61
+ const series2 = yColumns.flatMap((yColName) => {
62
+ const yIndex = result.columns.indexOf(yColName);
63
+ if (yIndex === -1) {
64
+ return [];
65
+ }
66
+ return seriesNames.map((seriesName) => {
67
+ const data = categories2.map((category) => {
68
+ const row = result.rows.find((r) => {
69
+ const rowSeriesValue = r[seriesIndex];
70
+ const rowXValue = r[xIndex];
71
+ return String(rowSeriesValue) === seriesName && String(rowXValue) === category;
72
+ });
73
+ if (!row) {
74
+ return null;
75
+ }
76
+ const value = row[yIndex];
77
+ if (value === null || value === void 0) {
78
+ return null;
79
+ }
80
+ return typeof value === "number" ? value : Number(value);
81
+ });
82
+ return {
83
+ name: seriesName,
84
+ data
85
+ };
86
+ });
87
+ });
88
+ return { categories: categories2, series: series2 };
89
+ }
90
+ const categories = result.rows.map((row) => {
91
+ const value = row[xIndex];
92
+ return value === null ? "" : String(value);
93
+ });
94
+ const series = yColumns.map((colName) => {
95
+ const yIndex = result.columns.indexOf(colName);
96
+ if (yIndex === -1) {
97
+ return null;
98
+ }
99
+ const data = result.rows.map((row) => {
100
+ const value = row[yIndex];
101
+ if (value === null || value === void 0) {
102
+ return null;
103
+ }
104
+ return typeof value === "number" ? value : Number(value);
105
+ });
106
+ return {
107
+ name: colName,
108
+ data
109
+ };
110
+ }).filter((s) => s !== null);
111
+ return { categories, series };
112
+ }
113
+ function dataPointsToChartData(data, xColumn, yColumns, seriesColumn) {
114
+ if (seriesColumn) {
115
+ const xValuesSet = /* @__PURE__ */ new Set();
116
+ data.forEach((point) => {
117
+ const xValue = point[xColumn];
118
+ xValuesSet.add(xValue === null ? "" : String(xValue));
119
+ });
120
+ const categories2 = Array.from(xValuesSet).sort();
121
+ const seriesNamesSet = /* @__PURE__ */ new Set();
122
+ data.forEach((point) => {
123
+ const seriesValue = point[seriesColumn];
124
+ seriesNamesSet.add(seriesValue === null ? "" : String(seriesValue));
125
+ });
126
+ const seriesNames = Array.from(seriesNamesSet).sort();
127
+ const series2 = yColumns.flatMap((yColName) => {
128
+ return seriesNames.map((seriesName) => {
129
+ const seriesData = categories2.map((category) => {
130
+ const point = data.find((p) => {
131
+ const pSeriesValue = p[seriesColumn];
132
+ const pXValue = p[xColumn];
133
+ return String(pSeriesValue) === seriesName && String(pXValue) === category;
134
+ });
135
+ if (!point) {
136
+ return null;
137
+ }
138
+ const value = point[yColName];
139
+ if (value === null || value === void 0) {
140
+ return null;
141
+ }
142
+ return typeof value === "number" ? value : Number(value);
143
+ });
144
+ return {
145
+ name: seriesName,
146
+ data: seriesData
147
+ };
148
+ });
149
+ });
150
+ return { categories: categories2, series: series2 };
151
+ }
152
+ const categories = data.map((point) => {
153
+ const value = point[xColumn];
154
+ return value === null ? "" : String(value);
155
+ });
156
+ const series = yColumns.map((colName) => ({
157
+ name: colName,
158
+ data: data.map((point) => {
159
+ const value = point[colName];
160
+ if (value === null || value === void 0) {
161
+ return null;
162
+ }
163
+ return typeof value === "number" ? value : Number(value);
164
+ })
165
+ }));
166
+ return { categories, series };
167
+ }
168
+ function isQueryResult(data) {
169
+ return data !== null && typeof data === "object" && "columns" in data && "rows" in data && Array.isArray(data.columns) && Array.isArray(data.rows);
170
+ }
171
+ function toChartData(data, xColumn, yColumns, seriesColumn) {
172
+ if (isQueryResult(data)) {
173
+ return queryResultToChartData(data, xColumn, yColumns, seriesColumn);
174
+ }
175
+ return dataPointsToChartData(data, xColumn, yColumns, seriesColumn);
176
+ }
177
+ function createChartTheme(theme) {
178
+ return {
179
+ color: theme.chart.colors,
180
+ backgroundColor: "transparent",
181
+ textStyle: {
182
+ fontFamily: theme.fonts.sans,
183
+ color: theme.colors.text
184
+ },
185
+ title: {
186
+ textStyle: {
187
+ color: theme.colors.text,
188
+ fontSize: 16,
189
+ fontWeight: 600
190
+ }
191
+ },
192
+ legend: {
193
+ textStyle: {
194
+ color: theme.colors.textMuted,
195
+ fontSize: 12
196
+ }
197
+ },
198
+ xAxis: {
199
+ axisLine: {
200
+ show: true,
201
+ lineStyle: { color: theme.chart.axisColor }
202
+ },
203
+ axisTick: {
204
+ show: true,
205
+ lineStyle: { color: theme.chart.axisColor }
206
+ },
207
+ axisLabel: {
208
+ color: theme.colors.textMuted,
209
+ fontSize: 11
210
+ },
211
+ splitLine: {
212
+ show: false,
213
+ lineStyle: { color: theme.chart.gridColor }
214
+ }
215
+ },
216
+ yAxis: {
217
+ axisLine: {
218
+ show: false,
219
+ lineStyle: { color: theme.chart.axisColor }
220
+ },
221
+ axisTick: {
222
+ show: false,
223
+ lineStyle: { color: theme.chart.axisColor }
224
+ },
225
+ axisLabel: {
226
+ color: theme.colors.textMuted,
227
+ fontSize: 11
228
+ },
229
+ splitLine: {
230
+ show: true,
231
+ lineStyle: { color: theme.chart.gridColor, type: "dashed" }
232
+ }
233
+ },
234
+ tooltip: {
235
+ backgroundColor: theme.chart.tooltipBackground,
236
+ borderColor: theme.colors.border,
237
+ borderWidth: 1,
238
+ textStyle: {
239
+ color: theme.name === "dark" ? "#f9fafb" : "#ffffff",
240
+ fontSize: 12
241
+ },
242
+ padding: [8, 12]
243
+ },
244
+ grid: {
245
+ left: 60,
246
+ right: 20,
247
+ top: 40,
248
+ bottom: 40,
249
+ containLabel: false
250
+ }
251
+ };
252
+ }
253
+ function applyThemeToOption(option, theme) {
254
+ const chartTheme = createChartTheme(theme);
255
+ return {
256
+ ...option,
257
+ // Disable animations to prevent sizing issues with notMerge=false
258
+ // Charts will still look good but won't animate on data changes
259
+ animation: false,
260
+ color: option.color || chartTheme.color,
261
+ backgroundColor: chartTheme.backgroundColor,
262
+ textStyle: {
263
+ ...chartTheme.textStyle,
264
+ ...typeof option.textStyle === "object" ? option.textStyle : {}
265
+ },
266
+ tooltip: {
267
+ ...chartTheme.tooltip,
268
+ ...typeof option.tooltip === "object" ? option.tooltip : {}
269
+ },
270
+ xAxis: mergeAxisConfig(option.xAxis, chartTheme.xAxis),
271
+ yAxis: mergeAxisConfig(option.yAxis, chartTheme.yAxis),
272
+ grid: {
273
+ ...chartTheme.grid,
274
+ ...typeof option.grid === "object" ? option.grid : {}
275
+ }
276
+ };
277
+ }
278
+ function mergeAxisConfig(axisOption, themeAxis) {
279
+ if (Array.isArray(axisOption)) {
280
+ return axisOption.map(
281
+ (axis) => mergeAxisConfig(axis, themeAxis)
282
+ );
283
+ }
284
+ if (typeof axisOption === "object" && axisOption !== null) {
285
+ return {
286
+ ...themeAxis,
287
+ ...axisOption,
288
+ axisLine: {
289
+ ...themeAxis.axisLine,
290
+ ...axisOption.axisLine || {}
291
+ },
292
+ axisLabel: {
293
+ ...themeAxis.axisLabel,
294
+ ...axisOption.axisLabel || {}
295
+ },
296
+ splitLine: {
297
+ ...themeAxis.splitLine,
298
+ ...axisOption.splitLine || {}
299
+ }
300
+ };
301
+ }
302
+ return themeAxis;
303
+ }
304
+ function formatAxisLabel(value, format, options) {
305
+ const { currencySymbol = "$", decimals = 2, compactNotation } = options || {};
306
+ switch (format) {
307
+ case "currency":
308
+ if (compactNotation) {
309
+ return `${currencySymbol}${formatCompactAtThreshold(value, compactNotation, decimals)}`;
310
+ }
311
+ return `${currencySymbol}${value.toLocaleString(void 0, {
312
+ minimumFractionDigits: decimals,
313
+ maximumFractionDigits: decimals
314
+ })}`;
315
+ case "percent":
316
+ return `${(value * 100).toFixed(decimals)}%`;
317
+ case "compact":
318
+ return formatCompact(value, decimals);
319
+ case "number":
320
+ default:
321
+ return value.toLocaleString(void 0, {
322
+ minimumFractionDigits: decimals,
323
+ maximumFractionDigits: decimals
324
+ });
325
+ }
326
+ }
327
+ function formatCompact(value, decimals = 1) {
328
+ const absValue = Math.abs(value);
329
+ const sign = value < 0 ? "-" : "";
330
+ if (absValue >= 1e9) {
331
+ return `${sign}${(absValue / 1e9).toFixed(decimals)}B`;
332
+ }
333
+ if (absValue >= 1e6) {
334
+ return `${sign}${(absValue / 1e6).toFixed(decimals)}M`;
335
+ }
336
+ if (absValue >= 1e3) {
337
+ return `${sign}${(absValue / 1e3).toFixed(decimals)}K`;
338
+ }
339
+ return `${sign}${absValue.toFixed(decimals)}`;
340
+ }
341
+ function formatCompactAtThreshold(value, notation, decimals = 0) {
342
+ const absValue = Math.abs(value);
343
+ const sign = value < 0 ? "-" : "";
344
+ const thresholds = {
345
+ K: { threshold: 1e3, divisor: 1e3 },
346
+ M: { threshold: 1e6, divisor: 1e6 },
347
+ B: { threshold: 1e9, divisor: 1e9 },
348
+ T: { threshold: 1e12, divisor: 1e12 }
349
+ };
350
+ const config = thresholds[notation];
351
+ if (absValue >= config.threshold) {
352
+ const formatted = (absValue / config.divisor).toFixed(decimals);
353
+ return `${sign}${formatted}${notation}`;
354
+ }
355
+ return `${sign}${absValue.toLocaleString(void 0, {
356
+ minimumFractionDigits: decimals,
357
+ maximumFractionDigits: decimals
358
+ })}`;
359
+ }
360
+ function formatMetricValue(value, format = "number", options) {
361
+ if (typeof value === "string") {
362
+ return value;
363
+ }
364
+ const { currencySymbol = "$", decimals = 0, compactNotation } = options || {};
365
+ switch (format) {
366
+ case "currency":
367
+ if (compactNotation) {
368
+ const compactValue = formatCompactAtThreshold(value, compactNotation, decimals);
369
+ return `${currencySymbol}${compactValue}`;
370
+ }
371
+ return `${currencySymbol}${value.toLocaleString(void 0, {
372
+ minimumFractionDigits: decimals,
373
+ maximumFractionDigits: decimals
374
+ })}`;
375
+ case "percent":
376
+ return `${(value * 100).toFixed(decimals)}%`;
377
+ case "compact":
378
+ return formatCompact(value, decimals);
379
+ case "number":
380
+ default:
381
+ if (compactNotation) {
382
+ return formatCompactAtThreshold(value, compactNotation, decimals);
383
+ }
384
+ return value.toLocaleString(void 0, {
385
+ minimumFractionDigits: decimals,
386
+ maximumFractionDigits: decimals
387
+ });
388
+ }
389
+ }
390
+ var DEFAULT_COLOR = "#3b82f6";
391
+ function getChartColors(theme, count) {
392
+ const themeColors = theme.chart.colors;
393
+ if (themeColors.length === 0) {
394
+ return Array(count).fill(DEFAULT_COLOR);
395
+ }
396
+ const result = [];
397
+ for (let i = 0; i < count; i++) {
398
+ const color = themeColors[i % themeColors.length];
399
+ result.push(color ?? DEFAULT_COLOR);
400
+ }
401
+ return result;
402
+ }
403
+ function createGradientColor(color, opacity = 0.2) {
404
+ return {
405
+ type: "linear",
406
+ x: 0,
407
+ y: 0,
408
+ x2: 0,
409
+ y2: 1,
410
+ colorStops: [
411
+ { offset: 0, color: adjustColorOpacity(color, opacity) },
412
+ { offset: 1, color: adjustColorOpacity(color, 0.02) }
413
+ ]
414
+ };
415
+ }
416
+ function adjustColorOpacity(hexColor, opacity) {
417
+ const hex = hexColor.replace("#", "");
418
+ const r = parseInt(hex.substring(0, 2), 16);
419
+ const g = parseInt(hex.substring(2, 4), 16);
420
+ const b = parseInt(hex.substring(4, 6), 16);
421
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
422
+ }
423
+ function createMarkLines(lines, theme) {
424
+ return {
425
+ silent: true,
426
+ symbol: "none",
427
+ data: lines.map((line) => ({
428
+ yAxis: line.value,
429
+ label: {
430
+ show: !!line.label,
431
+ formatter: line.label || "",
432
+ position: "end",
433
+ color: line.color || theme.colors.textMuted,
434
+ fontSize: 11
435
+ },
436
+ lineStyle: {
437
+ color: line.color || theme.colors.textMuted,
438
+ type: line.lineStyle || "dashed",
439
+ width: 1
440
+ }
441
+ }))
442
+ };
443
+ }
444
+ function isChartDataEmpty(data) {
445
+ if (isQueryResult(data)) {
446
+ return data.rows.length === 0;
447
+ }
448
+ return data.length === 0;
449
+ }
450
+ function createEmptyStateGraphic(message = "No data available") {
451
+ return {
452
+ type: "text",
453
+ left: "center",
454
+ top: "middle",
455
+ style: {
456
+ text: message,
457
+ fontSize: 14,
458
+ fill: "#9ca3af"
459
+ }
460
+ };
461
+ }
462
+ echarts__namespace.use([
463
+ charts.BarChart,
464
+ charts.LineChart,
465
+ charts.PieChart,
466
+ charts.ScatterChart,
467
+ components.TitleComponent,
468
+ components.TooltipComponent,
469
+ components.GridComponent,
470
+ components.LegendComponent,
471
+ components.MarkLineComponent,
472
+ components.MarkPointComponent,
473
+ components.DataZoomComponent,
474
+ renderers.CanvasRenderer
475
+ ]);
476
+ function EChartWrapper({
477
+ option,
478
+ loading = false,
479
+ height = 300,
480
+ width = "100%",
481
+ theme: themeOverride,
482
+ onEvents,
483
+ className
484
+ }) {
485
+ const { theme, resolvedMode } = chunkLMTG3LRC_cjs.useTheme();
486
+ const chartRef = react.useRef(null);
487
+ const prevOptionRef = react.useRef("");
488
+ const themedOption = applyThemeToOption(option, theme);
489
+ const shouldSetOption = react.useCallback(
490
+ (_prevProps, props) => {
491
+ const newOptionString = JSON.stringify(props.option);
492
+ if (prevOptionRef.current === newOptionString) {
493
+ return false;
494
+ }
495
+ prevOptionRef.current = newOptionString;
496
+ return true;
497
+ },
498
+ []
499
+ );
500
+ const effectiveTheme = themeOverride || resolvedMode;
501
+ const handleResize = react.useCallback(() => {
502
+ if (chartRef.current) {
503
+ const chartInstance = chartRef.current.getEchartsInstance();
504
+ chartInstance?.resize();
505
+ }
506
+ }, []);
507
+ const containerStyle = {
508
+ width: typeof width === "number" ? `${width}px` : width,
509
+ height: typeof height === "number" ? `${height}px` : height,
510
+ position: "relative"
511
+ };
512
+ const loadingStyle = {
513
+ position: "absolute",
514
+ top: 0,
515
+ left: 0,
516
+ right: 0,
517
+ bottom: 0,
518
+ display: "flex",
519
+ alignItems: "center",
520
+ justifyContent: "center",
521
+ backgroundColor: theme.colors.surface,
522
+ opacity: 0.9,
523
+ zIndex: 10
524
+ };
525
+ const spinnerStyle = {
526
+ width: "32px",
527
+ height: "32px",
528
+ border: `3px solid ${theme.colors.border}`,
529
+ borderTopColor: theme.colors.primary,
530
+ borderRadius: "50%",
531
+ animation: "prismiq-spin 0.8s linear infinite"
532
+ };
533
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyle, className, children: [
534
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
535
+ @keyframes prismiq-spin {
536
+ to { transform: rotate(360deg); }
537
+ }
538
+ ` }),
539
+ loading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: loadingStyle, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: spinnerStyle }) }),
540
+ /* @__PURE__ */ jsxRuntime.jsx(
541
+ ReactEChartsCore__default.default,
542
+ {
543
+ ref: chartRef,
544
+ echarts: echarts__namespace,
545
+ option: themedOption,
546
+ notMerge: false,
547
+ lazyUpdate: true,
548
+ shouldSetOption,
549
+ theme: effectiveTheme === "dark" ? "dark" : void 0,
550
+ onEvents,
551
+ style: { width: "100%", height: "100%" },
552
+ opts: { renderer: "canvas" },
553
+ onChartReady: handleResize
554
+ }
555
+ )
556
+ ] });
557
+ }
558
+ function TrendIndicator({
559
+ trend,
560
+ trendPositive = "up",
561
+ size = "md"
562
+ }) {
563
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
564
+ const isPositive = trend.direction === "up" && trendPositive === "up" || trend.direction === "down" && trendPositive === "down";
565
+ const isNegative = trend.direction === "up" && trendPositive === "down" || trend.direction === "down" && trendPositive === "up";
566
+ const getColor = () => {
567
+ if (trend.direction === "flat") {
568
+ return theme.colors.textMuted;
569
+ }
570
+ if (isPositive) {
571
+ return theme.colors.success;
572
+ }
573
+ if (isNegative) {
574
+ return theme.colors.error;
575
+ }
576
+ return theme.colors.textMuted;
577
+ };
578
+ const getArrow = () => {
579
+ switch (trend.direction) {
580
+ case "up":
581
+ return "\u2191";
582
+ // up arrow
583
+ case "down":
584
+ return "\u2193";
585
+ // down arrow
586
+ case "flat":
587
+ default:
588
+ return "\u2192";
589
+ }
590
+ };
591
+ const sizeStyles = {
592
+ sm: { fontSize: theme.fontSizes.xs },
593
+ md: { fontSize: theme.fontSizes.sm },
594
+ lg: { fontSize: theme.fontSizes.base }
595
+ };
596
+ const containerStyle = {
597
+ display: "inline-flex",
598
+ alignItems: "center",
599
+ gap: "4px",
600
+ color: getColor(),
601
+ ...sizeStyles[size]
602
+ };
603
+ const arrowStyle = {
604
+ fontWeight: 600
605
+ };
606
+ const valueStyle = {
607
+ fontWeight: 500
608
+ };
609
+ const labelStyle = {
610
+ color: theme.colors.textMuted,
611
+ marginLeft: "4px"
612
+ };
613
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { style: containerStyle, children: [
614
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: arrowStyle, children: getArrow() }),
615
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: valueStyle, children: [
616
+ Math.abs(trend.value).toFixed(1),
617
+ "%"
618
+ ] }),
619
+ trend.label && /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelStyle, children: trend.label })
620
+ ] });
621
+ }
622
+ echarts__namespace.use([charts.LineChart, components.GridComponent, renderers.CanvasRenderer]);
623
+ function Sparkline({
624
+ data,
625
+ color,
626
+ height = 40,
627
+ width = "100%"
628
+ }) {
629
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
630
+ const lineColor = color || theme.chart.colors[0] || theme.colors.primary;
631
+ if (!data || data.length === 0) {
632
+ return null;
633
+ }
634
+ const option = {
635
+ animation: false,
636
+ grid: {
637
+ left: 0,
638
+ right: 0,
639
+ top: 0,
640
+ bottom: 0
641
+ },
642
+ xAxis: {
643
+ type: "category",
644
+ show: false,
645
+ data: data.map((_, i) => i)
646
+ },
647
+ yAxis: {
648
+ type: "value",
649
+ show: false,
650
+ min: "dataMin",
651
+ max: "dataMax"
652
+ },
653
+ series: [
654
+ {
655
+ type: "line",
656
+ data,
657
+ smooth: true,
658
+ symbol: "none",
659
+ lineStyle: {
660
+ color: lineColor,
661
+ width: 2
662
+ },
663
+ areaStyle: {
664
+ color: createGradientColor(lineColor, 0.3)
665
+ }
666
+ }
667
+ ]
668
+ };
669
+ return /* @__PURE__ */ jsxRuntime.jsx(
670
+ ReactEChartsCore2__default.default,
671
+ {
672
+ echarts: echarts__namespace,
673
+ option,
674
+ style: { width, height },
675
+ opts: { renderer: "canvas" },
676
+ notMerge: true,
677
+ lazyUpdate: true
678
+ }
679
+ );
680
+ }
681
+ function MetricCard({
682
+ title,
683
+ value,
684
+ format = "number",
685
+ currencySymbol = "$",
686
+ decimals = 0,
687
+ compactNotation,
688
+ trend,
689
+ trendPositive = "up",
690
+ sparklineData,
691
+ sparklineColor,
692
+ size = "md",
693
+ loading = false,
694
+ centered = false,
695
+ className,
696
+ onClick
697
+ }) {
698
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
699
+ const containerRef = react.useRef(null);
700
+ const [containerSize, setContainerSize] = react.useState({ width: 300, height: 200 });
701
+ react.useEffect(() => {
702
+ const measureSize = () => {
703
+ if (containerRef.current) {
704
+ setContainerSize({
705
+ width: containerRef.current.offsetWidth,
706
+ height: containerRef.current.offsetHeight
707
+ });
708
+ }
709
+ };
710
+ measureSize();
711
+ window.addEventListener("resize", measureSize);
712
+ const resizeObserver = new ResizeObserver(measureSize);
713
+ if (containerRef.current) {
714
+ resizeObserver.observe(containerRef.current);
715
+ }
716
+ return () => {
717
+ window.removeEventListener("resize", measureSize);
718
+ resizeObserver.disconnect();
719
+ };
720
+ }, []);
721
+ const formattedValueForSizing = formatMetricValue(value, format, {
722
+ currencySymbol,
723
+ decimals,
724
+ compactNotation
725
+ });
726
+ const calculateResponsiveFontSize = () => {
727
+ if (!centered) {
728
+ const sizeMap = {
729
+ sm: theme.fontSizes.xl,
730
+ md: theme.fontSizes["2xl"],
731
+ lg: "28px"
732
+ };
733
+ return sizeMap[size];
734
+ }
735
+ const { width: containerWidth, height: containerHeight } = containerSize;
736
+ const availableWidth = containerWidth - 32;
737
+ const charCount = formattedValueForSizing.length || 1;
738
+ const maxFontByWidth = availableWidth / (charCount * 0.6);
739
+ const maxFontByHeight = containerHeight * 0.25;
740
+ const scaledSize = Math.max(24, Math.min(96, Math.min(maxFontByWidth, maxFontByHeight)));
741
+ return `${scaledSize}px`;
742
+ };
743
+ const sizeConfig = {
744
+ sm: {
745
+ padding: theme.spacing.md,
746
+ titleSize: theme.fontSizes.xs,
747
+ valueSize: theme.fontSizes.xl,
748
+ sparklineHeight: 32
749
+ },
750
+ md: {
751
+ padding: theme.spacing.lg,
752
+ titleSize: theme.fontSizes.sm,
753
+ valueSize: theme.fontSizes["2xl"],
754
+ sparklineHeight: 40
755
+ },
756
+ lg: {
757
+ padding: theme.spacing.xl,
758
+ titleSize: theme.fontSizes.base,
759
+ valueSize: "28px",
760
+ sparklineHeight: 50
761
+ }
762
+ };
763
+ const config = sizeConfig[size];
764
+ const responsiveValueSize = calculateResponsiveFontSize();
765
+ const containerStyle = {
766
+ backgroundColor: theme.colors.surface,
767
+ border: `1px solid ${theme.colors.border}`,
768
+ borderRadius: theme.radius.lg,
769
+ padding: centered ? theme.spacing.md : config.padding,
770
+ cursor: onClick ? "pointer" : "default",
771
+ transition: "box-shadow 0.2s ease, border-color 0.2s ease",
772
+ position: "relative",
773
+ overflow: "hidden",
774
+ ...centered && {
775
+ display: "flex",
776
+ alignItems: "center",
777
+ justifyContent: "center",
778
+ height: "100%"
779
+ }
780
+ };
781
+ const headerStyle = {
782
+ display: "flex",
783
+ justifyContent: "space-between",
784
+ alignItems: "flex-start",
785
+ marginBottom: theme.spacing.sm
786
+ };
787
+ const titleStyle = {
788
+ fontSize: config.titleSize,
789
+ fontWeight: 500,
790
+ color: theme.colors.textMuted,
791
+ margin: 0
792
+ };
793
+ const valueStyle = {
794
+ fontSize: responsiveValueSize,
795
+ fontWeight: 600,
796
+ color: theme.colors.text,
797
+ margin: 0,
798
+ lineHeight: 1.2,
799
+ ...centered && {
800
+ textAlign: "center"
801
+ }
802
+ };
803
+ const sparklineContainerStyle = {
804
+ marginTop: theme.spacing.md
805
+ };
806
+ const skeletonStyle = {
807
+ backgroundColor: theme.colors.border,
808
+ borderRadius: theme.radius.sm,
809
+ animation: "prismiq-pulse 1.5s ease-in-out infinite"
810
+ };
811
+ const formattedValue = formattedValueForSizing;
812
+ return /* @__PURE__ */ jsxRuntime.jsxs(
813
+ "div",
814
+ {
815
+ ref: containerRef,
816
+ style: containerStyle,
817
+ className,
818
+ onClick,
819
+ role: onClick ? "button" : void 0,
820
+ tabIndex: onClick ? 0 : void 0,
821
+ onKeyDown: onClick ? (e) => {
822
+ if (e.key === "Enter" || e.key === " ") {
823
+ e.preventDefault();
824
+ onClick();
825
+ }
826
+ } : void 0,
827
+ children: [
828
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
829
+ @keyframes prismiq-pulse {
830
+ 0%, 100% { opacity: 1; }
831
+ 50% { opacity: 0.5; }
832
+ }
833
+ ` }),
834
+ centered ? loading ? /* @__PURE__ */ jsxRuntime.jsx(
835
+ "div",
836
+ {
837
+ style: {
838
+ ...skeletonStyle,
839
+ width: "120px",
840
+ height: "32px"
841
+ }
842
+ }
843
+ ) : /* @__PURE__ */ jsxRuntime.jsx("p", { style: valueStyle, children: formattedValue }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
844
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
845
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...skeletonStyle, width: "80px", height: "14px" } }) : /* @__PURE__ */ jsxRuntime.jsx("h3", { style: titleStyle, children: title }),
846
+ trend && !loading && /* @__PURE__ */ jsxRuntime.jsx(
847
+ TrendIndicator,
848
+ {
849
+ trend,
850
+ trendPositive,
851
+ size
852
+ }
853
+ )
854
+ ] }),
855
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(
856
+ "div",
857
+ {
858
+ style: {
859
+ ...skeletonStyle,
860
+ width: "120px",
861
+ height: size === "sm" ? "20px" : size === "lg" ? "32px" : "24px",
862
+ marginTop: theme.spacing.xs
863
+ }
864
+ }
865
+ ) : /* @__PURE__ */ jsxRuntime.jsx("p", { style: valueStyle, children: formattedValue }),
866
+ sparklineData && sparklineData.length > 0 && !loading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: sparklineContainerStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
867
+ Sparkline,
868
+ {
869
+ data: sparklineData,
870
+ color: sparklineColor,
871
+ height: config.sparklineHeight
872
+ }
873
+ ) }),
874
+ sparklineData && loading && /* @__PURE__ */ jsxRuntime.jsx(
875
+ "div",
876
+ {
877
+ style: {
878
+ ...skeletonStyle,
879
+ width: "100%",
880
+ height: `${config.sparklineHeight}px`,
881
+ marginTop: theme.spacing.md
882
+ }
883
+ }
884
+ )
885
+ ] })
886
+ ]
887
+ }
888
+ );
889
+ }
890
+ function BarChart2({
891
+ data,
892
+ xAxis,
893
+ yAxis,
894
+ orientation = "vertical",
895
+ stacked = false,
896
+ showDataLabels = false,
897
+ showLegend = true,
898
+ legendPosition = "top",
899
+ referenceLines,
900
+ colors,
901
+ xAxisLabel,
902
+ yAxisLabel,
903
+ xAxisFormat,
904
+ yAxisFormat = "number",
905
+ currencySymbol = "$",
906
+ compactNotation,
907
+ decimalDigits = 0,
908
+ loading = false,
909
+ error,
910
+ height = 300,
911
+ width = "100%",
912
+ className,
913
+ onDataPointClick,
914
+ crossFilter,
915
+ selectedValue
916
+ }) {
917
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
918
+ const yColumns = react.useMemo(
919
+ () => Array.isArray(yAxis) ? yAxis : [yAxis],
920
+ [yAxis]
921
+ );
922
+ const chartData = react.useMemo(
923
+ () => toChartData(data, xAxis, yColumns),
924
+ [data, xAxis, yColumns]
925
+ );
926
+ const dateFormatter = react.useMemo(
927
+ () => xAxisFormat ? chunk4AVL6GQK_cjs.createDateFormatter(xAxisFormat) : null,
928
+ [xAxisFormat]
929
+ );
930
+ const formattedCategories = react.useMemo(() => {
931
+ if (!dateFormatter) return chartData.categories;
932
+ return chartData.categories.map((cat) => dateFormatter(cat));
933
+ }, [chartData.categories, dateFormatter]);
934
+ const seriesColors = react.useMemo(
935
+ () => colors || getChartColors(theme, yColumns.length),
936
+ [colors, theme, yColumns.length]
937
+ );
938
+ const isEmpty = isChartDataEmpty(data);
939
+ const option = react.useMemo(() => {
940
+ if (isEmpty) {
941
+ return {
942
+ graphic: createEmptyStateGraphic()
943
+ };
944
+ }
945
+ const isHorizontal = orientation === "horizontal";
946
+ const categoryAxis = {
947
+ type: "category",
948
+ data: formattedCategories,
949
+ name: isHorizontal ? yAxisLabel : xAxisLabel,
950
+ nameLocation: "middle",
951
+ nameGap: 35,
952
+ axisLabel: {
953
+ rotate: isHorizontal ? 0 : formattedCategories.length > 10 ? 45 : 0,
954
+ interval: 0,
955
+ hideOverlap: true
956
+ }
957
+ };
958
+ const valueAxis = {
959
+ type: "value",
960
+ name: isHorizontal ? xAxisLabel : yAxisLabel,
961
+ nameLocation: "middle",
962
+ nameGap: 50,
963
+ axisLabel: {
964
+ formatter: (value) => formatAxisLabel(value, yAxisFormat, {
965
+ currencySymbol,
966
+ decimals: decimalDigits,
967
+ compactNotation
968
+ })
969
+ }
970
+ };
971
+ const series = chartData.series.map((s, index) => {
972
+ const baseColor = seriesColors[index] ?? theme.colors.primary;
973
+ return {
974
+ type: "bar",
975
+ name: s.name,
976
+ data: s.data.map((value, dataIndex) => {
977
+ const categoryValue = chartData.categories[dataIndex];
978
+ const isSelected = selectedValue != null && categoryValue === selectedValue;
979
+ const isOther = selectedValue != null && categoryValue !== selectedValue;
980
+ return {
981
+ value,
982
+ itemStyle: {
983
+ color: baseColor,
984
+ opacity: isOther ? 0.3 : 1,
985
+ borderRadius: stacked ? 0 : [4, 4, 0, 0],
986
+ // Highlight selected bar
987
+ ...isSelected && {
988
+ borderColor: theme.colors.primary,
989
+ borderWidth: 2
990
+ }
991
+ }
992
+ };
993
+ }),
994
+ stack: stacked ? "stack" : void 0,
995
+ label: showDataLabels ? {
996
+ show: true,
997
+ position: isHorizontal ? "right" : "top",
998
+ formatter: (params) => {
999
+ const rawValue = typeof params.value === "object" && params.value !== null ? params.value.value : params.value;
1000
+ return rawValue !== null && rawValue !== void 0 ? formatAxisLabel(rawValue, yAxisFormat, {
1001
+ currencySymbol,
1002
+ decimals: decimalDigits,
1003
+ compactNotation
1004
+ }) : "";
1005
+ },
1006
+ fontSize: 10,
1007
+ color: theme.colors.textMuted
1008
+ } : void 0,
1009
+ emphasis: {
1010
+ focus: "series",
1011
+ itemStyle: {
1012
+ shadowBlur: 10,
1013
+ shadowOffsetX: 0,
1014
+ shadowColor: "rgba(0, 0, 0, 0.2)"
1015
+ }
1016
+ },
1017
+ markLine: index === 0 && referenceLines ? createMarkLines(referenceLines, theme) : void 0
1018
+ };
1019
+ });
1020
+ const legend = showLegend ? {
1021
+ show: yColumns.length > 1,
1022
+ data: chartData.series.map((s) => s.name),
1023
+ selectedMode: "multiple",
1024
+ [legendPosition === "left" || legendPosition === "right" ? "orient" : "orient"]: legendPosition === "left" || legendPosition === "right" ? "vertical" : "horizontal",
1025
+ [legendPosition]: legendPosition === "left" || legendPosition === "right" ? 10 : legendPosition === "top" ? 10 : void 0,
1026
+ bottom: legendPosition === "bottom" ? 10 : void 0
1027
+ } : void 0;
1028
+ const grid = {
1029
+ left: legendPosition === "left" ? 100 : 60,
1030
+ right: legendPosition === "right" ? 100 : 20,
1031
+ top: legendPosition === "top" ? 50 : 40,
1032
+ bottom: legendPosition === "bottom" ? 50 : 40,
1033
+ containLabel: false
1034
+ };
1035
+ return {
1036
+ tooltip: {
1037
+ trigger: "axis",
1038
+ axisPointer: {
1039
+ type: "shadow"
1040
+ },
1041
+ formatter: (params) => {
1042
+ if (!Array.isArray(params) || params.length === 0) return "";
1043
+ const firstParam = params[0];
1044
+ if (!firstParam) return "";
1045
+ const header = `<div style="font-weight: 600; margin-bottom: 4px;">${firstParam.name}</div>`;
1046
+ const items = params.map(
1047
+ (p) => {
1048
+ const rawValue = typeof p.value === "object" && p.value !== null ? p.value.value : p.value;
1049
+ return `<div>${p.marker} ${p.seriesName}: ${rawValue !== null && rawValue !== void 0 ? formatAxisLabel(rawValue, yAxisFormat, {
1050
+ currencySymbol,
1051
+ decimals: decimalDigits,
1052
+ compactNotation
1053
+ }) : "-"}</div>`;
1054
+ }
1055
+ ).join("");
1056
+ return header + items;
1057
+ }
1058
+ },
1059
+ legend,
1060
+ grid,
1061
+ xAxis: isHorizontal ? valueAxis : categoryAxis,
1062
+ yAxis: isHorizontal ? categoryAxis : valueAxis,
1063
+ series
1064
+ };
1065
+ }, [
1066
+ isEmpty,
1067
+ orientation,
1068
+ chartData,
1069
+ formattedCategories,
1070
+ xAxisLabel,
1071
+ yAxisLabel,
1072
+ yAxisFormat,
1073
+ stacked,
1074
+ seriesColors,
1075
+ showDataLabels,
1076
+ showLegend,
1077
+ legendPosition,
1078
+ referenceLines,
1079
+ theme,
1080
+ yColumns.length,
1081
+ selectedValue,
1082
+ crossFilter?.enabled
1083
+ ]);
1084
+ const handleClick = react.useCallback(
1085
+ (params) => {
1086
+ const p = params;
1087
+ const rawValue = typeof p.value === "object" ? p.value?.value : p.value;
1088
+ const clickParams = {
1089
+ seriesName: p.seriesName ?? "",
1090
+ dataIndex: p.dataIndex ?? 0,
1091
+ value: rawValue ?? 0,
1092
+ name: p.name ?? ""
1093
+ };
1094
+ onDataPointClick?.(clickParams);
1095
+ },
1096
+ [onDataPointClick]
1097
+ );
1098
+ const handleEvents = react.useMemo(() => {
1099
+ if (!onDataPointClick && !crossFilter?.enabled) return void 0;
1100
+ return {
1101
+ click: handleClick
1102
+ };
1103
+ }, [onDataPointClick, crossFilter?.enabled, handleClick]);
1104
+ if (error) {
1105
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1106
+ "div",
1107
+ {
1108
+ style: {
1109
+ display: "flex",
1110
+ alignItems: "center",
1111
+ justifyContent: "center",
1112
+ height: typeof height === "number" ? `${height}px` : height,
1113
+ width: typeof width === "number" ? `${width}px` : width,
1114
+ color: theme.colors.error,
1115
+ fontSize: theme.fontSizes.sm
1116
+ },
1117
+ className,
1118
+ children: [
1119
+ "Error loading chart: ",
1120
+ error.message
1121
+ ]
1122
+ }
1123
+ );
1124
+ }
1125
+ return /* @__PURE__ */ jsxRuntime.jsx(
1126
+ EChartWrapper,
1127
+ {
1128
+ option,
1129
+ loading,
1130
+ height,
1131
+ width,
1132
+ className,
1133
+ onEvents: handleEvents
1134
+ }
1135
+ );
1136
+ }
1137
+ function LineChart3({
1138
+ data,
1139
+ xAxis,
1140
+ yAxis,
1141
+ seriesColumn,
1142
+ maxSeries,
1143
+ smooth = false,
1144
+ showArea = false,
1145
+ showPoints = false,
1146
+ showDataLabels = false,
1147
+ showLegend = true,
1148
+ referenceLines,
1149
+ colors,
1150
+ xAxisLabel,
1151
+ yAxisLabel,
1152
+ xAxisFormat,
1153
+ yAxisFormat = "number",
1154
+ loading = false,
1155
+ error,
1156
+ height = 300,
1157
+ width = "100%",
1158
+ className,
1159
+ onDataPointClick,
1160
+ crossFilter,
1161
+ selectedValue
1162
+ }) {
1163
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
1164
+ const yColumns = react.useMemo(
1165
+ () => Array.isArray(yAxis) ? yAxis : [yAxis],
1166
+ [yAxis]
1167
+ );
1168
+ const rawChartData = react.useMemo(
1169
+ () => toChartData(data, xAxis, yColumns, seriesColumn),
1170
+ [data, xAxis, yColumns, seriesColumn]
1171
+ );
1172
+ const chartData = react.useMemo(() => {
1173
+ if (!maxSeries || rawChartData.series.length <= maxSeries) {
1174
+ return rawChartData;
1175
+ }
1176
+ const seriesWithTotals = rawChartData.series.map((s) => ({
1177
+ ...s,
1178
+ total: s.data.reduce((sum, val) => sum + (val ?? 0), 0)
1179
+ }));
1180
+ const topSeries = seriesWithTotals.sort((a, b) => (b.total ?? 0) - (a.total ?? 0)).slice(0, maxSeries).map(({ total: _total, ...rest }) => rest);
1181
+ return {
1182
+ categories: rawChartData.categories,
1183
+ series: topSeries
1184
+ };
1185
+ }, [rawChartData, maxSeries]);
1186
+ const dateFormatter = react.useMemo(
1187
+ () => xAxisFormat ? chunk4AVL6GQK_cjs.createDateFormatter(xAxisFormat) : null,
1188
+ [xAxisFormat]
1189
+ );
1190
+ const formattedCategories = react.useMemo(() => {
1191
+ if (!dateFormatter) {
1192
+ return chartData.categories;
1193
+ }
1194
+ return chartData.categories.map((cat) => dateFormatter(cat));
1195
+ }, [chartData.categories, dateFormatter]);
1196
+ const seriesColors = react.useMemo(
1197
+ () => colors || getChartColors(theme, chartData.series.length),
1198
+ [colors, theme, chartData.series.length]
1199
+ );
1200
+ const isEmpty = isChartDataEmpty(data);
1201
+ const option = react.useMemo(() => {
1202
+ if (isEmpty) {
1203
+ return {
1204
+ graphic: createEmptyStateGraphic()
1205
+ };
1206
+ }
1207
+ const series = chartData.series.map((s, index) => {
1208
+ const color = seriesColors[index] ?? theme.colors.primary;
1209
+ const seriesData = s.data.map((value, dataIndex) => {
1210
+ const categoryValue = chartData.categories[dataIndex];
1211
+ const isSelected = selectedValue != null && categoryValue === selectedValue;
1212
+ const isOther = selectedValue != null && categoryValue !== selectedValue;
1213
+ return {
1214
+ value,
1215
+ itemStyle: {
1216
+ color,
1217
+ opacity: isOther ? 0.3 : 1,
1218
+ // Highlight selected point
1219
+ ...isSelected && {
1220
+ borderColor: theme.colors.primary,
1221
+ borderWidth: 3
1222
+ }
1223
+ },
1224
+ symbolSize: isSelected ? 10 : showPoints ? 6 : 0
1225
+ };
1226
+ });
1227
+ return {
1228
+ type: "line",
1229
+ name: s.name,
1230
+ data: seriesData,
1231
+ smooth: smooth ? 0.3 : false,
1232
+ symbol: showPoints || selectedValue != null ? "circle" : "none",
1233
+ symbolSize: showPoints ? 6 : 0,
1234
+ itemStyle: {
1235
+ color
1236
+ },
1237
+ lineStyle: {
1238
+ color,
1239
+ width: 2,
1240
+ opacity: selectedValue != null ? 0.5 : 1
1241
+ },
1242
+ areaStyle: showArea ? {
1243
+ color: createGradientColor(color, selectedValue != null ? 0.15 : 0.3)
1244
+ } : void 0,
1245
+ label: showDataLabels ? {
1246
+ show: true,
1247
+ position: "top",
1248
+ formatter: (params) => params.value !== null ? formatAxisLabel(params.value, yAxisFormat) : "",
1249
+ fontSize: 10,
1250
+ color: theme.colors.textMuted
1251
+ } : void 0,
1252
+ emphasis: {
1253
+ focus: "series",
1254
+ itemStyle: {
1255
+ shadowBlur: 10,
1256
+ shadowOffsetX: 0,
1257
+ shadowColor: "rgba(0, 0, 0, 0.2)"
1258
+ }
1259
+ },
1260
+ markLine: index === 0 && referenceLines ? createMarkLines(referenceLines, theme) : void 0,
1261
+ // Enable cursor pointer when cross-filter is enabled
1262
+ cursor: crossFilter?.enabled ? "pointer" : "default"
1263
+ };
1264
+ });
1265
+ const legend = showLegend ? {
1266
+ show: chartData.series.length > 1,
1267
+ data: chartData.series.map((s) => s.name),
1268
+ selectedMode: "multiple",
1269
+ top: 10
1270
+ } : void 0;
1271
+ return {
1272
+ tooltip: {
1273
+ trigger: "axis",
1274
+ axisPointer: {
1275
+ type: "cross",
1276
+ label: {
1277
+ backgroundColor: theme.chart.tooltipBackground
1278
+ }
1279
+ },
1280
+ formatter: (params) => {
1281
+ if (!Array.isArray(params) || params.length === 0) return "";
1282
+ const firstParam = params[0];
1283
+ if (!firstParam) return "";
1284
+ const header = `<div style="font-weight: 600; margin-bottom: 4px;">${firstParam.name}</div>`;
1285
+ const items = params.map(
1286
+ (p) => `<div>${p.marker} ${p.seriesName}: ${p.value !== null ? formatAxisLabel(p.value, yAxisFormat) : "-"}</div>`
1287
+ ).join("");
1288
+ return header + items;
1289
+ }
1290
+ },
1291
+ legend,
1292
+ grid: {
1293
+ left: 60,
1294
+ right: 20,
1295
+ top: legend ? 50 : 40,
1296
+ bottom: 40
1297
+ },
1298
+ xAxis: {
1299
+ type: "category",
1300
+ data: formattedCategories,
1301
+ name: xAxisLabel,
1302
+ nameLocation: "middle",
1303
+ nameGap: 35,
1304
+ axisLabel: {
1305
+ rotate: formattedCategories.length > 10 ? 45 : 0,
1306
+ interval: 0,
1307
+ hideOverlap: true
1308
+ },
1309
+ boundaryGap: false
1310
+ },
1311
+ yAxis: {
1312
+ type: "value",
1313
+ name: yAxisLabel,
1314
+ nameLocation: "middle",
1315
+ nameGap: 50,
1316
+ axisLabel: {
1317
+ formatter: (value) => formatAxisLabel(value, yAxisFormat)
1318
+ }
1319
+ },
1320
+ series
1321
+ };
1322
+ }, [
1323
+ isEmpty,
1324
+ chartData,
1325
+ formattedCategories,
1326
+ smooth,
1327
+ showPoints,
1328
+ showArea,
1329
+ showDataLabels,
1330
+ showLegend,
1331
+ referenceLines,
1332
+ seriesColors,
1333
+ xAxisLabel,
1334
+ yAxisLabel,
1335
+ yAxisFormat,
1336
+ theme,
1337
+ selectedValue,
1338
+ crossFilter?.enabled
1339
+ ]);
1340
+ const handleClick = react.useCallback(
1341
+ (params) => {
1342
+ const p = params;
1343
+ const rawValue = typeof p.value === "object" ? p.value?.value : p.value;
1344
+ const clickParams = {
1345
+ seriesName: p.seriesName ?? "",
1346
+ dataIndex: p.dataIndex ?? 0,
1347
+ value: rawValue ?? 0,
1348
+ name: p.name ?? ""
1349
+ };
1350
+ onDataPointClick?.(clickParams);
1351
+ },
1352
+ [onDataPointClick]
1353
+ );
1354
+ const handleEvents = react.useMemo(() => {
1355
+ if (!onDataPointClick && !crossFilter?.enabled) return void 0;
1356
+ return {
1357
+ click: handleClick
1358
+ };
1359
+ }, [onDataPointClick, crossFilter?.enabled, handleClick]);
1360
+ if (error) {
1361
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1362
+ "div",
1363
+ {
1364
+ style: {
1365
+ display: "flex",
1366
+ alignItems: "center",
1367
+ justifyContent: "center",
1368
+ height: typeof height === "number" ? `${height}px` : height,
1369
+ width: typeof width === "number" ? `${width}px` : width,
1370
+ color: theme.colors.error,
1371
+ fontSize: theme.fontSizes.sm
1372
+ },
1373
+ className,
1374
+ children: [
1375
+ "Error loading chart: ",
1376
+ error.message
1377
+ ]
1378
+ }
1379
+ );
1380
+ }
1381
+ return /* @__PURE__ */ jsxRuntime.jsx(
1382
+ EChartWrapper,
1383
+ {
1384
+ option,
1385
+ loading,
1386
+ height,
1387
+ width,
1388
+ className,
1389
+ onEvents: handleEvents
1390
+ }
1391
+ );
1392
+ }
1393
+ function AreaChart({
1394
+ data,
1395
+ xAxis,
1396
+ yAxis,
1397
+ stacked = true,
1398
+ stackType = "normal",
1399
+ smooth = false,
1400
+ showLegend = true,
1401
+ opacity = 0.7,
1402
+ colors,
1403
+ xAxisLabel,
1404
+ yAxisLabel,
1405
+ xAxisFormat,
1406
+ loading = false,
1407
+ error,
1408
+ height = 300,
1409
+ width = "100%",
1410
+ className,
1411
+ onDataPointClick,
1412
+ crossFilter,
1413
+ selectedValue
1414
+ }) {
1415
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
1416
+ const yColumns = react.useMemo(
1417
+ () => Array.isArray(yAxis) ? yAxis : [yAxis],
1418
+ [yAxis]
1419
+ );
1420
+ const chartData = react.useMemo(
1421
+ () => toChartData(data, xAxis, yColumns),
1422
+ [data, xAxis, yColumns]
1423
+ );
1424
+ const dateFormatter = react.useMemo(
1425
+ () => xAxisFormat ? chunk4AVL6GQK_cjs.createDateFormatter(xAxisFormat) : null,
1426
+ [xAxisFormat]
1427
+ );
1428
+ const formattedCategories = react.useMemo(() => {
1429
+ if (!dateFormatter) return chartData.categories;
1430
+ return chartData.categories.map((cat) => dateFormatter(cat));
1431
+ }, [chartData.categories, dateFormatter]);
1432
+ const seriesColors = react.useMemo(
1433
+ () => colors || getChartColors(theme, yColumns.length),
1434
+ [colors, theme, yColumns.length]
1435
+ );
1436
+ const isEmpty = isChartDataEmpty(data);
1437
+ const option = react.useMemo(() => {
1438
+ if (isEmpty) {
1439
+ return {
1440
+ graphic: createEmptyStateGraphic()
1441
+ };
1442
+ }
1443
+ let processedData = chartData;
1444
+ if (stacked && stackType === "percent") {
1445
+ const totals = chartData.categories.map((_, catIndex) => {
1446
+ let total = 0;
1447
+ chartData.series.forEach((s) => {
1448
+ const val = s.data[catIndex];
1449
+ if (val !== null && val !== void 0) {
1450
+ total += val;
1451
+ }
1452
+ });
1453
+ return total;
1454
+ });
1455
+ processedData = {
1456
+ categories: chartData.categories,
1457
+ series: chartData.series.map((s) => ({
1458
+ ...s,
1459
+ data: s.data.map((val, catIndex) => {
1460
+ if (val === null) return null;
1461
+ const total = totals[catIndex] ?? 1;
1462
+ return total > 0 ? val / total * 100 : 0;
1463
+ })
1464
+ }))
1465
+ };
1466
+ }
1467
+ const series = processedData.series.map((s, index) => {
1468
+ const color = seriesColors[index] ?? theme.colors.primary;
1469
+ const seriesData = s.data.map((value, dataIndex) => {
1470
+ const categoryValue = processedData.categories[dataIndex];
1471
+ const isSelected = selectedValue != null && categoryValue === selectedValue;
1472
+ const isOther = selectedValue != null && categoryValue !== selectedValue;
1473
+ return {
1474
+ value,
1475
+ itemStyle: {
1476
+ opacity: isOther ? 0.3 : 1
1477
+ },
1478
+ // Show marker on selected point
1479
+ symbol: isSelected ? "circle" : "none",
1480
+ symbolSize: isSelected ? 8 : 0
1481
+ };
1482
+ });
1483
+ const baseOpacity = selectedValue != null ? opacity * 0.5 : opacity;
1484
+ return {
1485
+ type: "line",
1486
+ name: s.name,
1487
+ data: seriesData,
1488
+ stack: stacked ? "stack" : void 0,
1489
+ smooth: smooth ? 0.3 : false,
1490
+ symbol: selectedValue != null ? "circle" : "none",
1491
+ symbolSize: 6,
1492
+ itemStyle: {
1493
+ color
1494
+ },
1495
+ lineStyle: {
1496
+ color,
1497
+ width: 1
1498
+ },
1499
+ areaStyle: {
1500
+ color: stacked ? adjustColorOpacity(color, baseOpacity) : createGradientColor(color, baseOpacity)
1501
+ },
1502
+ emphasis: {
1503
+ focus: "series"
1504
+ },
1505
+ // Enable cursor pointer when cross-filter is enabled
1506
+ cursor: crossFilter?.enabled ? "pointer" : "default"
1507
+ };
1508
+ });
1509
+ const legend = showLegend ? {
1510
+ show: yColumns.length > 1,
1511
+ data: processedData.series.map((s) => s.name),
1512
+ selectedMode: "multiple",
1513
+ top: 10
1514
+ } : void 0;
1515
+ const yAxisFormat = stacked && stackType === "percent" ? "percent" : "number";
1516
+ return {
1517
+ tooltip: {
1518
+ trigger: "axis",
1519
+ axisPointer: {
1520
+ type: "cross",
1521
+ label: {
1522
+ backgroundColor: theme.chart.tooltipBackground
1523
+ }
1524
+ },
1525
+ formatter: (params) => {
1526
+ if (!Array.isArray(params) || params.length === 0) return "";
1527
+ const firstParam = params[0];
1528
+ if (!firstParam) return "";
1529
+ const header = `<div style="font-weight: 600; margin-bottom: 4px;">${firstParam.name}</div>`;
1530
+ const items = params.map((p) => {
1531
+ if (p.value === null) {
1532
+ return `<div>${p.marker} ${p.seriesName}: -</div>`;
1533
+ }
1534
+ const formatted = stackType === "percent" ? `${p.value.toFixed(1)}%` : formatAxisLabel(p.value, "compact");
1535
+ return `<div>${p.marker} ${p.seriesName}: ${formatted}</div>`;
1536
+ }).join("");
1537
+ return header + items;
1538
+ }
1539
+ },
1540
+ legend,
1541
+ grid: {
1542
+ left: 60,
1543
+ right: 20,
1544
+ top: legend ? 50 : 40,
1545
+ bottom: 40
1546
+ },
1547
+ xAxis: {
1548
+ type: "category",
1549
+ data: formattedCategories,
1550
+ name: xAxisLabel,
1551
+ nameLocation: "middle",
1552
+ nameGap: 35,
1553
+ axisLabel: {
1554
+ rotate: formattedCategories.length > 10 ? 45 : 0,
1555
+ interval: 0,
1556
+ hideOverlap: true
1557
+ },
1558
+ boundaryGap: false
1559
+ },
1560
+ yAxis: {
1561
+ type: "value",
1562
+ name: yAxisLabel,
1563
+ nameLocation: "middle",
1564
+ nameGap: 50,
1565
+ max: stackType === "percent" ? 100 : void 0,
1566
+ axisLabel: {
1567
+ formatter: (value) => {
1568
+ if (stackType === "percent") {
1569
+ return `${value.toFixed(0)}%`;
1570
+ }
1571
+ return formatAxisLabel(value, yAxisFormat);
1572
+ }
1573
+ }
1574
+ },
1575
+ series
1576
+ };
1577
+ }, [
1578
+ isEmpty,
1579
+ chartData,
1580
+ formattedCategories,
1581
+ stacked,
1582
+ stackType,
1583
+ smooth,
1584
+ showLegend,
1585
+ opacity,
1586
+ seriesColors,
1587
+ xAxisLabel,
1588
+ yAxisLabel,
1589
+ theme,
1590
+ yColumns.length,
1591
+ selectedValue,
1592
+ crossFilter?.enabled
1593
+ ]);
1594
+ const handleClick = react.useCallback(
1595
+ (params) => {
1596
+ const p = params;
1597
+ const rawValue = typeof p.value === "object" ? p.value?.value : p.value;
1598
+ const clickParams = {
1599
+ seriesName: p.seriesName ?? "",
1600
+ dataIndex: p.dataIndex ?? 0,
1601
+ value: rawValue ?? 0,
1602
+ name: p.name ?? ""
1603
+ };
1604
+ onDataPointClick?.(clickParams);
1605
+ },
1606
+ [onDataPointClick]
1607
+ );
1608
+ const handleEvents = react.useMemo(() => {
1609
+ if (!onDataPointClick && !crossFilter?.enabled) return void 0;
1610
+ return {
1611
+ click: handleClick
1612
+ };
1613
+ }, [onDataPointClick, crossFilter?.enabled, handleClick]);
1614
+ if (error) {
1615
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1616
+ "div",
1617
+ {
1618
+ style: {
1619
+ display: "flex",
1620
+ alignItems: "center",
1621
+ justifyContent: "center",
1622
+ height: typeof height === "number" ? `${height}px` : height,
1623
+ width: typeof width === "number" ? `${width}px` : width,
1624
+ color: theme.colors.error,
1625
+ fontSize: theme.fontSizes.sm
1626
+ },
1627
+ className,
1628
+ children: [
1629
+ "Error loading chart: ",
1630
+ error.message
1631
+ ]
1632
+ }
1633
+ );
1634
+ }
1635
+ return /* @__PURE__ */ jsxRuntime.jsx(
1636
+ EChartWrapper,
1637
+ {
1638
+ option,
1639
+ loading,
1640
+ height,
1641
+ width,
1642
+ className,
1643
+ onEvents: handleEvents
1644
+ }
1645
+ );
1646
+ }
1647
+ function PieChart2({
1648
+ data,
1649
+ labelColumn,
1650
+ valueColumn,
1651
+ variant = "pie",
1652
+ donutRatio = 0.5,
1653
+ showLabels = true,
1654
+ labelPosition = "outside",
1655
+ showPercentage = false,
1656
+ showLegend = true,
1657
+ colors,
1658
+ startAngle = 90,
1659
+ sortSlices = "none",
1660
+ loading = false,
1661
+ error,
1662
+ height = 300,
1663
+ width = "100%",
1664
+ className,
1665
+ onDataPointClick,
1666
+ crossFilter,
1667
+ selectedValue,
1668
+ labelFormat
1669
+ }) {
1670
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
1671
+ const containerRef = react.useRef(null);
1672
+ const [containerWidth, setContainerWidth] = react.useState(0);
1673
+ react.useEffect(() => {
1674
+ const measureWidth = () => {
1675
+ if (containerRef.current) {
1676
+ setContainerWidth(containerRef.current.offsetWidth);
1677
+ }
1678
+ };
1679
+ measureWidth();
1680
+ window.addEventListener("resize", measureWidth);
1681
+ return () => window.removeEventListener("resize", measureWidth);
1682
+ }, []);
1683
+ const isNarrow = containerWidth < 300;
1684
+ const legendOrient = isNarrow ? "horizontal" : "vertical";
1685
+ const legendPosition = isNarrow ? { bottom: 0, left: "center" } : { left: "55%", top: "middle" };
1686
+ const chartData = react.useMemo(
1687
+ () => toChartData(data, labelColumn, [valueColumn]),
1688
+ [data, labelColumn, valueColumn]
1689
+ );
1690
+ const dateFormatter = react.useMemo(
1691
+ () => labelFormat ? chunk4AVL6GQK_cjs.createDateFormatter(labelFormat) : null,
1692
+ [labelFormat]
1693
+ );
1694
+ const formattedCategories = react.useMemo(() => {
1695
+ if (!dateFormatter) return chartData.categories;
1696
+ return chartData.categories.map((cat) => dateFormatter(cat));
1697
+ }, [chartData.categories, dateFormatter]);
1698
+ const pieData = react.useMemo(() => {
1699
+ if (chartData.series.length === 0) {
1700
+ return [];
1701
+ }
1702
+ const series = chartData.series[0];
1703
+ if (!series) {
1704
+ return [];
1705
+ }
1706
+ const items = formattedCategories.map((name, index) => ({
1707
+ name,
1708
+ value: series.data[index] ?? 0
1709
+ }));
1710
+ if (sortSlices === "asc") {
1711
+ items.sort((a, b) => (a.value || 0) - (b.value || 0));
1712
+ } else if (sortSlices === "desc") {
1713
+ items.sort((a, b) => (b.value || 0) - (a.value || 0));
1714
+ }
1715
+ return items;
1716
+ }, [formattedCategories, chartData.series, sortSlices]);
1717
+ const seriesColors = react.useMemo(
1718
+ () => colors || getChartColors(theme, pieData.length),
1719
+ [colors, theme, pieData.length]
1720
+ );
1721
+ const isEmpty = isChartDataEmpty(data);
1722
+ const option = react.useMemo(() => {
1723
+ if (isEmpty) {
1724
+ return {
1725
+ graphic: createEmptyStateGraphic()
1726
+ };
1727
+ }
1728
+ const total = pieData.reduce((sum, item) => sum + (item.value || 0), 0);
1729
+ const innerRadius = variant === "donut" ? `${donutRatio * 50}%` : "0%";
1730
+ let outerRadius;
1731
+ let center;
1732
+ if (showLegend) {
1733
+ if (isNarrow) {
1734
+ outerRadius = "55%";
1735
+ center = ["50%", "35%"];
1736
+ } else {
1737
+ outerRadius = "50%";
1738
+ center = ["25%", "50%"];
1739
+ }
1740
+ } else {
1741
+ outerRadius = labelPosition === "outside" ? "60%" : "75%";
1742
+ center = ["50%", "50%"];
1743
+ }
1744
+ const effectiveLabelPosition = showLegend && labelPosition === "outside" ? "inside" : labelPosition;
1745
+ const effectiveShowLabels = showLegend && labelPosition === "outside" ? false : showLabels;
1746
+ const label = effectiveShowLabels ? {
1747
+ show: true,
1748
+ position: effectiveLabelPosition,
1749
+ formatter: (params) => {
1750
+ if (showPercentage) {
1751
+ return effectiveLabelPosition === "inside" ? `${params.percent.toFixed(0)}%` : `${params.name}: ${params.percent.toFixed(1)}%`;
1752
+ }
1753
+ return effectiveLabelPosition === "inside" ? formatAxisLabel(params.value, "compact") : `${params.name}: ${formatAxisLabel(params.value, "compact")}`;
1754
+ },
1755
+ color: effectiveLabelPosition === "inside" ? "#ffffff" : theme.colors.text,
1756
+ fontSize: effectiveLabelPosition === "inside" ? 11 : 12
1757
+ } : { show: false };
1758
+ const labelLine = effectiveShowLabels && effectiveLabelPosition === "outside" ? {
1759
+ show: true,
1760
+ length: 10,
1761
+ length2: 10,
1762
+ lineStyle: {
1763
+ color: theme.colors.border
1764
+ }
1765
+ } : { show: false };
1766
+ const legend = showLegend ? {
1767
+ show: true,
1768
+ orient: legendOrient,
1769
+ ...legendPosition,
1770
+ selectedMode: "multiple",
1771
+ data: pieData.map((item) => item.name),
1772
+ formatter: (name) => {
1773
+ const item = pieData.find((d) => d.name === name);
1774
+ if (!item || total === 0) return name;
1775
+ const percent = (item.value || 0) / total * 100;
1776
+ return `${name} (${percent.toFixed(1)}%)`;
1777
+ },
1778
+ textStyle: {
1779
+ fontSize: isNarrow ? 11 : 12
1780
+ },
1781
+ itemGap: isNarrow ? 6 : 8,
1782
+ itemWidth: isNarrow ? 12 : 14,
1783
+ itemHeight: isNarrow ? 12 : 14
1784
+ } : void 0;
1785
+ return {
1786
+ tooltip: {
1787
+ trigger: "item",
1788
+ formatter: (params) => {
1789
+ const formatted = formatAxisLabel(params.value, "number");
1790
+ return `${params.marker} ${params.name}<br/>Value: ${formatted}<br/>Percent: ${params.percent.toFixed(1)}%`;
1791
+ }
1792
+ },
1793
+ legend,
1794
+ series: [
1795
+ {
1796
+ type: "pie",
1797
+ radius: [innerRadius, outerRadius],
1798
+ center,
1799
+ startAngle,
1800
+ data: pieData.map((item, index) => {
1801
+ const baseColor = seriesColors[index] ?? theme.colors.primary;
1802
+ const isSelected = selectedValue != null && item.name === selectedValue;
1803
+ const isOther = selectedValue != null && item.name !== selectedValue;
1804
+ return {
1805
+ ...item,
1806
+ itemStyle: {
1807
+ color: baseColor,
1808
+ opacity: isOther ? 0.3 : 1,
1809
+ // Highlight selected slice
1810
+ ...isSelected && {
1811
+ borderColor: theme.colors.primary,
1812
+ borderWidth: 3,
1813
+ shadowBlur: 15,
1814
+ shadowColor: "rgba(0, 0, 0, 0.3)"
1815
+ }
1816
+ }
1817
+ };
1818
+ }),
1819
+ label,
1820
+ labelLine,
1821
+ emphasis: {
1822
+ itemStyle: {
1823
+ shadowBlur: 10,
1824
+ shadowOffsetX: 0,
1825
+ shadowColor: "rgba(0, 0, 0, 0.2)"
1826
+ },
1827
+ // Disable emphasis label to avoid conflict with legend and tooltip
1828
+ label: {
1829
+ show: false
1830
+ }
1831
+ },
1832
+ // Enable cursor pointer when cross-filter is enabled
1833
+ cursor: crossFilter?.enabled ? "pointer" : "default",
1834
+ animationType: "scale",
1835
+ animationEasing: "elasticOut"
1836
+ }
1837
+ ]
1838
+ };
1839
+ }, [
1840
+ isEmpty,
1841
+ pieData,
1842
+ variant,
1843
+ donutRatio,
1844
+ showLabels,
1845
+ labelPosition,
1846
+ showPercentage,
1847
+ showLegend,
1848
+ startAngle,
1849
+ seriesColors,
1850
+ theme,
1851
+ selectedValue,
1852
+ crossFilter?.enabled,
1853
+ isNarrow,
1854
+ legendOrient,
1855
+ legendPosition
1856
+ ]);
1857
+ const handleClick = react.useCallback(
1858
+ (params) => {
1859
+ const p = params;
1860
+ const clickParams = {
1861
+ seriesName: p.seriesName ?? valueColumn,
1862
+ dataIndex: p.dataIndex ?? 0,
1863
+ value: p.value ?? 0,
1864
+ name: p.name ?? ""
1865
+ };
1866
+ onDataPointClick?.(clickParams);
1867
+ },
1868
+ [onDataPointClick, valueColumn]
1869
+ );
1870
+ const handleEvents = react.useMemo(() => {
1871
+ if (!onDataPointClick && !crossFilter?.enabled) return void 0;
1872
+ return {
1873
+ click: handleClick
1874
+ };
1875
+ }, [onDataPointClick, crossFilter?.enabled, handleClick]);
1876
+ if (error) {
1877
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1878
+ "div",
1879
+ {
1880
+ ref: containerRef,
1881
+ style: {
1882
+ display: "flex",
1883
+ alignItems: "center",
1884
+ justifyContent: "center",
1885
+ height: typeof height === "number" ? `${height}px` : height,
1886
+ width: typeof width === "number" ? `${width}px` : width,
1887
+ color: theme.colors.error,
1888
+ fontSize: theme.fontSizes.sm
1889
+ },
1890
+ className,
1891
+ children: [
1892
+ "Error loading chart: ",
1893
+ error.message
1894
+ ]
1895
+ }
1896
+ );
1897
+ }
1898
+ if (containerWidth === 0) {
1899
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, style: { height, width }, className });
1900
+ }
1901
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, style: { height, width }, children: /* @__PURE__ */ jsxRuntime.jsx(
1902
+ EChartWrapper,
1903
+ {
1904
+ option,
1905
+ loading,
1906
+ height,
1907
+ width,
1908
+ className,
1909
+ onEvents: handleEvents
1910
+ }
1911
+ ) });
1912
+ }
1913
+ function extractScatterData(data, xColumn, yColumn, sizeColumn, colorColumn, labelColumn) {
1914
+ const points = [];
1915
+ const colorSet = /* @__PURE__ */ new Set();
1916
+ if (isQueryResult(data)) {
1917
+ const xIndex = data.columns.indexOf(xColumn);
1918
+ const yIndex = data.columns.indexOf(yColumn);
1919
+ const sizeIndex = sizeColumn ? data.columns.indexOf(sizeColumn) : -1;
1920
+ const colorIndex = colorColumn ? data.columns.indexOf(colorColumn) : -1;
1921
+ const labelIndex = labelColumn ? data.columns.indexOf(labelColumn) : -1;
1922
+ if (xIndex === -1 || yIndex === -1) {
1923
+ return { points: [], colorCategories: [] };
1924
+ }
1925
+ data.rows.forEach((row, index) => {
1926
+ const x = row[xIndex];
1927
+ const y = row[yIndex];
1928
+ if (x !== null && y !== null) {
1929
+ const size = sizeIndex >= 0 ? row[sizeIndex] : void 0;
1930
+ const color = colorIndex >= 0 ? String(row[colorIndex]) : void 0;
1931
+ const label = labelIndex >= 0 ? String(row[labelIndex]) : void 0;
1932
+ if (color) colorSet.add(color);
1933
+ points.push({
1934
+ x: typeof x === "number" ? x : Number(x),
1935
+ y: typeof y === "number" ? y : Number(y),
1936
+ size: size !== null && size !== void 0 ? Number(size) : void 0,
1937
+ color,
1938
+ label,
1939
+ index
1940
+ });
1941
+ }
1942
+ });
1943
+ } else {
1944
+ data.forEach((point, index) => {
1945
+ const x = point[xColumn];
1946
+ const y = point[yColumn];
1947
+ if (x !== null && x !== void 0 && y !== null && y !== void 0) {
1948
+ const size = sizeColumn ? point[sizeColumn] : void 0;
1949
+ const color = colorColumn ? String(point[colorColumn]) : void 0;
1950
+ const label = labelColumn ? String(point[labelColumn]) : void 0;
1951
+ if (color) colorSet.add(color);
1952
+ points.push({
1953
+ x: typeof x === "number" ? x : Number(x),
1954
+ y: typeof y === "number" ? y : Number(y),
1955
+ size: size !== null && size !== void 0 ? Number(size) : void 0,
1956
+ color,
1957
+ label,
1958
+ index
1959
+ });
1960
+ }
1961
+ });
1962
+ }
1963
+ return { points, colorCategories: Array.from(colorSet) };
1964
+ }
1965
+ function calculateTrendline(points) {
1966
+ if (points.length < 2) return null;
1967
+ const n = points.length;
1968
+ let sumX = 0;
1969
+ let sumY = 0;
1970
+ let sumXY = 0;
1971
+ let sumX2 = 0;
1972
+ let minX = Infinity;
1973
+ let maxX = -Infinity;
1974
+ points.forEach((p) => {
1975
+ sumX += p.x;
1976
+ sumY += p.y;
1977
+ sumXY += p.x * p.y;
1978
+ sumX2 += p.x * p.x;
1979
+ minX = Math.min(minX, p.x);
1980
+ maxX = Math.max(maxX, p.x);
1981
+ });
1982
+ const denominator = n * sumX2 - sumX * sumX;
1983
+ if (denominator === 0) return null;
1984
+ const slope = (n * sumXY - sumX * sumY) / denominator;
1985
+ const intercept = (sumY - slope * sumX) / n;
1986
+ return { slope, intercept, minX, maxX };
1987
+ }
1988
+ function ScatterChart2({
1989
+ data,
1990
+ xAxis,
1991
+ yAxis,
1992
+ sizeColumn,
1993
+ colorColumn,
1994
+ minSize = 10,
1995
+ maxSize = 50,
1996
+ showLabels = false,
1997
+ labelColumn,
1998
+ showTrendline = false,
1999
+ xAxisLabel,
2000
+ yAxisLabel,
2001
+ loading = false,
2002
+ error,
2003
+ height = 300,
2004
+ width = "100%",
2005
+ className,
2006
+ onDataPointClick
2007
+ }) {
2008
+ const { theme } = chunkLMTG3LRC_cjs.useTheme();
2009
+ const { points, colorCategories } = react.useMemo(
2010
+ () => extractScatterData(data, xAxis, yAxis, sizeColumn, colorColumn, labelColumn),
2011
+ [data, xAxis, yAxis, sizeColumn, colorColumn, labelColumn]
2012
+ );
2013
+ const categoryColors = react.useMemo(
2014
+ () => getChartColors(theme, Math.max(colorCategories.length, 1)),
2015
+ [theme, colorCategories.length]
2016
+ );
2017
+ const isEmpty = isChartDataEmpty(data) || points.length === 0;
2018
+ const option = react.useMemo(() => {
2019
+ if (isEmpty) {
2020
+ return {
2021
+ graphic: createEmptyStateGraphic()
2022
+ };
2023
+ }
2024
+ let sizeScale = () => minSize;
2025
+ if (sizeColumn) {
2026
+ const sizes = points.map((p) => p.size).filter((s) => s !== void 0);
2027
+ if (sizes.length > 0) {
2028
+ const minSizeVal = Math.min(...sizes);
2029
+ const maxSizeVal = Math.max(...sizes);
2030
+ const sizeRange = maxSizeVal - minSizeVal || 1;
2031
+ sizeScale = (val) => {
2032
+ const normalized = (val - minSizeVal) / sizeRange;
2033
+ return minSize + normalized * (maxSize - minSize);
2034
+ };
2035
+ }
2036
+ }
2037
+ const seriesMap = /* @__PURE__ */ new Map();
2038
+ if (colorColumn && colorCategories.length > 0) {
2039
+ colorCategories.forEach((cat) => {
2040
+ seriesMap.set(cat, []);
2041
+ });
2042
+ points.forEach((p) => {
2043
+ const cat = p.color || "default";
2044
+ const arr = seriesMap.get(cat);
2045
+ if (arr) {
2046
+ arr.push([
2047
+ p.x,
2048
+ p.y,
2049
+ p.size !== void 0 ? sizeScale(p.size) : minSize,
2050
+ p.label,
2051
+ String(p.index)
2052
+ ]);
2053
+ }
2054
+ });
2055
+ } else {
2056
+ seriesMap.set("data", points.map((p) => [
2057
+ p.x,
2058
+ p.y,
2059
+ p.size !== void 0 ? sizeScale(p.size) : minSize,
2060
+ p.label,
2061
+ String(p.index)
2062
+ ]));
2063
+ }
2064
+ const series = Array.from(seriesMap.entries()).map(
2065
+ ([name, seriesData], index) => ({
2066
+ type: "scatter",
2067
+ name,
2068
+ data: seriesData,
2069
+ symbolSize: (dataItem) => dataItem[2],
2070
+ itemStyle: {
2071
+ color: categoryColors[index] ?? theme.colors.primary
2072
+ },
2073
+ label: showLabels ? {
2074
+ show: true,
2075
+ position: "top",
2076
+ formatter: (params) => params.data[3] || "",
2077
+ fontSize: 10,
2078
+ color: theme.colors.textMuted
2079
+ } : void 0,
2080
+ emphasis: {
2081
+ focus: "series",
2082
+ itemStyle: {
2083
+ shadowBlur: 10,
2084
+ shadowOffsetX: 0,
2085
+ shadowColor: "rgba(0, 0, 0, 0.2)"
2086
+ }
2087
+ }
2088
+ })
2089
+ );
2090
+ if (showTrendline) {
2091
+ const trend = calculateTrendline(points);
2092
+ if (trend) {
2093
+ const y1 = trend.slope * trend.minX + trend.intercept;
2094
+ const y2 = trend.slope * trend.maxX + trend.intercept;
2095
+ series.push({
2096
+ type: "line",
2097
+ name: "Trendline",
2098
+ data: [
2099
+ [trend.minX, y1],
2100
+ [trend.maxX, y2]
2101
+ ],
2102
+ symbol: "none",
2103
+ lineStyle: {
2104
+ color: theme.colors.textMuted,
2105
+ type: "dashed",
2106
+ width: 2
2107
+ },
2108
+ silent: true
2109
+ });
2110
+ }
2111
+ }
2112
+ const legend = colorColumn && colorCategories.length > 1 ? {
2113
+ show: true,
2114
+ data: colorCategories,
2115
+ top: 10
2116
+ } : void 0;
2117
+ return {
2118
+ tooltip: {
2119
+ trigger: "item",
2120
+ formatter: (params) => {
2121
+ if (!params.data) return "";
2122
+ const [x, y, , label] = params.data;
2123
+ let html = `${params.marker}`;
2124
+ if (colorColumn) {
2125
+ html += ` ${params.seriesName}<br/>`;
2126
+ }
2127
+ if (label) {
2128
+ html += `${label}<br/>`;
2129
+ }
2130
+ html += `${xAxis}: ${formatAxisLabel(x, "number")}<br/>`;
2131
+ html += `${yAxis}: ${formatAxisLabel(y, "number")}`;
2132
+ return html;
2133
+ }
2134
+ },
2135
+ legend,
2136
+ grid: {
2137
+ left: 60,
2138
+ right: 20,
2139
+ top: legend ? 50 : 40,
2140
+ bottom: 40
2141
+ },
2142
+ xAxis: {
2143
+ type: "value",
2144
+ name: xAxisLabel || xAxis,
2145
+ nameLocation: "middle",
2146
+ nameGap: 35,
2147
+ axisLabel: {
2148
+ formatter: (value) => formatAxisLabel(value, "compact")
2149
+ },
2150
+ splitLine: {
2151
+ show: true,
2152
+ lineStyle: {
2153
+ type: "dashed"
2154
+ }
2155
+ }
2156
+ },
2157
+ yAxis: {
2158
+ type: "value",
2159
+ name: yAxisLabel || yAxis,
2160
+ nameLocation: "middle",
2161
+ nameGap: 50,
2162
+ axisLabel: {
2163
+ formatter: (value) => formatAxisLabel(value, "compact")
2164
+ },
2165
+ splitLine: {
2166
+ show: true,
2167
+ lineStyle: {
2168
+ type: "dashed"
2169
+ }
2170
+ }
2171
+ },
2172
+ series
2173
+ };
2174
+ }, [
2175
+ isEmpty,
2176
+ points,
2177
+ colorColumn,
2178
+ colorCategories,
2179
+ categoryColors,
2180
+ sizeColumn,
2181
+ minSize,
2182
+ maxSize,
2183
+ showLabels,
2184
+ showTrendline,
2185
+ xAxis,
2186
+ yAxis,
2187
+ xAxisLabel,
2188
+ yAxisLabel,
2189
+ theme
2190
+ ]);
2191
+ const handleEvents = react.useMemo(() => {
2192
+ if (!onDataPointClick) return void 0;
2193
+ return {
2194
+ click: (params) => {
2195
+ const p = params;
2196
+ if (!p.data) return;
2197
+ const [x, y, , , indexStr] = p.data;
2198
+ const clickParams = {
2199
+ seriesName: p.seriesName ?? "",
2200
+ dataIndex: indexStr ? parseInt(indexStr, 10) : p.dataIndex ?? 0,
2201
+ value: y,
2202
+ name: String(x)
2203
+ };
2204
+ onDataPointClick(clickParams);
2205
+ }
2206
+ };
2207
+ }, [onDataPointClick]);
2208
+ if (error) {
2209
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2210
+ "div",
2211
+ {
2212
+ style: {
2213
+ display: "flex",
2214
+ alignItems: "center",
2215
+ justifyContent: "center",
2216
+ height: typeof height === "number" ? `${height}px` : height,
2217
+ width: typeof width === "number" ? `${width}px` : width,
2218
+ color: theme.colors.error,
2219
+ fontSize: theme.fontSizes.sm
2220
+ },
2221
+ className,
2222
+ children: [
2223
+ "Error loading chart: ",
2224
+ error.message
2225
+ ]
2226
+ }
2227
+ );
2228
+ }
2229
+ return /* @__PURE__ */ jsxRuntime.jsx(
2230
+ EChartWrapper,
2231
+ {
2232
+ option,
2233
+ loading,
2234
+ height,
2235
+ width,
2236
+ className,
2237
+ onEvents: handleEvents
2238
+ }
2239
+ );
2240
+ }
2241
+
2242
+ // src/charts/autoSuggest.ts
2243
+ function categorizeColumn(dataType) {
2244
+ const normalizedType = dataType.toLowerCase();
2245
+ if (normalizedType.includes("date") || normalizedType.includes("time") || normalizedType.includes("timestamp")) {
2246
+ return "date";
2247
+ }
2248
+ if (normalizedType.includes("int") || normalizedType.includes("numeric") || normalizedType.includes("decimal") || normalizedType.includes("float") || normalizedType.includes("double") || normalizedType.includes("real") || normalizedType.includes("money")) {
2249
+ return "numeric";
2250
+ }
2251
+ if (normalizedType.includes("char") || normalizedType.includes("text") || normalizedType.includes("varchar") || normalizedType.includes("bool") || normalizedType.includes("uuid")) {
2252
+ return "categorical";
2253
+ }
2254
+ return "unknown";
2255
+ }
2256
+ function countUniqueValues(result, columnIndex) {
2257
+ const uniqueValues = /* @__PURE__ */ new Set();
2258
+ result.rows.forEach((row) => {
2259
+ uniqueValues.add(row[columnIndex]);
2260
+ });
2261
+ return uniqueValues.size;
2262
+ }
2263
+ function analyzeColumns(result, selections) {
2264
+ return selections.map((sel) => {
2265
+ const columnIndex = result.columns.indexOf(sel.alias || sel.column);
2266
+ const typeIndex = columnIndex !== -1 ? columnIndex : 0;
2267
+ const dataType = result.column_types[typeIndex] || "unknown";
2268
+ return {
2269
+ name: sel.alias || sel.column,
2270
+ category: categorizeColumn(dataType),
2271
+ uniqueCount: columnIndex !== -1 ? countUniqueValues(result, columnIndex) : 0,
2272
+ hasAggregation: sel.aggregation !== "none"
2273
+ };
2274
+ });
2275
+ }
2276
+ function suggestChartType(result, columns) {
2277
+ const suggestions = [];
2278
+ if (!result || result.rows.length === 0 || columns.length === 0) {
2279
+ return [];
2280
+ }
2281
+ const analyzedColumns = analyzeColumns(result, columns);
2282
+ const dateColumns = analyzedColumns.filter((c) => c.category === "date");
2283
+ const numericColumns = analyzedColumns.filter((c) => c.category === "numeric");
2284
+ const categoricalColumns = analyzedColumns.filter((c) => c.category === "categorical");
2285
+ const aggregatedColumns = analyzedColumns.filter((c) => c.hasAggregation);
2286
+ if (result.rows.length === 1 && numericColumns.length === 1) {
2287
+ const numericCol = numericColumns[0];
2288
+ if (numericCol) {
2289
+ const colIndex = result.columns.indexOf(numericCol.name);
2290
+ const value = colIndex !== -1 ? result.rows[0]?.[colIndex] : 0;
2291
+ suggestions.push({
2292
+ type: "metric",
2293
+ confidence: 0.95,
2294
+ reason: "Single numeric value is best displayed as a metric card",
2295
+ config: {
2296
+ title: numericCol.name,
2297
+ value: typeof value === "number" ? value : 0,
2298
+ format: "number"
2299
+ }
2300
+ });
2301
+ }
2302
+ }
2303
+ if (dateColumns.length >= 1 && numericColumns.length >= 1) {
2304
+ const dateCol = dateColumns[0];
2305
+ if (dateCol) {
2306
+ const xAxis = dateCol.name;
2307
+ const yAxis = numericColumns.map((c) => c.name);
2308
+ suggestions.push({
2309
+ type: "line",
2310
+ confidence: 0.9,
2311
+ reason: "Time series data is best visualized as a line chart",
2312
+ config: {
2313
+ xAxis,
2314
+ yAxis: yAxis.length === 1 ? yAxis[0] : yAxis,
2315
+ smooth: true,
2316
+ showPoints: result.rows.length <= 20
2317
+ }
2318
+ });
2319
+ if (numericColumns.length > 1) {
2320
+ suggestions.push({
2321
+ type: "area",
2322
+ confidence: 0.75,
2323
+ reason: "Multiple time series can be compared with stacked area chart",
2324
+ config: {
2325
+ xAxis,
2326
+ yAxis,
2327
+ stacked: true,
2328
+ smooth: true
2329
+ }
2330
+ });
2331
+ }
2332
+ }
2333
+ }
2334
+ if (categoricalColumns.length >= 1 && numericColumns.length >= 1) {
2335
+ const categoryCol = categoricalColumns[0];
2336
+ if (categoryCol) {
2337
+ const xAxis = categoryCol.name;
2338
+ const yAxis = numericColumns.map((c) => c.name);
2339
+ const uniqueCount = categoryCol.uniqueCount;
2340
+ if (uniqueCount <= 20) {
2341
+ suggestions.push({
2342
+ type: "bar",
2343
+ confidence: 0.85,
2344
+ reason: "Categorical data with numeric values is best shown as a bar chart",
2345
+ config: {
2346
+ xAxis,
2347
+ yAxis: yAxis.length === 1 ? yAxis[0] : yAxis,
2348
+ orientation: uniqueCount > 10 ? "horizontal" : "vertical",
2349
+ stacked: numericColumns.length > 1
2350
+ }
2351
+ });
2352
+ }
2353
+ if (uniqueCount <= 7 && numericColumns.length === 1) {
2354
+ const numericCol = numericColumns[0];
2355
+ if (numericCol) {
2356
+ suggestions.push({
2357
+ type: "pie",
2358
+ confidence: 0.8,
2359
+ reason: "Small number of categories is well suited for a pie chart",
2360
+ config: {
2361
+ labelColumn: xAxis,
2362
+ valueColumn: numericCol.name,
2363
+ variant: uniqueCount <= 5 ? "donut" : "pie",
2364
+ showPercentage: true
2365
+ }
2366
+ });
2367
+ }
2368
+ }
2369
+ }
2370
+ }
2371
+ if (numericColumns.length >= 2 && dateColumns.length === 0) {
2372
+ const hasEnoughPoints = result.rows.length >= 5;
2373
+ const numericCol0 = numericColumns[0];
2374
+ const numericCol1 = numericColumns[1];
2375
+ const numericCol2 = numericColumns[2];
2376
+ if (hasEnoughPoints && numericCol0 && numericCol1) {
2377
+ suggestions.push({
2378
+ type: "scatter",
2379
+ confidence: 0.7,
2380
+ reason: "Two numeric columns can show correlation in a scatter plot",
2381
+ config: {
2382
+ xAxis: numericCol0.name,
2383
+ yAxis: numericCol1.name,
2384
+ sizeColumn: numericCol2?.name,
2385
+ showTrendline: true
2386
+ }
2387
+ });
2388
+ }
2389
+ }
2390
+ if (numericColumns.length > 1 && categoricalColumns.length >= 1 && dateColumns.length === 0 && aggregatedColumns.length > 0) {
2391
+ const categoryCol = categoricalColumns[0];
2392
+ if (categoryCol) {
2393
+ const xAxis = categoryCol.name;
2394
+ const yAxis = numericColumns.map((c) => c.name);
2395
+ const hasBarSuggestion = suggestions.some(
2396
+ (s) => s.type === "bar" && s.confidence >= 0.85
2397
+ );
2398
+ if (!hasBarSuggestion) {
2399
+ suggestions.push({
2400
+ type: "bar",
2401
+ confidence: 0.65,
2402
+ reason: "Multiple numeric metrics can be compared with grouped bars",
2403
+ config: {
2404
+ xAxis,
2405
+ yAxis,
2406
+ orientation: "vertical",
2407
+ stacked: false,
2408
+ showLegend: true
2409
+ }
2410
+ });
2411
+ }
2412
+ }
2413
+ }
2414
+ if (suggestions.length === 0 && analyzedColumns.length >= 2) {
2415
+ const firstCol = analyzedColumns[0];
2416
+ const secondCol = analyzedColumns[1];
2417
+ if (firstCol && secondCol) {
2418
+ suggestions.push({
2419
+ type: "bar",
2420
+ confidence: 0.5,
2421
+ reason: "Default visualization for the selected data",
2422
+ config: {
2423
+ xAxis: firstCol.name,
2424
+ yAxis: secondCol.name
2425
+ }
2426
+ });
2427
+ }
2428
+ }
2429
+ suggestions.sort((a, b) => b.confidence - a.confidence);
2430
+ return suggestions;
2431
+ }
2432
+
2433
+ exports.AreaChart = AreaChart;
2434
+ exports.BarChart = BarChart2;
2435
+ exports.EChartWrapper = EChartWrapper;
2436
+ exports.LineChart = LineChart3;
2437
+ exports.MetricCard = MetricCard;
2438
+ exports.PieChart = PieChart2;
2439
+ exports.ScatterChart = ScatterChart2;
2440
+ exports.Sparkline = Sparkline;
2441
+ exports.TrendIndicator = TrendIndicator;
2442
+ exports.adjustColorOpacity = adjustColorOpacity;
2443
+ exports.applyThemeToOption = applyThemeToOption;
2444
+ exports.createChartTheme = createChartTheme;
2445
+ exports.createEmptyStateGraphic = createEmptyStateGraphic;
2446
+ exports.createGradientColor = createGradientColor;
2447
+ exports.createMarkLines = createMarkLines;
2448
+ exports.dataPointsToChartData = dataPointsToChartData;
2449
+ exports.formatAxisLabel = formatAxisLabel;
2450
+ exports.formatCompact = formatCompact;
2451
+ exports.formatMetricValue = formatMetricValue;
2452
+ exports.getChartColors = getChartColors;
2453
+ exports.isChartDataEmpty = isChartDataEmpty;
2454
+ exports.isQueryResult = isQueryResult;
2455
+ exports.queryResultToChartData = queryResultToChartData;
2456
+ exports.suggestChartType = suggestChartType;
2457
+ exports.toChartData = toChartData;
2458
+ //# sourceMappingURL=chunk-NK7HKX2J.cjs.map
2459
+ //# sourceMappingURL=chunk-NK7HKX2J.cjs.map