@pagamio/frontend-commons-lib 0.8.213 → 0.8.214
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/TanstackQueryProvider.d.ts +146 -0
- package/lib/api/TanstackQueryProvider.js +140 -0
- package/lib/api/index.d.ts +2 -0
- package/lib/api/index.js +2 -0
- package/lib/api/tanstackQuery.d.ts +249 -0
- package/lib/api/tanstackQuery.js +299 -0
- package/lib/components/layout/Sidebar.js +47 -24
- package/lib/components/ui/Sheet.d.ts +1 -1
- package/lib/context/SidebarContext.d.ts +10 -0
- package/lib/dashboard-visuals-v2/DashboardWrapperV2.d.ts +81 -0
- package/lib/dashboard-visuals-v2/DashboardWrapperV2.js +217 -0
- package/lib/dashboard-visuals-v2/cards/CardGrid.d.ts +22 -0
- package/lib/dashboard-visuals-v2/cards/CardGrid.js +27 -0
- package/lib/dashboard-visuals-v2/cards/InfoCard.d.ts +7 -0
- package/lib/dashboard-visuals-v2/cards/InfoCard.js +26 -0
- package/lib/dashboard-visuals-v2/cards/MetricCard.d.ts +7 -0
- package/lib/dashboard-visuals-v2/cards/MetricCard.js +37 -0
- package/lib/dashboard-visuals-v2/cards/StatCard.d.ts +7 -0
- package/lib/dashboard-visuals-v2/cards/StatCard.js +92 -0
- package/lib/dashboard-visuals-v2/cards/TopItemsCard.d.ts +7 -0
- package/lib/dashboard-visuals-v2/cards/TopItemsCard.js +34 -0
- package/lib/dashboard-visuals-v2/cards/TransactionListCard.d.ts +7 -0
- package/lib/dashboard-visuals-v2/cards/TransactionListCard.js +24 -0
- package/lib/dashboard-visuals-v2/cards/index.d.ts +9 -0
- package/lib/dashboard-visuals-v2/cards/index.js +9 -0
- package/lib/dashboard-visuals-v2/charts/AreaChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/AreaChart.js +124 -0
- package/lib/dashboard-visuals-v2/charts/BarChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/BarChart.js +106 -0
- package/lib/dashboard-visuals-v2/charts/BaseChart.d.ts +61 -0
- package/lib/dashboard-visuals-v2/charts/BaseChart.js +173 -0
- package/lib/dashboard-visuals-v2/charts/DonutChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/DonutChart.js +108 -0
- package/lib/dashboard-visuals-v2/charts/HeatmapChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/HeatmapChart.js +101 -0
- package/lib/dashboard-visuals-v2/charts/LineChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/LineChart.js +109 -0
- package/lib/dashboard-visuals-v2/charts/MixedChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/MixedChart.js +106 -0
- package/lib/dashboard-visuals-v2/charts/PieChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/PieChart.js +10 -0
- package/lib/dashboard-visuals-v2/charts/RadialChart.d.ts +7 -0
- package/lib/dashboard-visuals-v2/charts/RadialChart.js +72 -0
- package/lib/dashboard-visuals-v2/charts/index.d.ts +12 -0
- package/lib/dashboard-visuals-v2/charts/index.js +12 -0
- package/lib/dashboard-visuals-v2/components/DataFetchingVisual.d.ts +0 -0
- package/lib/dashboard-visuals-v2/components/DataFetchingVisual.js +1 -0
- package/lib/dashboard-visuals-v2/components/index.d.ts +0 -0
- package/lib/dashboard-visuals-v2/components/index.js +1 -0
- package/lib/dashboard-visuals-v2/hooks/index.d.ts +4 -0
- package/lib/dashboard-visuals-v2/hooks/index.js +4 -0
- package/lib/dashboard-visuals-v2/hooks/useChartData.d.ts +72 -0
- package/lib/dashboard-visuals-v2/hooks/useChartData.js +122 -0
- package/lib/dashboard-visuals-v2/index.d.ts +10 -0
- package/lib/dashboard-visuals-v2/index.js +16 -0
- package/lib/dashboard-visuals-v2/types/card.types.d.ts +237 -0
- package/lib/dashboard-visuals-v2/types/card.types.js +30 -0
- package/lib/dashboard-visuals-v2/types/chart.types.d.ts +308 -0
- package/lib/dashboard-visuals-v2/types/chart.types.js +25 -0
- package/lib/dashboard-visuals-v2/types/index.d.ts +6 -0
- package/lib/dashboard-visuals-v2/types/index.js +6 -0
- package/lib/dashboard-visuals-v2/utils/index.d.ts +0 -0
- package/lib/dashboard-visuals-v2/utils/index.js +1 -0
- package/lib/dashboard-visuals-v2/utils/propsTransformer.d.ts +0 -0
- package/lib/dashboard-visuals-v2/utils/propsTransformer.js +1 -0
- package/lib/dashboard-visuals-v2/visualRegistry.d.ts +59 -0
- package/lib/dashboard-visuals-v2/visualRegistry.js +110 -0
- package/lib/data-table-v2/DataTable.d.ts +7 -0
- package/lib/data-table-v2/DataTable.js +206 -0
- package/lib/data-table-v2/components/DataTableBody.d.ts +19 -0
- package/lib/data-table-v2/components/DataTableBody.js +20 -0
- package/lib/data-table-v2/components/DataTableEmpty.d.ts +17 -0
- package/lib/data-table-v2/components/DataTableEmpty.js +13 -0
- package/lib/data-table-v2/components/DataTableError.d.ts +16 -0
- package/lib/data-table-v2/components/DataTableError.js +14 -0
- package/lib/data-table-v2/components/DataTableHeader.d.ts +15 -0
- package/lib/data-table-v2/components/DataTableHeader.js +31 -0
- package/lib/data-table-v2/components/DataTableLoading.d.ts +14 -0
- package/lib/data-table-v2/components/DataTableLoading.js +19 -0
- package/lib/data-table-v2/components/DataTablePagination.d.ts +36 -0
- package/lib/data-table-v2/components/DataTablePagination.js +20 -0
- package/lib/data-table-v2/components/DataTableRowActions.d.ts +13 -0
- package/lib/data-table-v2/components/DataTableRowActions.js +57 -0
- package/lib/data-table-v2/components/DataTableSearch.d.ts +19 -0
- package/lib/data-table-v2/components/DataTableSearch.js +33 -0
- package/lib/data-table-v2/components/DataTableToolbar.d.ts +54 -0
- package/lib/data-table-v2/components/DataTableToolbar.js +28 -0
- package/lib/data-table-v2/components/index.d.ts +12 -0
- package/lib/data-table-v2/components/index.js +12 -0
- package/lib/data-table-v2/hooks/index.d.ts +4 -0
- package/lib/data-table-v2/hooks/index.js +4 -0
- package/lib/data-table-v2/hooks/useTableData.d.ts +118 -0
- package/lib/data-table-v2/hooks/useTableData.js +210 -0
- package/lib/data-table-v2/index.d.ts +9 -0
- package/lib/data-table-v2/index.js +12 -0
- package/lib/data-table-v2/types/index.d.ts +296 -0
- package/lib/data-table-v2/types/index.js +1 -0
- package/lib/data-table-v2/utils/export.d.ts +26 -0
- package/lib/data-table-v2/utils/export.js +92 -0
- package/lib/data-table-v2/utils/index.d.ts +4 -0
- package/lib/data-table-v2/utils/index.js +4 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +23 -0
- package/lib/styles.css +212 -0
- package/package.json +7 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { BaseChart } from './BaseChart';
|
|
4
|
+
/**
|
|
5
|
+
* Area Chart component
|
|
6
|
+
* Line chart with filled area underneath
|
|
7
|
+
*/
|
|
8
|
+
export function AreaChart({ data = [], series: providedSeries, categories: providedCategories, xKey = 'label', yKey = 'value', yKeys, seriesNames, curve = 'smooth', strokeWidth = 2, showMarkers = false, markerSize = 4, fillOpacity = 0.3, gradient = true, style, tooltip, xAxis, yAxis, apexOptions, onDataPointClick, ...baseProps }) {
|
|
9
|
+
// Build series from data
|
|
10
|
+
const chartSeries = useMemo(() => {
|
|
11
|
+
if (providedSeries) {
|
|
12
|
+
return providedSeries.map((s) => ({
|
|
13
|
+
name: s.name,
|
|
14
|
+
data: s.data,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
if (yKeys && yKeys.length > 0) {
|
|
18
|
+
return yKeys.map((key, index) => ({
|
|
19
|
+
name: seriesNames?.[index] ?? String(key),
|
|
20
|
+
data: data.map((item) => Number(item[key]) || 0),
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
name: seriesNames?.[0] ?? String(yKey),
|
|
26
|
+
data: data.map((item) => Number(item[yKey]) || 0),
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
}, [providedSeries, data, yKey, yKeys, seriesNames]);
|
|
30
|
+
// Build categories from data
|
|
31
|
+
const categories = useMemo(() => {
|
|
32
|
+
if (providedCategories)
|
|
33
|
+
return providedCategories;
|
|
34
|
+
return data.map((item) => String(item[xKey] ?? ''));
|
|
35
|
+
}, [providedCategories, data, xKey]);
|
|
36
|
+
const isEmpty = chartSeries.every((s) => s.data.length === 0);
|
|
37
|
+
const curveMap = {
|
|
38
|
+
smooth: 'smooth',
|
|
39
|
+
straight: 'straight',
|
|
40
|
+
stepline: 'stepline',
|
|
41
|
+
};
|
|
42
|
+
const options = useMemo(() => ({
|
|
43
|
+
chart: {
|
|
44
|
+
events: onDataPointClick
|
|
45
|
+
? {
|
|
46
|
+
markerClick: (event, chartContext, config) => {
|
|
47
|
+
void event;
|
|
48
|
+
void chartContext;
|
|
49
|
+
const { dataPointIndex, seriesIndex } = config;
|
|
50
|
+
onDataPointClick(dataPointIndex, seriesIndex, data[dataPointIndex]);
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
: undefined,
|
|
54
|
+
},
|
|
55
|
+
stroke: {
|
|
56
|
+
curve: curveMap[curve] ?? 'smooth',
|
|
57
|
+
width: strokeWidth,
|
|
58
|
+
},
|
|
59
|
+
markers: {
|
|
60
|
+
size: showMarkers ? markerSize : 0,
|
|
61
|
+
strokeWidth: 2,
|
|
62
|
+
hover: {
|
|
63
|
+
size: markerSize + 2,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
fill: gradient
|
|
67
|
+
? {
|
|
68
|
+
type: 'gradient',
|
|
69
|
+
gradient: {
|
|
70
|
+
shadeIntensity: 1,
|
|
71
|
+
opacityFrom: fillOpacity + 0.2,
|
|
72
|
+
opacityTo: 0.1,
|
|
73
|
+
stops: [0, 90, 100],
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
: {
|
|
77
|
+
type: 'solid',
|
|
78
|
+
opacity: fillOpacity,
|
|
79
|
+
},
|
|
80
|
+
xaxis: {
|
|
81
|
+
categories,
|
|
82
|
+
title: xAxis?.title ? { text: xAxis.title } : undefined,
|
|
83
|
+
labels: {
|
|
84
|
+
show: xAxis?.show !== false,
|
|
85
|
+
formatter: xAxis?.formatter,
|
|
86
|
+
},
|
|
87
|
+
type: xAxis?.type,
|
|
88
|
+
},
|
|
89
|
+
yaxis: {
|
|
90
|
+
title: yAxis?.title ? { text: yAxis.title } : undefined,
|
|
91
|
+
labels: {
|
|
92
|
+
show: yAxis?.show !== false,
|
|
93
|
+
formatter: yAxis?.formatter,
|
|
94
|
+
},
|
|
95
|
+
min: yAxis?.min,
|
|
96
|
+
max: yAxis?.max,
|
|
97
|
+
tickAmount: yAxis?.tickAmount,
|
|
98
|
+
},
|
|
99
|
+
tooltip: {
|
|
100
|
+
enabled: tooltip?.enabled !== false,
|
|
101
|
+
shared: tooltip?.shared ?? true,
|
|
102
|
+
y: {
|
|
103
|
+
formatter: tooltip?.valueFormatter,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
...apexOptions,
|
|
107
|
+
}), [
|
|
108
|
+
curve,
|
|
109
|
+
strokeWidth,
|
|
110
|
+
showMarkers,
|
|
111
|
+
markerSize,
|
|
112
|
+
fillOpacity,
|
|
113
|
+
gradient,
|
|
114
|
+
categories,
|
|
115
|
+
xAxis,
|
|
116
|
+
yAxis,
|
|
117
|
+
tooltip,
|
|
118
|
+
apexOptions,
|
|
119
|
+
onDataPointClick,
|
|
120
|
+
data,
|
|
121
|
+
]);
|
|
122
|
+
return (_jsx(BaseChart, { type: "area", options: options, series: chartSeries, isEmpty: isEmpty, style: style, ...baseProps }));
|
|
123
|
+
}
|
|
124
|
+
export default AreaChart;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BarChartProps, ChartDataPoint } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Bar Chart component
|
|
4
|
+
* Supports vertical/horizontal bars, stacking, and multi-series
|
|
5
|
+
*/
|
|
6
|
+
export declare function BarChart<TData extends ChartDataPoint = ChartDataPoint>({ data, series: providedSeries, categories: providedCategories, xKey, yKey, yKeys, seriesNames, horizontal, stacked, borderRadius, columnWidth, style, tooltip, xAxis, yAxis, apexOptions, onDataPointClick, ...baseProps }: BarChartProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default BarChart;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { BaseChart } from './BaseChart';
|
|
4
|
+
/**
|
|
5
|
+
* Bar Chart component
|
|
6
|
+
* Supports vertical/horizontal bars, stacking, and multi-series
|
|
7
|
+
*/
|
|
8
|
+
export function BarChart({ data = [], series: providedSeries, categories: providedCategories, xKey = 'label', yKey = 'value', yKeys, seriesNames, horizontal = false, stacked = false, borderRadius = 4, columnWidth = '60%', style, tooltip, xAxis, yAxis, apexOptions, onDataPointClick, ...baseProps }) {
|
|
9
|
+
// Build series from data
|
|
10
|
+
const chartSeries = useMemo(() => {
|
|
11
|
+
if (providedSeries) {
|
|
12
|
+
return providedSeries.map((s) => ({
|
|
13
|
+
name: s.name,
|
|
14
|
+
data: s.data,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
if (yKeys && yKeys.length > 0) {
|
|
18
|
+
// Multi-series from data
|
|
19
|
+
return yKeys.map((key, index) => ({
|
|
20
|
+
name: seriesNames?.[index] ?? String(key),
|
|
21
|
+
data: data.map((item) => Number(item[key]) || 0),
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
// Single series from data
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
name: seriesNames?.[0] ?? String(yKey),
|
|
28
|
+
data: data.map((item) => Number(item[yKey]) || 0),
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
}, [providedSeries, data, yKey, yKeys, seriesNames]);
|
|
32
|
+
// Build categories from data
|
|
33
|
+
const categories = useMemo(() => {
|
|
34
|
+
if (providedCategories)
|
|
35
|
+
return providedCategories;
|
|
36
|
+
return data.map((item) => String(item[xKey] ?? ''));
|
|
37
|
+
}, [providedCategories, data, xKey]);
|
|
38
|
+
// Check if data is empty
|
|
39
|
+
const isEmpty = chartSeries.every((s) => s.data.length === 0);
|
|
40
|
+
// Build ApexCharts options
|
|
41
|
+
const options = useMemo(() => ({
|
|
42
|
+
chart: {
|
|
43
|
+
stacked,
|
|
44
|
+
events: onDataPointClick
|
|
45
|
+
? {
|
|
46
|
+
dataPointSelection: (event, chartContext, config) => {
|
|
47
|
+
void event;
|
|
48
|
+
void chartContext;
|
|
49
|
+
const { dataPointIndex, seriesIndex } = config;
|
|
50
|
+
onDataPointClick(dataPointIndex, seriesIndex, data[dataPointIndex]);
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
: undefined,
|
|
54
|
+
},
|
|
55
|
+
plotOptions: {
|
|
56
|
+
bar: {
|
|
57
|
+
horizontal,
|
|
58
|
+
borderRadius,
|
|
59
|
+
columnWidth,
|
|
60
|
+
dataLabels: {
|
|
61
|
+
position: 'top',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
xaxis: {
|
|
66
|
+
categories,
|
|
67
|
+
title: xAxis?.title ? { text: xAxis.title } : undefined,
|
|
68
|
+
labels: {
|
|
69
|
+
show: xAxis?.show !== false,
|
|
70
|
+
formatter: xAxis?.formatter,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
yaxis: {
|
|
74
|
+
title: yAxis?.title ? { text: yAxis.title } : undefined,
|
|
75
|
+
labels: {
|
|
76
|
+
show: yAxis?.show !== false,
|
|
77
|
+
formatter: yAxis?.formatter,
|
|
78
|
+
},
|
|
79
|
+
min: yAxis?.min,
|
|
80
|
+
max: yAxis?.max,
|
|
81
|
+
tickAmount: yAxis?.tickAmount,
|
|
82
|
+
},
|
|
83
|
+
tooltip: {
|
|
84
|
+
enabled: tooltip?.enabled !== false,
|
|
85
|
+
shared: tooltip?.shared ?? true,
|
|
86
|
+
y: {
|
|
87
|
+
formatter: tooltip?.valueFormatter,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
...apexOptions,
|
|
91
|
+
}), [
|
|
92
|
+
stacked,
|
|
93
|
+
horizontal,
|
|
94
|
+
borderRadius,
|
|
95
|
+
columnWidth,
|
|
96
|
+
categories,
|
|
97
|
+
xAxis,
|
|
98
|
+
yAxis,
|
|
99
|
+
tooltip,
|
|
100
|
+
apexOptions,
|
|
101
|
+
onDataPointClick,
|
|
102
|
+
data,
|
|
103
|
+
]);
|
|
104
|
+
return _jsx(BaseChart, { type: "bar", options: options, series: chartSeries, isEmpty: isEmpty, style: style, ...baseProps });
|
|
105
|
+
}
|
|
106
|
+
export default BarChart;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Base chart wrapper component for ApexCharts
|
|
3
|
+
* Provides loading, error, and empty states with consistent styling
|
|
4
|
+
*/
|
|
5
|
+
import type { ApexOptions } from 'apexcharts';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import type { ChartStyleOptions } from '../types';
|
|
8
|
+
/**
|
|
9
|
+
* Props for BaseChart component
|
|
10
|
+
*/
|
|
11
|
+
export interface BaseChartComponentProps {
|
|
12
|
+
/** ApexCharts chart type */
|
|
13
|
+
type: 'bar' | 'line' | 'area' | 'pie' | 'donut' | 'radialBar' | 'heatmap' | 'treemap' | 'scatter';
|
|
14
|
+
/** ApexCharts options (will be merged with base options) */
|
|
15
|
+
options: ApexOptions;
|
|
16
|
+
/** ApexCharts series data */
|
|
17
|
+
series: ApexOptions['series'];
|
|
18
|
+
/** Whether data is empty */
|
|
19
|
+
isEmpty?: boolean;
|
|
20
|
+
/** Chart title */
|
|
21
|
+
title?: string;
|
|
22
|
+
/** Chart subtitle */
|
|
23
|
+
subtitle?: string;
|
|
24
|
+
/** Loading state */
|
|
25
|
+
loading?: boolean;
|
|
26
|
+
/** Error message */
|
|
27
|
+
error?: string | null;
|
|
28
|
+
/** Empty state message */
|
|
29
|
+
emptyMessage?: string;
|
|
30
|
+
/** Styling options */
|
|
31
|
+
style?: ChartStyleOptions;
|
|
32
|
+
/** Custom class name */
|
|
33
|
+
className?: string;
|
|
34
|
+
/** Class names for sub-components */
|
|
35
|
+
classNames?: {
|
|
36
|
+
container?: string;
|
|
37
|
+
header?: string;
|
|
38
|
+
title?: string;
|
|
39
|
+
subtitle?: string;
|
|
40
|
+
chart?: string;
|
|
41
|
+
loading?: string;
|
|
42
|
+
error?: string;
|
|
43
|
+
empty?: string;
|
|
44
|
+
};
|
|
45
|
+
/** Header action element */
|
|
46
|
+
headerAction?: React.ReactNode;
|
|
47
|
+
/** Chart colors */
|
|
48
|
+
colors?: string[];
|
|
49
|
+
/** Show legend */
|
|
50
|
+
showLegend?: boolean;
|
|
51
|
+
/** Show grid */
|
|
52
|
+
showGrid?: boolean;
|
|
53
|
+
/** Chart height */
|
|
54
|
+
height?: number | string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Base chart wrapper component
|
|
58
|
+
* Handles loading, error, empty states and provides consistent styling
|
|
59
|
+
*/
|
|
60
|
+
export declare const BaseChart: React.FC<BaseChartComponentProps>;
|
|
61
|
+
export default BaseChart;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import Chart from 'react-apexcharts';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import { DEFAULT_CHART_COLORS, DEFAULT_CHART_STYLE } from '../types/chart.types';
|
|
6
|
+
/**
|
|
7
|
+
* Loading skeleton for charts
|
|
8
|
+
*/
|
|
9
|
+
const ChartLoading = ({ height, className }) => (_jsx("div", { className: twMerge('animate-pulse bg-gray-200 dark:bg-gray-700 rounded-lg', className), style: { height: typeof height === 'number' ? `${height}px` : height } }));
|
|
10
|
+
/**
|
|
11
|
+
* Error state component
|
|
12
|
+
*/
|
|
13
|
+
const ChartError = ({ message, className }) => (_jsx("div", { className: twMerge('flex items-center justify-center p-8 bg-red-50 dark:bg-red-900/20 rounded-lg border border-red-200 dark:border-red-800', className), children: _jsxs("div", { className: "text-center", children: [_jsx("svg", { className: "w-12 h-12 mx-auto text-red-400 dark:text-red-500 mb-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }), _jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })] }) }));
|
|
14
|
+
/**
|
|
15
|
+
* Empty state component
|
|
16
|
+
*/
|
|
17
|
+
const ChartEmpty = ({ message, className }) => (_jsx("div", { className: twMerge('flex items-center justify-center p-8 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700', className), children: _jsxs("div", { className: "text-center", children: [_jsx("svg", { className: "w-12 h-12 mx-auto text-gray-400 dark:text-gray-500 mb-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" }) }), _jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: message })] }) }));
|
|
18
|
+
/**
|
|
19
|
+
* Chart header component
|
|
20
|
+
*/
|
|
21
|
+
const ChartHeader = ({ title, subtitle, action, classNames }) => {
|
|
22
|
+
if (!title && !action)
|
|
23
|
+
return null;
|
|
24
|
+
return (_jsxs("div", { className: twMerge('flex items-center justify-between mb-4', classNames?.header), children: [_jsxs("div", { children: [title && (_jsx("h3", { className: twMerge('text-lg font-semibold text-gray-900 dark:text-white', classNames?.title), children: title })), subtitle && (_jsx("p", { className: twMerge('text-sm text-gray-500 dark:text-gray-400 mt-0.5', classNames?.subtitle), children: subtitle }))] }), action && _jsx("div", { children: action })] }));
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Base chart wrapper component
|
|
28
|
+
* Handles loading, error, empty states and provides consistent styling
|
|
29
|
+
*/
|
|
30
|
+
export const BaseChart = ({ type, options, series, title, subtitle, loading = false, error = null, isEmpty = false, emptyMessage = 'No data available', style = {}, className, classNames = {}, headerAction, colors, showLegend, showGrid, height, }) => {
|
|
31
|
+
// Merge style options with defaults
|
|
32
|
+
const mergedStyle = useMemo(() => ({
|
|
33
|
+
...DEFAULT_CHART_STYLE,
|
|
34
|
+
...style,
|
|
35
|
+
...(colors && { colors }),
|
|
36
|
+
...(typeof showLegend !== 'undefined' && { showLegend }),
|
|
37
|
+
...(height && { height }),
|
|
38
|
+
}), [style, colors, showLegend, height]);
|
|
39
|
+
// Build base ApexCharts options
|
|
40
|
+
const baseOptions = useMemo(() => ({
|
|
41
|
+
chart: {
|
|
42
|
+
type,
|
|
43
|
+
toolbar: {
|
|
44
|
+
show: mergedStyle.showToolbar,
|
|
45
|
+
},
|
|
46
|
+
animations: {
|
|
47
|
+
enabled: !mergedStyle.disableAnimations,
|
|
48
|
+
speed: mergedStyle.animationDuration,
|
|
49
|
+
animateGradually: {
|
|
50
|
+
enabled: true,
|
|
51
|
+
delay: 150,
|
|
52
|
+
},
|
|
53
|
+
dynamicAnimation: {
|
|
54
|
+
enabled: true,
|
|
55
|
+
speed: 350,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
fontFamily: 'inherit',
|
|
59
|
+
background: 'transparent',
|
|
60
|
+
},
|
|
61
|
+
colors: mergedStyle.colors ?? DEFAULT_CHART_COLORS,
|
|
62
|
+
legend: {
|
|
63
|
+
show: mergedStyle.showLegend,
|
|
64
|
+
position: mergedStyle.legendPosition,
|
|
65
|
+
horizontalAlign: 'left',
|
|
66
|
+
fontSize: '13px',
|
|
67
|
+
fontWeight: 500,
|
|
68
|
+
markers: {
|
|
69
|
+
size: 6,
|
|
70
|
+
strokeWidth: 0,
|
|
71
|
+
offsetX: -2,
|
|
72
|
+
},
|
|
73
|
+
itemMargin: {
|
|
74
|
+
horizontal: 12,
|
|
75
|
+
vertical: 4,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
dataLabels: {
|
|
79
|
+
enabled: mergedStyle.showDataLabels,
|
|
80
|
+
},
|
|
81
|
+
stroke: {
|
|
82
|
+
curve: 'smooth',
|
|
83
|
+
},
|
|
84
|
+
grid: {
|
|
85
|
+
borderColor: '#E5E7EB',
|
|
86
|
+
strokeDashArray: 4,
|
|
87
|
+
xaxis: {
|
|
88
|
+
lines: {
|
|
89
|
+
show: false,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
yaxis: {
|
|
93
|
+
lines: {
|
|
94
|
+
show: true,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
tooltip: {
|
|
99
|
+
theme: 'light',
|
|
100
|
+
style: {
|
|
101
|
+
fontSize: '13px',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
states: {
|
|
105
|
+
hover: {
|
|
106
|
+
filter: {
|
|
107
|
+
type: 'darken',
|
|
108
|
+
value: 0.9,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
active: {
|
|
112
|
+
filter: {
|
|
113
|
+
type: 'darken',
|
|
114
|
+
value: 0.8,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
responsive: [
|
|
119
|
+
{
|
|
120
|
+
breakpoint: 640,
|
|
121
|
+
options: {
|
|
122
|
+
legend: {
|
|
123
|
+
position: 'bottom',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
}), [type, mergedStyle]);
|
|
129
|
+
// Deep merge base options with provided options
|
|
130
|
+
const mergedOptions = useMemo(() => {
|
|
131
|
+
return deepMerge(baseOptions, options);
|
|
132
|
+
}, [baseOptions, options]);
|
|
133
|
+
// Get chart height
|
|
134
|
+
const chartHeight = mergedStyle.height ?? DEFAULT_CHART_STYLE.height;
|
|
135
|
+
// Render loading state
|
|
136
|
+
if (loading) {
|
|
137
|
+
return (_jsxs("div", { className: twMerge('bg-white dark:bg-gray-900 rounded-xl p-4', className, classNames.container), children: [_jsx(ChartHeader, { title: title, subtitle: subtitle, action: headerAction, classNames: classNames }), _jsx(ChartLoading, { height: chartHeight, className: classNames.loading })] }));
|
|
138
|
+
}
|
|
139
|
+
// Render error state
|
|
140
|
+
if (error) {
|
|
141
|
+
return (_jsxs("div", { className: twMerge('bg-white dark:bg-gray-900 rounded-xl p-4', className, classNames.container), children: [_jsx(ChartHeader, { title: title, subtitle: subtitle, action: headerAction, classNames: classNames }), _jsx(ChartError, { message: error, className: classNames.error })] }));
|
|
142
|
+
}
|
|
143
|
+
// Render empty state
|
|
144
|
+
if (isEmpty) {
|
|
145
|
+
return (_jsxs("div", { className: twMerge('bg-white dark:bg-gray-900 rounded-xl p-4', className, classNames.container), children: [_jsx(ChartHeader, { title: title, subtitle: subtitle, action: headerAction, classNames: classNames }), _jsx(ChartEmpty, { message: emptyMessage, className: classNames.empty })] }));
|
|
146
|
+
}
|
|
147
|
+
return (_jsxs("div", { className: twMerge('bg-white dark:bg-gray-900 rounded-xl p-4', className, classNames.container), children: [_jsx(ChartHeader, { title: title, subtitle: subtitle, action: headerAction, classNames: classNames }), _jsx("div", { className: classNames.chart, children: _jsx(Chart, { type: type, options: mergedOptions, series: series, height: chartHeight, width: mergedStyle.width ?? '100%' }) })] }));
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Deep merge utility for ApexCharts options
|
|
151
|
+
*/
|
|
152
|
+
function deepMerge(target, source) {
|
|
153
|
+
const result = { ...target };
|
|
154
|
+
for (const key in source) {
|
|
155
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
156
|
+
const sourceValue = source[key];
|
|
157
|
+
const targetValue = result[key];
|
|
158
|
+
if (sourceValue &&
|
|
159
|
+
typeof sourceValue === 'object' &&
|
|
160
|
+
!Array.isArray(sourceValue) &&
|
|
161
|
+
targetValue &&
|
|
162
|
+
typeof targetValue === 'object' &&
|
|
163
|
+
!Array.isArray(targetValue)) {
|
|
164
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
165
|
+
}
|
|
166
|
+
else if (sourceValue !== undefined) {
|
|
167
|
+
result[key] = sourceValue;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
export default BaseChart;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ChartDataPoint, DonutChartProps } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Donut Chart component
|
|
4
|
+
* Ring chart with optional center content
|
|
5
|
+
*/
|
|
6
|
+
export declare function DonutChart<TData extends ChartDataPoint = ChartDataPoint>({ data, labelKey, valueKey, labels: providedLabels, values: providedValues, donutSize, showTotal, totalLabel, totalFormatter, style, tooltip, apexOptions, onDataPointClick, ...baseProps }: DonutChartProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default DonutChart;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { BaseChart } from './BaseChart';
|
|
4
|
+
/**
|
|
5
|
+
* Donut Chart component
|
|
6
|
+
* Ring chart with optional center content
|
|
7
|
+
*/
|
|
8
|
+
export function DonutChart({ data = [], labelKey = 'label', valueKey = 'value', labels: providedLabels, values: providedValues, donutSize = '65%', showTotal = true, totalLabel = 'Total', totalFormatter, style, tooltip, apexOptions, onDataPointClick, ...baseProps }) {
|
|
9
|
+
// Build labels and values from data
|
|
10
|
+
const { labels, values } = useMemo(() => {
|
|
11
|
+
if (providedLabels && providedValues) {
|
|
12
|
+
return { labels: providedLabels, values: providedValues };
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
labels: data.map((item) => String(item[labelKey] ?? '')),
|
|
16
|
+
values: data.map((item) => Number(item[valueKey]) || 0),
|
|
17
|
+
};
|
|
18
|
+
}, [data, labelKey, valueKey, providedLabels, providedValues]);
|
|
19
|
+
const isEmpty = values.length === 0 || values.every((v) => v === 0);
|
|
20
|
+
// Calculate total for center display
|
|
21
|
+
const total = useMemo(() => values.reduce((acc, val) => acc + val, 0), [values]);
|
|
22
|
+
const options = useMemo(() => ({
|
|
23
|
+
chart: {
|
|
24
|
+
events: onDataPointClick
|
|
25
|
+
? {
|
|
26
|
+
dataPointSelection: (event, chartContext, config) => {
|
|
27
|
+
void event;
|
|
28
|
+
void chartContext;
|
|
29
|
+
const { dataPointIndex } = config;
|
|
30
|
+
onDataPointClick(dataPointIndex, 0, data[dataPointIndex]);
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
: undefined,
|
|
34
|
+
},
|
|
35
|
+
labels,
|
|
36
|
+
plotOptions: {
|
|
37
|
+
pie: {
|
|
38
|
+
donut: {
|
|
39
|
+
size: donutSize,
|
|
40
|
+
labels: {
|
|
41
|
+
show: showTotal,
|
|
42
|
+
name: {
|
|
43
|
+
show: true,
|
|
44
|
+
fontSize: '14px',
|
|
45
|
+
fontWeight: 600,
|
|
46
|
+
color: '#6B7280',
|
|
47
|
+
},
|
|
48
|
+
value: {
|
|
49
|
+
show: true,
|
|
50
|
+
fontSize: '24px',
|
|
51
|
+
fontWeight: 700,
|
|
52
|
+
color: '#111827',
|
|
53
|
+
formatter: totalFormatter ? (val) => totalFormatter(Number(val)) : (val) => val,
|
|
54
|
+
},
|
|
55
|
+
total: {
|
|
56
|
+
show: showTotal,
|
|
57
|
+
showAlways: true,
|
|
58
|
+
label: totalLabel,
|
|
59
|
+
fontSize: '14px',
|
|
60
|
+
fontWeight: 600,
|
|
61
|
+
color: '#6B7280',
|
|
62
|
+
formatter: totalFormatter
|
|
63
|
+
? () => totalFormatter(total)
|
|
64
|
+
: (w) => {
|
|
65
|
+
const sum = w.globals.seriesTotals.reduce((a, b) => a + b, 0);
|
|
66
|
+
return sum.toLocaleString();
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
dataLabels: {
|
|
74
|
+
enabled: false,
|
|
75
|
+
},
|
|
76
|
+
legend: {
|
|
77
|
+
position: 'right',
|
|
78
|
+
fontSize: '13px',
|
|
79
|
+
markers: {
|
|
80
|
+
size: 6,
|
|
81
|
+
strokeWidth: 0,
|
|
82
|
+
},
|
|
83
|
+
formatter: (seriesName, opts) => {
|
|
84
|
+
const value = opts.w.globals.series[opts.seriesIndex];
|
|
85
|
+
return `${seriesName}: ${value.toLocaleString()}`;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
tooltip: {
|
|
89
|
+
enabled: tooltip?.enabled !== false,
|
|
90
|
+
y: {
|
|
91
|
+
formatter: tooltip?.valueFormatter ?? ((val) => val.toLocaleString()),
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
responsive: [
|
|
95
|
+
{
|
|
96
|
+
breakpoint: 640,
|
|
97
|
+
options: {
|
|
98
|
+
legend: {
|
|
99
|
+
position: 'bottom',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
...apexOptions,
|
|
105
|
+
}), [labels, donutSize, showTotal, totalLabel, totalFormatter, total, tooltip, apexOptions, onDataPointClick, data]);
|
|
106
|
+
return _jsx(BaseChart, { type: "donut", options: options, series: values, isEmpty: isEmpty, style: style, ...baseProps });
|
|
107
|
+
}
|
|
108
|
+
export default DonutChart;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ChartDataPoint, HeatmapChartProps } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Heatmap Chart component
|
|
4
|
+
* Grid-based visualization with color intensity
|
|
5
|
+
*/
|
|
6
|
+
export declare function HeatmapChart<TData extends ChartDataPoint = ChartDataPoint>({ data, series: providedSeries, categories: providedCategories, xKey, yKey, valueKey, colorScale, showValue, style, tooltip, xAxis, yAxis, apexOptions, onDataPointClick, ...baseProps }: HeatmapChartProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default HeatmapChart;
|