@optilogic/charts 1.0.0-beta.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.cjs +3034 -174
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +489 -192
  4. package/dist/index.d.ts +489 -192
  5. package/dist/index.js +3006 -175
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/cartesian/area-chart.tsx +177 -0
  9. package/src/cartesian/bar-chart.tsx +217 -0
  10. package/src/cartesian/composed-chart.tsx +222 -0
  11. package/src/cartesian/line-chart.tsx +159 -0
  12. package/src/cartesian/scatter-chart.tsx +158 -0
  13. package/src/cartesian/waterfall-chart.tsx +171 -0
  14. package/src/dashboard/chart-builder.tsx +310 -0
  15. package/src/dashboard/chart-renderer.tsx +250 -0
  16. package/src/dashboard/kpi-card.tsx +121 -0
  17. package/src/dashboard/scenario-comparison.tsx +235 -0
  18. package/src/dashboard/sparkline.tsx +86 -0
  19. package/src/index.ts +50 -19
  20. package/src/radial/donut-chart.tsx +135 -0
  21. package/src/radial/pie-chart.tsx +153 -0
  22. package/src/radial/radar-chart.tsx +111 -0
  23. package/src/radial/radial-bar-chart.tsx +115 -0
  24. package/src/shared/chart-container.tsx +104 -0
  25. package/src/shared/chart-legend.tsx +57 -0
  26. package/src/shared/chart-tooltip.tsx +159 -0
  27. package/src/shared/colors.ts +37 -0
  28. package/src/shared/formatters.ts +51 -0
  29. package/src/shared/types.ts +66 -0
  30. package/src/shared/use-live-data.ts +83 -0
  31. package/src/specialized/funnel-chart.tsx +93 -0
  32. package/src/specialized/gantt-chart.tsx +416 -0
  33. package/src/specialized/heatmap-chart.tsx +250 -0
  34. package/src/specialized/sankey-chart.tsx +155 -0
  35. package/src/specialized/treemap-chart.tsx +121 -0
  36. package/src/bar-chart.tsx +0 -337
  37. package/src/line-chart.tsx +0 -266
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var React = require('react');
3
+ var React17 = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
4
5
  var recharts = require('recharts');
5
6
  var core = require('@optilogic/core');
6
- var jsxRuntime = require('react/jsx-runtime');
7
7
 
8
8
  function _interopNamespace(e) {
9
9
  if (e && e.__esModule) return e;
@@ -23,21 +23,388 @@ function _interopNamespace(e) {
23
23
  return Object.freeze(n);
24
24
  }
25
25
 
26
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
26
+ var React17__namespace = /*#__PURE__*/_interopNamespace(React17);
27
27
 
28
- // src/line-chart.tsx
28
+ // src/shared/colors.ts
29
29
  var CHART_COLORS = [
30
30
  "hsl(var(--chart-1))",
31
31
  "hsl(var(--chart-2))",
32
32
  "hsl(var(--chart-3))",
33
33
  "hsl(var(--chart-4))",
34
- "hsl(var(--chart-5))"
34
+ "hsl(var(--chart-5))",
35
+ "hsl(var(--chart-6))",
36
+ "hsl(var(--chart-7))",
37
+ "hsl(var(--chart-8))",
38
+ "hsl(var(--chart-9))",
39
+ "hsl(var(--chart-10))",
40
+ "hsl(var(--chart-11))",
41
+ "hsl(var(--chart-12))"
35
42
  ];
36
43
  function getChartColor(index, custom) {
37
44
  if (custom) return custom;
38
45
  return CHART_COLORS[index % CHART_COLORS.length] ?? "hsl(var(--chart-1))";
39
46
  }
40
- var LineChart = React__namespace.forwardRef(
47
+ var SEMANTIC_COLORS = {
48
+ positive: "hsl(var(--success))",
49
+ negative: "hsl(var(--destructive))",
50
+ neutral: "hsl(var(--muted-foreground))",
51
+ warning: "hsl(var(--warning))"
52
+ };
53
+ function getSemanticColor(name) {
54
+ return SEMANTIC_COLORS[name];
55
+ }
56
+ var ChartTooltipContent = React17__namespace.memo(function ChartTooltipContent2({
57
+ active,
58
+ payload,
59
+ label,
60
+ config
61
+ }) {
62
+ if (!active || !payload?.length) return null;
63
+ const items = payload;
64
+ const formattedLabel = config?.labelFormatter ? config.labelFormatter(String(label)) : String(label ?? "");
65
+ const total = config?.showTotal ? items.reduce((sum, item) => sum + (Number(item.value) || 0), 0) : null;
66
+ return /* @__PURE__ */ jsxRuntime.jsxs(
67
+ "div",
68
+ {
69
+ style: {
70
+ background: "hsl(var(--card))",
71
+ border: "1px solid hsl(var(--border))",
72
+ borderRadius: 6,
73
+ padding: "8px 10px",
74
+ fontSize: 11,
75
+ lineHeight: 1.5,
76
+ boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
77
+ minWidth: 120
78
+ },
79
+ children: [
80
+ formattedLabel && /* @__PURE__ */ jsxRuntime.jsx(
81
+ "div",
82
+ {
83
+ style: {
84
+ color: "hsl(var(--foreground))",
85
+ fontWeight: 600,
86
+ marginBottom: 4,
87
+ borderBottom: "1px solid hsl(var(--border))",
88
+ paddingBottom: 4
89
+ },
90
+ children: formattedLabel
91
+ }
92
+ ),
93
+ items.map((item, i) => {
94
+ const formatted = config?.formatter ? config.formatter(Number(item.value), item.name) : String(item.value);
95
+ const displayValue = Array.isArray(formatted) ? formatted[0] : formatted;
96
+ const displayName = Array.isArray(formatted) ? formatted[1] : item.name;
97
+ let delta = null;
98
+ if (config?.showDelta && config.baseline) {
99
+ const baselineValue = Number(
100
+ item.payload?.[config.baseline] ?? 0
101
+ );
102
+ if (baselineValue !== 0) {
103
+ const diff = Number(item.value) - baselineValue;
104
+ const pct = (diff / baselineValue * 100).toFixed(1);
105
+ const sign = diff >= 0 ? "+" : "";
106
+ const color = diff > 0 ? "hsl(var(--success))" : diff < 0 ? "hsl(var(--destructive))" : "hsl(var(--muted-foreground))";
107
+ delta = /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color, marginLeft: 4, fontSize: 10 }, children: [
108
+ diff >= 0 ? "\u25B2" : "\u25BC",
109
+ " ",
110
+ sign,
111
+ pct,
112
+ "%"
113
+ ] });
114
+ }
115
+ }
116
+ return /* @__PURE__ */ jsxRuntime.jsxs(
117
+ "div",
118
+ {
119
+ style: {
120
+ display: "flex",
121
+ alignItems: "center",
122
+ justifyContent: "space-between",
123
+ gap: 12,
124
+ padding: "1px 0"
125
+ },
126
+ children: [
127
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
128
+ /* @__PURE__ */ jsxRuntime.jsx(
129
+ "span",
130
+ {
131
+ style: {
132
+ width: 8,
133
+ height: 8,
134
+ borderRadius: "50%",
135
+ background: item.color,
136
+ flexShrink: 0
137
+ }
138
+ }
139
+ ),
140
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "hsl(var(--muted-foreground))" }, children: displayName })
141
+ ] }),
142
+ /* @__PURE__ */ jsxRuntime.jsxs(
143
+ "span",
144
+ {
145
+ style: {
146
+ fontWeight: 600,
147
+ color: "hsl(var(--foreground))",
148
+ fontVariantNumeric: "tabular-nums"
149
+ },
150
+ children: [
151
+ displayValue,
152
+ delta
153
+ ]
154
+ }
155
+ )
156
+ ]
157
+ },
158
+ item.dataKey ?? i
159
+ );
160
+ }),
161
+ total != null && /* @__PURE__ */ jsxRuntime.jsxs(
162
+ "div",
163
+ {
164
+ style: {
165
+ borderTop: "1px solid hsl(var(--border))",
166
+ marginTop: 4,
167
+ paddingTop: 4,
168
+ display: "flex",
169
+ justifyContent: "space-between",
170
+ fontWeight: 600,
171
+ color: "hsl(var(--foreground))"
172
+ },
173
+ children: [
174
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
175
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: config?.formatter ? config.formatter(total, "Total") : total })
176
+ ]
177
+ }
178
+ )
179
+ ]
180
+ }
181
+ );
182
+ });
183
+ function resolveTooltipProps(tooltip) {
184
+ if (tooltip === false || tooltip === void 0) return null;
185
+ if (tooltip === true) return { content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, {}) };
186
+ return {
187
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartTooltipContent, { config: tooltip })
188
+ };
189
+ }
190
+ var ChartLegendContent = React17__namespace.memo(function ChartLegendContent2({
191
+ payload
192
+ }) {
193
+ if (!payload?.length) return null;
194
+ return /* @__PURE__ */ jsxRuntime.jsx(
195
+ "div",
196
+ {
197
+ style: {
198
+ display: "flex",
199
+ flexWrap: "wrap",
200
+ gap: "8px 16px",
201
+ fontSize: 11,
202
+ lineHeight: 1,
203
+ padding: "0 0 4px"
204
+ },
205
+ children: payload.map((entry, i) => /* @__PURE__ */ jsxRuntime.jsxs(
206
+ "span",
207
+ {
208
+ style: { display: "flex", alignItems: "center", gap: 5 },
209
+ children: [
210
+ /* @__PURE__ */ jsxRuntime.jsx(
211
+ "span",
212
+ {
213
+ style: {
214
+ width: 8,
215
+ height: 8,
216
+ borderRadius: "50%",
217
+ background: entry.color,
218
+ flexShrink: 0
219
+ }
220
+ }
221
+ ),
222
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "hsl(var(--muted-foreground))" }, children: entry.value })
223
+ ]
224
+ },
225
+ entry.dataKey ?? i
226
+ ))
227
+ }
228
+ );
229
+ });
230
+ function resolveLegendConfig(legend) {
231
+ if (legend === false || legend === void 0) return null;
232
+ if (legend === true) return { position: "top", align: "right" };
233
+ return legend;
234
+ }
235
+ var ChartContainer = React17__namespace.forwardRef(function ChartContainer2({
236
+ children,
237
+ className,
238
+ height = "100%",
239
+ loading,
240
+ empty,
241
+ emptyMessage = "No data available",
242
+ title,
243
+ description
244
+ }, ref) {
245
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: core.cn("w-full", className), style: { height }, children: [
246
+ (title || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
247
+ title && /* @__PURE__ */ jsxRuntime.jsx(
248
+ "div",
249
+ {
250
+ style: {
251
+ fontSize: 13,
252
+ fontWeight: 600,
253
+ color: "hsl(var(--foreground))"
254
+ },
255
+ children: title
256
+ }
257
+ ),
258
+ description && /* @__PURE__ */ jsxRuntime.jsx(
259
+ "div",
260
+ {
261
+ style: {
262
+ fontSize: 11,
263
+ color: "hsl(var(--muted-foreground))",
264
+ marginTop: 2
265
+ },
266
+ children: description
267
+ }
268
+ )
269
+ ] }),
270
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(
271
+ "div",
272
+ {
273
+ style: {
274
+ width: "100%",
275
+ height: title || description ? "calc(100% - 40px)" : "100%",
276
+ display: "flex",
277
+ alignItems: "center",
278
+ justifyContent: "center"
279
+ },
280
+ children: /* @__PURE__ */ jsxRuntime.jsx(
281
+ "div",
282
+ {
283
+ className: "animate-pulse",
284
+ style: {
285
+ width: "80%",
286
+ height: "60%",
287
+ borderRadius: 6,
288
+ background: "hsl(var(--muted))"
289
+ }
290
+ }
291
+ )
292
+ }
293
+ ) : empty ? /* @__PURE__ */ jsxRuntime.jsx(
294
+ "div",
295
+ {
296
+ style: {
297
+ width: "100%",
298
+ height: title || description ? "calc(100% - 40px)" : "100%",
299
+ display: "flex",
300
+ alignItems: "center",
301
+ justifyContent: "center",
302
+ color: "hsl(var(--muted-foreground))",
303
+ fontSize: 12
304
+ },
305
+ children: emptyMessage
306
+ }
307
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
308
+ recharts.ResponsiveContainer,
309
+ {
310
+ width: "100%",
311
+ height: title || description ? "calc(100% - 40px)" : "100%",
312
+ children
313
+ }
314
+ )
315
+ ] });
316
+ });
317
+ function useLiveData(config = {}) {
318
+ const {
319
+ initial = [],
320
+ maxPoints = 200,
321
+ interval = 2e3,
322
+ fetcher,
323
+ paused: initialPaused = false
324
+ } = config;
325
+ const [data, setData] = React17.useState(initial);
326
+ const [isPaused, setIsPaused] = React17.useState(initialPaused);
327
+ const bufferRef = React17.useRef(initial);
328
+ const push = React17.useCallback(
329
+ (...items) => {
330
+ bufferRef.current = [...bufferRef.current, ...items].slice(-maxPoints);
331
+ setData(bufferRef.current);
332
+ },
333
+ [maxPoints]
334
+ );
335
+ const replace = React17.useCallback((items) => {
336
+ bufferRef.current = items;
337
+ setData(items);
338
+ }, []);
339
+ const pause = React17.useCallback(() => setIsPaused(true), []);
340
+ const resume = React17.useCallback(() => setIsPaused(false), []);
341
+ React17.useEffect(() => {
342
+ if (!fetcher || isPaused) return;
343
+ let cancelled = false;
344
+ const tick = async () => {
345
+ try {
346
+ const result = await fetcher();
347
+ if (!cancelled) {
348
+ bufferRef.current = result.slice(-maxPoints);
349
+ setData(bufferRef.current);
350
+ }
351
+ } catch {
352
+ }
353
+ };
354
+ tick();
355
+ const id = setInterval(tick, interval);
356
+ return () => {
357
+ cancelled = true;
358
+ clearInterval(id);
359
+ };
360
+ }, [fetcher, interval, isPaused, maxPoints]);
361
+ return { data, push, replace, isPaused, pause, resume };
362
+ }
363
+
364
+ // src/shared/formatters.ts
365
+ var compactThresholds = [
366
+ [1e9, "B"],
367
+ [1e6, "M"],
368
+ [1e3, "K"]
369
+ ];
370
+ function formatCompact(value, decimals = 1) {
371
+ for (const [threshold, suffix] of compactThresholds) {
372
+ if (Math.abs(value) >= threshold) {
373
+ return `${(value / threshold).toFixed(decimals)}${suffix}`;
374
+ }
375
+ }
376
+ return value.toLocaleString();
377
+ }
378
+ function formatCurrency(value, currency = "USD", decimals) {
379
+ if (Math.abs(value) >= 1e6) {
380
+ return `$${formatCompact(value, decimals ?? 1)}`;
381
+ }
382
+ return value.toLocaleString("en-US", {
383
+ style: "currency",
384
+ currency,
385
+ minimumFractionDigits: decimals ?? 0,
386
+ maximumFractionDigits: decimals ?? 0
387
+ });
388
+ }
389
+ function formatPercent(value, decimals = 1) {
390
+ return `${value.toFixed(decimals)}%`;
391
+ }
392
+ function formatUnit(value, unit, decimals = 1) {
393
+ return `${value.toLocaleString(void 0, { maximumFractionDigits: decimals })} ${unit}`;
394
+ }
395
+ function formatDuration(seconds) {
396
+ if (seconds < 60) return `${Math.round(seconds)}s`;
397
+ if (seconds < 3600) return `${Math.round(seconds / 60)}m`;
398
+ if (seconds < 86400) {
399
+ const h2 = Math.floor(seconds / 3600);
400
+ const m = Math.round(seconds % 3600 / 60);
401
+ return m > 0 ? `${h2}h ${m}m` : `${h2}h`;
402
+ }
403
+ const d = Math.floor(seconds / 86400);
404
+ const h = Math.round(seconds % 86400 / 3600);
405
+ return h > 0 ? `${d}d ${h}h` : `${d}d`;
406
+ }
407
+ var LineChart = React17__namespace.forwardRef(
41
408
  ({
42
409
  data,
43
410
  series,
@@ -47,112 +414,105 @@ var LineChart = React__namespace.forwardRef(
47
414
  tooltip = true,
48
415
  legend = false,
49
416
  animate = false,
417
+ live = false,
50
418
  className,
51
419
  height = "100%",
52
- margin = { top: 8, right: 12, left: 0, bottom: 4 }
420
+ margin = { top: 8, right: 12, left: 0, bottom: 4 },
421
+ loading
53
422
  }, ref) => {
54
- const gridConfig = React__namespace.useMemo(() => {
423
+ const gridConfig = React17__namespace.useMemo(() => {
55
424
  if (grid === false) return null;
56
425
  if (grid === true) return { vertical: false, horizontal: true };
57
426
  return grid;
58
427
  }, [grid]);
59
- const legendConfig = React__namespace.useMemo(() => {
60
- if (legend === false) return null;
61
- if (legend === true)
62
- return { position: "top", align: "right" };
63
- return legend;
64
- }, [legend]);
65
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: core.cn("w-full", className), style: { height }, children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, margin, children: [
66
- gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
67
- recharts.CartesianGrid,
68
- {
69
- strokeDasharray: "3 3",
70
- stroke: "hsl(var(--divider))",
71
- vertical: gridConfig.vertical ?? false,
72
- horizontal: gridConfig.horizontal ?? true
73
- }
74
- ),
75
- /* @__PURE__ */ jsxRuntime.jsx(
76
- recharts.XAxis,
77
- {
78
- dataKey: xAxis.dataKey,
79
- tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
80
- tickLine: false,
81
- axisLine: false,
82
- minTickGap: xAxis.minTickGap ?? 24,
83
- tickFormatter: xAxis.tickFormatter,
84
- label: xAxis.label ? {
85
- value: xAxis.label,
86
- position: "insideBottom",
87
- offset: -4,
88
- fontSize: 11,
89
- fill: "hsl(var(--muted-foreground))"
90
- } : void 0
91
- }
92
- ),
93
- /* @__PURE__ */ jsxRuntime.jsx(
94
- recharts.YAxis,
95
- {
96
- domain: yAxis?.domain ?? ["auto", "auto"],
97
- tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
98
- tickLine: false,
99
- axisLine: false,
100
- width: yAxis?.width ?? 30,
101
- tickFormatter: yAxis?.tickFormatter,
102
- label: yAxis?.label ? {
103
- value: yAxis.label,
104
- angle: -90,
105
- position: "insideLeft",
106
- fontSize: 11,
107
- fill: "hsl(var(--muted-foreground))"
108
- } : void 0
109
- }
110
- ),
111
- tooltip && /* @__PURE__ */ jsxRuntime.jsx(
112
- recharts.Tooltip,
113
- {
114
- contentStyle: {
115
- background: "hsl(var(--card))",
116
- border: "1px solid hsl(var(--border))",
117
- borderRadius: 6,
118
- fontSize: 11
119
- },
120
- labelStyle: {
121
- color: "hsl(var(--foreground))",
122
- fontWeight: 500,
123
- marginBottom: 4
124
- },
125
- itemStyle: {
126
- color: "hsl(var(--foreground))"
127
- }
128
- }
129
- ),
130
- legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
131
- recharts.Legend,
132
- {
133
- verticalAlign: legendConfig.position ?? "top",
134
- align: legendConfig.align ?? "right",
135
- wrapperStyle: { fontSize: 11, paddingBottom: 4 }
136
- }
137
- ),
138
- series.map((s, index) => /* @__PURE__ */ jsxRuntime.jsx(
139
- recharts.Line,
140
- {
141
- type: s.type ?? "monotone",
142
- dataKey: s.dataKey,
143
- name: s.name,
144
- stroke: getChartColor(index, s.color),
145
- strokeWidth: s.strokeWidth ?? 2,
146
- dot: s.dot ?? false,
147
- isAnimationActive: animate
148
- },
149
- s.dataKey
150
- ))
151
- ] }) }) });
428
+ const legendConfig = resolveLegendConfig(legend);
429
+ const tooltipProps = resolveTooltipProps(tooltip);
430
+ const isAnimated = live ? false : animate;
431
+ return /* @__PURE__ */ jsxRuntime.jsx(
432
+ ChartContainer,
433
+ {
434
+ ref,
435
+ className,
436
+ height,
437
+ loading,
438
+ empty: !data?.length,
439
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, margin, children: [
440
+ gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
441
+ recharts.CartesianGrid,
442
+ {
443
+ strokeDasharray: "3 3",
444
+ stroke: "hsl(var(--divider))",
445
+ vertical: gridConfig.vertical ?? false,
446
+ horizontal: gridConfig.horizontal ?? true
447
+ }
448
+ ),
449
+ /* @__PURE__ */ jsxRuntime.jsx(
450
+ recharts.XAxis,
451
+ {
452
+ dataKey: xAxis.dataKey,
453
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
454
+ tickLine: false,
455
+ axisLine: false,
456
+ minTickGap: xAxis.minTickGap ?? 24,
457
+ tickFormatter: xAxis.tickFormatter,
458
+ label: xAxis.label ? {
459
+ value: xAxis.label,
460
+ position: "insideBottom",
461
+ offset: -4,
462
+ fontSize: 11,
463
+ fill: "hsl(var(--muted-foreground))"
464
+ } : void 0
465
+ }
466
+ ),
467
+ /* @__PURE__ */ jsxRuntime.jsx(
468
+ recharts.YAxis,
469
+ {
470
+ domain: yAxis?.domain ?? ["auto", "auto"],
471
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
472
+ tickLine: false,
473
+ axisLine: false,
474
+ width: yAxis?.width ?? 30,
475
+ tickFormatter: yAxis?.tickFormatter,
476
+ label: yAxis?.label ? {
477
+ value: yAxis.label,
478
+ angle: -90,
479
+ position: "insideLeft",
480
+ fontSize: 11,
481
+ fill: "hsl(var(--muted-foreground))"
482
+ } : void 0
483
+ }
484
+ ),
485
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
486
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
487
+ recharts.Legend,
488
+ {
489
+ verticalAlign: legendConfig.position ?? "top",
490
+ align: legendConfig.align ?? "right",
491
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
492
+ }
493
+ ),
494
+ series.map((s, index) => /* @__PURE__ */ jsxRuntime.jsx(
495
+ recharts.Line,
496
+ {
497
+ type: s.type ?? "monotone",
498
+ dataKey: s.dataKey,
499
+ name: s.name,
500
+ stroke: getChartColor(index, s.color),
501
+ strokeWidth: s.strokeWidth ?? 2,
502
+ strokeDasharray: s.strokeDasharray,
503
+ dot: s.dot ?? false,
504
+ isAnimationActive: isAnimated,
505
+ animationDuration: isAnimated ? 300 : 0
506
+ },
507
+ s.dataKey
508
+ ))
509
+ ] })
510
+ }
511
+ );
152
512
  }
153
513
  );
154
514
  LineChart.displayName = "LineChart";
155
- var BarChart = React__namespace.forwardRef(
515
+ var BarChart = React17__namespace.forwardRef(
156
516
  ({
157
517
  data,
158
518
  series,
@@ -163,105 +523,351 @@ var BarChart = React__namespace.forwardRef(
163
523
  tooltip = true,
164
524
  legend = false,
165
525
  animate = true,
526
+ live = false,
166
527
  barSize,
167
528
  barGap,
168
529
  barCategoryGap,
169
530
  className,
170
531
  height = "100%",
171
- margin = { top: 8, right: 12, left: 0, bottom: 4 }
532
+ margin = { top: 8, right: 12, left: 0, bottom: 4 },
533
+ loading
172
534
  }, ref) => {
173
- const gridConfig = React__namespace.useMemo(() => {
535
+ const gridConfig = React17__namespace.useMemo(() => {
174
536
  if (grid === false) return null;
175
537
  if (grid === true) return { vertical: false, horizontal: true };
176
538
  return grid;
177
539
  }, [grid]);
178
- const legendConfig = React__namespace.useMemo(() => {
179
- if (legend === false) return null;
180
- if (legend === true)
181
- return { position: "top", align: "right" };
182
- return legend;
183
- }, [legend]);
540
+ const legendConfig = resolveLegendConfig(legend);
541
+ const tooltipProps = resolveTooltipProps(tooltip);
542
+ const isAnimated = live ? false : animate;
184
543
  const isHorizontal = layout === "horizontal";
185
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: core.cn("w-full", className), style: { height }, children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(
186
- recharts.BarChart,
544
+ return /* @__PURE__ */ jsxRuntime.jsx(
545
+ ChartContainer,
187
546
  {
188
- data,
189
- layout: isHorizontal ? "vertical" : "horizontal",
190
- margin,
191
- barSize,
192
- barGap,
193
- barCategoryGap,
194
- children: [
547
+ ref,
548
+ className,
549
+ height,
550
+ loading,
551
+ empty: !data?.length,
552
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
553
+ recharts.BarChart,
554
+ {
555
+ data,
556
+ layout: isHorizontal ? "vertical" : "horizontal",
557
+ margin,
558
+ barSize,
559
+ barGap,
560
+ barCategoryGap,
561
+ children: [
562
+ gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
563
+ recharts.CartesianGrid,
564
+ {
565
+ strokeDasharray: "3 3",
566
+ stroke: "hsl(var(--divider))",
567
+ vertical: isHorizontal ? gridConfig.horizontal ?? true : gridConfig.vertical ?? false,
568
+ horizontal: isHorizontal ? gridConfig.vertical ?? false : gridConfig.horizontal ?? true
569
+ }
570
+ ),
571
+ isHorizontal ? /* @__PURE__ */ jsxRuntime.jsx(
572
+ recharts.XAxis,
573
+ {
574
+ type: "number",
575
+ domain: yAxis?.domain ?? ["auto", "auto"],
576
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
577
+ tickLine: false,
578
+ axisLine: false,
579
+ tickFormatter: yAxis?.tickFormatter,
580
+ label: yAxis?.label ? {
581
+ value: yAxis.label,
582
+ position: "insideBottom",
583
+ offset: -4,
584
+ fontSize: 11,
585
+ fill: "hsl(var(--muted-foreground))"
586
+ } : void 0
587
+ }
588
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
589
+ recharts.XAxis,
590
+ {
591
+ dataKey: xAxis.dataKey,
592
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
593
+ tickLine: false,
594
+ axisLine: false,
595
+ minTickGap: xAxis.minTickGap ?? 24,
596
+ tickFormatter: xAxis.tickFormatter,
597
+ label: xAxis.label ? {
598
+ value: xAxis.label,
599
+ position: "insideBottom",
600
+ offset: -4,
601
+ fontSize: 11,
602
+ fill: "hsl(var(--muted-foreground))"
603
+ } : void 0
604
+ }
605
+ ),
606
+ isHorizontal ? /* @__PURE__ */ jsxRuntime.jsx(
607
+ recharts.YAxis,
608
+ {
609
+ type: "category",
610
+ dataKey: xAxis.dataKey,
611
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
612
+ tickLine: false,
613
+ axisLine: false,
614
+ width: yAxis?.width ?? 80,
615
+ tickFormatter: xAxis.tickFormatter
616
+ }
617
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
618
+ recharts.YAxis,
619
+ {
620
+ domain: yAxis?.domain ?? ["auto", "auto"],
621
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
622
+ tickLine: false,
623
+ axisLine: false,
624
+ width: yAxis?.width ?? 30,
625
+ tickFormatter: yAxis?.tickFormatter,
626
+ label: yAxis?.label ? {
627
+ value: yAxis.label,
628
+ angle: -90,
629
+ position: "insideLeft",
630
+ fontSize: 11,
631
+ fill: "hsl(var(--muted-foreground))"
632
+ } : void 0
633
+ }
634
+ ),
635
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(
636
+ recharts.Tooltip,
637
+ {
638
+ ...tooltipProps,
639
+ cursor: { fill: "hsl(var(--accent))", fillOpacity: 0.3 }
640
+ }
641
+ ),
642
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
643
+ recharts.Legend,
644
+ {
645
+ verticalAlign: legendConfig.position ?? "top",
646
+ align: legendConfig.align ?? "right",
647
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
648
+ }
649
+ ),
650
+ series.map((s, index) => /* @__PURE__ */ jsxRuntime.jsx(
651
+ recharts.Bar,
652
+ {
653
+ dataKey: s.dataKey,
654
+ name: s.name,
655
+ fill: getChartColor(index, s.color),
656
+ stackId: s.stackId,
657
+ radius: s.radius ?? 0,
658
+ isAnimationActive: isAnimated,
659
+ animationDuration: isAnimated ? 300 : 0
660
+ },
661
+ s.dataKey
662
+ ))
663
+ ]
664
+ }
665
+ )
666
+ }
667
+ );
668
+ }
669
+ );
670
+ BarChart.displayName = "BarChart";
671
+ var AreaChart = React17__namespace.forwardRef(
672
+ ({
673
+ data,
674
+ series,
675
+ xAxis,
676
+ yAxis,
677
+ grid = true,
678
+ tooltip = true,
679
+ legend = false,
680
+ animate = true,
681
+ live = false,
682
+ className,
683
+ height = "100%",
684
+ margin = { top: 8, right: 12, left: 0, bottom: 4 },
685
+ loading
686
+ }, ref) => {
687
+ const gridConfig = React17__namespace.useMemo(() => {
688
+ if (grid === false) return null;
689
+ if (grid === true) return { vertical: false, horizontal: true };
690
+ return grid;
691
+ }, [grid]);
692
+ const legendConfig = resolveLegendConfig(legend);
693
+ const tooltipProps = resolveTooltipProps(tooltip);
694
+ const isAnimated = live ? false : animate;
695
+ return /* @__PURE__ */ jsxRuntime.jsx(
696
+ ChartContainer,
697
+ {
698
+ ref,
699
+ className,
700
+ height,
701
+ loading,
702
+ empty: !data?.length,
703
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.AreaChart, { data, margin, children: [
704
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: series.map((s, index) => {
705
+ const color = getChartColor(index, s.color);
706
+ return /* @__PURE__ */ jsxRuntime.jsxs(
707
+ "linearGradient",
708
+ {
709
+ id: `area-gradient-${s.dataKey}`,
710
+ x1: "0",
711
+ y1: "0",
712
+ x2: "0",
713
+ y2: "1",
714
+ children: [
715
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "5%", stopColor: color, stopOpacity: 0.3 }),
716
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "95%", stopColor: color, stopOpacity: 0.05 })
717
+ ]
718
+ },
719
+ s.dataKey
720
+ );
721
+ }) }),
195
722
  gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
196
723
  recharts.CartesianGrid,
197
724
  {
198
725
  strokeDasharray: "3 3",
199
726
  stroke: "hsl(var(--divider))",
200
- vertical: isHorizontal ? gridConfig.horizontal ?? true : gridConfig.vertical ?? false,
201
- horizontal: isHorizontal ? gridConfig.vertical ?? false : gridConfig.horizontal ?? true
727
+ vertical: gridConfig.vertical ?? false,
728
+ horizontal: gridConfig.horizontal ?? true
202
729
  }
203
730
  ),
204
- isHorizontal ? /* @__PURE__ */ jsxRuntime.jsx(
731
+ /* @__PURE__ */ jsxRuntime.jsx(
205
732
  recharts.XAxis,
206
733
  {
207
- type: "number",
208
- domain: yAxis?.domain ?? ["auto", "auto"],
734
+ dataKey: xAxis.dataKey,
209
735
  tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
210
736
  tickLine: false,
211
737
  axisLine: false,
212
- tickFormatter: yAxis?.tickFormatter,
213
- label: yAxis?.label ? {
214
- value: yAxis.label,
738
+ minTickGap: xAxis.minTickGap ?? 24,
739
+ tickFormatter: xAxis.tickFormatter,
740
+ label: xAxis.label ? {
741
+ value: xAxis.label,
215
742
  position: "insideBottom",
216
743
  offset: -4,
217
744
  fontSize: 11,
218
745
  fill: "hsl(var(--muted-foreground))"
219
746
  } : void 0
220
747
  }
221
- ) : /* @__PURE__ */ jsxRuntime.jsx(
222
- recharts.XAxis,
748
+ ),
749
+ /* @__PURE__ */ jsxRuntime.jsx(
750
+ recharts.YAxis,
223
751
  {
224
- dataKey: xAxis.dataKey,
752
+ domain: yAxis?.domain ?? ["auto", "auto"],
225
753
  tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
226
754
  tickLine: false,
227
755
  axisLine: false,
228
- minTickGap: xAxis.minTickGap ?? 24,
229
- tickFormatter: xAxis.tickFormatter,
230
- label: xAxis.label ? {
231
- value: xAxis.label,
232
- position: "insideBottom",
233
- offset: -4,
756
+ width: yAxis?.width ?? 30,
757
+ tickFormatter: yAxis?.tickFormatter,
758
+ label: yAxis?.label ? {
759
+ value: yAxis.label,
760
+ angle: -90,
761
+ position: "insideLeft",
234
762
  fontSize: 11,
235
763
  fill: "hsl(var(--muted-foreground))"
236
764
  } : void 0
237
765
  }
238
766
  ),
239
- isHorizontal ? /* @__PURE__ */ jsxRuntime.jsx(
240
- recharts.YAxis,
767
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
768
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
769
+ recharts.Legend,
770
+ {
771
+ verticalAlign: legendConfig.position ?? "top",
772
+ align: legendConfig.align ?? "right",
773
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
774
+ }
775
+ ),
776
+ series.map((s, index) => /* @__PURE__ */ jsxRuntime.jsx(
777
+ recharts.Area,
778
+ {
779
+ type: s.type ?? "monotone",
780
+ dataKey: s.dataKey,
781
+ name: s.name,
782
+ stroke: getChartColor(index, s.color),
783
+ strokeWidth: s.strokeWidth ?? 2,
784
+ fill: `url(#area-gradient-${s.dataKey})`,
785
+ fillOpacity: s.fillOpacity ?? 1,
786
+ stackId: s.stackId,
787
+ isAnimationActive: isAnimated,
788
+ animationDuration: isAnimated ? 300 : 0
789
+ },
790
+ s.dataKey
791
+ ))
792
+ ] })
793
+ }
794
+ );
795
+ }
796
+ );
797
+ AreaChart.displayName = "AreaChart";
798
+ var ScatterChart = React17__namespace.forwardRef(
799
+ ({
800
+ series,
801
+ xAxis,
802
+ yAxis,
803
+ zAxis,
804
+ grid = true,
805
+ tooltip = true,
806
+ legend = false,
807
+ animate = true,
808
+ live = false,
809
+ className,
810
+ height = "100%",
811
+ margin = { top: 8, right: 12, left: 0, bottom: 4 },
812
+ loading
813
+ }, ref) => {
814
+ const gridConfig = React17__namespace.useMemo(() => {
815
+ if (grid === false) return null;
816
+ if (grid === true) return { vertical: true, horizontal: true };
817
+ return grid;
818
+ }, [grid]);
819
+ const legendConfig = resolveLegendConfig(legend);
820
+ const tooltipProps = resolveTooltipProps(tooltip);
821
+ const isAnimated = live ? false : animate;
822
+ const hasZ = series.some((s) => s.zDataKey);
823
+ return /* @__PURE__ */ jsxRuntime.jsx(
824
+ ChartContainer,
825
+ {
826
+ ref,
827
+ className,
828
+ height,
829
+ loading,
830
+ empty: !series.some((s) => s.data?.length),
831
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.ScatterChart, { margin, children: [
832
+ gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
833
+ recharts.CartesianGrid,
834
+ {
835
+ strokeDasharray: "3 3",
836
+ stroke: "hsl(var(--divider))",
837
+ vertical: gridConfig.vertical ?? true,
838
+ horizontal: gridConfig.horizontal ?? true
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsxRuntime.jsx(
842
+ recharts.XAxis,
241
843
  {
242
- type: "category",
243
844
  dataKey: xAxis.dataKey,
845
+ name: xAxis.name ?? xAxis.dataKey,
846
+ type: "number",
244
847
  tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
245
848
  tickLine: false,
246
849
  axisLine: false,
247
- width: yAxis?.width ?? 80,
248
850
  tickFormatter: xAxis.tickFormatter,
249
851
  label: xAxis.label ? {
250
852
  value: xAxis.label,
251
- angle: -90,
252
- position: "insideLeft",
853
+ position: "insideBottom",
854
+ offset: -4,
253
855
  fontSize: 11,
254
856
  fill: "hsl(var(--muted-foreground))"
255
857
  } : void 0
256
858
  }
257
- ) : /* @__PURE__ */ jsxRuntime.jsx(
859
+ ),
860
+ /* @__PURE__ */ jsxRuntime.jsx(
258
861
  recharts.YAxis,
259
862
  {
863
+ dataKey: yAxis?.domain ? void 0 : "y",
864
+ name: yAxis?.name,
865
+ type: "number",
260
866
  domain: yAxis?.domain ?? ["auto", "auto"],
261
867
  tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
262
868
  tickLine: false,
263
869
  axisLine: false,
264
- width: yAxis?.width ?? 30,
870
+ width: yAxis?.width ?? 40,
265
871
  tickFormatter: yAxis?.tickFormatter,
266
872
  label: yAxis?.label ? {
267
873
  value: yAxis.label,
@@ -272,56 +878,2310 @@ var BarChart = React__namespace.forwardRef(
272
878
  } : void 0
273
879
  }
274
880
  ),
275
- tooltip && /* @__PURE__ */ jsxRuntime.jsx(
276
- recharts.Tooltip,
277
- {
278
- contentStyle: {
279
- background: "hsl(var(--card))",
280
- border: "1px solid hsl(var(--border))",
281
- borderRadius: 6,
282
- fontSize: 11
283
- },
284
- labelStyle: {
285
- color: "hsl(var(--foreground))",
286
- fontWeight: 500,
287
- marginBottom: 4
288
- },
289
- itemStyle: {
290
- color: "hsl(var(--foreground))"
291
- },
292
- cursor: { fill: "hsl(var(--accent))", fillOpacity: 0.3 }
293
- }
294
- ),
881
+ hasZ && /* @__PURE__ */ jsxRuntime.jsx(recharts.ZAxis, { range: zAxis?.range ?? [40, 400] }),
882
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
295
883
  legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
296
884
  recharts.Legend,
297
885
  {
298
886
  verticalAlign: legendConfig.position ?? "top",
299
887
  align: legendConfig.align ?? "right",
300
- wrapperStyle: { fontSize: 11, paddingBottom: 4 }
888
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
301
889
  }
302
890
  ),
303
891
  series.map((s, index) => /* @__PURE__ */ jsxRuntime.jsx(
304
- recharts.Bar,
892
+ recharts.Scatter,
305
893
  {
306
- dataKey: s.dataKey,
307
894
  name: s.name,
895
+ data: s.data,
308
896
  fill: getChartColor(index, s.color),
309
- stackId: s.stackId,
310
- radius: s.radius ?? 0,
311
- isAnimationActive: animate
897
+ isAnimationActive: isAnimated
312
898
  },
313
- s.dataKey
899
+ s.name
314
900
  ))
315
- ]
901
+ ] })
316
902
  }
317
- ) }) });
903
+ );
318
904
  }
319
905
  );
320
- BarChart.displayName = "BarChart";
906
+ ScatterChart.displayName = "ScatterChart";
907
+ var ComposedChart = React17__namespace.forwardRef(
908
+ ({
909
+ data,
910
+ series,
911
+ xAxis,
912
+ yAxis,
913
+ yAxisRight,
914
+ grid = true,
915
+ tooltip = true,
916
+ legend = false,
917
+ animate = true,
918
+ live = false,
919
+ className,
920
+ height = "100%",
921
+ margin = { top: 8, right: 12, left: 0, bottom: 4 },
922
+ loading
923
+ }, ref) => {
924
+ const gridConfig = React17__namespace.useMemo(() => {
925
+ if (grid === false) return null;
926
+ if (grid === true) return { vertical: false, horizontal: true };
927
+ return grid;
928
+ }, [grid]);
929
+ const legendConfig = resolveLegendConfig(legend);
930
+ const tooltipProps = resolveTooltipProps(tooltip);
931
+ const isAnimated = live ? false : animate;
932
+ return /* @__PURE__ */ jsxRuntime.jsx(
933
+ ChartContainer,
934
+ {
935
+ ref,
936
+ className,
937
+ height,
938
+ loading,
939
+ empty: !data?.length,
940
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.ComposedChart, { data, margin, children: [
941
+ gridConfig && /* @__PURE__ */ jsxRuntime.jsx(
942
+ recharts.CartesianGrid,
943
+ {
944
+ strokeDasharray: "3 3",
945
+ stroke: "hsl(var(--divider))",
946
+ vertical: gridConfig.vertical ?? false,
947
+ horizontal: gridConfig.horizontal ?? true
948
+ }
949
+ ),
950
+ /* @__PURE__ */ jsxRuntime.jsx(
951
+ recharts.XAxis,
952
+ {
953
+ dataKey: xAxis.dataKey,
954
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
955
+ tickLine: false,
956
+ axisLine: false,
957
+ minTickGap: xAxis.minTickGap ?? 24,
958
+ tickFormatter: xAxis.tickFormatter,
959
+ label: xAxis.label ? {
960
+ value: xAxis.label,
961
+ position: "insideBottom",
962
+ offset: -4,
963
+ fontSize: 11,
964
+ fill: "hsl(var(--muted-foreground))"
965
+ } : void 0
966
+ }
967
+ ),
968
+ /* @__PURE__ */ jsxRuntime.jsx(
969
+ recharts.YAxis,
970
+ {
971
+ yAxisId: "left",
972
+ domain: yAxis?.domain ?? ["auto", "auto"],
973
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
974
+ tickLine: false,
975
+ axisLine: false,
976
+ width: yAxis?.width ?? 40,
977
+ tickFormatter: yAxis?.tickFormatter,
978
+ label: yAxis?.label ? {
979
+ value: yAxis.label,
980
+ angle: -90,
981
+ position: "insideLeft",
982
+ fontSize: 11,
983
+ fill: "hsl(var(--muted-foreground))"
984
+ } : void 0
985
+ }
986
+ ),
987
+ yAxisRight && /* @__PURE__ */ jsxRuntime.jsx(
988
+ recharts.YAxis,
989
+ {
990
+ yAxisId: yAxisRight.id,
991
+ orientation: "right",
992
+ domain: yAxisRight.domain ?? ["auto", "auto"],
993
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
994
+ tickLine: false,
995
+ axisLine: false,
996
+ width: yAxisRight.width ?? 40,
997
+ tickFormatter: yAxisRight.tickFormatter,
998
+ label: yAxisRight.label ? {
999
+ value: yAxisRight.label,
1000
+ angle: 90,
1001
+ position: "insideRight",
1002
+ fontSize: 11,
1003
+ fill: "hsl(var(--muted-foreground))"
1004
+ } : void 0
1005
+ }
1006
+ ),
1007
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
1008
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
1009
+ recharts.Legend,
1010
+ {
1011
+ verticalAlign: legendConfig.position ?? "top",
1012
+ align: legendConfig.align ?? "right",
1013
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
1014
+ }
1015
+ ),
1016
+ series.map((s, index) => {
1017
+ const color = getChartColor(index, s.color);
1018
+ const yAxisId = s.yAxisId ?? "left";
1019
+ const props = {
1020
+ key: s.dataKey,
1021
+ dataKey: s.dataKey,
1022
+ name: s.name,
1023
+ yAxisId,
1024
+ isAnimationActive: isAnimated,
1025
+ animationDuration: isAnimated ? 300 : 0
1026
+ };
1027
+ switch (s.type) {
1028
+ case "line":
1029
+ return /* @__PURE__ */ jsxRuntime.jsx(
1030
+ recharts.Line,
1031
+ {
1032
+ ...props,
1033
+ type: "monotone",
1034
+ stroke: color,
1035
+ strokeWidth: s.strokeWidth ?? 2,
1036
+ strokeDasharray: s.strokeDasharray,
1037
+ dot: false
1038
+ }
1039
+ );
1040
+ case "bar":
1041
+ return /* @__PURE__ */ jsxRuntime.jsx(
1042
+ recharts.Bar,
1043
+ {
1044
+ ...props,
1045
+ fill: color,
1046
+ stackId: s.stackId,
1047
+ radius: s.radius ?? 0
1048
+ }
1049
+ );
1050
+ case "area":
1051
+ return /* @__PURE__ */ jsxRuntime.jsx(
1052
+ recharts.Area,
1053
+ {
1054
+ ...props,
1055
+ type: "monotone",
1056
+ stroke: color,
1057
+ fill: color,
1058
+ fillOpacity: s.fillOpacity ?? 0.15,
1059
+ strokeWidth: s.strokeWidth ?? 2,
1060
+ stackId: s.stackId
1061
+ }
1062
+ );
1063
+ }
1064
+ })
1065
+ ] })
1066
+ }
1067
+ );
1068
+ }
1069
+ );
1070
+ ComposedChart.displayName = "ComposedChart";
1071
+ function buildWaterfallData(items) {
1072
+ let running = 0;
1073
+ return items.map((item) => {
1074
+ if (item.isTotal) {
1075
+ const row = {
1076
+ name: item.name,
1077
+ invisible: 0,
1078
+ delta: running,
1079
+ isTotal: true,
1080
+ rawValue: running
1081
+ };
1082
+ return row;
1083
+ }
1084
+ const start = running;
1085
+ running += item.value;
1086
+ const base = item.value >= 0 ? start : running;
1087
+ return {
1088
+ name: item.name,
1089
+ invisible: base,
1090
+ delta: Math.abs(item.value),
1091
+ isTotal: false,
1092
+ rawValue: item.value
1093
+ };
1094
+ });
1095
+ }
1096
+ var WaterfallChart = React17__namespace.forwardRef(
1097
+ ({
1098
+ data,
1099
+ xAxis,
1100
+ yAxis,
1101
+ tooltip = true,
1102
+ positiveColor,
1103
+ negativeColor,
1104
+ totalColor,
1105
+ animate = true,
1106
+ live = false,
1107
+ className,
1108
+ height = "100%",
1109
+ margin = { top: 8, right: 12, left: 0, bottom: 4 },
1110
+ loading
1111
+ }, ref) => {
1112
+ const rows = React17__namespace.useMemo(() => buildWaterfallData(data), [data]);
1113
+ const tooltipProps = resolveTooltipProps(tooltip);
1114
+ const isAnimated = live ? false : animate;
1115
+ const posColor = positiveColor ?? getSemanticColor("positive");
1116
+ const negColor = negativeColor ?? getSemanticColor("negative");
1117
+ const totColor = totalColor ?? "hsl(var(--chart-3))";
1118
+ return /* @__PURE__ */ jsxRuntime.jsx(
1119
+ ChartContainer,
1120
+ {
1121
+ ref,
1122
+ className,
1123
+ height,
1124
+ loading,
1125
+ empty: !data?.length,
1126
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data: rows, margin, children: [
1127
+ /* @__PURE__ */ jsxRuntime.jsx(
1128
+ recharts.CartesianGrid,
1129
+ {
1130
+ strokeDasharray: "3 3",
1131
+ stroke: "hsl(var(--divider))",
1132
+ vertical: false
1133
+ }
1134
+ ),
1135
+ /* @__PURE__ */ jsxRuntime.jsx(
1136
+ recharts.XAxis,
1137
+ {
1138
+ dataKey: "name",
1139
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
1140
+ tickLine: false,
1141
+ axisLine: false,
1142
+ tickFormatter: xAxis?.tickFormatter
1143
+ }
1144
+ ),
1145
+ /* @__PURE__ */ jsxRuntime.jsx(
1146
+ recharts.YAxis,
1147
+ {
1148
+ domain: yAxis?.domain ?? ["auto", "auto"],
1149
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" },
1150
+ tickLine: false,
1151
+ axisLine: false,
1152
+ width: yAxis?.width ?? 40,
1153
+ tickFormatter: yAxis?.tickFormatter,
1154
+ label: yAxis?.label ? {
1155
+ value: yAxis.label,
1156
+ angle: -90,
1157
+ position: "insideLeft",
1158
+ fontSize: 11,
1159
+ fill: "hsl(var(--muted-foreground))"
1160
+ } : void 0
1161
+ }
1162
+ ),
1163
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.ReferenceLine, { y: 0, stroke: "hsl(var(--divider))" }),
1164
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
1165
+ /* @__PURE__ */ jsxRuntime.jsx(
1166
+ recharts.Bar,
1167
+ {
1168
+ dataKey: "invisible",
1169
+ stackId: "waterfall",
1170
+ fill: "transparent",
1171
+ isAnimationActive: false
1172
+ }
1173
+ ),
1174
+ /* @__PURE__ */ jsxRuntime.jsx(
1175
+ recharts.Bar,
1176
+ {
1177
+ dataKey: "delta",
1178
+ stackId: "waterfall",
1179
+ isAnimationActive: isAnimated,
1180
+ animationDuration: isAnimated ? 300 : 0,
1181
+ radius: [2, 2, 0, 0],
1182
+ children: rows.map((row, i) => /* @__PURE__ */ jsxRuntime.jsx(
1183
+ recharts.Cell,
1184
+ {
1185
+ fill: row.isTotal ? totColor : row.rawValue >= 0 ? posColor : negColor
1186
+ },
1187
+ i
1188
+ ))
1189
+ }
1190
+ )
1191
+ ] })
1192
+ }
1193
+ );
1194
+ }
1195
+ );
1196
+ WaterfallChart.displayName = "WaterfallChart";
1197
+ var RADIAN = Math.PI / 180;
1198
+ function defaultRenderLabel({
1199
+ cx,
1200
+ cy,
1201
+ midAngle,
1202
+ innerRadius,
1203
+ outerRadius,
1204
+ percent
1205
+ }) {
1206
+ const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
1207
+ const x = cx + radius * Math.cos(-midAngle * RADIAN);
1208
+ const y = cy + radius * Math.sin(-midAngle * RADIAN);
1209
+ if (percent < 0.04) return null;
1210
+ return /* @__PURE__ */ jsxRuntime.jsx(
1211
+ "text",
1212
+ {
1213
+ x,
1214
+ y,
1215
+ fill: "hsl(var(--card-foreground))",
1216
+ textAnchor: "middle",
1217
+ dominantBaseline: "central",
1218
+ fontSize: 10,
1219
+ fontWeight: 600,
1220
+ children: `${(percent * 100).toFixed(0)}%`
1221
+ }
1222
+ );
1223
+ }
1224
+ var PieChart = React17__namespace.forwardRef(
1225
+ ({
1226
+ data,
1227
+ innerRadius = 0,
1228
+ outerRadius = "80%",
1229
+ paddingAngle = 2,
1230
+ startAngle = 90,
1231
+ endAngle = -270,
1232
+ legend = false,
1233
+ tooltip = true,
1234
+ label = false,
1235
+ animate = true,
1236
+ live = false,
1237
+ className,
1238
+ height = "100%",
1239
+ margin = { top: 8, right: 8, left: 8, bottom: 8 },
1240
+ loading
1241
+ }, ref) => {
1242
+ const legendConfig = resolveLegendConfig(legend);
1243
+ const tooltipProps = resolveTooltipProps(tooltip);
1244
+ const isAnimated = live ? false : animate;
1245
+ const renderLabel = label === true ? defaultRenderLabel : typeof label === "function" ? (entry) => label(entry) : void 0;
1246
+ return /* @__PURE__ */ jsxRuntime.jsx(
1247
+ ChartContainer,
1248
+ {
1249
+ ref,
1250
+ className,
1251
+ height,
1252
+ loading,
1253
+ empty: !data?.length,
1254
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { margin, children: [
1255
+ /* @__PURE__ */ jsxRuntime.jsx(
1256
+ recharts.Pie,
1257
+ {
1258
+ data,
1259
+ dataKey: "value",
1260
+ nameKey: "name",
1261
+ cx: "50%",
1262
+ cy: "50%",
1263
+ innerRadius,
1264
+ outerRadius,
1265
+ paddingAngle,
1266
+ startAngle,
1267
+ endAngle,
1268
+ isAnimationActive: isAnimated,
1269
+ animationDuration: isAnimated ? 400 : 0,
1270
+ label: renderLabel,
1271
+ labelLine: false,
1272
+ stroke: "hsl(var(--card))",
1273
+ strokeWidth: 2,
1274
+ children: data.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(
1275
+ recharts.Cell,
1276
+ {
1277
+ fill: getChartColor(index, entry.color)
1278
+ },
1279
+ entry.name
1280
+ ))
1281
+ }
1282
+ ),
1283
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
1284
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
1285
+ recharts.Legend,
1286
+ {
1287
+ verticalAlign: legendConfig.position ?? "bottom",
1288
+ align: legendConfig.align ?? "center",
1289
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
1290
+ }
1291
+ )
1292
+ ] })
1293
+ }
1294
+ );
1295
+ }
1296
+ );
1297
+ PieChart.displayName = "PieChart";
1298
+ var DonutChart = React17__namespace.forwardRef(
1299
+ ({
1300
+ data,
1301
+ innerRadius = "60%",
1302
+ outerRadius = "80%",
1303
+ paddingAngle = 2,
1304
+ legend = false,
1305
+ tooltip = true,
1306
+ centerLabel,
1307
+ centerValue,
1308
+ animate = true,
1309
+ live = false,
1310
+ className,
1311
+ height = "100%",
1312
+ margin = { top: 8, right: 8, left: 8, bottom: 8 },
1313
+ loading
1314
+ }, ref) => {
1315
+ const legendConfig = resolveLegendConfig(legend);
1316
+ const tooltipProps = resolveTooltipProps(tooltip);
1317
+ const isAnimated = live ? false : animate;
1318
+ return /* @__PURE__ */ jsxRuntime.jsx(
1319
+ ChartContainer,
1320
+ {
1321
+ ref,
1322
+ className,
1323
+ height,
1324
+ loading,
1325
+ empty: !data?.length,
1326
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { margin, children: [
1327
+ /* @__PURE__ */ jsxRuntime.jsx(
1328
+ recharts.Pie,
1329
+ {
1330
+ data,
1331
+ dataKey: "value",
1332
+ nameKey: "name",
1333
+ cx: "50%",
1334
+ cy: "50%",
1335
+ innerRadius,
1336
+ outerRadius,
1337
+ paddingAngle,
1338
+ startAngle: 90,
1339
+ endAngle: -270,
1340
+ isAnimationActive: isAnimated,
1341
+ animationDuration: isAnimated ? 400 : 0,
1342
+ stroke: "hsl(var(--card))",
1343
+ strokeWidth: 2,
1344
+ children: data.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(
1345
+ recharts.Cell,
1346
+ {
1347
+ fill: getChartColor(index, entry.color)
1348
+ },
1349
+ entry.name
1350
+ ))
1351
+ }
1352
+ ),
1353
+ (centerLabel || centerValue) && /* @__PURE__ */ jsxRuntime.jsxs(
1354
+ "text",
1355
+ {
1356
+ x: "50%",
1357
+ y: "50%",
1358
+ textAnchor: "middle",
1359
+ dominantBaseline: "central",
1360
+ children: [
1361
+ centerValue && /* @__PURE__ */ jsxRuntime.jsx(
1362
+ "tspan",
1363
+ {
1364
+ x: "50%",
1365
+ dy: centerLabel ? "-0.5em" : "0",
1366
+ fontSize: 20,
1367
+ fontWeight: 700,
1368
+ fill: "hsl(var(--foreground))",
1369
+ children: centerValue
1370
+ }
1371
+ ),
1372
+ centerLabel && /* @__PURE__ */ jsxRuntime.jsx(
1373
+ "tspan",
1374
+ {
1375
+ x: "50%",
1376
+ dy: centerValue ? "1.4em" : "0",
1377
+ fontSize: 11,
1378
+ fill: "hsl(var(--muted-foreground))",
1379
+ children: centerLabel
1380
+ }
1381
+ )
1382
+ ]
1383
+ }
1384
+ ),
1385
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
1386
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
1387
+ recharts.Legend,
1388
+ {
1389
+ verticalAlign: legendConfig.position ?? "bottom",
1390
+ align: legendConfig.align ?? "center",
1391
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
1392
+ }
1393
+ )
1394
+ ] })
1395
+ }
1396
+ );
1397
+ }
1398
+ );
1399
+ DonutChart.displayName = "DonutChart";
1400
+ var RadarChart = React17__namespace.forwardRef(
1401
+ ({
1402
+ data,
1403
+ series,
1404
+ categoryKey,
1405
+ domain,
1406
+ legend = false,
1407
+ tooltip = true,
1408
+ animate = true,
1409
+ live = false,
1410
+ className,
1411
+ height = "100%",
1412
+ margin = { top: 8, right: 8, left: 8, bottom: 8 },
1413
+ loading
1414
+ }, ref) => {
1415
+ const legendConfig = resolveLegendConfig(legend);
1416
+ const tooltipProps = resolveTooltipProps(tooltip);
1417
+ const isAnimated = live ? false : animate;
1418
+ return /* @__PURE__ */ jsxRuntime.jsx(
1419
+ ChartContainer,
1420
+ {
1421
+ ref,
1422
+ className,
1423
+ height,
1424
+ loading,
1425
+ empty: !data?.length,
1426
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.RadarChart, { data, margin, cx: "50%", cy: "50%", children: [
1427
+ /* @__PURE__ */ jsxRuntime.jsx(recharts.PolarGrid, { stroke: "hsl(var(--divider))" }),
1428
+ /* @__PURE__ */ jsxRuntime.jsx(
1429
+ recharts.PolarAngleAxis,
1430
+ {
1431
+ dataKey: categoryKey,
1432
+ tick: { fontSize: 10, fill: "hsl(var(--muted-foreground))" }
1433
+ }
1434
+ ),
1435
+ /* @__PURE__ */ jsxRuntime.jsx(
1436
+ recharts.PolarRadiusAxis,
1437
+ {
1438
+ domain,
1439
+ tick: { fontSize: 9, fill: "hsl(var(--muted-foreground))" },
1440
+ axisLine: false
1441
+ }
1442
+ ),
1443
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
1444
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
1445
+ recharts.Legend,
1446
+ {
1447
+ verticalAlign: legendConfig.position ?? "bottom",
1448
+ align: legendConfig.align ?? "center",
1449
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
1450
+ }
1451
+ ),
1452
+ series.map((s, index) => {
1453
+ const color = getChartColor(index, s.color);
1454
+ return /* @__PURE__ */ jsxRuntime.jsx(
1455
+ recharts.Radar,
1456
+ {
1457
+ name: s.name,
1458
+ dataKey: s.dataKey,
1459
+ stroke: color,
1460
+ strokeWidth: s.strokeWidth ?? 2,
1461
+ strokeDasharray: s.strokeDasharray,
1462
+ fill: color,
1463
+ fillOpacity: s.fillOpacity ?? 0.15,
1464
+ isAnimationActive: isAnimated,
1465
+ animationDuration: isAnimated ? 400 : 0
1466
+ },
1467
+ s.dataKey
1468
+ );
1469
+ })
1470
+ ] })
1471
+ }
1472
+ );
1473
+ }
1474
+ );
1475
+ RadarChart.displayName = "RadarChart";
1476
+ var RadialBarChart = React17__namespace.forwardRef(
1477
+ ({
1478
+ data,
1479
+ innerRadius = "30%",
1480
+ outerRadius = "90%",
1481
+ startAngle = 180,
1482
+ endAngle = 0,
1483
+ legend = false,
1484
+ tooltip = true,
1485
+ showLabels = true,
1486
+ animate = true,
1487
+ live = false,
1488
+ className,
1489
+ height = "100%",
1490
+ margin = { top: 8, right: 8, left: 8, bottom: 8 },
1491
+ loading
1492
+ }, ref) => {
1493
+ const legendConfig = resolveLegendConfig(legend);
1494
+ const tooltipProps = resolveTooltipProps(tooltip);
1495
+ const isAnimated = live ? false : animate;
1496
+ const coloredData = React17__namespace.useMemo(
1497
+ () => data.map((d, i) => ({
1498
+ ...d,
1499
+ fill: d.fill ?? getChartColor(i)
1500
+ })),
1501
+ [data]
1502
+ );
1503
+ return /* @__PURE__ */ jsxRuntime.jsx(
1504
+ ChartContainer,
1505
+ {
1506
+ ref,
1507
+ className,
1508
+ height,
1509
+ loading,
1510
+ empty: !data?.length,
1511
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1512
+ recharts.RadialBarChart,
1513
+ {
1514
+ data: coloredData,
1515
+ innerRadius,
1516
+ outerRadius,
1517
+ startAngle,
1518
+ endAngle,
1519
+ margin,
1520
+ cx: "50%",
1521
+ cy: "50%",
1522
+ children: [
1523
+ /* @__PURE__ */ jsxRuntime.jsx(
1524
+ recharts.RadialBar,
1525
+ {
1526
+ dataKey: "value",
1527
+ background: { fill: "hsl(var(--muted))" },
1528
+ isAnimationActive: isAnimated,
1529
+ animationDuration: isAnimated ? 400 : 0,
1530
+ label: showLabels ? {
1531
+ position: "insideStart",
1532
+ fill: "hsl(var(--foreground))",
1533
+ fontSize: 10,
1534
+ fontWeight: 600
1535
+ } : false
1536
+ }
1537
+ ),
1538
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps }),
1539
+ legendConfig && /* @__PURE__ */ jsxRuntime.jsx(
1540
+ recharts.Legend,
1541
+ {
1542
+ verticalAlign: legendConfig.position ?? "bottom",
1543
+ align: legendConfig.align ?? "center",
1544
+ content: /* @__PURE__ */ jsxRuntime.jsx(ChartLegendContent, {})
1545
+ }
1546
+ )
1547
+ ]
1548
+ }
1549
+ )
1550
+ }
1551
+ );
1552
+ }
1553
+ );
1554
+ RadialBarChart.displayName = "RadialBarChart";
1555
+ function SankeyNodeRenderer({
1556
+ x,
1557
+ y,
1558
+ width,
1559
+ height,
1560
+ index,
1561
+ payload
1562
+ }) {
1563
+ const fill = payload.color ?? getChartColor(index);
1564
+ return /* @__PURE__ */ jsxRuntime.jsxs(recharts.Layer, { children: [
1565
+ /* @__PURE__ */ jsxRuntime.jsx(
1566
+ recharts.Rectangle,
1567
+ {
1568
+ x,
1569
+ y,
1570
+ width,
1571
+ height,
1572
+ fill,
1573
+ fillOpacity: 0.9
1574
+ }
1575
+ ),
1576
+ /* @__PURE__ */ jsxRuntime.jsx(
1577
+ "text",
1578
+ {
1579
+ x: x + width + 6,
1580
+ y: y + height / 2,
1581
+ textAnchor: "start",
1582
+ dominantBaseline: "central",
1583
+ fontSize: 10,
1584
+ fill: "hsl(var(--foreground))",
1585
+ children: payload.name
1586
+ }
1587
+ )
1588
+ ] }, `node-${index}`);
1589
+ }
1590
+ function SankeyLinkRenderer({
1591
+ sourceX,
1592
+ sourceY,
1593
+ sourceControlX,
1594
+ targetX,
1595
+ targetY,
1596
+ targetControlX,
1597
+ linkWidth,
1598
+ index,
1599
+ payload
1600
+ }) {
1601
+ const sourceColor = payload.source.color ?? getChartColor(index);
1602
+ return /* @__PURE__ */ jsxRuntime.jsx(recharts.Layer, { children: /* @__PURE__ */ jsxRuntime.jsx(
1603
+ "path",
1604
+ {
1605
+ d: `
1606
+ M${sourceX},${sourceY}
1607
+ C${sourceControlX},${sourceY} ${targetControlX},${targetY} ${targetX},${targetY}
1608
+ `,
1609
+ fill: "none",
1610
+ stroke: sourceColor,
1611
+ strokeWidth: linkWidth,
1612
+ strokeOpacity: 0.3
1613
+ }
1614
+ ) }, `link-${index}`);
1615
+ }
1616
+ var SankeyChart = React17__namespace.forwardRef(
1617
+ ({
1618
+ data,
1619
+ nodeWidth = 10,
1620
+ nodePadding = 20,
1621
+ tooltip = true,
1622
+ className,
1623
+ height = "100%",
1624
+ margin = { top: 8, right: 80, left: 8, bottom: 8 },
1625
+ loading
1626
+ }, ref) => {
1627
+ const tooltipProps = resolveTooltipProps(tooltip);
1628
+ return /* @__PURE__ */ jsxRuntime.jsx(
1629
+ ChartContainer,
1630
+ {
1631
+ ref,
1632
+ className,
1633
+ height,
1634
+ loading,
1635
+ empty: !data?.nodes?.length,
1636
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1637
+ recharts.Sankey,
1638
+ {
1639
+ data,
1640
+ nodeWidth,
1641
+ nodePadding,
1642
+ margin,
1643
+ node: SankeyNodeRenderer,
1644
+ link: SankeyLinkRenderer,
1645
+ children: tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps })
1646
+ }
1647
+ )
1648
+ }
1649
+ );
1650
+ }
1651
+ );
1652
+ SankeyChart.displayName = "SankeyChart";
1653
+ function TreemapContent({
1654
+ x,
1655
+ y,
1656
+ width,
1657
+ height,
1658
+ index,
1659
+ name,
1660
+ depth,
1661
+ color
1662
+ }) {
1663
+ const fill = color ?? getChartColor(index);
1664
+ const showLabel = width > 40 && height > 20;
1665
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
1666
+ /* @__PURE__ */ jsxRuntime.jsx(
1667
+ "rect",
1668
+ {
1669
+ x,
1670
+ y,
1671
+ width,
1672
+ height,
1673
+ fill,
1674
+ fillOpacity: depth === 1 ? 0.85 : 0.6,
1675
+ stroke: "hsl(var(--card))",
1676
+ strokeWidth: 2,
1677
+ rx: 2
1678
+ }
1679
+ ),
1680
+ showLabel && /* @__PURE__ */ jsxRuntime.jsx(
1681
+ "text",
1682
+ {
1683
+ x: x + width / 2,
1684
+ y: y + height / 2,
1685
+ textAnchor: "middle",
1686
+ dominantBaseline: "central",
1687
+ fontSize: Math.min(11, width / 6),
1688
+ fill: "hsl(var(--card-foreground))",
1689
+ fontWeight: 500,
1690
+ style: { pointerEvents: "none" },
1691
+ children: name.length > width / 7 ? `${name.slice(0, Math.floor(width / 7))}\u2026` : name
1692
+ }
1693
+ )
1694
+ ] });
1695
+ }
1696
+ var TreemapChart = React17__namespace.forwardRef(
1697
+ ({
1698
+ data,
1699
+ dataKey = "value",
1700
+ aspectRatio = 4 / 3,
1701
+ tooltip = true,
1702
+ animate = true,
1703
+ live = false,
1704
+ className,
1705
+ height = "100%",
1706
+ margin,
1707
+ loading
1708
+ }, ref) => {
1709
+ const tooltipProps = resolveTooltipProps(tooltip);
1710
+ const isAnimated = live ? false : animate;
1711
+ return /* @__PURE__ */ jsxRuntime.jsx(
1712
+ ChartContainer,
1713
+ {
1714
+ ref,
1715
+ className,
1716
+ height,
1717
+ loading,
1718
+ empty: !data?.length,
1719
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1720
+ recharts.Treemap,
1721
+ {
1722
+ data,
1723
+ dataKey,
1724
+ aspectRatio,
1725
+ isAnimationActive: isAnimated,
1726
+ animationDuration: isAnimated ? 400 : 0,
1727
+ content: /* @__PURE__ */ jsxRuntime.jsx(TreemapContent, { x: 0, y: 0, width: 0, height: 0, index: 0, name: "", depth: 1 }),
1728
+ children: tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps })
1729
+ }
1730
+ )
1731
+ }
1732
+ );
1733
+ }
1734
+ );
1735
+ TreemapChart.displayName = "TreemapChart";
1736
+ var FunnelChart = React17__namespace.forwardRef(
1737
+ ({
1738
+ data,
1739
+ tooltip = true,
1740
+ showLabels = true,
1741
+ animate = true,
1742
+ live = false,
1743
+ className,
1744
+ height = "100%",
1745
+ margin = { top: 8, right: 8, left: 8, bottom: 8 },
1746
+ loading
1747
+ }, ref) => {
1748
+ const tooltipProps = resolveTooltipProps(tooltip);
1749
+ const isAnimated = live ? false : animate;
1750
+ return /* @__PURE__ */ jsxRuntime.jsx(
1751
+ ChartContainer,
1752
+ {
1753
+ ref,
1754
+ className,
1755
+ height,
1756
+ loading,
1757
+ empty: !data?.length,
1758
+ children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.FunnelChart, { margin, children: [
1759
+ /* @__PURE__ */ jsxRuntime.jsxs(
1760
+ recharts.Funnel,
1761
+ {
1762
+ dataKey: "value",
1763
+ data,
1764
+ isAnimationActive: isAnimated,
1765
+ animationDuration: isAnimated ? 400 : 0,
1766
+ children: [
1767
+ data.map((entry, index) => /* @__PURE__ */ jsxRuntime.jsx(
1768
+ recharts.Cell,
1769
+ {
1770
+ fill: getChartColor(index, entry.color),
1771
+ stroke: "hsl(var(--card))",
1772
+ strokeWidth: 2
1773
+ },
1774
+ entry.name
1775
+ )),
1776
+ showLabels && /* @__PURE__ */ jsxRuntime.jsx(
1777
+ recharts.LabelList,
1778
+ {
1779
+ dataKey: "name",
1780
+ position: "center",
1781
+ fill: "#ffffff",
1782
+ fontSize: 13,
1783
+ fontWeight: 600,
1784
+ style: {
1785
+ textShadow: "0 1px 3px rgba(0,0,0,0.4)",
1786
+ paintOrder: "stroke",
1787
+ stroke: "rgba(0,0,0,0.2)",
1788
+ strokeWidth: 2,
1789
+ strokeLinejoin: "round"
1790
+ }
1791
+ }
1792
+ )
1793
+ ]
1794
+ }
1795
+ ),
1796
+ tooltipProps && /* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { ...tooltipProps })
1797
+ ] })
1798
+ }
1799
+ );
1800
+ }
1801
+ );
1802
+ FunnelChart.displayName = "FunnelChart";
1803
+ var ROW_HEIGHT_DEFAULT = 36;
1804
+ var LABEL_WIDTH_DEFAULT = 160;
1805
+ var HEADER_HEIGHT = 32;
1806
+ function getTimeBounds(tasks, milestones) {
1807
+ let min = Infinity;
1808
+ let max = -Infinity;
1809
+ for (const t of tasks) {
1810
+ if (t.start.getTime() < min) min = t.start.getTime();
1811
+ if (t.end.getTime() > max) max = t.end.getTime();
1812
+ }
1813
+ for (const m of milestones) {
1814
+ if (m.date.getTime() < min) min = m.date.getTime();
1815
+ if (m.date.getTime() > max) max = m.date.getTime();
1816
+ }
1817
+ const pad = (max - min) * 0.05 || 864e5;
1818
+ return { min: min - pad, max: max + pad, span: max - min + 2 * pad };
1819
+ }
1820
+ function generateTicks(min, max, scale) {
1821
+ const ticks = [];
1822
+ const d = new Date(min);
1823
+ if (scale === "day") {
1824
+ d.setHours(0, 0, 0, 0);
1825
+ while (d.getTime() <= max) {
1826
+ ticks.push({
1827
+ pos: d.getTime(),
1828
+ label: d.toLocaleDateString(void 0, { month: "short", day: "numeric" })
1829
+ });
1830
+ d.setDate(d.getDate() + 1);
1831
+ }
1832
+ } else if (scale === "week") {
1833
+ d.setHours(0, 0, 0, 0);
1834
+ d.setDate(d.getDate() - d.getDay());
1835
+ while (d.getTime() <= max) {
1836
+ ticks.push({
1837
+ pos: d.getTime(),
1838
+ label: d.toLocaleDateString(void 0, { month: "short", day: "numeric" })
1839
+ });
1840
+ d.setDate(d.getDate() + 7);
1841
+ }
1842
+ } else {
1843
+ d.setDate(1);
1844
+ d.setHours(0, 0, 0, 0);
1845
+ while (d.getTime() <= max) {
1846
+ ticks.push({
1847
+ pos: d.getTime(),
1848
+ label: d.toLocaleDateString(void 0, { month: "short", year: "2-digit" })
1849
+ });
1850
+ d.setMonth(d.getMonth() + 1);
1851
+ }
1852
+ }
1853
+ return ticks;
1854
+ }
1855
+ var GanttChart = React17__namespace.forwardRef(
1856
+ function GanttChart2({
1857
+ tasks,
1858
+ milestones = [],
1859
+ timeScale = "day",
1860
+ className,
1861
+ height = 400,
1862
+ rowHeight = ROW_HEIGHT_DEFAULT,
1863
+ labelWidth = LABEL_WIDTH_DEFAULT,
1864
+ onTaskClick
1865
+ }, ref) {
1866
+ const containerRef = React17__namespace.useRef(null);
1867
+ const [hoveredId, setHoveredId] = React17__namespace.useState(null);
1868
+ const [tooltipInfo, setTooltipInfo] = React17__namespace.useState(null);
1869
+ const groups = React17__namespace.useMemo(() => {
1870
+ const map = /* @__PURE__ */ new Map();
1871
+ for (const t of tasks) {
1872
+ const g = t.group ?? "";
1873
+ if (!map.has(g)) map.set(g, []);
1874
+ map.get(g).push(t);
1875
+ }
1876
+ return map;
1877
+ }, [tasks]);
1878
+ const orderedTasks = React17__namespace.useMemo(() => {
1879
+ const result = [];
1880
+ for (const group of groups.values()) {
1881
+ result.push(...group.sort((a, b) => a.start.getTime() - b.start.getTime()));
1882
+ }
1883
+ return result;
1884
+ }, [groups]);
1885
+ const taskIndex = React17__namespace.useMemo(() => {
1886
+ const m = /* @__PURE__ */ new Map();
1887
+ orderedTasks.forEach((t, i) => m.set(t.id, i));
1888
+ return m;
1889
+ }, [orderedTasks]);
1890
+ const bounds = React17__namespace.useMemo(
1891
+ () => getTimeBounds(tasks, milestones),
1892
+ [tasks, milestones]
1893
+ );
1894
+ const ticks = React17__namespace.useMemo(
1895
+ () => generateTicks(bounds.min, bounds.max, timeScale),
1896
+ [bounds, timeScale]
1897
+ );
1898
+ const chartHeight = typeof height === "number" ? height : void 0;
1899
+ const svgHeight = HEADER_HEIGHT + orderedTasks.length * rowHeight + 8;
1900
+ function xOf(time, chartWidth) {
1901
+ return (time - bounds.min) / bounds.span * chartWidth;
1902
+ }
1903
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1904
+ "div",
1905
+ {
1906
+ ref: (node) => {
1907
+ containerRef.current = node;
1908
+ if (typeof ref === "function") ref(node);
1909
+ else if (ref) ref.current = node;
1910
+ },
1911
+ className: core.cn("w-full overflow-auto relative", className),
1912
+ style: { height },
1913
+ children: [
1914
+ /* @__PURE__ */ jsxRuntime.jsxs(
1915
+ "svg",
1916
+ {
1917
+ width: "100%",
1918
+ height: Math.max(svgHeight, chartHeight ?? svgHeight),
1919
+ style: { minWidth: labelWidth + 400 },
1920
+ children: [
1921
+ /* @__PURE__ */ jsxRuntime.jsx(
1922
+ "rect",
1923
+ {
1924
+ x: 0,
1925
+ y: 0,
1926
+ width: labelWidth,
1927
+ height: svgHeight,
1928
+ fill: "hsl(var(--card))"
1929
+ }
1930
+ ),
1931
+ /* @__PURE__ */ jsxRuntime.jsx(
1932
+ "line",
1933
+ {
1934
+ x1: labelWidth,
1935
+ y1: 0,
1936
+ x2: labelWidth,
1937
+ y2: svgHeight,
1938
+ stroke: "hsl(var(--border))"
1939
+ }
1940
+ ),
1941
+ /* @__PURE__ */ jsxRuntime.jsx("g", { children: ticks.map((tick, i) => {
1942
+ const x = labelWidth + xOf(tick.pos, 1e3);
1943
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
1944
+ /* @__PURE__ */ jsxRuntime.jsx(
1945
+ "line",
1946
+ {
1947
+ x1: x,
1948
+ y1: HEADER_HEIGHT,
1949
+ x2: x,
1950
+ y2: svgHeight,
1951
+ stroke: "hsl(var(--divider))",
1952
+ strokeDasharray: "2 4"
1953
+ }
1954
+ ),
1955
+ /* @__PURE__ */ jsxRuntime.jsx(
1956
+ "text",
1957
+ {
1958
+ x: x + 4,
1959
+ y: HEADER_HEIGHT - 10,
1960
+ fontSize: 9,
1961
+ fill: "hsl(var(--muted-foreground))",
1962
+ children: tick.label
1963
+ }
1964
+ )
1965
+ ] }, i);
1966
+ }) }),
1967
+ orderedTasks.map((task, i) => {
1968
+ const y = HEADER_HEIGHT + i * rowHeight;
1969
+ const barX = labelWidth + xOf(task.start.getTime(), 1e3);
1970
+ const barW = xOf(task.end.getTime(), 1e3) - xOf(task.start.getTime(), 1e3);
1971
+ const barH = rowHeight * 0.55;
1972
+ const barY = y + (rowHeight - barH) / 2;
1973
+ const color = task.color ?? getChartColor(i);
1974
+ const isHovered = hoveredId === task.id;
1975
+ const progress = task.progress ?? 0;
1976
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1977
+ "g",
1978
+ {
1979
+ onMouseEnter: (e) => {
1980
+ setHoveredId(task.id);
1981
+ const rect = containerRef.current?.getBoundingClientRect();
1982
+ setTooltipInfo({
1983
+ task,
1984
+ x: e.clientX - (rect?.left ?? 0) + (containerRef.current?.scrollLeft ?? 0),
1985
+ y: e.clientY - (rect?.top ?? 0) + (containerRef.current?.scrollTop ?? 0)
1986
+ });
1987
+ },
1988
+ onMouseLeave: () => {
1989
+ setHoveredId(null);
1990
+ setTooltipInfo(null);
1991
+ },
1992
+ onClick: () => onTaskClick?.(task),
1993
+ style: { cursor: onTaskClick ? "pointer" : "default" },
1994
+ children: [
1995
+ i % 2 === 0 && /* @__PURE__ */ jsxRuntime.jsx(
1996
+ "rect",
1997
+ {
1998
+ x: 0,
1999
+ y,
2000
+ width: "100%",
2001
+ height: rowHeight,
2002
+ fill: "hsl(var(--muted))",
2003
+ fillOpacity: 0.3
2004
+ }
2005
+ ),
2006
+ /* @__PURE__ */ jsxRuntime.jsx(
2007
+ "text",
2008
+ {
2009
+ x: 12,
2010
+ y: y + rowHeight / 2,
2011
+ dominantBaseline: "central",
2012
+ fontSize: 11,
2013
+ fill: "hsl(var(--foreground))",
2014
+ fontWeight: isHovered ? 600 : 400,
2015
+ children: task.name.length > labelWidth / 8 ? `${task.name.slice(0, Math.floor(labelWidth / 8))}\u2026` : task.name
2016
+ }
2017
+ ),
2018
+ /* @__PURE__ */ jsxRuntime.jsx(
2019
+ "rect",
2020
+ {
2021
+ x: barX,
2022
+ y: barY,
2023
+ width: Math.max(barW, 2),
2024
+ height: barH,
2025
+ rx: 3,
2026
+ fill: color,
2027
+ fillOpacity: 0.25,
2028
+ stroke: isHovered ? color : "none",
2029
+ strokeWidth: isHovered ? 1.5 : 0
2030
+ }
2031
+ ),
2032
+ progress > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2033
+ "rect",
2034
+ {
2035
+ x: barX,
2036
+ y: barY,
2037
+ width: Math.max(barW * progress / 100, 2),
2038
+ height: barH,
2039
+ rx: 3,
2040
+ fill: color,
2041
+ fillOpacity: 0.85
2042
+ }
2043
+ )
2044
+ ]
2045
+ },
2046
+ task.id
2047
+ );
2048
+ }),
2049
+ orderedTasks.map(
2050
+ (task) => (task.dependencies ?? []).map((depId) => {
2051
+ const fromIdx = taskIndex.get(depId);
2052
+ if (fromIdx === void 0) return null;
2053
+ const toIdx = taskIndex.get(task.id);
2054
+ const fromTask = orderedTasks[fromIdx];
2055
+ const fromEndX = labelWidth + xOf(fromTask.end.getTime(), 1e3);
2056
+ const fromY = HEADER_HEIGHT + fromIdx * rowHeight + rowHeight / 2;
2057
+ const toStartX = labelWidth + xOf(task.start.getTime(), 1e3);
2058
+ const toY = HEADER_HEIGHT + toIdx * rowHeight + rowHeight / 2;
2059
+ const midX = (fromEndX + toStartX) / 2;
2060
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx(
2061
+ "path",
2062
+ {
2063
+ d: `M${fromEndX},${fromY} C${midX},${fromY} ${midX},${toY} ${toStartX},${toY}`,
2064
+ fill: "none",
2065
+ stroke: "hsl(var(--muted-foreground))",
2066
+ strokeWidth: 1,
2067
+ strokeDasharray: "3 2",
2068
+ markerEnd: "url(#arrow)"
2069
+ }
2070
+ ) }, `${depId}-${task.id}`);
2071
+ })
2072
+ ),
2073
+ milestones.map((m, i) => {
2074
+ const x = labelWidth + xOf(m.date.getTime(), 1e3);
2075
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
2076
+ /* @__PURE__ */ jsxRuntime.jsx(
2077
+ "line",
2078
+ {
2079
+ x1: x,
2080
+ y1: HEADER_HEIGHT,
2081
+ x2: x,
2082
+ y2: svgHeight,
2083
+ stroke: m.color ?? "hsl(var(--warning))",
2084
+ strokeWidth: 1.5,
2085
+ strokeDasharray: "4 3"
2086
+ }
2087
+ ),
2088
+ /* @__PURE__ */ jsxRuntime.jsx(
2089
+ "polygon",
2090
+ {
2091
+ points: `${x},${HEADER_HEIGHT - 2} ${x + 5},${HEADER_HEIGHT + 6} ${x},${HEADER_HEIGHT + 14} ${x - 5},${HEADER_HEIGHT + 6}`,
2092
+ fill: m.color ?? "hsl(var(--warning))"
2093
+ }
2094
+ )
2095
+ ] }, m.id);
2096
+ }),
2097
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx(
2098
+ "marker",
2099
+ {
2100
+ id: "arrow",
2101
+ viewBox: "0 0 6 6",
2102
+ refX: 6,
2103
+ refY: 3,
2104
+ markerWidth: 6,
2105
+ markerHeight: 6,
2106
+ orient: "auto-start-reverse",
2107
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2108
+ "path",
2109
+ {
2110
+ d: "M 0 0 L 6 3 L 0 6 z",
2111
+ fill: "hsl(var(--muted-foreground))"
2112
+ }
2113
+ )
2114
+ }
2115
+ ) })
2116
+ ]
2117
+ }
2118
+ ),
2119
+ tooltipInfo && /* @__PURE__ */ jsxRuntime.jsxs(
2120
+ "div",
2121
+ {
2122
+ style: {
2123
+ position: "absolute",
2124
+ left: tooltipInfo.x + 12,
2125
+ top: tooltipInfo.y - 10,
2126
+ background: "hsl(var(--card))",
2127
+ border: "1px solid hsl(var(--border))",
2128
+ borderRadius: 6,
2129
+ padding: "6px 10px",
2130
+ fontSize: 11,
2131
+ lineHeight: 1.5,
2132
+ boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
2133
+ pointerEvents: "none",
2134
+ zIndex: 50,
2135
+ maxWidth: 220
2136
+ },
2137
+ children: [
2138
+ /* @__PURE__ */ jsxRuntime.jsx(
2139
+ "div",
2140
+ {
2141
+ style: {
2142
+ fontWeight: 600,
2143
+ color: "hsl(var(--foreground))",
2144
+ marginBottom: 2
2145
+ },
2146
+ children: tooltipInfo.task.name
2147
+ }
2148
+ ),
2149
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "hsl(var(--muted-foreground))" }, children: [
2150
+ tooltipInfo.task.start.toLocaleDateString(),
2151
+ " \u2013",
2152
+ " ",
2153
+ tooltipInfo.task.end.toLocaleDateString()
2154
+ ] }),
2155
+ tooltipInfo.task.progress != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "hsl(var(--muted-foreground))" }, children: [
2156
+ "Progress: ",
2157
+ tooltipInfo.task.progress,
2158
+ "%"
2159
+ ] })
2160
+ ]
2161
+ }
2162
+ )
2163
+ ]
2164
+ }
2165
+ );
2166
+ }
2167
+ );
2168
+ GanttChart.displayName = "GanttChart";
2169
+ var DEFAULT_SCALE = {
2170
+ min: "hsl(var(--chart-9))",
2171
+ mid: "hsl(var(--chart-4))",
2172
+ max: "hsl(var(--chart-7))"
2173
+ };
2174
+ function interpolateColor(t, scale) {
2175
+ if (!scale.mid) {
2176
+ return `color-mix(in srgb, ${scale.min} ${(1 - t) * 100}%, ${scale.max})`;
2177
+ }
2178
+ if (t <= 0.5) {
2179
+ const t22 = t * 2;
2180
+ return `color-mix(in srgb, ${scale.min} ${(1 - t22) * 100}%, ${scale.mid})`;
2181
+ }
2182
+ const t2 = (t - 0.5) * 2;
2183
+ return `color-mix(in srgb, ${scale.mid} ${(1 - t2) * 100}%, ${scale.max})`;
2184
+ }
2185
+ var HeatmapChart = React17__namespace.forwardRef(
2186
+ function HeatmapChart2({
2187
+ data,
2188
+ xLabels,
2189
+ yLabels,
2190
+ colorScale = DEFAULT_SCALE,
2191
+ cellSize = 40,
2192
+ showValues = true,
2193
+ valueFormatter,
2194
+ className,
2195
+ height,
2196
+ loading,
2197
+ onCellClick
2198
+ }, ref) {
2199
+ const containerRef = React17__namespace.useRef(null);
2200
+ const [hoveredCell, setHoveredCell] = React17__namespace.useState(null);
2201
+ const [tooltipPos, setTooltipPos] = React17__namespace.useState({ x: 0, y: 0 });
2202
+ const { valueMap, minVal, maxVal } = React17__namespace.useMemo(() => {
2203
+ const map = /* @__PURE__ */ new Map();
2204
+ let lo = Infinity;
2205
+ let hi = -Infinity;
2206
+ for (const cell of data) {
2207
+ map.set(`${cell.x}|${cell.y}`, cell.value);
2208
+ if (cell.value < lo) lo = cell.value;
2209
+ if (cell.value > hi) hi = cell.value;
2210
+ }
2211
+ return { valueMap: map, minVal: lo, maxVal: hi };
2212
+ }, [data]);
2213
+ const normalize = (v) => maxVal === minVal ? 0.5 : (v - minVal) / (maxVal - minVal);
2214
+ const labelColWidth = 80;
2215
+ const svgWidth = labelColWidth + xLabels.length * cellSize;
2216
+ const svgHeight = 28 + yLabels.length * cellSize;
2217
+ if (loading) {
2218
+ return /* @__PURE__ */ jsxRuntime.jsx(
2219
+ "div",
2220
+ {
2221
+ ref,
2222
+ className: core.cn("w-full flex items-center justify-center", className),
2223
+ style: { height: height ?? svgHeight },
2224
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2225
+ "div",
2226
+ {
2227
+ className: "animate-pulse",
2228
+ style: {
2229
+ width: "80%",
2230
+ height: "60%",
2231
+ borderRadius: 6,
2232
+ background: "hsl(var(--muted))"
2233
+ }
2234
+ }
2235
+ )
2236
+ }
2237
+ );
2238
+ }
2239
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2240
+ "div",
2241
+ {
2242
+ ref: (node) => {
2243
+ containerRef.current = node;
2244
+ if (typeof ref === "function") ref(node);
2245
+ else if (ref) ref.current = node;
2246
+ },
2247
+ className: core.cn("w-full overflow-auto relative", className),
2248
+ style: { height },
2249
+ children: [
2250
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: svgWidth, height: svgHeight, children: [
2251
+ xLabels.map((label, i) => /* @__PURE__ */ jsxRuntime.jsx(
2252
+ "text",
2253
+ {
2254
+ x: labelColWidth + i * cellSize + cellSize / 2,
2255
+ y: 14,
2256
+ textAnchor: "middle",
2257
+ fontSize: 9,
2258
+ fill: "hsl(var(--muted-foreground))",
2259
+ children: label
2260
+ },
2261
+ `x-${i}`
2262
+ )),
2263
+ yLabels.map((yLabel, yi) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
2264
+ /* @__PURE__ */ jsxRuntime.jsx(
2265
+ "text",
2266
+ {
2267
+ x: labelColWidth - 8,
2268
+ y: 28 + yi * cellSize + cellSize / 2,
2269
+ textAnchor: "end",
2270
+ dominantBaseline: "central",
2271
+ fontSize: 9,
2272
+ fill: "hsl(var(--muted-foreground))",
2273
+ children: yLabel
2274
+ }
2275
+ ),
2276
+ xLabels.map((xLabel, xi) => {
2277
+ const key = `${xLabel}|${yLabel}`;
2278
+ const val = valueMap.get(key);
2279
+ const t = val != null ? normalize(val) : 0;
2280
+ const cx = labelColWidth + xi * cellSize;
2281
+ const cy = 28 + yi * cellSize;
2282
+ const cellData = { x: xLabel, y: yLabel, value: val ?? 0 };
2283
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2284
+ "g",
2285
+ {
2286
+ onMouseEnter: (e) => {
2287
+ setHoveredCell(cellData);
2288
+ const rect = containerRef.current?.getBoundingClientRect();
2289
+ setTooltipPos({
2290
+ x: e.clientX - (rect?.left ?? 0) + (containerRef.current?.scrollLeft ?? 0),
2291
+ y: e.clientY - (rect?.top ?? 0) + (containerRef.current?.scrollTop ?? 0)
2292
+ });
2293
+ },
2294
+ onMouseLeave: () => setHoveredCell(null),
2295
+ onClick: () => onCellClick?.(cellData),
2296
+ style: { cursor: onCellClick ? "pointer" : "default" },
2297
+ children: [
2298
+ /* @__PURE__ */ jsxRuntime.jsx(
2299
+ "rect",
2300
+ {
2301
+ x: cx + 1,
2302
+ y: cy + 1,
2303
+ width: cellSize - 2,
2304
+ height: cellSize - 2,
2305
+ rx: 3,
2306
+ fill: val != null ? interpolateColor(t, colorScale) : "hsl(var(--muted))",
2307
+ fillOpacity: val != null ? 0.85 : 0.3,
2308
+ stroke: hoveredCell?.x === xLabel && hoveredCell?.y === yLabel ? "hsl(var(--foreground))" : "none",
2309
+ strokeWidth: 1.5
2310
+ }
2311
+ ),
2312
+ showValues && val != null && cellSize >= 32 && /* @__PURE__ */ jsxRuntime.jsx(
2313
+ "text",
2314
+ {
2315
+ x: cx + cellSize / 2,
2316
+ y: cy + cellSize / 2,
2317
+ textAnchor: "middle",
2318
+ dominantBaseline: "central",
2319
+ fontSize: Math.min(10, cellSize / 4.5),
2320
+ fill: "hsl(var(--foreground))",
2321
+ fontWeight: 500,
2322
+ style: { pointerEvents: "none" },
2323
+ children: valueFormatter ? valueFormatter(val) : val.toLocaleString()
2324
+ }
2325
+ )
2326
+ ]
2327
+ },
2328
+ key
2329
+ );
2330
+ })
2331
+ ] }, `row-${yi}`))
2332
+ ] }),
2333
+ hoveredCell && /* @__PURE__ */ jsxRuntime.jsxs(
2334
+ "div",
2335
+ {
2336
+ style: {
2337
+ position: "absolute",
2338
+ left: tooltipPos.x + 12,
2339
+ top: tooltipPos.y - 10,
2340
+ background: "hsl(var(--card))",
2341
+ border: "1px solid hsl(var(--border))",
2342
+ borderRadius: 6,
2343
+ padding: "6px 10px",
2344
+ fontSize: 11,
2345
+ lineHeight: 1.5,
2346
+ boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
2347
+ pointerEvents: "none",
2348
+ zIndex: 50,
2349
+ maxWidth: 200
2350
+ },
2351
+ children: [
2352
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "hsl(var(--muted-foreground))" }, children: [
2353
+ String(hoveredCell.x),
2354
+ " / ",
2355
+ String(hoveredCell.y)
2356
+ ] }),
2357
+ /* @__PURE__ */ jsxRuntime.jsx(
2358
+ "div",
2359
+ {
2360
+ style: {
2361
+ fontWeight: 600,
2362
+ color: "hsl(var(--foreground))",
2363
+ fontVariantNumeric: "tabular-nums"
2364
+ },
2365
+ children: valueFormatter ? valueFormatter(hoveredCell.value) : hoveredCell.value.toLocaleString()
2366
+ }
2367
+ )
2368
+ ]
2369
+ }
2370
+ )
2371
+ ]
2372
+ }
2373
+ );
2374
+ }
2375
+ );
2376
+ HeatmapChart.displayName = "HeatmapChart";
2377
+ var Sparkline = React17__namespace.memo(function Sparkline2({
2378
+ data,
2379
+ variant = "line",
2380
+ color,
2381
+ width = "100%",
2382
+ height = 24,
2383
+ strokeWidth = 1.5,
2384
+ className
2385
+ }) {
2386
+ const chartColor = color ?? getChartColor(0);
2387
+ const points = React17__namespace.useMemo(
2388
+ () => data.map((v, i) => ({ i, v })),
2389
+ [data]
2390
+ );
2391
+ if (!points.length) return null;
2392
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { width, height }, children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: variant === "bar" ? /* @__PURE__ */ jsxRuntime.jsx(recharts.BarChart, { data: points, margin: { top: 0, right: 0, left: 0, bottom: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(recharts.Bar, { dataKey: "v", fill: chartColor, fillOpacity: 0.7, isAnimationActive: false }) }) : variant === "area" ? /* @__PURE__ */ jsxRuntime.jsxs(recharts.AreaChart, { data: points, margin: { top: 0, right: 0, left: 0, bottom: 0 }, children: [
2393
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: "sparkArea", x1: "0", y1: "0", x2: "0", y2: "1", children: [
2394
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "5%", stopColor: chartColor, stopOpacity: 0.3 }),
2395
+ /* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "95%", stopColor: chartColor, stopOpacity: 0.05 })
2396
+ ] }) }),
2397
+ /* @__PURE__ */ jsxRuntime.jsx(
2398
+ recharts.Area,
2399
+ {
2400
+ type: "monotone",
2401
+ dataKey: "v",
2402
+ stroke: chartColor,
2403
+ strokeWidth,
2404
+ fill: "url(#sparkArea)",
2405
+ isAnimationActive: false,
2406
+ dot: false
2407
+ }
2408
+ )
2409
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(recharts.LineChart, { data: points, margin: { top: 0, right: 0, left: 0, bottom: 0 }, children: /* @__PURE__ */ jsxRuntime.jsx(
2410
+ recharts.Line,
2411
+ {
2412
+ type: "monotone",
2413
+ dataKey: "v",
2414
+ stroke: chartColor,
2415
+ strokeWidth,
2416
+ dot: false,
2417
+ isAnimationActive: false
2418
+ }
2419
+ ) }) }) });
2420
+ });
2421
+ Sparkline.displayName = "Sparkline";
2422
+ var KPICard = React17__namespace.memo(function KPICard2({
2423
+ label,
2424
+ value,
2425
+ previousValue,
2426
+ changeLabel,
2427
+ sparklineData,
2428
+ sparklineVariant = "area",
2429
+ sparklineColor,
2430
+ icon,
2431
+ className
2432
+ }) {
2433
+ const currentNum = typeof value === "number" ? value : parseFloat(String(value));
2434
+ const hasDelta = previousValue != null && !isNaN(currentNum) && previousValue !== 0;
2435
+ const delta = hasDelta ? (currentNum - previousValue) / previousValue * 100 : null;
2436
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2437
+ "div",
2438
+ {
2439
+ className: core.cn(
2440
+ "rounded-lg border p-4 flex flex-col gap-2",
2441
+ className
2442
+ ),
2443
+ style: {
2444
+ background: "hsl(var(--card))",
2445
+ borderColor: "hsl(var(--border))"
2446
+ },
2447
+ children: [
2448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2449
+ /* @__PURE__ */ jsxRuntime.jsx(
2450
+ "span",
2451
+ {
2452
+ style: {
2453
+ fontSize: 12,
2454
+ color: "hsl(var(--muted-foreground))",
2455
+ fontWeight: 500
2456
+ },
2457
+ children: label
2458
+ }
2459
+ ),
2460
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "hsl(var(--muted-foreground))" }, children: icon })
2461
+ ] }),
2462
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end justify-between gap-3", children: [
2463
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
2464
+ /* @__PURE__ */ jsxRuntime.jsx(
2465
+ "span",
2466
+ {
2467
+ style: {
2468
+ fontSize: 22,
2469
+ fontWeight: 700,
2470
+ color: "hsl(var(--foreground))",
2471
+ lineHeight: 1,
2472
+ fontVariantNumeric: "tabular-nums"
2473
+ },
2474
+ children: value
2475
+ }
2476
+ ),
2477
+ delta != null && /* @__PURE__ */ jsxRuntime.jsxs(
2478
+ "span",
2479
+ {
2480
+ style: {
2481
+ fontSize: 11,
2482
+ fontWeight: 500,
2483
+ color: delta > 0 ? "hsl(var(--success))" : delta < 0 ? "hsl(var(--destructive))" : "hsl(var(--muted-foreground))",
2484
+ display: "flex",
2485
+ alignItems: "center",
2486
+ gap: 2
2487
+ },
2488
+ children: [
2489
+ delta >= 0 ? "\u25B2" : "\u25BC",
2490
+ " ",
2491
+ delta >= 0 ? "+" : "",
2492
+ delta.toFixed(1),
2493
+ "%",
2494
+ changeLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "hsl(var(--muted-foreground))", marginLeft: 4 }, children: changeLabel })
2495
+ ]
2496
+ }
2497
+ )
2498
+ ] }),
2499
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
2500
+ Sparkline,
2501
+ {
2502
+ data: sparklineData,
2503
+ variant: sparklineVariant,
2504
+ color: sparklineColor ?? (delta != null ? delta >= 0 ? "hsl(var(--success))" : "hsl(var(--destructive))" : void 0),
2505
+ width: 80,
2506
+ height: 32
2507
+ }
2508
+ )
2509
+ ] })
2510
+ ]
2511
+ }
2512
+ );
2513
+ });
2514
+ KPICard.displayName = "KPICard";
2515
+ function buildOverlayData(scenarios, categoryKey, metrics) {
2516
+ const merged = /* @__PURE__ */ new Map();
2517
+ for (const scenario of scenarios) {
2518
+ for (const row of scenario.data) {
2519
+ const key = String(row[categoryKey]);
2520
+ if (!merged.has(key)) merged.set(key, { [categoryKey]: row[categoryKey] });
2521
+ const target = merged.get(key);
2522
+ for (const m of metrics) {
2523
+ target[`${scenario.name}_${m}`] = row[m];
2524
+ }
2525
+ }
2526
+ }
2527
+ const data = Array.from(merged.values());
2528
+ const series = scenarios.flatMap(
2529
+ (s, si) => metrics.map((m) => ({
2530
+ dataKey: `${s.name}_${m}`,
2531
+ name: `${s.name} \u2013 ${m}`,
2532
+ color: s.color,
2533
+ strokeDasharray: si > 0 ? "5 3" : void 0
2534
+ }))
2535
+ );
2536
+ return { data, series };
2537
+ }
2538
+ function buildDeltaData(scenarios, baselineIndex, categoryKey, metrics) {
2539
+ const baseline = scenarios[baselineIndex];
2540
+ if (!baseline) return { data: [], series: [] };
2541
+ const baseMap = /* @__PURE__ */ new Map();
2542
+ for (const row of baseline.data) {
2543
+ baseMap.set(String(row[categoryKey]), row);
2544
+ }
2545
+ const comparisons = scenarios.filter((_, i) => i !== baselineIndex);
2546
+ const merged = /* @__PURE__ */ new Map();
2547
+ for (const scenario of comparisons) {
2548
+ for (const row of scenario.data) {
2549
+ const key = String(row[categoryKey]);
2550
+ if (!merged.has(key)) merged.set(key, { [categoryKey]: row[categoryKey] });
2551
+ const target = merged.get(key);
2552
+ const baseRow = baseMap.get(key);
2553
+ for (const m of metrics) {
2554
+ const base = Number(baseRow?.[m] ?? 0);
2555
+ const val = Number(row[m] ?? 0);
2556
+ target[`${scenario.name}_${m}`] = val - base;
2557
+ }
2558
+ }
2559
+ }
2560
+ const data = Array.from(merged.values());
2561
+ const series = comparisons.flatMap(
2562
+ (s) => metrics.map((m) => ({
2563
+ dataKey: `${s.name}_${m}`,
2564
+ name: `${s.name} \u0394 ${m}`
2565
+ }))
2566
+ );
2567
+ return { data, series };
2568
+ }
2569
+ function buildScorecardData(scenarios, metrics) {
2570
+ const data = metrics.map((m) => {
2571
+ const row = { metric: m };
2572
+ for (const s of scenarios) {
2573
+ const values = s.data.map((d) => Number(d[m] ?? 0));
2574
+ const avg = values.length ? values.reduce((a, b) => a + b, 0) / values.length : 0;
2575
+ row[s.name] = Math.round(avg * 10) / 10;
2576
+ }
2577
+ return row;
2578
+ });
2579
+ const series = scenarios.map((s, i) => ({
2580
+ dataKey: s.name,
2581
+ name: s.name,
2582
+ color: s.color,
2583
+ strokeDasharray: i > 0 ? "5 3" : void 0
2584
+ }));
2585
+ return { data, series };
2586
+ }
2587
+ var ScenarioComparison = React17__namespace.memo(function ScenarioComparison2({
2588
+ scenarios,
2589
+ metrics,
2590
+ categoryKey,
2591
+ mode = "overlay",
2592
+ baselineIndex = 0,
2593
+ tooltip = true,
2594
+ className,
2595
+ height = 350
2596
+ }) {
2597
+ if (!scenarios.length || !metrics.length) return null;
2598
+ if (mode === "side-by-side") {
2599
+ return /* @__PURE__ */ jsxRuntime.jsx(
2600
+ "div",
2601
+ {
2602
+ className: core.cn("grid gap-4", className),
2603
+ style: {
2604
+ gridTemplateColumns: `repeat(${scenarios.length}, 1fr)`
2605
+ },
2606
+ children: scenarios.map((scenario) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { height }, children: [
2607
+ /* @__PURE__ */ jsxRuntime.jsx(
2608
+ "div",
2609
+ {
2610
+ style: {
2611
+ fontSize: 12,
2612
+ fontWeight: 600,
2613
+ color: "hsl(var(--foreground))",
2614
+ marginBottom: 6
2615
+ },
2616
+ children: scenario.name
2617
+ }
2618
+ ),
2619
+ /* @__PURE__ */ jsxRuntime.jsx(
2620
+ LineChart,
2621
+ {
2622
+ data: scenario.data,
2623
+ series: metrics.map((m) => ({
2624
+ dataKey: m,
2625
+ name: m,
2626
+ color: scenario.color
2627
+ })),
2628
+ xAxis: { dataKey: categoryKey },
2629
+ tooltip,
2630
+ legend: metrics.length > 1,
2631
+ height: "calc(100% - 24px)"
2632
+ }
2633
+ )
2634
+ ] }, scenario.name))
2635
+ }
2636
+ );
2637
+ }
2638
+ if (mode === "overlay") {
2639
+ const { data, series } = buildOverlayData(scenarios, categoryKey, metrics);
2640
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { height }, children: /* @__PURE__ */ jsxRuntime.jsx(
2641
+ LineChart,
2642
+ {
2643
+ data,
2644
+ series,
2645
+ xAxis: { dataKey: categoryKey },
2646
+ tooltip,
2647
+ legend: true,
2648
+ height: "100%"
2649
+ }
2650
+ ) });
2651
+ }
2652
+ if (mode === "delta") {
2653
+ const { data, series } = buildDeltaData(
2654
+ scenarios,
2655
+ baselineIndex,
2656
+ categoryKey,
2657
+ metrics
2658
+ );
2659
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { height }, children: /* @__PURE__ */ jsxRuntime.jsx(
2660
+ BarChart,
2661
+ {
2662
+ data,
2663
+ series: series.map((s) => ({ ...s })),
2664
+ xAxis: { dataKey: categoryKey },
2665
+ tooltip,
2666
+ legend: true,
2667
+ height: "100%"
2668
+ }
2669
+ ) });
2670
+ }
2671
+ if (mode === "scorecard") {
2672
+ const { data, series } = buildScorecardData(scenarios, metrics);
2673
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { height }, children: /* @__PURE__ */ jsxRuntime.jsx(
2674
+ RadarChart,
2675
+ {
2676
+ data,
2677
+ series: series.map((s) => ({
2678
+ ...s,
2679
+ fillOpacity: 0.1
2680
+ })),
2681
+ categoryKey: "metric",
2682
+ tooltip,
2683
+ legend: true,
2684
+ height: "100%"
2685
+ }
2686
+ ) });
2687
+ }
2688
+ return null;
2689
+ });
2690
+ ScenarioComparison.displayName = "ScenarioComparison";
2691
+ function resolveLegendFromString(val) {
2692
+ if (!val || val === "none") return false;
2693
+ const parts = val.split("-");
2694
+ return {
2695
+ position: parts[0] ?? "top",
2696
+ align: parts[1] ?? "right"
2697
+ };
2698
+ }
2699
+ var ChartRenderer = React17__namespace.memo(function ChartRenderer2({
2700
+ config,
2701
+ data,
2702
+ height = "100%",
2703
+ className
2704
+ }) {
2705
+ if (!data?.length || !config.series.length) {
2706
+ return /* @__PURE__ */ jsxRuntime.jsx(
2707
+ "div",
2708
+ {
2709
+ className,
2710
+ style: {
2711
+ height,
2712
+ display: "flex",
2713
+ alignItems: "center",
2714
+ justifyContent: "center",
2715
+ color: "hsl(var(--muted-foreground))",
2716
+ fontSize: 12
2717
+ },
2718
+ children: "Configure a chart to preview"
2719
+ }
2720
+ );
2721
+ }
2722
+ const legend = resolveLegendFromString(config.legend);
2723
+ const common = {
2724
+ className,
2725
+ height,
2726
+ grid: config.grid ?? true,
2727
+ animate: config.animate ?? true,
2728
+ tooltip: config.tooltip ?? true,
2729
+ legend
2730
+ };
2731
+ const xAxis = { dataKey: config.categoryKey };
2732
+ const series = config.series;
2733
+ switch (config.type) {
2734
+ case "line":
2735
+ return /* @__PURE__ */ jsxRuntime.jsx(LineChart, { data, series, xAxis, ...common });
2736
+ case "bar":
2737
+ return /* @__PURE__ */ jsxRuntime.jsx(BarChart, { data, series, xAxis, ...common });
2738
+ case "area":
2739
+ return /* @__PURE__ */ jsxRuntime.jsx(AreaChart, { data, series, xAxis, ...common });
2740
+ case "pie":
2741
+ return /* @__PURE__ */ jsxRuntime.jsx(
2742
+ PieChart,
2743
+ {
2744
+ data: data.map((d) => ({
2745
+ name: String(d[config.categoryKey]),
2746
+ value: Number(d[series[0].dataKey] ?? 0)
2747
+ })),
2748
+ label: true,
2749
+ ...common
2750
+ }
2751
+ );
2752
+ case "donut":
2753
+ return /* @__PURE__ */ jsxRuntime.jsx(
2754
+ DonutChart,
2755
+ {
2756
+ data: data.map((d) => ({
2757
+ name: String(d[config.categoryKey]),
2758
+ value: Number(d[series[0].dataKey] ?? 0)
2759
+ })),
2760
+ ...common
2761
+ }
2762
+ );
2763
+ case "scatter":
2764
+ return /* @__PURE__ */ jsxRuntime.jsx(
2765
+ ScatterChart,
2766
+ {
2767
+ series: [
2768
+ {
2769
+ name: series[0]?.name ?? "Data",
2770
+ data
2771
+ }
2772
+ ],
2773
+ xAxis: { ...xAxis, name: config.categoryKey },
2774
+ ...common
2775
+ }
2776
+ );
2777
+ case "radar":
2778
+ return /* @__PURE__ */ jsxRuntime.jsx(
2779
+ RadarChart,
2780
+ {
2781
+ data,
2782
+ series,
2783
+ categoryKey: config.categoryKey,
2784
+ ...common
2785
+ }
2786
+ );
2787
+ case "composed":
2788
+ return /* @__PURE__ */ jsxRuntime.jsx(
2789
+ ComposedChart,
2790
+ {
2791
+ data,
2792
+ series: series.map((s) => ({
2793
+ type: s.composedType ?? "bar",
2794
+ dataKey: s.dataKey,
2795
+ name: s.name,
2796
+ color: s.color
2797
+ })),
2798
+ xAxis,
2799
+ ...common
2800
+ }
2801
+ );
2802
+ case "waterfall":
2803
+ return /* @__PURE__ */ jsxRuntime.jsx(
2804
+ WaterfallChart,
2805
+ {
2806
+ data: data.map((d) => ({
2807
+ name: String(d[config.categoryKey]),
2808
+ value: Number(d[series[0]?.dataKey] ?? 0)
2809
+ })),
2810
+ ...common
2811
+ }
2812
+ );
2813
+ case "funnel":
2814
+ return /* @__PURE__ */ jsxRuntime.jsx(
2815
+ FunnelChart,
2816
+ {
2817
+ data: data.map((d) => ({
2818
+ name: String(d[config.categoryKey]),
2819
+ value: Number(d[series[0]?.dataKey] ?? 0)
2820
+ })),
2821
+ ...common
2822
+ }
2823
+ );
2824
+ case "treemap":
2825
+ return /* @__PURE__ */ jsxRuntime.jsx(
2826
+ TreemapChart,
2827
+ {
2828
+ data: data.map((d) => ({
2829
+ name: String(d[config.categoryKey]),
2830
+ value: Number(d[series[0]?.dataKey] ?? 0)
2831
+ })),
2832
+ ...common
2833
+ }
2834
+ );
2835
+ case "radialBar":
2836
+ return /* @__PURE__ */ jsxRuntime.jsx(
2837
+ RadialBarChart,
2838
+ {
2839
+ data: data.map((d) => ({
2840
+ name: String(d[config.categoryKey]),
2841
+ value: Number(d[series[0]?.dataKey] ?? 0)
2842
+ })),
2843
+ ...common
2844
+ }
2845
+ );
2846
+ case "heatmap": {
2847
+ if (series.length < 2) {
2848
+ return /* @__PURE__ */ jsxRuntime.jsx(
2849
+ "div",
2850
+ {
2851
+ style: {
2852
+ height,
2853
+ display: "flex",
2854
+ alignItems: "center",
2855
+ justifyContent: "center",
2856
+ color: "hsl(var(--muted-foreground))",
2857
+ fontSize: 12
2858
+ },
2859
+ children: "Heatmap requires at least 2 series (x, value)"
2860
+ }
2861
+ );
2862
+ }
2863
+ const xLabels = Array.from(
2864
+ new Set(data.map((d) => String(d[config.categoryKey])))
2865
+ );
2866
+ const yLabels = Array.from(
2867
+ new Set(data.map((d) => String(d[series[0].dataKey])))
2868
+ );
2869
+ const cells = data.map((d) => ({
2870
+ x: String(d[config.categoryKey]),
2871
+ y: String(d[series[0].dataKey]),
2872
+ value: Number(d[series[1].dataKey] ?? 0)
2873
+ }));
2874
+ return /* @__PURE__ */ jsxRuntime.jsx(
2875
+ HeatmapChart,
2876
+ {
2877
+ data: cells,
2878
+ xLabels,
2879
+ yLabels,
2880
+ height,
2881
+ className
2882
+ }
2883
+ );
2884
+ }
2885
+ default:
2886
+ return null;
2887
+ }
2888
+ });
2889
+ ChartRenderer.displayName = "ChartRenderer";
2890
+ var CHART_TYPE_OPTIONS = [
2891
+ { value: "line", label: "Line" },
2892
+ { value: "bar", label: "Bar" },
2893
+ { value: "area", label: "Area" },
2894
+ { value: "pie", label: "Pie" },
2895
+ { value: "donut", label: "Donut" },
2896
+ { value: "scatter", label: "Scatter" },
2897
+ { value: "radar", label: "Radar" },
2898
+ { value: "composed", label: "Composed" },
2899
+ { value: "waterfall", label: "Waterfall" },
2900
+ { value: "funnel", label: "Funnel" },
2901
+ { value: "treemap", label: "Treemap" },
2902
+ { value: "radialBar", label: "Radial Bar" },
2903
+ { value: "heatmap", label: "Heatmap" }
2904
+ ];
2905
+ var LEGEND_POSITIONS = [
2906
+ { value: "none", label: "None" },
2907
+ { value: "top-left", label: "Top Left" },
2908
+ { value: "top-center", label: "Top Center" },
2909
+ { value: "top-right", label: "Top Right" },
2910
+ { value: "bottom-center", label: "Bottom Center" }
2911
+ ];
2912
+ function useControlledConfig(initial, columns) {
2913
+ const defaultConfig = {
2914
+ type: "bar",
2915
+ categoryKey: columns[0] ?? "",
2916
+ series: columns.length > 1 ? [{ dataKey: columns[1], name: columns[1] }] : [],
2917
+ legend: "none",
2918
+ grid: true,
2919
+ animate: true
2920
+ };
2921
+ return React17__namespace.useState({ ...defaultConfig, ...initial });
2922
+ }
2923
+ var selectStyle = {
2924
+ width: "100%",
2925
+ padding: "5px 8px",
2926
+ fontSize: 12,
2927
+ borderRadius: 4,
2928
+ border: "1px solid hsl(var(--border))",
2929
+ background: "hsl(var(--card))",
2930
+ color: "hsl(var(--foreground))"
2931
+ };
2932
+ var labelStyle = {
2933
+ fontSize: 11,
2934
+ fontWeight: 500,
2935
+ color: "hsl(var(--muted-foreground))",
2936
+ marginBottom: 3,
2937
+ display: "block"
2938
+ };
2939
+ var ChartBuilder = React17__namespace.memo(function ChartBuilder2({
2940
+ columns,
2941
+ data,
2942
+ onChange,
2943
+ onSave,
2944
+ initialConfig,
2945
+ className
2946
+ }) {
2947
+ const [config, setConfig] = useControlledConfig(initialConfig, columns);
2948
+ React17__namespace.useEffect(() => {
2949
+ onChange?.(config);
2950
+ }, [config, onChange]);
2951
+ const addSeries = () => {
2952
+ const unused = columns.find(
2953
+ (c) => c !== config.categoryKey && !config.series.some((s) => s.dataKey === c)
2954
+ );
2955
+ if (!unused) return;
2956
+ setConfig((prev) => ({
2957
+ ...prev,
2958
+ series: [...prev.series, { dataKey: unused, name: unused }]
2959
+ }));
2960
+ };
2961
+ const removeSeries = (index) => {
2962
+ setConfig((prev) => ({
2963
+ ...prev,
2964
+ series: prev.series.filter((_, i) => i !== index)
2965
+ }));
2966
+ };
2967
+ const updateSeries = (index, field, value) => {
2968
+ setConfig((prev) => ({
2969
+ ...prev,
2970
+ series: prev.series.map(
2971
+ (s, i) => i === index ? { ...s, [field]: value } : s
2972
+ )
2973
+ }));
2974
+ };
2975
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2976
+ "div",
2977
+ {
2978
+ className: core.cn("flex gap-4", className),
2979
+ style: { minHeight: 400 },
2980
+ children: [
2981
+ /* @__PURE__ */ jsxRuntime.jsxs(
2982
+ "div",
2983
+ {
2984
+ className: "flex flex-col gap-3 shrink-0 overflow-y-auto",
2985
+ style: {
2986
+ width: 240,
2987
+ padding: 12,
2988
+ background: "hsl(var(--card))",
2989
+ border: "1px solid hsl(var(--border))",
2990
+ borderRadius: 8
2991
+ },
2992
+ children: [
2993
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, fontWeight: 600, color: "hsl(var(--foreground))" }, children: "Chart Builder" }),
2994
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2995
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: labelStyle, children: "Chart Type" }),
2996
+ /* @__PURE__ */ jsxRuntime.jsx(
2997
+ "select",
2998
+ {
2999
+ style: selectStyle,
3000
+ value: config.type,
3001
+ onChange: (e) => setConfig((prev) => ({ ...prev, type: e.target.value })),
3002
+ children: CHART_TYPE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
3003
+ }
3004
+ )
3005
+ ] }),
3006
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3007
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: labelStyle, children: "Category Axis" }),
3008
+ /* @__PURE__ */ jsxRuntime.jsx(
3009
+ "select",
3010
+ {
3011
+ style: selectStyle,
3012
+ value: config.categoryKey,
3013
+ onChange: (e) => setConfig((prev) => ({ ...prev, categoryKey: e.target.value })),
3014
+ children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c, children: c }, c))
3015
+ }
3016
+ )
3017
+ ] }),
3018
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3019
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: labelStyle, children: "Series" }),
3020
+ config.series.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs(
3021
+ "div",
3022
+ {
3023
+ className: "flex gap-1 items-center",
3024
+ style: { marginBottom: 4 },
3025
+ children: [
3026
+ /* @__PURE__ */ jsxRuntime.jsx(
3027
+ "select",
3028
+ {
3029
+ style: { ...selectStyle, flex: 1 },
3030
+ value: s.dataKey,
3031
+ onChange: (e) => updateSeries(i, "dataKey", e.target.value),
3032
+ children: columns.filter((c) => c !== config.categoryKey).map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c, children: c }, c))
3033
+ }
3034
+ ),
3035
+ /* @__PURE__ */ jsxRuntime.jsx(
3036
+ "button",
3037
+ {
3038
+ onClick: () => removeSeries(i),
3039
+ style: {
3040
+ padding: "2px 6px",
3041
+ fontSize: 14,
3042
+ lineHeight: 1,
3043
+ border: "1px solid hsl(var(--border))",
3044
+ borderRadius: 4,
3045
+ background: "hsl(var(--card))",
3046
+ color: "hsl(var(--muted-foreground))",
3047
+ cursor: "pointer"
3048
+ },
3049
+ children: "\xD7"
3050
+ }
3051
+ )
3052
+ ]
3053
+ },
3054
+ i
3055
+ )),
3056
+ /* @__PURE__ */ jsxRuntime.jsx(
3057
+ "button",
3058
+ {
3059
+ onClick: addSeries,
3060
+ style: {
3061
+ width: "100%",
3062
+ padding: "4px 8px",
3063
+ fontSize: 11,
3064
+ border: "1px dashed hsl(var(--border))",
3065
+ borderRadius: 4,
3066
+ background: "transparent",
3067
+ color: "hsl(var(--muted-foreground))",
3068
+ cursor: "pointer",
3069
+ marginTop: 2
3070
+ },
3071
+ children: "+ Add Series"
3072
+ }
3073
+ )
3074
+ ] }),
3075
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3076
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: labelStyle, children: "Legend" }),
3077
+ /* @__PURE__ */ jsxRuntime.jsx(
3078
+ "select",
3079
+ {
3080
+ style: selectStyle,
3081
+ value: config.legend,
3082
+ onChange: (e) => setConfig((prev) => ({ ...prev, legend: e.target.value })),
3083
+ children: LEGEND_POSITIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
3084
+ }
3085
+ )
3086
+ ] }),
3087
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3088
+ /* @__PURE__ */ jsxRuntime.jsx(
3089
+ "input",
3090
+ {
3091
+ type: "checkbox",
3092
+ id: "grid-toggle",
3093
+ checked: config.grid,
3094
+ onChange: (e) => setConfig((prev) => ({ ...prev, grid: e.target.checked }))
3095
+ }
3096
+ ),
3097
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "grid-toggle", style: { ...labelStyle, margin: 0 }, children: "Show Grid" })
3098
+ ] }),
3099
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3100
+ /* @__PURE__ */ jsxRuntime.jsx(
3101
+ "input",
3102
+ {
3103
+ type: "checkbox",
3104
+ id: "animate-toggle",
3105
+ checked: config.animate,
3106
+ onChange: (e) => setConfig((prev) => ({ ...prev, animate: e.target.checked }))
3107
+ }
3108
+ ),
3109
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "animate-toggle", style: { ...labelStyle, margin: 0 }, children: "Animate" })
3110
+ ] }),
3111
+ onSave && /* @__PURE__ */ jsxRuntime.jsx(
3112
+ "button",
3113
+ {
3114
+ onClick: () => onSave(config),
3115
+ style: {
3116
+ marginTop: 8,
3117
+ padding: "6px 12px",
3118
+ fontSize: 12,
3119
+ fontWeight: 600,
3120
+ borderRadius: 6,
3121
+ border: "none",
3122
+ background: "hsl(var(--primary))",
3123
+ color: "hsl(var(--primary-foreground))",
3124
+ cursor: "pointer"
3125
+ },
3126
+ children: "Save Chart"
3127
+ }
3128
+ )
3129
+ ]
3130
+ }
3131
+ ),
3132
+ /* @__PURE__ */ jsxRuntime.jsx(
3133
+ "div",
3134
+ {
3135
+ className: "flex-1",
3136
+ style: {
3137
+ border: "1px solid hsl(var(--border))",
3138
+ borderRadius: 8,
3139
+ padding: 12,
3140
+ background: "hsl(var(--background))",
3141
+ minHeight: 300
3142
+ },
3143
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChartRenderer, { config, data, height: "100%" })
3144
+ }
3145
+ )
3146
+ ]
3147
+ }
3148
+ );
3149
+ });
3150
+ ChartBuilder.displayName = "ChartBuilder";
321
3151
 
3152
+ exports.AreaChart = AreaChart;
322
3153
  exports.BarChart = BarChart;
323
3154
  exports.CHART_COLORS = CHART_COLORS;
3155
+ exports.ChartBuilder = ChartBuilder;
3156
+ exports.ChartContainer = ChartContainer;
3157
+ exports.ChartLegendContent = ChartLegendContent;
3158
+ exports.ChartRenderer = ChartRenderer;
3159
+ exports.ChartTooltipContent = ChartTooltipContent;
3160
+ exports.ComposedChart = ComposedChart;
3161
+ exports.DonutChart = DonutChart;
3162
+ exports.FunnelChart = FunnelChart;
3163
+ exports.GanttChart = GanttChart;
3164
+ exports.HeatmapChart = HeatmapChart;
3165
+ exports.KPICard = KPICard;
324
3166
  exports.LineChart = LineChart;
3167
+ exports.PieChart = PieChart;
3168
+ exports.RadarChart = RadarChart;
3169
+ exports.RadialBarChart = RadialBarChart;
3170
+ exports.SankeyChart = SankeyChart;
3171
+ exports.ScatterChart = ScatterChart;
3172
+ exports.ScenarioComparison = ScenarioComparison;
3173
+ exports.Sparkline = Sparkline;
3174
+ exports.TreemapChart = TreemapChart;
3175
+ exports.WaterfallChart = WaterfallChart;
3176
+ exports.formatCompact = formatCompact;
3177
+ exports.formatCurrency = formatCurrency;
3178
+ exports.formatDuration = formatDuration;
3179
+ exports.formatPercent = formatPercent;
3180
+ exports.formatUnit = formatUnit;
325
3181
  exports.getChartColor = getChartColor;
3182
+ exports.getSemanticColor = getSemanticColor;
3183
+ exports.resolveLegendConfig = resolveLegendConfig;
3184
+ exports.resolveTooltipProps = resolveTooltipProps;
3185
+ exports.useLiveData = useLiveData;
326
3186
  //# sourceMappingURL=index.cjs.map
327
3187
  //# sourceMappingURL=index.cjs.map