@mdxui/tremor 6.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 (35) hide show
  1. package/README.md +255 -0
  2. package/dist/dashboard/components/index.d.ts +355 -0
  3. package/dist/dashboard/components/index.js +549 -0
  4. package/dist/dashboard/components/index.js.map +1 -0
  5. package/dist/dashboard/index.d.ts +275 -0
  6. package/dist/dashboard/index.js +1062 -0
  7. package/dist/dashboard/index.js.map +1 -0
  8. package/dist/database/index.d.ts +334 -0
  9. package/dist/database/index.js +474 -0
  10. package/dist/database/index.js.map +1 -0
  11. package/dist/index.d.ts +9 -0
  12. package/dist/index.js +1089 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/insights/components/index.d.ts +362 -0
  15. package/dist/insights/components/index.js +1397 -0
  16. package/dist/insights/components/index.js.map +1 -0
  17. package/dist/insights/index.d.ts +360 -0
  18. package/dist/insights/index.js +1815 -0
  19. package/dist/insights/index.js.map +1 -0
  20. package/dist/overview/components/index.d.ts +86 -0
  21. package/dist/overview/components/index.js +775 -0
  22. package/dist/overview/components/index.js.map +1 -0
  23. package/dist/overview/index.d.ts +301 -0
  24. package/dist/overview/index.js +1077 -0
  25. package/dist/overview/index.js.map +1 -0
  26. package/dist/shared/index.d.ts +296 -0
  27. package/dist/shared/index.js +395 -0
  28. package/dist/shared/index.js.map +1 -0
  29. package/dist/solar/components/index.d.ts +341 -0
  30. package/dist/solar/components/index.js +831 -0
  31. package/dist/solar/components/index.js.map +1 -0
  32. package/dist/solar/index.d.ts +301 -0
  33. package/dist/solar/index.js +1130 -0
  34. package/dist/solar/index.js.map +1 -0
  35. package/package.json +135 -0
@@ -0,0 +1,1397 @@
1
+ // src/insights/components/charts/area-chart.tsx
2
+ import * as React from "react";
3
+ import {
4
+ Area,
5
+ CartesianGrid,
6
+ AreaChart as RechartsAreaChart,
7
+ Legend as RechartsLegend,
8
+ ResponsiveContainer,
9
+ Tooltip,
10
+ XAxis,
11
+ YAxis
12
+ } from "recharts";
13
+ import { twMerge } from "tailwind-merge";
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ var chartColors = {
16
+ blue: "#3b82f6",
17
+ green: "#22c55e",
18
+ red: "#ef4444",
19
+ yellow: "#eab308",
20
+ purple: "#a855f7",
21
+ cyan: "#06b6d4",
22
+ orange: "#f97316",
23
+ pink: "#ec4899",
24
+ indigo: "#6366f1",
25
+ teal: "#14b8a6",
26
+ emerald: "#10b981",
27
+ gray: "#6b7280"
28
+ };
29
+ function getColor(color, index) {
30
+ if (chartColors[color]) return chartColors[color];
31
+ const defaultColors = Object.values(chartColors);
32
+ return defaultColors[index % defaultColors.length];
33
+ }
34
+ var AreaChart = React.forwardRef(
35
+ ({
36
+ data,
37
+ index,
38
+ categories,
39
+ colors,
40
+ valueFormatter,
41
+ startEndOnly = false,
42
+ showLegend = true,
43
+ showGridLines = true,
44
+ showAnimation = true,
45
+ stack = false,
46
+ curveType = "monotone",
47
+ connectNulls = false,
48
+ yAxisWidth = 56,
49
+ minValue,
50
+ maxValue,
51
+ className
52
+ }, ref) => {
53
+ const formatValue = valueFormatter || ((value) => value.toString());
54
+ return /* @__PURE__ */ jsx("div", { ref, className: twMerge("h-80 w-full", className), children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(
55
+ RechartsAreaChart,
56
+ {
57
+ data,
58
+ margin: { top: 10, right: 30, left: 0, bottom: 0 },
59
+ children: [
60
+ showGridLines && /* @__PURE__ */ jsx(
61
+ CartesianGrid,
62
+ {
63
+ strokeDasharray: "3 3",
64
+ className: "stroke-gray-200 dark:stroke-gray-800",
65
+ horizontal: true,
66
+ vertical: false
67
+ }
68
+ ),
69
+ /* @__PURE__ */ jsx(
70
+ XAxis,
71
+ {
72
+ dataKey: index,
73
+ tick: { fontSize: 12 },
74
+ tickLine: false,
75
+ axisLine: false,
76
+ className: "fill-gray-500 text-xs",
77
+ tickFormatter: startEndOnly ? void 0 : void 0
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsx(
81
+ YAxis,
82
+ {
83
+ width: yAxisWidth,
84
+ tick: { fontSize: 12 },
85
+ tickLine: false,
86
+ axisLine: false,
87
+ tickFormatter: formatValue,
88
+ className: "fill-gray-500 text-xs",
89
+ domain: [minValue ?? "auto", maxValue ?? "auto"]
90
+ }
91
+ ),
92
+ /* @__PURE__ */ jsx(
93
+ Tooltip,
94
+ {
95
+ formatter: (value, name) => {
96
+ const numValue = typeof value === "number" ? value : 0;
97
+ return [formatValue(numValue), String(name)];
98
+ },
99
+ contentStyle: {
100
+ backgroundColor: "white",
101
+ border: "1px solid #e5e7eb",
102
+ borderRadius: "6px",
103
+ boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)"
104
+ }
105
+ }
106
+ ),
107
+ showLegend && /* @__PURE__ */ jsx(RechartsLegend, { verticalAlign: "top", height: 36 }),
108
+ categories.map((category, idx) => {
109
+ const color = colors?.[idx] || category;
110
+ return /* @__PURE__ */ jsx(
111
+ Area,
112
+ {
113
+ type: curveType,
114
+ dataKey: category,
115
+ stroke: getColor(color, idx),
116
+ fill: getColor(color, idx),
117
+ fillOpacity: 0.3,
118
+ strokeWidth: 2,
119
+ stackId: stack ? "stack" : void 0,
120
+ isAnimationActive: showAnimation,
121
+ connectNulls
122
+ },
123
+ category
124
+ );
125
+ })
126
+ ]
127
+ }
128
+ ) }) });
129
+ }
130
+ );
131
+ AreaChart.displayName = "AreaChart";
132
+
133
+ // src/insights/components/charts/bar-chart.tsx
134
+ import * as React2 from "react";
135
+ import {
136
+ Bar,
137
+ CartesianGrid as CartesianGrid2,
138
+ BarChart as RechartsBarChart,
139
+ Legend as RechartsLegend2,
140
+ ResponsiveContainer as ResponsiveContainer2,
141
+ Tooltip as Tooltip2,
142
+ XAxis as XAxis2,
143
+ YAxis as YAxis2
144
+ } from "recharts";
145
+ import { twMerge as twMerge2 } from "tailwind-merge";
146
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
147
+ var chartColors2 = {
148
+ blue: "#3b82f6",
149
+ green: "#22c55e",
150
+ red: "#ef4444",
151
+ yellow: "#eab308",
152
+ purple: "#a855f7",
153
+ cyan: "#06b6d4",
154
+ orange: "#f97316",
155
+ pink: "#ec4899",
156
+ indigo: "#6366f1",
157
+ teal: "#14b8a6",
158
+ emerald: "#10b981",
159
+ gray: "#6b7280"
160
+ };
161
+ function getColor2(color, index) {
162
+ if (chartColors2[color]) return chartColors2[color];
163
+ const defaultColors = Object.values(chartColors2);
164
+ return defaultColors[index % defaultColors.length];
165
+ }
166
+ var BarChart = React2.forwardRef(
167
+ ({
168
+ data,
169
+ index,
170
+ categories,
171
+ colors,
172
+ valueFormatter,
173
+ layout = "vertical",
174
+ stack = false,
175
+ relative = false,
176
+ showLegend = true,
177
+ showGridLines = true,
178
+ showAnimation = true,
179
+ yAxisWidth = 56,
180
+ barCategoryGap,
181
+ className
182
+ }, ref) => {
183
+ const formatValue = valueFormatter || ((value) => value.toString());
184
+ const rechartsLayout = layout === "horizontal" ? "vertical" : "horizontal";
185
+ return /* @__PURE__ */ jsx2("div", { ref, className: twMerge2("h-80 w-full", className), children: /* @__PURE__ */ jsx2(ResponsiveContainer2, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs2(
186
+ RechartsBarChart,
187
+ {
188
+ data,
189
+ layout: rechartsLayout,
190
+ margin: { top: 10, right: 30, left: 0, bottom: 0 },
191
+ barCategoryGap,
192
+ stackOffset: relative ? "expand" : void 0,
193
+ children: [
194
+ showGridLines && /* @__PURE__ */ jsx2(
195
+ CartesianGrid2,
196
+ {
197
+ strokeDasharray: "3 3",
198
+ className: "stroke-gray-200 dark:stroke-gray-800",
199
+ horizontal: rechartsLayout !== "vertical",
200
+ vertical: rechartsLayout === "vertical"
201
+ }
202
+ ),
203
+ rechartsLayout === "horizontal" ? /* @__PURE__ */ jsxs2(Fragment, { children: [
204
+ /* @__PURE__ */ jsx2(
205
+ XAxis2,
206
+ {
207
+ dataKey: index,
208
+ tick: { fontSize: 12 },
209
+ tickLine: false,
210
+ axisLine: false,
211
+ className: "fill-gray-500 text-xs"
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsx2(
215
+ YAxis2,
216
+ {
217
+ width: yAxisWidth,
218
+ tick: { fontSize: 12 },
219
+ tickLine: false,
220
+ axisLine: false,
221
+ tickFormatter: relative ? (value) => `${(value * 100).toFixed(0)}%` : formatValue,
222
+ className: "fill-gray-500 text-xs"
223
+ }
224
+ )
225
+ ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
226
+ /* @__PURE__ */ jsx2(
227
+ XAxis2,
228
+ {
229
+ type: "number",
230
+ tick: { fontSize: 12 },
231
+ tickLine: false,
232
+ axisLine: false,
233
+ tickFormatter: relative ? (value) => `${(value * 100).toFixed(0)}%` : formatValue,
234
+ className: "fill-gray-500 text-xs"
235
+ }
236
+ ),
237
+ /* @__PURE__ */ jsx2(
238
+ YAxis2,
239
+ {
240
+ type: "category",
241
+ dataKey: index,
242
+ width: yAxisWidth,
243
+ tick: { fontSize: 12 },
244
+ tickLine: false,
245
+ axisLine: false,
246
+ className: "fill-gray-500 text-xs"
247
+ }
248
+ )
249
+ ] }),
250
+ /* @__PURE__ */ jsx2(
251
+ Tooltip2,
252
+ {
253
+ formatter: (value, name) => {
254
+ const numValue = typeof value === "number" ? value : 0;
255
+ return [
256
+ relative ? `${(numValue * 100).toFixed(1)}%` : formatValue(numValue),
257
+ String(name)
258
+ ];
259
+ },
260
+ contentStyle: {
261
+ backgroundColor: "white",
262
+ border: "1px solid #e5e7eb",
263
+ borderRadius: "6px",
264
+ boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)"
265
+ }
266
+ }
267
+ ),
268
+ showLegend && /* @__PURE__ */ jsx2(RechartsLegend2, { verticalAlign: "top", height: 36 }),
269
+ categories.map((category, idx) => {
270
+ const color = colors?.[idx] || category;
271
+ return /* @__PURE__ */ jsx2(
272
+ Bar,
273
+ {
274
+ dataKey: category,
275
+ fill: getColor2(color, idx),
276
+ stackId: stack || relative ? "stack" : void 0,
277
+ isAnimationActive: showAnimation,
278
+ radius: [4, 4, 0, 0]
279
+ },
280
+ category
281
+ );
282
+ })
283
+ ]
284
+ }
285
+ ) }) });
286
+ }
287
+ );
288
+ BarChart.displayName = "BarChart";
289
+
290
+ // src/insights/components/charts/bar-chart-variant.tsx
291
+ import * as React3 from "react";
292
+ import {
293
+ Bar as Bar2,
294
+ CartesianGrid as CartesianGrid3,
295
+ Label,
296
+ BarChart as RechartsBarChart2,
297
+ Legend as RechartsLegend3,
298
+ ResponsiveContainer as ResponsiveContainer3,
299
+ Tooltip as Tooltip3,
300
+ XAxis as XAxis3,
301
+ YAxis as YAxis3
302
+ } from "recharts";
303
+ import { twMerge as twMerge3 } from "tailwind-merge";
304
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
305
+ var chartColors3 = {
306
+ blue: { fill: "#3b82f6", stroke: "#2563eb" },
307
+ emerald: { fill: "#10b981", stroke: "#059669" },
308
+ violet: { fill: "#8b5cf6", stroke: "#7c3aed" },
309
+ amber: { fill: "#f59e0b", stroke: "#d97706" },
310
+ gray: { fill: "#6b7280", stroke: "#4b5563" },
311
+ cyan: { fill: "#06b6d4", stroke: "#0891b2" },
312
+ pink: { fill: "#ec4899", stroke: "#db2777" },
313
+ lime: { fill: "#84cc16", stroke: "#65a30d" },
314
+ fuchsia: { fill: "#d946ef", stroke: "#c026d3" },
315
+ orange: { fill: "#f97316", stroke: "#ea580c" }
316
+ };
317
+ function getColor3(color, index) {
318
+ if (chartColors3[color]) return chartColors3[color];
319
+ const defaultColors = Object.values(chartColors3);
320
+ return defaultColors[index % defaultColors.length];
321
+ }
322
+ var renderShape = (props, activeBar, activeLegend, strokeColor, layout) => {
323
+ const { name, payload, value } = props;
324
+ let { x, width, y, height } = props;
325
+ let lineX1, lineY1, lineX2, lineY2;
326
+ if (layout === "horizontal" && height < 0) {
327
+ y += height;
328
+ height = Math.abs(height);
329
+ } else if (layout === "vertical" && width < 0) {
330
+ x += width;
331
+ width = Math.abs(width);
332
+ }
333
+ if (layout === "horizontal") {
334
+ lineX1 = x;
335
+ lineY1 = y;
336
+ lineX2 = x + width;
337
+ lineY2 = y;
338
+ } else {
339
+ lineX1 = x + width;
340
+ lineY1 = y;
341
+ lineX2 = x + width;
342
+ lineY2 = y + height;
343
+ }
344
+ const isActive = activeBar && activeBar.value === value && JSON.stringify(activeBar.payload) === JSON.stringify(payload);
345
+ const opacity = activeBar || activeLegend && activeLegend !== name ? isActive ? 0.2 : 0.1 : 0.2;
346
+ const lineOpacity = activeBar || activeLegend && activeLegend !== name ? isActive ? 1 : 0.5 : 1;
347
+ return /* @__PURE__ */ jsxs3("g", { children: [
348
+ /* @__PURE__ */ jsx3(
349
+ "rect",
350
+ {
351
+ x,
352
+ y,
353
+ width,
354
+ height,
355
+ fill: "currentColor",
356
+ opacity
357
+ }
358
+ ),
359
+ /* @__PURE__ */ jsx3(
360
+ "line",
361
+ {
362
+ x1: lineX1,
363
+ y1: lineY1,
364
+ x2: lineX2,
365
+ y2: lineY2,
366
+ stroke: strokeColor,
367
+ strokeWidth: "2",
368
+ opacity: lineOpacity
369
+ }
370
+ )
371
+ ] });
372
+ };
373
+ var BarChartVariant = React3.forwardRef((props, forwardedRef) => {
374
+ const {
375
+ data = [],
376
+ categories = [],
377
+ index,
378
+ colors = ["blue", "emerald", "violet", "amber"],
379
+ valueFormatter = (value) => value.toString(),
380
+ xValueFormatter = (value) => value.toString(),
381
+ showXAxis = true,
382
+ showYAxis = true,
383
+ showGridLines = true,
384
+ yAxisWidth = 56,
385
+ showTooltip = true,
386
+ showLegend = true,
387
+ autoMinValue = false,
388
+ minValue,
389
+ maxValue,
390
+ allowDecimals = true,
391
+ barCategoryGap = "2%",
392
+ xAxisLabel,
393
+ yAxisLabel,
394
+ type = "default",
395
+ legendPosition = "right",
396
+ layout = "horizontal",
397
+ className,
398
+ onValueChange,
399
+ syncId,
400
+ ...other
401
+ } = props;
402
+ const [legendHeight] = React3.useState(60);
403
+ const [activeLegend, setActiveLegend] = React3.useState(
404
+ void 0
405
+ );
406
+ const [activeBar, setActiveBar] = React3.useState(void 0);
407
+ const stacked = type === "stacked" || type === "percent";
408
+ const getYAxisDomain = () => {
409
+ const min = autoMinValue ? "auto" : minValue ?? 0;
410
+ const max = maxValue ?? "auto";
411
+ return [min, max];
412
+ };
413
+ const yAxisDomain = getYAxisDomain();
414
+ function valueToPercent(value) {
415
+ return `${(value * 100).toFixed(0)}%`;
416
+ }
417
+ function onBarClick(barData) {
418
+ if (!onValueChange) return;
419
+ if (activeBar && JSON.stringify(activeBar) === JSON.stringify(barData)) {
420
+ setActiveLegend(void 0);
421
+ setActiveBar(void 0);
422
+ onValueChange(null);
423
+ } else {
424
+ setActiveBar(barData);
425
+ onValueChange(barData);
426
+ }
427
+ }
428
+ return /* @__PURE__ */ jsx3(
429
+ "div",
430
+ {
431
+ ref: forwardedRef,
432
+ className: twMerge3("h-80 w-full", className),
433
+ ...other,
434
+ children: /* @__PURE__ */ jsx3(ResponsiveContainer3, { children: /* @__PURE__ */ jsxs3(
435
+ RechartsBarChart2,
436
+ {
437
+ data,
438
+ margin: {
439
+ bottom: xAxisLabel ? 30 : void 0,
440
+ left: yAxisLabel ? 20 : void 0,
441
+ right: yAxisLabel ? 5 : void 0,
442
+ top: 10
443
+ },
444
+ stackOffset: type === "percent" ? "expand" : void 0,
445
+ layout,
446
+ barCategoryGap,
447
+ syncId,
448
+ children: [
449
+ showGridLines && /* @__PURE__ */ jsx3(
450
+ CartesianGrid3,
451
+ {
452
+ className: "stroke-gray-100 stroke-1 dark:stroke-gray-900",
453
+ horizontal: layout !== "vertical",
454
+ vertical: layout === "vertical"
455
+ }
456
+ ),
457
+ /* @__PURE__ */ jsx3(
458
+ XAxis3,
459
+ {
460
+ hide: !showXAxis,
461
+ tick: {
462
+ transform: layout !== "vertical" ? "translate(0, 6)" : void 0
463
+ },
464
+ fill: "",
465
+ stroke: "",
466
+ className: "text-xs fill-gray-500 dark:fill-gray-500",
467
+ tickLine: false,
468
+ axisLine: false,
469
+ minTickGap: 5,
470
+ tickFormatter: xValueFormatter,
471
+ ...layout !== "vertical" ? {
472
+ dataKey: index
473
+ } : {
474
+ type: "number",
475
+ domain: yAxisDomain,
476
+ tickFormatter: type === "percent" ? valueToPercent : valueFormatter,
477
+ allowDecimals
478
+ },
479
+ children: xAxisLabel && /* @__PURE__ */ jsx3(
480
+ Label,
481
+ {
482
+ position: "insideBottom",
483
+ offset: -20,
484
+ className: "fill-gray-800 text-sm font-medium dark:fill-gray-200",
485
+ children: xAxisLabel
486
+ }
487
+ )
488
+ }
489
+ ),
490
+ /* @__PURE__ */ jsx3(
491
+ YAxis3,
492
+ {
493
+ width: yAxisWidth,
494
+ hide: !showYAxis,
495
+ axisLine: false,
496
+ tickLine: layout === "horizontal",
497
+ tickSize: 6,
498
+ fill: "",
499
+ stroke: "",
500
+ className: "text-xs fill-gray-500 stroke-gray-800 dark:fill-gray-500 dark:stroke-gray-300",
501
+ tick: {
502
+ transform: layout !== "vertical" ? "translate(-3, 0)" : "translate(0, 0)"
503
+ },
504
+ ...layout !== "vertical" ? {
505
+ type: "number",
506
+ domain: yAxisDomain,
507
+ tickFormatter: type === "percent" ? valueToPercent : valueFormatter,
508
+ allowDecimals
509
+ } : {
510
+ dataKey: index,
511
+ type: "category",
512
+ interval: "equidistantPreserveStart"
513
+ },
514
+ children: yAxisLabel && /* @__PURE__ */ jsx3(
515
+ Label,
516
+ {
517
+ position: "insideLeft",
518
+ style: { textAnchor: "middle" },
519
+ angle: -90,
520
+ offset: -15,
521
+ className: "fill-gray-800 text-sm font-medium dark:fill-gray-200",
522
+ children: yAxisLabel
523
+ }
524
+ )
525
+ }
526
+ ),
527
+ /* @__PURE__ */ jsx3(
528
+ Tooltip3,
529
+ {
530
+ wrapperStyle: { outline: "none" },
531
+ isAnimationActive: true,
532
+ animationDuration: 100,
533
+ cursor: { fill: "#d1d5db", opacity: "0.15" },
534
+ offset: 20,
535
+ position: {
536
+ y: layout === "horizontal" ? 0 : void 0,
537
+ x: layout === "horizontal" ? void 0 : yAxisWidth + 20
538
+ },
539
+ content: showTooltip ? ({ active, payload, label }) => {
540
+ if (active && payload && payload.length) {
541
+ return /* @__PURE__ */ jsxs3("div", { className: "w-44 rounded-md border border-gray-200 bg-white text-sm shadow-md dark:border-gray-800 dark:bg-gray-950", children: [
542
+ /* @__PURE__ */ jsx3("div", { className: "border-b border-inherit p-2", children: /* @__PURE__ */ jsx3("p", { className: "font-medium text-gray-900 dark:text-gray-50", children: xValueFormatter ? xValueFormatter(label) : label }) }),
543
+ /* @__PURE__ */ jsx3("div", { className: "space-y-1 p-2", children: payload.map(
544
+ (item, idx) => /* @__PURE__ */ jsxs3(
545
+ "div",
546
+ {
547
+ className: "flex items-center justify-between space-x-4",
548
+ children: [
549
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center space-x-2", children: [
550
+ /* @__PURE__ */ jsx3(
551
+ "span",
552
+ {
553
+ className: "size-2.5 shrink-0 rounded-sm",
554
+ style: {
555
+ backgroundColor: getColor3(
556
+ colors[idx] || "gray",
557
+ idx
558
+ ).fill
559
+ },
560
+ "aria-hidden": "true"
561
+ }
562
+ ),
563
+ /* @__PURE__ */ jsx3("p", { className: "whitespace-nowrap text-right text-gray-700 dark:text-gray-300", children: item.dataKey })
564
+ ] }),
565
+ /* @__PURE__ */ jsx3("p", { className: "whitespace-nowrap text-right font-medium tabular-nums text-gray-900 dark:text-gray-50", children: valueFormatter(item.value) })
566
+ ]
567
+ },
568
+ idx.toString()
569
+ )
570
+ ) })
571
+ ] });
572
+ }
573
+ return null;
574
+ } : () => null
575
+ }
576
+ ),
577
+ showLegend && /* @__PURE__ */ jsx3(RechartsLegend3, { verticalAlign: "top", height: legendHeight }),
578
+ categories.map((category, idx) => {
579
+ const colorConfig = getColor3(colors[idx] || "gray", idx);
580
+ return /* @__PURE__ */ jsx3(
581
+ Bar2,
582
+ {
583
+ name: category,
584
+ dataKey: category,
585
+ stackId: stacked ? "stack" : void 0,
586
+ isAnimationActive: false,
587
+ fill: colorConfig.fill,
588
+ className: onValueChange ? "cursor-pointer" : "",
589
+ shape: (shapeProps) => renderShape(
590
+ shapeProps,
591
+ activeBar,
592
+ activeLegend,
593
+ colorConfig.stroke,
594
+ layout
595
+ ),
596
+ onClick: (barData) => onBarClick(barData)
597
+ },
598
+ category
599
+ );
600
+ })
601
+ ]
602
+ }
603
+ ) })
604
+ }
605
+ );
606
+ });
607
+ BarChartVariant.displayName = "BarChartVariant";
608
+
609
+ // src/insights/components/charts/donut-chart.tsx
610
+ import * as React4 from "react";
611
+ import {
612
+ Cell,
613
+ Pie,
614
+ Legend as RechartsLegend4,
615
+ PieChart as RechartsPieChart,
616
+ ResponsiveContainer as ResponsiveContainer4,
617
+ Tooltip as Tooltip4
618
+ } from "recharts";
619
+ import { twMerge as twMerge4 } from "tailwind-merge";
620
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
621
+ var chartColors4 = {
622
+ blue: "#3b82f6",
623
+ green: "#22c55e",
624
+ red: "#ef4444",
625
+ yellow: "#eab308",
626
+ purple: "#a855f7",
627
+ cyan: "#06b6d4",
628
+ orange: "#f97316",
629
+ pink: "#ec4899",
630
+ indigo: "#6366f1",
631
+ teal: "#14b8a6",
632
+ emerald: "#10b981",
633
+ gray: "#6b7280"
634
+ };
635
+ function getColor4(color, index) {
636
+ if (color && chartColors4[color]) return chartColors4[color];
637
+ if (color && color.startsWith("#")) return color;
638
+ const defaultColors = Object.values(chartColors4);
639
+ return defaultColors[index % defaultColors.length];
640
+ }
641
+ var DonutChart = React4.forwardRef(
642
+ ({
643
+ data,
644
+ category,
645
+ value,
646
+ colors,
647
+ variant = "donut",
648
+ label,
649
+ showLegend = true,
650
+ showTooltip = true,
651
+ animationDuration = 500,
652
+ valueFormatter,
653
+ className
654
+ }, ref) => {
655
+ const formatValue = valueFormatter || ((val) => val.toString());
656
+ const innerRadius = variant === "donut" ? "60%" : 0;
657
+ return /* @__PURE__ */ jsx4("div", { ref, className: twMerge4("h-80 w-full", className), children: /* @__PURE__ */ jsx4(ResponsiveContainer4, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs4(RechartsPieChart, { children: [
658
+ /* @__PURE__ */ jsx4(
659
+ Pie,
660
+ {
661
+ data,
662
+ dataKey: value,
663
+ nameKey: category,
664
+ cx: "50%",
665
+ cy: "50%",
666
+ innerRadius,
667
+ outerRadius: "80%",
668
+ paddingAngle: 2,
669
+ isAnimationActive: animationDuration > 0,
670
+ animationDuration,
671
+ label: label ? false : void 0,
672
+ children: data.map((entry, index) => {
673
+ const entryColor = entry.color || colors?.[index];
674
+ return /* @__PURE__ */ jsx4(
675
+ Cell,
676
+ {
677
+ fill: getColor4(entryColor, index),
678
+ strokeWidth: 0
679
+ },
680
+ `cell-${index.toString()}`
681
+ );
682
+ })
683
+ }
684
+ ),
685
+ showTooltip && /* @__PURE__ */ jsx4(
686
+ Tooltip4,
687
+ {
688
+ formatter: (val, name) => {
689
+ const numValue = typeof val === "number" ? val : 0;
690
+ return [formatValue(numValue), String(name)];
691
+ },
692
+ contentStyle: {
693
+ backgroundColor: "white",
694
+ border: "1px solid #e5e7eb",
695
+ borderRadius: "6px",
696
+ boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)"
697
+ }
698
+ }
699
+ ),
700
+ showLegend && /* @__PURE__ */ jsx4(RechartsLegend4, { verticalAlign: "bottom", height: 36 }),
701
+ label && variant === "donut" && /* @__PURE__ */ jsx4(
702
+ "text",
703
+ {
704
+ x: "50%",
705
+ y: "50%",
706
+ textAnchor: "middle",
707
+ dominantBaseline: "middle",
708
+ className: "fill-gray-900 text-lg font-semibold dark:fill-gray-50",
709
+ children: label
710
+ }
711
+ )
712
+ ] }) }) });
713
+ }
714
+ );
715
+ DonutChart.displayName = "DonutChart";
716
+
717
+ // src/insights/components/charts/transaction-chart.tsx
718
+ import * as React5 from "react";
719
+ import { twMerge as twMerge5 } from "tailwind-merge";
720
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
721
+ var InfoIcon = ({ className }) => /* @__PURE__ */ jsx5(
722
+ "svg",
723
+ {
724
+ xmlns: "http://www.w3.org/2000/svg",
725
+ fill: "none",
726
+ viewBox: "0 0 24 24",
727
+ strokeWidth: 1.5,
728
+ stroke: "currentColor",
729
+ className,
730
+ "aria-hidden": "true",
731
+ children: /* @__PURE__ */ jsx5(
732
+ "path",
733
+ {
734
+ strokeLinecap: "round",
735
+ strokeLinejoin: "round",
736
+ d: "M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"
737
+ }
738
+ )
739
+ }
740
+ );
741
+ function formatCurrency(value, maxFractionDigits = 0) {
742
+ return new Intl.NumberFormat("en-US", {
743
+ style: "currency",
744
+ currency: "USD",
745
+ maximumFractionDigits: maxFractionDigits
746
+ }).format(value);
747
+ }
748
+ function formatNumber(value) {
749
+ return new Intl.NumberFormat("en-US").format(value);
750
+ }
751
+ var chartConfigs = {
752
+ amount: {
753
+ title: "Total Transaction Amount",
754
+ tooltipContent: "Total amount of transactions for the selected period and amount range.",
755
+ color: "blue",
756
+ valueFormatter: (number) => formatCurrency(number),
757
+ xValueFormatter: (dateString) => {
758
+ const date = new Date(dateString);
759
+ return date.toLocaleDateString("en-GB", {
760
+ day: "2-digit",
761
+ month: "2-digit",
762
+ year: "2-digit"
763
+ });
764
+ }
765
+ },
766
+ count: {
767
+ title: "Transaction Count",
768
+ tooltipContent: "Total number of transactions for the selected period and amount range.",
769
+ color: "blue",
770
+ valueFormatter: (number) => formatNumber(number),
771
+ xValueFormatter: (dateString) => {
772
+ const date = new Date(dateString);
773
+ return date.toLocaleDateString("en-GB", {
774
+ day: "2-digit",
775
+ month: "2-digit",
776
+ year: "2-digit"
777
+ });
778
+ }
779
+ },
780
+ category: {
781
+ title: "Top 5 Categories by Transaction Amount",
782
+ tooltipContent: "Total amount of transactions for the top 5 categories in the selected period and amount range.",
783
+ valueFormatter: (number) => formatCurrency(number),
784
+ layout: "vertical",
785
+ color: "emerald"
786
+ },
787
+ merchant: {
788
+ title: "Top 5 Merchants by Transaction Amount",
789
+ tooltipContent: "Total amount of transactions for the top 5 merchants in the selected period and amount range.",
790
+ valueFormatter: (number) => formatCurrency(number),
791
+ layout: "vertical",
792
+ color: "orange"
793
+ }
794
+ };
795
+ var TransactionChart = React5.forwardRef(
796
+ ({
797
+ type,
798
+ data,
799
+ yAxisWidth,
800
+ showYAxis = true,
801
+ title,
802
+ tooltipContent,
803
+ className,
804
+ ...other
805
+ }, ref) => {
806
+ const config = chartConfigs[type];
807
+ const chartTitle = title || config.title;
808
+ const chartTooltip = tooltipContent || config.tooltipContent;
809
+ const totalValue = React5.useMemo(
810
+ () => Math.round(data.reduce((sum, item) => sum + item.value, 0)),
811
+ [data]
812
+ );
813
+ return /* @__PURE__ */ jsxs5("div", { ref, className: twMerge5("w-full", className), ...other, children: [
814
+ /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
815
+ /* @__PURE__ */ jsx5(
816
+ "h2",
817
+ {
818
+ id: `${type}-chart-title`,
819
+ className: "text-sm text-gray-600 dark:text-gray-400",
820
+ children: chartTitle
821
+ }
822
+ ),
823
+ /* @__PURE__ */ jsx5(
824
+ "button",
825
+ {
826
+ type: "button",
827
+ className: "inline-flex items-center",
828
+ title: chartTooltip,
829
+ children: /* @__PURE__ */ jsx5(InfoIcon, { className: "size-4 text-gray-600 dark:text-gray-400" })
830
+ }
831
+ )
832
+ ] }) }),
833
+ /* @__PURE__ */ jsx5(
834
+ "p",
835
+ {
836
+ className: "mt-2 text-2xl font-semibold text-gray-900 dark:text-gray-50",
837
+ "aria-live": "polite",
838
+ children: config.valueFormatter(totalValue)
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsx5(
842
+ BarChartVariant,
843
+ {
844
+ data,
845
+ index: "key",
846
+ categories: ["value"],
847
+ showLegend: false,
848
+ colors: [config.color],
849
+ yAxisWidth,
850
+ valueFormatter: config.valueFormatter,
851
+ xValueFormatter: config.xValueFormatter,
852
+ showYAxis,
853
+ className: "mt-6 h-48",
854
+ layout: config.layout,
855
+ barCategoryGap: "6%",
856
+ "aria-labelledby": `${type}-chart-title`,
857
+ role: "figure",
858
+ "aria-roledescription": "chart"
859
+ }
860
+ )
861
+ ] });
862
+ }
863
+ );
864
+ TransactionChart.displayName = "TransactionChart";
865
+
866
+ // src/insights/components/kpi/kpi-card.tsx
867
+ import { twMerge as twMerge6 } from "tailwind-merge";
868
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
869
+ var icons = {
870
+ users: ({ className }) => /* @__PURE__ */ jsx6(
871
+ "svg",
872
+ {
873
+ className,
874
+ fill: "none",
875
+ viewBox: "0 0 24 24",
876
+ stroke: "currentColor",
877
+ strokeWidth: 1.5,
878
+ children: /* @__PURE__ */ jsx6(
879
+ "path",
880
+ {
881
+ strokeLinecap: "round",
882
+ strokeLinejoin: "round",
883
+ d: "M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"
884
+ }
885
+ )
886
+ }
887
+ ),
888
+ revenue: ({ className }) => /* @__PURE__ */ jsx6(
889
+ "svg",
890
+ {
891
+ className,
892
+ fill: "none",
893
+ viewBox: "0 0 24 24",
894
+ stroke: "currentColor",
895
+ strokeWidth: 1.5,
896
+ children: /* @__PURE__ */ jsx6(
897
+ "path",
898
+ {
899
+ strokeLinecap: "round",
900
+ strokeLinejoin: "round",
901
+ d: "M12 6v12m-3-2.818l.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.879 4.006 0l.415.33M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
902
+ }
903
+ )
904
+ }
905
+ ),
906
+ chart: ({ className }) => /* @__PURE__ */ jsx6(
907
+ "svg",
908
+ {
909
+ className,
910
+ fill: "none",
911
+ viewBox: "0 0 24 24",
912
+ stroke: "currentColor",
913
+ strokeWidth: 1.5,
914
+ children: /* @__PURE__ */ jsx6(
915
+ "path",
916
+ {
917
+ strokeLinecap: "round",
918
+ strokeLinejoin: "round",
919
+ d: "M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z"
920
+ }
921
+ )
922
+ }
923
+ )
924
+ };
925
+ function getTrendColorClass(trend) {
926
+ switch (trend) {
927
+ case "up":
928
+ return "text-emerald-500";
929
+ case "down":
930
+ return "text-red-500";
931
+ case "neutral":
932
+ default:
933
+ return "text-gray-500";
934
+ }
935
+ }
936
+ function formatChange(change) {
937
+ if (change === void 0) return "";
938
+ const sign = change > 0 ? "+" : "";
939
+ return `${sign}${change}%`;
940
+ }
941
+ function getVariantClasses(variant) {
942
+ switch (variant) {
943
+ case "outlined":
944
+ return "border border-gray-200 dark:border-gray-800";
945
+ case "elevated":
946
+ return "shadow-lg";
947
+ case "ghost":
948
+ return "bg-transparent";
949
+ default:
950
+ return "";
951
+ }
952
+ }
953
+ function KPICard({
954
+ label,
955
+ value,
956
+ previousValue,
957
+ change,
958
+ trend,
959
+ prefix = "",
960
+ suffix = "",
961
+ target,
962
+ format: _format = "number",
963
+ icon,
964
+ title: _title,
965
+ description: _description,
966
+ size: _size,
967
+ variant = "default",
968
+ loading = false,
969
+ error,
970
+ className
971
+ }) {
972
+ const displayValue = typeof value === "number" ? String(value) : value;
973
+ const formattedValue = `${prefix}${displayValue}${suffix}`;
974
+ const IconComponent = icon ? icons[icon] : null;
975
+ if (loading) {
976
+ return /* @__PURE__ */ jsx6(
977
+ "div",
978
+ {
979
+ "data-testid": "kpi-skeleton",
980
+ className: twMerge6(
981
+ "relative w-full rounded-lg border p-6 text-left",
982
+ "bg-white dark:bg-gray-950",
983
+ "border-gray-200 dark:border-gray-900",
984
+ getVariantClasses(variant),
985
+ className
986
+ ),
987
+ "aria-busy": "true",
988
+ "aria-label": `Loading ${label}`,
989
+ children: /* @__PURE__ */ jsxs6("div", { className: "animate-pulse", children: [
990
+ /* @__PURE__ */ jsx6("div", { className: "h-4 w-24 bg-gray-200 dark:bg-gray-800 rounded mb-3" }),
991
+ /* @__PURE__ */ jsx6("div", { className: "h-8 w-32 bg-gray-200 dark:bg-gray-800 rounded mb-2" }),
992
+ /* @__PURE__ */ jsx6("div", { className: "h-4 w-16 bg-gray-200 dark:bg-gray-800 rounded" })
993
+ ] })
994
+ }
995
+ );
996
+ }
997
+ return /* @__PURE__ */ jsxs6(
998
+ "div",
999
+ {
1000
+ "data-testid": "kpi-card",
1001
+ className: twMerge6(
1002
+ "relative w-full rounded-lg border p-6 text-left shadow-sm",
1003
+ "bg-white dark:bg-gray-950",
1004
+ "border-gray-200 dark:border-gray-900",
1005
+ getVariantClasses(variant),
1006
+ className
1007
+ ),
1008
+ "aria-label": `${label}: ${formattedValue}`,
1009
+ children: [
1010
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
1011
+ IconComponent && /* @__PURE__ */ jsx6("div", { "data-testid": "kpi-icon", className: "flex-shrink-0", children: /* @__PURE__ */ jsx6(IconComponent, { className: "h-5 w-5 text-gray-500 dark:text-gray-400" }) }),
1012
+ /* @__PURE__ */ jsx6("h3", { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: label })
1013
+ ] }),
1014
+ /* @__PURE__ */ jsx6("p", { className: "mt-2 text-3xl font-semibold tracking-tight text-gray-900 dark:text-gray-50", children: formattedValue }),
1015
+ (trend || change !== void 0) && /* @__PURE__ */ jsxs6("div", { className: "mt-2 flex items-center gap-2", children: [
1016
+ /* @__PURE__ */ jsxs6(
1017
+ "span",
1018
+ {
1019
+ "data-testid": "trend-indicator",
1020
+ className: twMerge6(
1021
+ "inline-flex items-center text-sm font-medium",
1022
+ getTrendColorClass(trend)
1023
+ ),
1024
+ children: [
1025
+ trend === "up" && /* @__PURE__ */ jsx6(
1026
+ "svg",
1027
+ {
1028
+ className: "h-4 w-4 mr-0.5",
1029
+ fill: "none",
1030
+ viewBox: "0 0 24 24",
1031
+ stroke: "currentColor",
1032
+ strokeWidth: 2,
1033
+ children: /* @__PURE__ */ jsx6(
1034
+ "path",
1035
+ {
1036
+ strokeLinecap: "round",
1037
+ strokeLinejoin: "round",
1038
+ d: "M7 11l5-5m0 0l5 5m-5-5v12"
1039
+ }
1040
+ )
1041
+ }
1042
+ ),
1043
+ trend === "down" && /* @__PURE__ */ jsx6(
1044
+ "svg",
1045
+ {
1046
+ className: "h-4 w-4 mr-0.5",
1047
+ fill: "none",
1048
+ viewBox: "0 0 24 24",
1049
+ stroke: "currentColor",
1050
+ strokeWidth: 2,
1051
+ children: /* @__PURE__ */ jsx6(
1052
+ "path",
1053
+ {
1054
+ strokeLinecap: "round",
1055
+ strokeLinejoin: "round",
1056
+ d: "M17 13l-5 5m0 0l-5-5m5 5V6"
1057
+ }
1058
+ )
1059
+ }
1060
+ ),
1061
+ formatChange(change)
1062
+ ]
1063
+ }
1064
+ ),
1065
+ previousValue !== void 0 && /* @__PURE__ */ jsxs6("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
1066
+ "from ",
1067
+ previousValue
1068
+ ] })
1069
+ ] }),
1070
+ target !== void 0 && /* @__PURE__ */ jsx6("div", { className: "mt-2", children: /* @__PURE__ */ jsxs6("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
1071
+ "target: ",
1072
+ target
1073
+ ] }) }),
1074
+ error && /* @__PURE__ */ jsx6("div", { className: "mt-2", children: /* @__PURE__ */ jsx6("span", { className: "text-sm text-red-500", children: error }) })
1075
+ ]
1076
+ }
1077
+ );
1078
+ }
1079
+
1080
+ // src/insights/components/tables/transactions-table.tsx
1081
+ import {
1082
+ flexRender,
1083
+ getCoreRowModel,
1084
+ getPaginationRowModel,
1085
+ getSortedRowModel,
1086
+ useReactTable
1087
+ } from "@tanstack/react-table";
1088
+ import * as React6 from "react";
1089
+ import { twMerge as twMerge7 } from "tailwind-merge";
1090
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1091
+ var statusVariants = {
1092
+ completed: "bg-emerald-50 text-emerald-900 ring-emerald-600/30 dark:bg-emerald-400/10 dark:text-emerald-400 dark:ring-emerald-400/20",
1093
+ pending: "bg-gray-50 text-gray-900 ring-gray-500/30 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20",
1094
+ failed: "bg-rose-50 text-rose-900 ring-rose-600/20 dark:bg-rose-400/10 dark:text-rose-500 dark:ring-rose-400/20",
1095
+ refunded: "bg-orange-50 text-orange-900 ring-orange-600/30 dark:bg-orange-400/10 dark:text-orange-500 dark:ring-orange-400/20"
1096
+ };
1097
+ function StatusBadge({ status }) {
1098
+ return /* @__PURE__ */ jsx7(
1099
+ "span",
1100
+ {
1101
+ className: twMerge7(
1102
+ "inline-flex items-center gap-x-1 whitespace-nowrap rounded-md px-2 py-1 text-xs font-medium ring-1 ring-inset",
1103
+ statusVariants[status]
1104
+ ),
1105
+ children: status
1106
+ }
1107
+ );
1108
+ }
1109
+ function formatCurrency2(amount, currency = "USD") {
1110
+ const absAmount = Math.abs(amount);
1111
+ const formatted = new Intl.NumberFormat("en-US", {
1112
+ style: "currency",
1113
+ currency,
1114
+ minimumFractionDigits: 2,
1115
+ maximumFractionDigits: 2
1116
+ }).format(absAmount);
1117
+ return amount < 0 ? `-${formatted}` : formatted;
1118
+ }
1119
+ function formatDate(dateString) {
1120
+ const date = new Date(dateString);
1121
+ return date.toLocaleDateString("en-US", {
1122
+ month: "short",
1123
+ day: "numeric",
1124
+ year: "numeric"
1125
+ });
1126
+ }
1127
+ function createColumns(currency = "USD") {
1128
+ return [
1129
+ {
1130
+ accessorKey: "date",
1131
+ header: "Date",
1132
+ cell: ({ getValue }) => {
1133
+ const date = getValue();
1134
+ return /* @__PURE__ */ jsx7("span", { className: "tabular-nums text-gray-900 dark:text-gray-50", children: formatDate(date) });
1135
+ }
1136
+ },
1137
+ {
1138
+ accessorKey: "description",
1139
+ header: "Description",
1140
+ cell: ({ getValue }) => /* @__PURE__ */ jsx7("span", { className: "text-gray-700 dark:text-gray-300", children: getValue() })
1141
+ },
1142
+ {
1143
+ accessorKey: "amount",
1144
+ header: "Amount",
1145
+ cell: ({ getValue, row }) => {
1146
+ const amount = getValue();
1147
+ const isNegative = row.original.type === "debit" || amount < 0;
1148
+ const displayAmount = isNegative && amount > 0 ? -amount : amount;
1149
+ return /* @__PURE__ */ jsx7(
1150
+ "span",
1151
+ {
1152
+ className: twMerge7(
1153
+ "tabular-nums font-medium",
1154
+ isNegative ? "text-rose-600 dark:text-rose-400" : "text-gray-900 dark:text-gray-50"
1155
+ ),
1156
+ children: formatCurrency2(displayAmount, currency)
1157
+ }
1158
+ );
1159
+ },
1160
+ meta: {
1161
+ className: "text-right"
1162
+ }
1163
+ },
1164
+ {
1165
+ accessorKey: "status",
1166
+ header: "Status",
1167
+ cell: ({ getValue }) => /* @__PURE__ */ jsx7(StatusBadge, { status: getValue() })
1168
+ }
1169
+ ];
1170
+ }
1171
+ function LoadingSkeleton() {
1172
+ return /* @__PURE__ */ jsx7("div", { "data-testid": "transactions-table-loading", className: "space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs7("div", { className: "animate-pulse flex space-x-4", children: [
1173
+ /* @__PURE__ */ jsx7("div", { className: "h-4 bg-gray-200 dark:bg-gray-700 rounded w-24" }),
1174
+ /* @__PURE__ */ jsx7("div", { className: "h-4 bg-gray-200 dark:bg-gray-700 rounded flex-1" }),
1175
+ /* @__PURE__ */ jsx7("div", { className: "h-4 bg-gray-200 dark:bg-gray-700 rounded w-20" }),
1176
+ /* @__PURE__ */ jsx7("div", { className: "h-4 bg-gray-200 dark:bg-gray-700 rounded w-16" })
1177
+ ] }, i)) });
1178
+ }
1179
+ function TransactionsTable(props) {
1180
+ const {
1181
+ transactions,
1182
+ title,
1183
+ currency = "USD",
1184
+ pageSize = 10,
1185
+ emptyMessage = "No transactions",
1186
+ loading = false,
1187
+ className
1188
+ } = props;
1189
+ const columns = React6.useMemo(() => createColumns(currency), [currency]);
1190
+ const table = useReactTable({
1191
+ data: transactions,
1192
+ columns,
1193
+ initialState: {
1194
+ pagination: {
1195
+ pageIndex: 0,
1196
+ pageSize
1197
+ }
1198
+ },
1199
+ getCoreRowModel: getCoreRowModel(),
1200
+ getPaginationRowModel: getPaginationRowModel(),
1201
+ getSortedRowModel: getSortedRowModel()
1202
+ });
1203
+ const totalRows = transactions.length;
1204
+ const currentPage = table.getState().pagination.pageIndex;
1205
+ const firstRowIndex = currentPage * pageSize + 1;
1206
+ const lastRowIndex = Math.min(totalRows, firstRowIndex + pageSize - 1);
1207
+ if (loading) {
1208
+ return /* @__PURE__ */ jsxs7("div", { className: twMerge7("space-y-4", className), children: [
1209
+ title && /* @__PURE__ */ jsx7("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-50", children: title }),
1210
+ /* @__PURE__ */ jsx7(LoadingSkeleton, {})
1211
+ ] });
1212
+ }
1213
+ return /* @__PURE__ */ jsxs7("div", { className: twMerge7("space-y-4", className), children: [
1214
+ title && /* @__PURE__ */ jsx7("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-50", children: title }),
1215
+ /* @__PURE__ */ jsx7("div", { className: "relative overflow-hidden overflow-x-auto", children: /* @__PURE__ */ jsxs7("table", { className: "w-full caption-bottom border-b border-gray-200 dark:border-gray-800", children: [
1216
+ /* @__PURE__ */ jsx7("thead", { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx7(
1217
+ "tr",
1218
+ {
1219
+ className: "border-y border-gray-200 dark:border-gray-800",
1220
+ children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx7(
1221
+ "th",
1222
+ {
1223
+ className: twMerge7(
1224
+ "border-b px-4 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-50 border-gray-200 dark:border-gray-800",
1225
+ header.column.columnDef.meta?.className
1226
+ ),
1227
+ children: flexRender(
1228
+ header.column.columnDef.header,
1229
+ header.getContext()
1230
+ )
1231
+ },
1232
+ header.id
1233
+ ))
1234
+ },
1235
+ headerGroup.id
1236
+ )) }),
1237
+ /* @__PURE__ */ jsx7("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-800", children: table.getRowModel().rows.length > 0 ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx7(
1238
+ "tr",
1239
+ {
1240
+ className: "hover:bg-gray-50 hover:dark:bg-gray-900",
1241
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx7(
1242
+ "td",
1243
+ {
1244
+ className: twMerge7(
1245
+ "p-4 text-sm text-gray-600 dark:text-gray-400",
1246
+ cell.column.columnDef.meta?.className
1247
+ ),
1248
+ children: flexRender(
1249
+ cell.column.columnDef.cell,
1250
+ cell.getContext()
1251
+ )
1252
+ },
1253
+ cell.id
1254
+ ))
1255
+ },
1256
+ row.id
1257
+ )) : /* @__PURE__ */ jsx7("tr", { children: /* @__PURE__ */ jsx7(
1258
+ "td",
1259
+ {
1260
+ colSpan: columns.length,
1261
+ className: "h-24 text-center text-sm text-gray-500 dark:text-gray-400",
1262
+ children: emptyMessage
1263
+ }
1264
+ ) }) })
1265
+ ] }) }),
1266
+ totalRows > pageSize && /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between", children: [
1267
+ /* @__PURE__ */ jsxs7("div", { className: "text-sm tabular-nums text-gray-500", children: [
1268
+ "Showing ",
1269
+ firstRowIndex,
1270
+ "-",
1271
+ lastRowIndex,
1272
+ " of ",
1273
+ totalRows
1274
+ ] }),
1275
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-x-1.5", children: [
1276
+ /* @__PURE__ */ jsx7(
1277
+ "button",
1278
+ {
1279
+ onClick: () => table.setPageIndex(0),
1280
+ disabled: !table.getCanPreviousPage(),
1281
+ className: "p-1.5 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 disabled:opacity-50 disabled:cursor-not-allowed",
1282
+ "aria-label": "First page",
1283
+ children: /* @__PURE__ */ jsx7(
1284
+ "svg",
1285
+ {
1286
+ className: "size-4",
1287
+ fill: "none",
1288
+ viewBox: "0 0 24 24",
1289
+ strokeWidth: 1.5,
1290
+ stroke: "currentColor",
1291
+ children: /* @__PURE__ */ jsx7(
1292
+ "path",
1293
+ {
1294
+ strokeLinecap: "round",
1295
+ strokeLinejoin: "round",
1296
+ d: "M18.75 19.5l-7.5-7.5 7.5-7.5M11.25 19.5l-7.5-7.5 7.5-7.5"
1297
+ }
1298
+ )
1299
+ }
1300
+ )
1301
+ }
1302
+ ),
1303
+ /* @__PURE__ */ jsx7(
1304
+ "button",
1305
+ {
1306
+ onClick: () => table.previousPage(),
1307
+ disabled: !table.getCanPreviousPage(),
1308
+ className: "p-1.5 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 disabled:opacity-50 disabled:cursor-not-allowed",
1309
+ "aria-label": "Previous page",
1310
+ children: /* @__PURE__ */ jsx7(
1311
+ "svg",
1312
+ {
1313
+ className: "size-4",
1314
+ fill: "none",
1315
+ viewBox: "0 0 24 24",
1316
+ strokeWidth: 1.5,
1317
+ stroke: "currentColor",
1318
+ children: /* @__PURE__ */ jsx7(
1319
+ "path",
1320
+ {
1321
+ strokeLinecap: "round",
1322
+ strokeLinejoin: "round",
1323
+ d: "M15.75 19.5L8.25 12l7.5-7.5"
1324
+ }
1325
+ )
1326
+ }
1327
+ )
1328
+ }
1329
+ ),
1330
+ /* @__PURE__ */ jsx7(
1331
+ "button",
1332
+ {
1333
+ onClick: () => table.nextPage(),
1334
+ disabled: !table.getCanNextPage(),
1335
+ className: "p-1.5 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 disabled:opacity-50 disabled:cursor-not-allowed",
1336
+ "aria-label": "Next page",
1337
+ children: /* @__PURE__ */ jsx7(
1338
+ "svg",
1339
+ {
1340
+ className: "size-4",
1341
+ fill: "none",
1342
+ viewBox: "0 0 24 24",
1343
+ strokeWidth: 1.5,
1344
+ stroke: "currentColor",
1345
+ children: /* @__PURE__ */ jsx7(
1346
+ "path",
1347
+ {
1348
+ strokeLinecap: "round",
1349
+ strokeLinejoin: "round",
1350
+ d: "M8.25 4.5l7.5 7.5-7.5 7.5"
1351
+ }
1352
+ )
1353
+ }
1354
+ )
1355
+ }
1356
+ ),
1357
+ /* @__PURE__ */ jsx7(
1358
+ "button",
1359
+ {
1360
+ onClick: () => table.setPageIndex(table.getPageCount() - 1),
1361
+ disabled: !table.getCanNextPage(),
1362
+ className: "p-1.5 text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 disabled:opacity-50 disabled:cursor-not-allowed",
1363
+ "aria-label": "Last page",
1364
+ children: /* @__PURE__ */ jsx7(
1365
+ "svg",
1366
+ {
1367
+ className: "size-4",
1368
+ fill: "none",
1369
+ viewBox: "0 0 24 24",
1370
+ strokeWidth: 1.5,
1371
+ stroke: "currentColor",
1372
+ children: /* @__PURE__ */ jsx7(
1373
+ "path",
1374
+ {
1375
+ strokeLinecap: "round",
1376
+ strokeLinejoin: "round",
1377
+ d: "M5.25 4.5l7.5 7.5-7.5 7.5M12.75 4.5l7.5 7.5-7.5 7.5"
1378
+ }
1379
+ )
1380
+ }
1381
+ )
1382
+ }
1383
+ )
1384
+ ] })
1385
+ ] })
1386
+ ] });
1387
+ }
1388
+ export {
1389
+ AreaChart,
1390
+ BarChart,
1391
+ BarChartVariant,
1392
+ DonutChart,
1393
+ KPICard,
1394
+ TransactionChart,
1395
+ TransactionsTable
1396
+ };
1397
+ //# sourceMappingURL=index.js.map