@kala-ui/react-app 0.1.0-beta.0 → 0.1.0-beta.10
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/CHANGELOG.md +83 -0
- package/README.md +9 -4
- package/dist/components/app-shell/app-shell.d.ts +8 -46
- package/dist/components/app-shell/app-shell.js +41 -42
- package/dist/components/app-shell/app-shell.types.d.ts +45 -0
- package/dist/components/app-shell/app-shell.types.js +2 -0
- package/dist/components/app-shell/index.d.ts +1 -0
- package/dist/components/charts/area-chart.d.ts +1 -1
- package/dist/components/charts/area-chart.js +4 -3
- package/dist/components/charts/bar-chart.d.ts +1 -1
- package/dist/components/charts/bar-chart.js +4 -3
- package/dist/components/charts/chart-skeleton.d.ts +0 -21
- package/dist/components/charts/chart-skeleton.js +2 -1
- package/dist/components/charts/chart-utils.d.ts +56 -0
- package/dist/components/charts/chart-utils.js +135 -0
- package/dist/components/charts/chart.d.ts +3 -1
- package/dist/components/charts/chart.js +14 -4
- package/dist/components/charts/chart.types.d.ts +3 -0
- package/dist/components/charts/donut-chart.d.ts +1 -1
- package/dist/components/charts/donut-chart.js +5 -4
- package/dist/components/charts/index.d.ts +1 -1
- package/dist/components/charts/index.js +1 -1
- package/dist/components/charts/line-chart.d.ts +1 -1
- package/dist/components/charts/line-chart.js +4 -3
- package/dist/components/charts/radial-bar-chart.d.ts +1 -1
- package/dist/components/charts/radial-bar-chart.js +4 -3
- package/dist/components/data-table/column-filters.js +1 -1
- package/dist/components/data-table/column-header-filter.js +1 -1
- package/dist/components/data-table/data-table-body-rows.js +1 -1
- package/dist/components/data-table/data-table-filter-chips.js +1 -1
- package/dist/components/data-table/data-table-header-row.js +1 -1
- package/dist/components/data-table/data-table-skeleton.js +1 -1
- package/dist/components/data-table/data-table-toolbar.js +1 -1
- package/dist/components/data-table/data-table.js +6 -4
- package/dist/components/data-table/data-table.types.d.ts +2 -0
- package/dist/components/data-table/index.d.ts +1 -1
- package/dist/components/data-table/index.js +1 -1
- package/dist/components/data-table/pagination-nav.js +1 -1
- package/dist/components/data-table/use-table-state.d.ts +29 -0
- package/dist/components/data-table/use-table-state.js +312 -0
- package/dist/components/dnd/dnd.d.ts +16 -98
- package/dist/components/dnd/dnd.js +36 -8
- package/dist/components/dnd/dnd.types.d.ts +92 -0
- package/dist/components/dnd/dnd.types.js +7 -0
- package/dist/components/dnd/index.d.ts +2 -1
- package/dist/components/dnd/index.js +1 -1
- package/dist/components/footer/footer.d.ts +2 -37
- package/dist/components/footer/footer.js +18 -2
- package/dist/components/footer/footer.types.d.ts +25 -0
- package/dist/components/footer/footer.types.js +2 -0
- package/dist/components/footer/index.d.ts +1 -1
- package/dist/components/header/header-skeleton.js +1 -1
- package/dist/components/header/header.js +6 -12
- package/dist/components/metric-card/index.d.ts +2 -1
- package/dist/components/metric-card/metric-card-skeleton.js +2 -1
- package/dist/components/metric-card/metric-card.d.ts +2 -14
- package/dist/components/metric-card/metric-card.js +33 -29
- package/dist/components/metric-card/metric-card.types.d.ts +3 -0
- package/dist/components/nav-link/index.d.ts +2 -1
- package/dist/components/nav-link/index.js +1 -1
- package/dist/components/nav-link/nav-link.d.ts +2 -25
- package/dist/components/nav-link/nav-link.js +43 -5
- package/dist/components/nav-link/nav-link.types.d.ts +23 -0
- package/dist/components/nav-link/nav-link.types.js +2 -0
- package/dist/components/navigation/index.d.ts +1 -1
- package/dist/components/navigation/navigation-skeleton.js +1 -1
- package/dist/components/navigation/navigation.d.ts +1 -24
- package/dist/components/navigation/navigation.js +9 -19
- package/dist/components/navigation/navigation.types.d.ts +15 -0
- package/dist/components/navigation/navigation.types.js +2 -0
- package/dist/components/session-card/index.d.ts +2 -1
- package/dist/components/session-card/index.js +1 -1
- package/dist/components/session-card/session-card-skeleton.d.ts +3 -1
- package/dist/components/session-card/session-card-skeleton.js +3 -2
- package/dist/components/session-card/session-card.d.ts +3 -26
- package/dist/components/session-card/session-card.js +23 -8
- package/dist/components/session-card/session-card.types.d.ts +26 -0
- package/dist/components/session-card/session-card.types.js +2 -0
- package/dist/components/sidebar/sidebar-skeleton.js +1 -1
- package/dist/components/sidebar/sidebar.js +6 -12
- package/dist/components/social-login-button/index.d.ts +3 -1
- package/dist/components/social-login-button/index.js +2 -1
- package/dist/components/social-login-button/social-login-button.d.ts +2 -20
- package/dist/components/social-login-button/social-login-button.js +9 -11
- package/dist/components/social-login-button/social-login-button.types.d.ts +28 -0
- package/dist/components/social-login-button/social-login-button.types.js +2 -0
- package/dist/components/social-login-button/social-login-buttons.d.ts +4 -0
- package/dist/components/social-login-button/social-login-buttons.js +18 -0
- package/dist/components/social-login-buttons/social-login-buttons.js +1 -1
- package/dist/components/sparkline-chart/sparkline-chart.js +1 -1
- package/dist/components/user-menu-dropdown/index.d.ts +2 -1
- package/dist/components/user-menu-dropdown/index.js +1 -1
- package/dist/components/user-menu-dropdown/user-menu-dropdown.d.ts +2 -31
- package/dist/components/user-menu-dropdown/user-menu-dropdown.js +14 -2
- package/dist/components/user-menu-dropdown/user-menu-dropdown.types.d.ts +16 -0
- package/dist/components/user-menu-dropdown/user-menu-dropdown.types.js +2 -0
- package/dist/config/app-shell.d.ts +13 -0
- package/dist/config/app-shell.js +20 -0
- package/dist/config/charts.d.ts +23 -0
- package/dist/config/charts.js +23 -0
- package/dist/config/footer.d.ts +16 -0
- package/dist/config/footer.js +16 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.js +7 -0
- package/dist/config/metric-card.d.ts +36 -0
- package/dist/config/metric-card.js +44 -0
- package/dist/config/session-card.d.ts +32 -0
- package/dist/config/session-card.js +32 -0
- package/dist/config/social-login-button.d.ts +15 -0
- package/dist/config/social-login-button.js +15 -0
- package/dist/config/user-menu-dropdown.d.ts +10 -0
- package/dist/config/user-menu-dropdown.js +10 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/styles/app.css +18 -53
- package/package.json +24 -28
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* Chart Utilities
|
|
4
|
+
* Helper functions and default configurations for charts
|
|
5
|
+
*/
|
|
6
|
+
import { getChartColors, getThemeAwareChartOptions } from "./theme-utils.js";
|
|
7
|
+
/**
|
|
8
|
+
* Get default chart options that match our design system
|
|
9
|
+
* @param theme - Optional theme override, otherwise detects from DOM
|
|
10
|
+
*/
|
|
11
|
+
export function getDefaultChartOptions(theme) {
|
|
12
|
+
const themeColors = getChartColors(theme);
|
|
13
|
+
const themeOptions = getThemeAwareChartOptions(theme);
|
|
14
|
+
return {
|
|
15
|
+
chart: {
|
|
16
|
+
fontFamily: "inherit",
|
|
17
|
+
foreColor: "var(--muted-foreground)",
|
|
18
|
+
background: "transparent",
|
|
19
|
+
toolbar: {
|
|
20
|
+
show: false,
|
|
21
|
+
},
|
|
22
|
+
zoom: {
|
|
23
|
+
enabled: false,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
grid: {
|
|
27
|
+
borderColor: themeColors.grid,
|
|
28
|
+
strokeDashArray: 3,
|
|
29
|
+
xaxis: {
|
|
30
|
+
lines: {
|
|
31
|
+
show: false,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
dataLabels: {
|
|
36
|
+
enabled: false,
|
|
37
|
+
},
|
|
38
|
+
tooltip: {
|
|
39
|
+
theme: themeOptions.tooltip.theme,
|
|
40
|
+
},
|
|
41
|
+
legend: {
|
|
42
|
+
labels: {
|
|
43
|
+
colors: themeOptions.legend.labels.colors,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Default color palette matching design tokens
|
|
50
|
+
* @param theme - Optional theme override, otherwise detects from DOM
|
|
51
|
+
* @deprecated Use getChartColors() instead for theme-aware colors
|
|
52
|
+
*/
|
|
53
|
+
export function defaultColors(theme) {
|
|
54
|
+
const colors = getChartColors(theme);
|
|
55
|
+
return {
|
|
56
|
+
primary: colors.primary,
|
|
57
|
+
success: colors.success,
|
|
58
|
+
warning: colors.warning,
|
|
59
|
+
destructive: colors.destructive,
|
|
60
|
+
info: colors.info,
|
|
61
|
+
mixed: colors.mixed,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Format number with appropriate units
|
|
66
|
+
*/
|
|
67
|
+
export function formatNumber(value) {
|
|
68
|
+
if (value >= 1000000) {
|
|
69
|
+
return `${(value / 1000000).toFixed(1)}M`;
|
|
70
|
+
}
|
|
71
|
+
if (value >= 1000) {
|
|
72
|
+
return `${(value / 1000).toFixed(1)}K`;
|
|
73
|
+
}
|
|
74
|
+
return value.toFixed(0);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Format currency values
|
|
78
|
+
*/
|
|
79
|
+
export function formatCurrency(value, currency = "USD") {
|
|
80
|
+
return new Intl.NumberFormat("en-US", {
|
|
81
|
+
style: "currency",
|
|
82
|
+
currency,
|
|
83
|
+
minimumFractionDigits: 0,
|
|
84
|
+
maximumFractionDigits: 2,
|
|
85
|
+
}).format(value);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Format percentage values
|
|
89
|
+
*/
|
|
90
|
+
export function formatPercentage(value, decimals = 1) {
|
|
91
|
+
return `${value.toFixed(decimals)}%`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Generate gradient colors for area charts
|
|
95
|
+
*/
|
|
96
|
+
export function createGradient(_color, opacity = 0.7) {
|
|
97
|
+
return {
|
|
98
|
+
type: "gradient",
|
|
99
|
+
gradient: {
|
|
100
|
+
shadeIntensity: 1,
|
|
101
|
+
opacityFrom: opacity,
|
|
102
|
+
opacityTo: opacity * 0.3,
|
|
103
|
+
stops: [0, 90, 100],
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get responsive breakpoints for charts
|
|
109
|
+
*/
|
|
110
|
+
export function getResponsiveOptions() {
|
|
111
|
+
return [
|
|
112
|
+
{
|
|
113
|
+
breakpoint: 768,
|
|
114
|
+
options: {
|
|
115
|
+
chart: {
|
|
116
|
+
height: 300,
|
|
117
|
+
},
|
|
118
|
+
legend: {
|
|
119
|
+
position: "bottom",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
breakpoint: 480,
|
|
125
|
+
options: {
|
|
126
|
+
chart: {
|
|
127
|
+
height: 250,
|
|
128
|
+
},
|
|
129
|
+
legend: {
|
|
130
|
+
show: false,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
}
|
|
@@ -11,6 +11,8 @@ export interface ChartProps extends Props {
|
|
|
11
11
|
emptyMessage?: string;
|
|
12
12
|
skeletonConfig?: ChartSkeletonConfig;
|
|
13
13
|
skeleton?: React.ReactNode;
|
|
14
|
+
/** Per-part overrides: root, empty, emptyIcon, emptyText. */
|
|
15
|
+
slotStyles?: import("@kala-ui/react/lib/slot-styles").SlotStyles;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Get tooltip theme from DOM safely (SSR-compatible)
|
|
@@ -20,6 +22,6 @@ declare function getTooltipTheme(): "dark" | "light";
|
|
|
20
22
|
* Base Chart Component - use this as the foundation for all charts
|
|
21
23
|
* Provides consistent styling, loading skeleton, and empty state
|
|
22
24
|
*/
|
|
23
|
-
export declare function Chart({ className, isLoading, isEmpty, emptyMessage, skeletonConfig, skeleton, ...props }: ChartProps): import("react").JSX.Element;
|
|
25
|
+
export declare function Chart({ className, isLoading, isEmpty, emptyMessage, skeletonConfig, skeleton, slotStyles: slotStylesRaw, ...props }: ChartProps): import("react").JSX.Element;
|
|
24
26
|
export { ChartSkeleton } from "./chart-skeleton";
|
|
25
27
|
export { getTooltipTheme };
|
|
@@ -4,8 +4,11 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
4
4
|
* Base Chart Component
|
|
5
5
|
* React component for ApexCharts with built-in loading and empty states
|
|
6
6
|
*/
|
|
7
|
+
import { useSlotStyles } from "@kala-ui/react/kala-provider";
|
|
8
|
+
import { applySlot } from "@kala-ui/react/lib/slot-styles";
|
|
7
9
|
import { cn } from "@kala-ui/react/lib/utils";
|
|
8
10
|
import { lazy, Suspense } from "react";
|
|
11
|
+
import { chartStyles } from "../../config/charts.js";
|
|
9
12
|
import { ChartSkeleton } from "./chart-skeleton.js";
|
|
10
13
|
// apexcharts touches `window` at module scope, so importing it statically
|
|
11
14
|
// crashes any SSR framework on the first render — and the root barrel
|
|
@@ -24,14 +27,20 @@ function getTooltipTheme() {
|
|
|
24
27
|
* Base Chart Component - use this as the foundation for all charts
|
|
25
28
|
* Provides consistent styling, loading skeleton, and empty state
|
|
26
29
|
*/
|
|
27
|
-
export function Chart({ className, isLoading, isEmpty, emptyMessage = "No data available", skeletonConfig, skeleton, ...props }) {
|
|
30
|
+
export function Chart({ className, isLoading, isEmpty, emptyMessage = "No data available", skeletonConfig, skeleton, slotStyles: slotStylesRaw, ...props }) {
|
|
31
|
+
const slotStyles = useSlotStyles("charts", slotStylesRaw);
|
|
32
|
+
const { "data-kala-component": _marker, ...chartProps } = props;
|
|
33
|
+
const markerProps = { "data-kala-component": _marker };
|
|
28
34
|
// Render skeleton if loading
|
|
29
35
|
if (isLoading) {
|
|
30
36
|
if (skeleton) {
|
|
31
37
|
return _jsx(_Fragment, { children: skeleton });
|
|
32
38
|
}
|
|
33
|
-
return _jsx(ChartSkeleton, { ...(skeletonConfig || {}), className: className });
|
|
39
|
+
return (_jsx(ChartSkeleton, { "data-kala-component": "charts-chart", ...(skeletonConfig || {}), className: className }));
|
|
34
40
|
}
|
|
41
|
+
const emptyPart = applySlot(chartStyles.empty, slotStyles?.empty);
|
|
42
|
+
const emptyIcon = applySlot(chartStyles.emptyIcon, slotStyles?.emptyIcon);
|
|
43
|
+
const emptyText = applySlot(chartStyles.emptyText, slotStyles?.emptyText);
|
|
35
44
|
// Render empty state when no data
|
|
36
45
|
if (isEmpty) {
|
|
37
46
|
// Height may arrive as a number (px) or a CSS length string ("20rem",
|
|
@@ -40,9 +49,10 @@ export function Chart({ className, isLoading, isEmpty, emptyMessage = "No data a
|
|
|
40
49
|
const height = typeof configuredHeight === "number"
|
|
41
50
|
? `${configuredHeight}px`
|
|
42
51
|
: configuredHeight;
|
|
43
|
-
return (_jsxs("div", {
|
|
52
|
+
return (_jsxs("div", { "data-kala-component": "charts-chart", className: cn(emptyPart.className, className), style: { height, ...emptyPart.style }, children: [_jsxs("svg", { className: emptyIcon.className, fill: "none", role: "img", "aria-label": "Chart empty state", stroke: "currentColor", viewBox: "0 0 24 24", children: [_jsx("title", { children: "No chart data" }), _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 13h2v8H3zM9 9h2v12H9zM15 5h2v16h-2zM21 1h2v20h-2z" })] }), _jsx("p", { className: emptyText.className, children: emptyMessage })] }));
|
|
44
53
|
}
|
|
45
|
-
|
|
54
|
+
const root = applySlot(cn(chartStyles.root, className), slotStyles?.root);
|
|
55
|
+
return (_jsx("div", { "data-kala-component": _marker ?? "charts-chart", className: root.className, style: root.style, children: _jsx(Suspense, { fallback: skeleton ?? (_jsx(ChartSkeleton, { ...(skeletonConfig || {}), className: className })), children: _jsx(ReactApexChart, { ...chartProps }) }) }));
|
|
46
56
|
}
|
|
47
57
|
export { ChartSkeleton } from "./chart-skeleton.js";
|
|
48
58
|
export { getTooltipTheme };
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Chart Component Types
|
|
3
3
|
* Type definitions for ApexCharts-based chart components
|
|
4
4
|
*/
|
|
5
|
+
import type { SlotStyles } from "@kala-ui/react/lib/slot-styles";
|
|
5
6
|
import type { ApexOptions } from "apexcharts";
|
|
6
7
|
/**
|
|
7
8
|
* Base chart props shared across all chart types
|
|
@@ -27,6 +28,8 @@ export interface BaseChartProps {
|
|
|
27
28
|
isLoading?: boolean;
|
|
28
29
|
/** Message shown when data is empty (default: "No data available") */
|
|
29
30
|
emptyMessage?: string;
|
|
31
|
+
/** Per-part overrides: root, empty, emptyIcon, emptyText, titleBlock, title, subtitle. */
|
|
32
|
+
slotStyles?: SlotStyles;
|
|
30
33
|
}
|
|
31
34
|
/**
|
|
32
35
|
* Series data point for single value charts
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* Circular charts for showing proportions and percentages
|
|
4
4
|
*/
|
|
5
5
|
import type { DonutChartProps } from "./chart.types";
|
|
6
|
-
export declare function DonutChart({ series, labels, colors, height, width, className, title, subtitle, animations, donut, donutSize, dataLabels, legend, isLoading, emptyMessage, options: customOptions, }: DonutChartProps): import("react").JSX.Element;
|
|
6
|
+
export declare function DonutChart({ series, labels, colors, height, width, className, title, subtitle, animations, donut, donutSize, dataLabels, legend, slotStyles, isLoading, emptyMessage, options: customOptions, }: DonutChartProps): import("react").JSX.Element;
|
|
7
7
|
export declare function PieChart(props: DonutChartProps): import("react").JSX.Element;
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
8
|
import { cn } from "@kala-ui/react/lib/utils";
|
|
9
9
|
import { useMemo } from "react";
|
|
10
|
+
import { chartStyles } from "../../config/charts.js";
|
|
10
11
|
import { Chart, getTooltipTheme } from "./chart.js";
|
|
11
12
|
import { useThemeAwareChart } from "./use-theme-aware-chart.js";
|
|
12
|
-
import { getDefaultChartOptions } from "./utils.js";
|
|
13
|
-
export function DonutChart({ series, labels, colors, height = 350, width = "100%", className, title, subtitle, animations = true, donut = true, donutSize = 65, dataLabels = true, legend = true, isLoading, emptyMessage, options: customOptions, }) {
|
|
13
|
+
import { getDefaultChartOptions } from "./chart-utils.js";
|
|
14
|
+
export function DonutChart({ series, labels, colors, height = 350, width = "100%", className, title, subtitle, animations = true, donut = true, donutSize = 65, dataLabels = true, legend = true, slotStyles, isLoading, emptyMessage, options: customOptions, }) {
|
|
14
15
|
const { colors: themeColors } = useThemeAwareChart();
|
|
15
16
|
const isEmpty = !isLoading && (series.length === 0 || labels.length === 0);
|
|
16
17
|
const chartOptions = useMemo(() => {
|
|
@@ -138,9 +139,9 @@ export function DonutChart({ series, labels, colors, height = 350, width = "100%
|
|
|
138
139
|
subtitle,
|
|
139
140
|
customOptions,
|
|
140
141
|
]);
|
|
141
|
-
return (_jsx(Chart, {
|
|
142
|
+
return (_jsx(Chart, { "data-kala-component": "charts-donut-chart", className: cn(chartStyles.root, className), slotStyles: slotStyles, options: chartOptions, series: series, type: donut ? "donut" : "pie", height: height, width: width, isLoading: isLoading, isEmpty: isEmpty, emptyMessage: emptyMessage }));
|
|
142
143
|
}
|
|
143
144
|
// Convenience alias for Pie charts
|
|
144
145
|
export function PieChart(props) {
|
|
145
|
-
return _jsx(DonutChart, { ...props, donut: false });
|
|
146
|
+
return (_jsx(DonutChart, { "data-kala-component": "charts-pie-chart", ...props, donut: false }));
|
|
146
147
|
}
|
|
@@ -12,4 +12,4 @@ export { LineChart } from "./line-chart.js";
|
|
|
12
12
|
export { RadialBarChart } from "./radial-bar-chart.js";
|
|
13
13
|
export * from "./theme-utils.js";
|
|
14
14
|
export { useThemeAwareChart } from "./use-theme-aware-chart.js";
|
|
15
|
-
export * from "./utils.js";
|
|
15
|
+
export * from "./chart-utils.js";
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Clean line charts for trends and time series data
|
|
4
4
|
*/
|
|
5
5
|
import type { LineChartProps } from "./chart.types";
|
|
6
|
-
export declare function LineChart({ series, categories, colors, height, width, className, title, subtitle, toolbar, animations, curve, strokeWidth, markers, yAxisLabel, isLoading, emptyMessage, options: customOptions, }: LineChartProps): import("react").JSX.Element;
|
|
6
|
+
export declare function LineChart({ series, categories, colors, height, width, className, title, subtitle, toolbar, animations, curve, strokeWidth, markers, yAxisLabel, slotStyles, isLoading, emptyMessage, options: customOptions, }: LineChartProps): import("react").JSX.Element;
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
8
|
import { cn } from "@kala-ui/react/lib/utils";
|
|
9
9
|
import { useMemo } from "react";
|
|
10
|
+
import { chartStyles } from "../../config/charts.js";
|
|
10
11
|
import { Chart, getTooltipTheme } from "./chart.js";
|
|
11
12
|
import { useThemeAwareChart } from "./use-theme-aware-chart.js";
|
|
12
|
-
import { getDefaultChartOptions } from "./utils.js";
|
|
13
|
+
import { getDefaultChartOptions } from "./chart-utils.js";
|
|
13
14
|
/**
|
|
14
15
|
* Check if series data is empty (no series or all series have empty data arrays)
|
|
15
16
|
*/
|
|
@@ -18,7 +19,7 @@ function isSeriesEmpty(series) {
|
|
|
18
19
|
return true;
|
|
19
20
|
return series.every((s) => !s.data || (Array.isArray(s.data) && s.data.length === 0));
|
|
20
21
|
}
|
|
21
|
-
export function LineChart({ series, categories, colors, height = 350, width = "100%", className, title, subtitle, toolbar = false, animations = true, curve = "smooth", strokeWidth = 2, markers = true, yAxisLabel, isLoading, emptyMessage, options: customOptions, }) {
|
|
22
|
+
export function LineChart({ series, categories, colors, height = 350, width = "100%", className, title, subtitle, toolbar = false, animations = true, curve = "smooth", strokeWidth = 2, markers = true, yAxisLabel, slotStyles, isLoading, emptyMessage, options: customOptions, }) {
|
|
22
23
|
const { colors: themeColors } = useThemeAwareChart();
|
|
23
24
|
const isEmpty = !isLoading && isSeriesEmpty(series);
|
|
24
25
|
const chartOptions = useMemo(() => {
|
|
@@ -154,5 +155,5 @@ export function LineChart({ series, categories, colors, height = 350, width = "1
|
|
|
154
155
|
subtitle,
|
|
155
156
|
customOptions,
|
|
156
157
|
]);
|
|
157
|
-
return (_jsx(Chart, {
|
|
158
|
+
return (_jsx(Chart, { "data-kala-component": "charts-line-chart", className: cn(chartStyles.root, className), slotStyles: slotStyles, options: chartOptions, series: series, type: "line", height: height, width: width, isLoading: isLoading, isEmpty: isEmpty, emptyMessage: emptyMessage }));
|
|
158
159
|
}
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* Circular progress bars for showing percentages and completion rates
|
|
4
4
|
*/
|
|
5
5
|
import type { RadialBarChartProps } from "./chart.types";
|
|
6
|
-
export declare function RadialBarChart({ series, labels, colors, height, width, className, title, subtitle, animations, dataLabels, hollowSize, isLoading, emptyMessage, options: customOptions, }: RadialBarChartProps): import("react").JSX.Element;
|
|
6
|
+
export declare function RadialBarChart({ series, labels, colors, height, width, className, title, subtitle, animations, dataLabels, hollowSize, slotStyles, isLoading, emptyMessage, options: customOptions, }: RadialBarChartProps): import("react").JSX.Element;
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
8
|
import { cn } from "@kala-ui/react/lib/utils";
|
|
9
9
|
import { useMemo } from "react";
|
|
10
|
+
import { chartStyles } from "../../config/charts.js";
|
|
10
11
|
import { Chart, getTooltipTheme } from "./chart.js";
|
|
11
12
|
import { useThemeAwareChart } from "./use-theme-aware-chart.js";
|
|
12
|
-
import { getDefaultChartOptions } from "./utils.js";
|
|
13
|
-
export function RadialBarChart({ series, labels, colors, height = 350, width = "100%", className, title, subtitle, animations = true, dataLabels = true, hollowSize = "50%", isLoading, emptyMessage, options: customOptions, }) {
|
|
13
|
+
import { getDefaultChartOptions } from "./chart-utils.js";
|
|
14
|
+
export function RadialBarChart({ series, labels, colors, height = 350, width = "100%", className, title, subtitle, animations = true, dataLabels = true, hollowSize = "50%", slotStyles, isLoading, emptyMessage, options: customOptions, }) {
|
|
14
15
|
const { colors: themeColors } = useThemeAwareChart();
|
|
15
16
|
const isEmpty = !isLoading && (series.length === 0 || labels.length === 0);
|
|
16
17
|
const chartOptions = useMemo(() => {
|
|
@@ -111,5 +112,5 @@ export function RadialBarChart({ series, labels, colors, height = 350, width = "
|
|
|
111
112
|
subtitle,
|
|
112
113
|
customOptions,
|
|
113
114
|
]);
|
|
114
|
-
return (_jsx(Chart, {
|
|
115
|
+
return (_jsx(Chart, { "data-kala-component": "charts-radial-bar-chart", className: cn(chartStyles.root, className), slotStyles: slotStyles, options: chartOptions, series: series, type: "radialBar", height: height, width: width, isLoading: isLoading, isEmpty: isEmpty, emptyMessage: emptyMessage }));
|
|
115
116
|
}
|
|
@@ -14,7 +14,7 @@ export function ColumnFilters({ filterableColumns, activeFilters, onFilterChange
|
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
16
|
const hasActiveFilters = activeFilters.length > 0;
|
|
17
|
-
return (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [filterableColumns.map((column) => {
|
|
17
|
+
return (_jsxs("div", { "data-kala-component": "data-table-column-filters", className: "flex flex-wrap items-center gap-2", children: [filterableColumns.map((column) => {
|
|
18
18
|
const activeFilter = activeFilters.find((f) => f.key === column.key);
|
|
19
19
|
const filterValue = activeFilter?.value;
|
|
20
20
|
if (column.type === "select" && column.options) {
|
|
@@ -64,7 +64,7 @@ export function ColumnHeaderFilter({ column, activeFilters, onFilterChange, onFi
|
|
|
64
64
|
onFilterRemove(column.key);
|
|
65
65
|
setTextValue("");
|
|
66
66
|
};
|
|
67
|
-
return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", className: "h-8 w-8 p-0 hover:bg-muted relative", "aria-label": `Filter by ${column.label}`, children: [_jsx(Filter, { className: `h-4 w-4 ${hasActiveFilter ? "text-primary" : "text-muted-foreground"}` }), hasActiveFilter ? (_jsx(Badge, { className: "absolute -top-1 -right-1 h-4 w-4 p-0 flex items-center justify-center text-[10px]", children: _jsx(Text, { size: "xs", weight: "bold", className: "text-primary-foreground", children: column.type === "text" ? "1" : activeCount }) })) : null] }) }), _jsx(PopoverContent, { className: "w-64 p-3", align: "start", children: _jsxs(Stack, { gap: 3, children: [_jsxs(Flex, { align: "center", justify: "between", children: [_jsxs(Heading, { size: "h6", weight: "medium", className: "text-sm", children: ["Filter by ", column.label] }), hasActiveFilter ? (_jsxs(Button, { variant: "ghost", size: "sm", onClick: handleClear, className: "h-7 px-2 text-xs text-muted-foreground", children: [_jsx(X, { className: "h-3 w-3 mr-1" }), "Clear"] })) : null] }), column.type === "select" && column.options ? (_jsx(Stack, { gap: 2, className: "max-h-[300px] overflow-y-auto", children: column.options.map((option) => {
|
|
67
|
+
return (_jsxs(Popover, { "data-kala-component": "data-table-column-header-filter", open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", className: "h-8 w-8 p-0 hover:bg-muted relative", "aria-label": `Filter by ${column.label}`, children: [_jsx(Filter, { className: `h-4 w-4 ${hasActiveFilter ? "text-primary" : "text-muted-foreground"}` }), hasActiveFilter ? (_jsx(Badge, { className: "absolute -top-1 -right-1 h-4 w-4 p-0 flex items-center justify-center text-[10px]", children: _jsx(Text, { size: "xs", weight: "bold", className: "text-primary-foreground", children: column.type === "text" ? "1" : activeCount }) })) : null] }) }), _jsx(PopoverContent, { className: "w-64 p-3", align: "start", children: _jsxs(Stack, { gap: 3, children: [_jsxs(Flex, { align: "center", justify: "between", children: [_jsxs(Heading, { size: "h6", weight: "medium", className: "text-sm", children: ["Filter by ", column.label] }), hasActiveFilter ? (_jsxs(Button, { variant: "ghost", size: "sm", onClick: handleClear, className: "h-7 px-2 text-xs text-muted-foreground", children: [_jsx(X, { className: "h-3 w-3 mr-1" }), "Clear"] })) : null] }), column.type === "select" && column.options ? (_jsx(Stack, { gap: 2, className: "max-h-[300px] overflow-y-auto", children: column.options.map((option) => {
|
|
68
68
|
const isChecked = selectedValues.includes(option.value);
|
|
69
69
|
return (_jsxs(Flex, { align: "center", gap: 2, children: [_jsx(Checkbox, { id: `${String(column.key)}-${option.value}`, checked: isChecked, onCheckedChange: (checked) => handleCheckboxChange(option.value, checked === true) }), _jsx(Label, { htmlFor: `${String(column.key)}-${option.value}`, className: "text-sm font-normal cursor-pointer flex-1 text-foreground", children: option.label })] }, option.value));
|
|
70
70
|
}) })) : (_jsxs(Stack, { gap: 2, children: [_jsx(Input, { type: "text", placeholder: column.placeholder || `Filter by ${column.label}`, value: textValue, onChange: (e) => setTextValue(e.target.value), onKeyDown: (e) => {
|
|
@@ -9,7 +9,7 @@ import { Checkbox } from "@kala-ui/react/checkbox";
|
|
|
9
9
|
import { cn } from "@kala-ui/react/lib/utils";
|
|
10
10
|
import { TableBody, TableCell, TableRow } from "@kala-ui/react/table";
|
|
11
11
|
export function DataTableBodyRows({ displayData, columns, selection, selectedIds, onSelectRow, onRowClick, compact, striped, hoverable, getRowClassName, getRowAttributes, hasPagination, hasFooter, }) {
|
|
12
|
-
return (_jsx(TableBody, { children: displayData.map((row, rowIndex) => {
|
|
12
|
+
return (_jsx(TableBody, { "data-kala-component": "data-table-body-rows", children: displayData.map((row, rowIndex) => {
|
|
13
13
|
const isSelectable = !selection?.isRowSelectable || selection.isRowSelectable(row);
|
|
14
14
|
const rowId = selection?.getRowId(row);
|
|
15
15
|
const isSelected = rowId ? selectedIds.has(rowId) : false;
|
|
@@ -13,7 +13,7 @@ import { X } from "lucide-react";
|
|
|
13
13
|
export function DataTableFilterChips({ filterConfigs, filterableColumns, onSetFilter, onRemoveFilter, onClearFilters, }) {
|
|
14
14
|
if (filterConfigs.length === 0)
|
|
15
15
|
return null;
|
|
16
|
-
return (_jsxs(Flex, { align: "center", gap: 2, className: "mb-4 flex-wrap", children: [_jsx(Text, { size: "sm", className: "text-muted-foreground", children: "Active filters:" }), filterConfigs.map((filter) => {
|
|
16
|
+
return (_jsxs(Flex, { "data-kala-component": "data-table-filter-chips", align: "center", gap: 2, className: "mb-4 flex-wrap", children: [_jsx(Text, { size: "sm", className: "text-muted-foreground", children: "Active filters:" }), filterConfigs.map((filter) => {
|
|
17
17
|
const column = filterableColumns.find((fc) => fc.key === filter.key);
|
|
18
18
|
if (!column)
|
|
19
19
|
return null;
|
|
@@ -13,7 +13,7 @@ import { TableHead, TableHeader, TableRow } from "@kala-ui/react/table";
|
|
|
13
13
|
import { ChevronDown, ChevronUp } from "lucide-react";
|
|
14
14
|
import { ColumnHeaderFilter } from "./column-header-filter.js";
|
|
15
15
|
export function DataTableHeaderRow({ columns, selection, sortConfig, onToggleSort, filterableColumns, filterConfigs, onSetFilter, onRemoveFilter, isAllSelected, isSomeSelected, onSelectAll, stickyHeader, }) {
|
|
16
|
-
return (_jsx(TableHeader, { className: stickyHeader
|
|
16
|
+
return (_jsx(TableHeader, { "data-kala-component": "data-table-header-row", className: stickyHeader
|
|
17
17
|
? "sticky top-0 z-1 bg-muted/95 backdrop-blur-sm [&_tr]:border-0"
|
|
18
18
|
: "[&_tr]:border-0", children: _jsxs(TableRow, { className: "border-0", children: [selection?.enabled && (_jsx(TableHead, { className: stickyHeader
|
|
19
19
|
? "w-12 rounded-tl-lg border-b border-border-strong/50"
|
|
@@ -15,7 +15,7 @@ import { Select, SelectTrigger, SelectValue } from "@kala-ui/react/select";
|
|
|
15
15
|
import { Skeleton } from "@kala-ui/react/skeleton";
|
|
16
16
|
import { TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@kala-ui/react/table";
|
|
17
17
|
export function DataTableSkeleton({ rows = 5, columns, showSearch = false, showFilters = false, filterCount = 3, showPagination = false, showSelection = false, showBulkActions = false, stickyHeader = true, stickyFooter = false, }) {
|
|
18
|
-
return (_jsxs("div", { className: "flex flex-col", children: [showSearch && (_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-4 shrink-0", children: [_jsx("div", { className: "flex-1 max-w-sm", children: _jsx(Input, { type: "search", placeholder: "Search...", disabled: true, className: "opacity-50" }) }), showBulkActions && (_jsxs("div", { className: "flex items-center gap-2 flex-wrap min-h-[36px]", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "0 selected" }), _jsx(Button, { variant: "outline", size: "sm", disabled: true, className: "opacity-50", children: "Edit" }), _jsx(Button, { variant: "outline", size: "sm", disabled: true, className: "opacity-50", children: "Delete" })] }))] })), showFilters && (_jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-4 shrink-0", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "Active filters:" }), Array.from({ length: filterCount }).map((_, i) => (_jsxs(Badge, { color: "secondary", className: "gap-1.5 pl-2 pr-1 py-1 bg-primary/10 text-primary border-primary/20", children: [_jsx("span", { className: "text-xs font-medium", children: "Filter: Value" }), _jsx(Button, { variant: "ghost", size: "sm", disabled: true, className: "h-4 w-4 p-0 hover:bg-primary/20 rounded-sm", children: _jsx(Skeleton, { className: "h-3 w-3" }) })] }, `filter-${i}`))), _jsx(Button, { variant: "ghost", size: "sm", disabled: true, className: "h-7 px-2 text-xs text-muted-foreground hover:text-foreground", children: "Clear all" })] })), _jsx("div", { className: cn("border relative overflow-hidden kala-surface-card", showPagination ? "rounded-t-lg border-b-0" : "rounded-lg", stickyFooter ? "flex-1 min-h-0" : ""), children: _jsx("div", { className: cn("overflow-auto relative", showPagination ? "rounded-t-lg" : "rounded-lg", stickyFooter ? "flex-1 min-h-0 max-h-[70vh]" : "max-h-[600px]"), children: _jsxs("table", { className: "w-full border-separate border-spacing-0 caption-bottom text-sm", children: [_jsx(TableHeader, { className: cn(stickyHeader && "sticky top-0 z-1 bg-muted/95 backdrop-blur-sm", "[&_tr]:border-0"), children: _jsxs(TableRow, { className: "border-0", children: [showSelection && (_jsx(TableHead, { className: cn("w-12 rounded-tl-lg", stickyHeader
|
|
18
|
+
return (_jsxs("div", { "data-kala-component": "data-table-skeleton", className: "flex flex-col", children: [showSearch && (_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 mb-4 shrink-0", children: [_jsx("div", { className: "flex-1 max-w-sm", children: _jsx(Input, { type: "search", placeholder: "Search...", disabled: true, className: "opacity-50" }) }), showBulkActions && (_jsxs("div", { className: "flex items-center gap-2 flex-wrap min-h-[36px]", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "0 selected" }), _jsx(Button, { variant: "outline", size: "sm", disabled: true, className: "opacity-50", children: "Edit" }), _jsx(Button, { variant: "outline", size: "sm", disabled: true, className: "opacity-50", children: "Delete" })] }))] })), showFilters && (_jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-4 shrink-0", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "Active filters:" }), Array.from({ length: filterCount }).map((_, i) => (_jsxs(Badge, { color: "secondary", className: "gap-1.5 pl-2 pr-1 py-1 bg-primary/10 text-primary border-primary/20", children: [_jsx("span", { className: "text-xs font-medium", children: "Filter: Value" }), _jsx(Button, { variant: "ghost", size: "sm", disabled: true, className: "h-4 w-4 p-0 hover:bg-primary/20 rounded-sm", children: _jsx(Skeleton, { className: "h-3 w-3" }) })] }, `filter-${i}`))), _jsx(Button, { variant: "ghost", size: "sm", disabled: true, className: "h-7 px-2 text-xs text-muted-foreground hover:text-foreground", children: "Clear all" })] })), _jsx("div", { className: cn("border relative overflow-hidden kala-surface-card", showPagination ? "rounded-t-lg border-b-0" : "rounded-lg", stickyFooter ? "flex-1 min-h-0" : ""), children: _jsx("div", { className: cn("overflow-auto relative", showPagination ? "rounded-t-lg" : "rounded-lg", stickyFooter ? "flex-1 min-h-0 max-h-[70vh]" : "max-h-[600px]"), children: _jsxs("table", { className: "w-full border-separate border-spacing-0 caption-bottom text-sm", children: [_jsx(TableHeader, { className: cn(stickyHeader && "sticky top-0 z-1 bg-muted/95 backdrop-blur-sm", "[&_tr]:border-0"), children: _jsxs(TableRow, { className: "border-0", children: [showSelection && (_jsx(TableHead, { className: cn("w-12 rounded-tl-lg", stickyHeader
|
|
19
19
|
? "border-b border-border-strong/50"
|
|
20
20
|
: "border-b"), children: _jsx(Checkbox, { disabled: true }) })), columns.map((column, index) => {
|
|
21
21
|
const isFirst = !showSelection && index === 0;
|
|
@@ -17,7 +17,7 @@ export function DataTableToolbar({ searchConfig, searchQuery, onSearchChange, bu
|
|
|
17
17
|
const showRight = toolbarContent || bulkActions;
|
|
18
18
|
if (!showSearch && !showRight)
|
|
19
19
|
return null;
|
|
20
|
-
return (_jsxs(Flex, { align: "center", justify: "between", gap: 4, className: cn("mb-4 flex-wrap", className), children: [showSearch && (_jsx(Box, { className: "flex-1 max-w-sm", children: _jsx(Input, { type: "text", placeholder: searchConfig?.placeholder, value: searchQuery, onChange: (e) => onSearchChange(e.target.value), prefixIcon: _jsx(Search, { className: "h-4 w-4" }), suffixIcon: searchQuery ? (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => onSearchChange(""), className: "p-1 text-muted-foreground hover:text-foreground h-auto", "aria-label": "Clear search", children: _jsx(X, { className: "h-4 w-4" }) })) : null, "aria-label": searchConfig?.ariaLabel }) })), showRight && (_jsxs(Flex, { align: "center", gap: 2, className: "flex-wrap", children: [toolbarContent, bulkActions && (_jsxs(Flex, { align: "center", gap: 2, className: "flex-wrap min-h-[36px]", children: [_jsxs(Text, { size: "sm", className: "text-muted-foreground", children: [selectedIdsCount, " selected"] }), bulkActions.map((action) => (_jsxs(Button, { variant: action.variant === "destructive"
|
|
20
|
+
return (_jsxs(Flex, { "data-kala-component": "data-table-toolbar", align: "center", justify: "between", gap: 4, className: cn("mb-4 flex-wrap", className), children: [showSearch && (_jsx(Box, { className: "flex-1 max-w-sm", children: _jsx(Input, { type: "text", placeholder: searchConfig?.placeholder, value: searchQuery, onChange: (e) => onSearchChange(e.target.value), prefixIcon: _jsx(Search, { className: "h-4 w-4" }), suffixIcon: searchQuery ? (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => onSearchChange(""), className: "p-1 text-muted-foreground hover:text-foreground h-auto", "aria-label": "Clear search", children: _jsx(X, { className: "h-4 w-4" }) })) : null, "aria-label": searchConfig?.ariaLabel }) })), showRight && (_jsxs(Flex, { align: "center", gap: 2, className: "flex-wrap", children: [toolbarContent, bulkActions && (_jsxs(Flex, { align: "center", gap: 2, className: "flex-wrap min-h-[36px]", children: [_jsxs(Text, { size: "sm", className: "text-muted-foreground", children: [selectedIdsCount, " selected"] }), bulkActions.map((action) => (_jsxs(Button, { variant: action.variant === "destructive"
|
|
21
21
|
? "solid"
|
|
22
22
|
: (action.variant ?? "outline"), color: action.variant === "destructive" ? "destructive" : undefined, size: "sm", onClick: () => action.onClick(selectedRows), disabled: selectedIdsCount === 0 || action.disabled, className: selectedIdsCount === 0
|
|
23
23
|
? "opacity-50 cursor-not-allowed"
|
|
@@ -37,7 +37,7 @@ import { DataTableHeaderRow } from "./data-table-header-row.js";
|
|
|
37
37
|
import { DataTableSkeleton } from "./data-table-skeleton.js";
|
|
38
38
|
import { DataTableToolbar } from "./data-table-toolbar.js";
|
|
39
39
|
import { PaginationNav } from "./pagination-nav.js";
|
|
40
|
-
import { useTableState } from "./
|
|
40
|
+
import { useTableState } from "./use-table-state.js";
|
|
41
41
|
/**
|
|
42
42
|
* DataTable Component
|
|
43
43
|
*/
|
|
@@ -212,7 +212,7 @@ export function DataTable({ data, columns, searchable, pagination, defaultSort,
|
|
|
212
212
|
// Render loading state
|
|
213
213
|
if (isLoading) {
|
|
214
214
|
if (skeleton) {
|
|
215
|
-
return (_jsx(Stack, { gap: 4, className: className, children: skeleton }));
|
|
215
|
+
return (_jsx(Stack, { "data-kala-component": "data-table", gap: 4, className: className, children: skeleton }));
|
|
216
216
|
}
|
|
217
217
|
const showSearch = !!searchConfig;
|
|
218
218
|
const showFilters = !!filterableColumns;
|
|
@@ -220,7 +220,7 @@ export function DataTable({ data, columns, searchable, pagination, defaultSort,
|
|
|
220
220
|
const showSelection = !!selection?.enabled;
|
|
221
221
|
const showBulkActions = !!bulkActions;
|
|
222
222
|
const skeletonRows = skeletonConfig?.rows ?? loadingConfig?.rows ?? 5;
|
|
223
|
-
return (_jsx(Stack, { gap: 4, className: className, children: _jsx(DataTableSkeleton, { rows: skeletonRows, columns: columns, showSearch: showSearch, showFilters: showFilters, showPagination: showPagination, showSelection: showSelection, showBulkActions: showBulkActions, stickyHeader: stickyHeader, stickyFooter: stickyFooter }) }));
|
|
223
|
+
return (_jsx(Stack, { "data-kala-component": "data-table", gap: 4, className: className, children: _jsx(DataTableSkeleton, { rows: skeletonRows, columns: columns, showSearch: showSearch, showFilters: showFilters, showPagination: showPagination, showSelection: showSelection, showBulkActions: showBulkActions, stickyHeader: stickyHeader, stickyFooter: stickyFooter }) }));
|
|
224
224
|
}
|
|
225
225
|
// Compute empty state config
|
|
226
226
|
const emptyConfig = {
|
|
@@ -230,7 +230,9 @@ export function DataTable({ data, columns, searchable, pagination, defaultSort,
|
|
|
230
230
|
: "There is no data to display at the moment.",
|
|
231
231
|
...emptyState,
|
|
232
232
|
};
|
|
233
|
-
return (_jsxs(Stack, { className: cn(stickyFooter ? "h-full min-h-0" : "", className), "aria-label": ariaLabel, role: ariaLabel ? "region" : undefined, gap: 0, children: [_jsx(DataTableToolbar, { searchConfig: searchConfig, searchQuery: searchQuery, onSearchChange: setSearchQuery, bulkActions: bulkActions, selectedRows: selectedRows, selectedIdsCount: selectedIds.size, toolbarContent: toolbarContent, hasData: data.length > 0, className: stickyFooter ? "shrink-0" : undefined }), filterableColumns && (_jsx("div", { className: stickyFooter ? "shrink-0" : undefined, children: _jsx(DataTableFilterChips, { filterConfigs: filterConfigs, filterableColumns: filterableColumns, onSetFilter: setFilter, onRemoveFilter: removeFilter, onClearFilters: clearFilters }) })), displayData.length === 0 && !filterConfigs.length && !searchQuery ? (_jsx(EmptyState, { title: emptyConfig.title, description: emptyConfig.description, ...(emptyState?.icon && { icon: emptyState.icon }), ...(emptyState?.action && { action: emptyState.action })
|
|
233
|
+
return (_jsxs(Stack, { "data-kala-component": "data-table", className: cn(stickyFooter ? "h-full min-h-0" : "", className), "aria-label": ariaLabel, role: ariaLabel ? "region" : undefined, gap: 0, children: [_jsx(DataTableToolbar, { searchConfig: searchConfig, searchQuery: searchQuery, onSearchChange: setSearchQuery, bulkActions: bulkActions, selectedRows: selectedRows, selectedIdsCount: selectedIds.size, toolbarContent: toolbarContent, hasData: data.length > 0, className: stickyFooter ? "shrink-0" : undefined }), filterableColumns && (_jsx("div", { className: stickyFooter ? "shrink-0" : undefined, children: _jsx(DataTableFilterChips, { filterConfigs: filterConfigs, filterableColumns: filterableColumns, onSetFilter: setFilter, onRemoveFilter: removeFilter, onClearFilters: clearFilters }) })), displayData.length === 0 && !filterConfigs.length && !searchQuery ? (_jsx(EmptyState, { title: emptyConfig.title, description: emptyConfig.description, ...(emptyState?.icon && { icon: emptyState.icon }), ...(emptyState?.action && { action: emptyState.action }), ...(emptyState?.slotStyles && {
|
|
234
|
+
slotStyles: emptyState.slotStyles,
|
|
235
|
+
}) })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { className: cn("border relative overflow-hidden kala-surface-card", stickyFooter && paginationConfig && displayData.length > 0
|
|
234
236
|
? "flex-1 min-h-0"
|
|
235
237
|
: "", bordered && "border-2", paginationConfig && displayData.length > 0
|
|
236
238
|
? "rounded-t-lg border-b-0"
|
|
@@ -121,6 +121,8 @@ export interface EmptyStateConfig {
|
|
|
121
121
|
label: string;
|
|
122
122
|
onClick: () => void;
|
|
123
123
|
};
|
|
124
|
+
/** Per-part overrides forwarded to the embedded EmptyState */
|
|
125
|
+
slotStyles?: EmptyStateProps["slotStyles"];
|
|
124
126
|
}
|
|
125
127
|
/**
|
|
126
128
|
* Loading state configuration - DEPRECATED: Use DataTableSkeletonConfig
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { DataTable, DataTableSkeleton } from "./data-table";
|
|
5
5
|
export type { BulkAction, ColumnDef, DataTableProps, DataTableSkeletonConfig, EmptyStateConfig, FilterableColumn, FilterConfig, FilterOperator, LoadingConfig, PaginationConfig, SearchConfig, SelectionConfig, SortConfig, SortDirection, TableState, } from "./data-table.types";
|
|
6
|
-
export { useTableState } from "./
|
|
6
|
+
export { useTableState } from "./use-table-state";
|
|
@@ -19,5 +19,5 @@ export function PaginationNav({ currentPage, totalPages, hasPreviousPage, hasNex
|
|
|
19
19
|
boundaries: 1,
|
|
20
20
|
onPageChange,
|
|
21
21
|
});
|
|
22
|
-
return (_jsxs(Flex, { align: "center", justify: "center", wrap: "wrap", gap: 1, children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: onPreviousPage, disabled: !hasPreviousPage, className: "h-8 w-8 p-0", children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), _jsx(Box, { as: "span", className: "sr-only", children: "Previous page" })] }), range.map((item, index) => item === DOTS ? (_jsx(Flex, { align: "center", justify: "center", className: "h-8 w-8", "aria-hidden": true, children: _jsx(MoreHorizontal, { className: "h-4 w-4 text-muted-foreground" }) }, `dots-${index}`)) : (_jsx(Button, { variant: item === currentPage ? "solid" : "outline", size: "sm", onClick: () => onPageChange(item), className: "h-8 w-8 p-0 text-xs", "aria-label": `Page ${item}`, "aria-current": item === currentPage ? "page" : undefined, children: item }, item))), _jsxs(Button, { variant: "outline", size: "sm", onClick: onNextPage, disabled: !hasNextPage, className: "h-8 w-8 p-0", children: [_jsx(ChevronRight, { className: "h-4 w-4" }), _jsx(Box, { as: "span", className: "sr-only", children: "Next page" })] })] }));
|
|
22
|
+
return (_jsxs(Flex, { "data-kala-component": "data-table-pagination-nav", align: "center", justify: "center", wrap: "wrap", gap: 1, children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: onPreviousPage, disabled: !hasPreviousPage, className: "h-8 w-8 p-0", children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), _jsx(Box, { as: "span", className: "sr-only", children: "Previous page" })] }), range.map((item, index) => item === DOTS ? (_jsx(Flex, { align: "center", justify: "center", className: "h-8 w-8", "aria-hidden": true, children: _jsx(MoreHorizontal, { className: "h-4 w-4 text-muted-foreground" }) }, `dots-${index}`)) : (_jsx(Button, { variant: item === currentPage ? "solid" : "outline", size: "sm", onClick: () => onPageChange(item), className: "h-8 w-8 p-0 text-xs", "aria-label": `Page ${item}`, "aria-current": item === currentPage ? "page" : undefined, children: item }, item))), _jsxs(Button, { variant: "outline", size: "sm", onClick: onNextPage, disabled: !hasNextPage, className: "h-8 w-8 p-0", children: [_jsx(ChevronRight, { className: "h-4 w-4" }), _jsx(Box, { as: "span", className: "sr-only", children: "Next page" })] })] }));
|
|
23
23
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTableState Hook
|
|
3
|
+
* Manages table state including sorting, filtering, pagination, and search
|
|
4
|
+
*/
|
|
5
|
+
import type { ColumnDef, FilterConfig, SearchConfig, SortConfig, TableState } from "./data-table.types";
|
|
6
|
+
interface UseTableStateOptions<TData> {
|
|
7
|
+
data: TData[];
|
|
8
|
+
columns: ColumnDef<TData>[];
|
|
9
|
+
defaultSort?: SortConfig<TData>;
|
|
10
|
+
defaultFilters?: FilterConfig<TData>[];
|
|
11
|
+
searchConfig?: SearchConfig<TData> | boolean;
|
|
12
|
+
pageSize?: number;
|
|
13
|
+
total?: number;
|
|
14
|
+
/** Controlled page number (1-indexed); omitted = uncontrolled */
|
|
15
|
+
page?: number;
|
|
16
|
+
/** Callback when sort changes */
|
|
17
|
+
onSortChange?: (sort: SortConfig<TData> | null) => void;
|
|
18
|
+
/** Callback when filters change */
|
|
19
|
+
onFilterChange?: (filters: FilterConfig<TData>[]) => void;
|
|
20
|
+
/** Callback when search query changes */
|
|
21
|
+
onSearchChange?: (query: string) => void;
|
|
22
|
+
/** Callback when pagination changes */
|
|
23
|
+
onPaginationChange?: (page: number, pageSize: number) => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hook to manage table state (sorting, filtering, search, pagination)
|
|
27
|
+
*/
|
|
28
|
+
export declare function useTableState<TData>({ data, columns, defaultSort, defaultFilters, searchConfig, pageSize: initialPageSize, total: manualTotal, page, onSortChange, onFilterChange, onSearchChange, onPaginationChange, }: UseTableStateOptions<TData>): TableState<TData>;
|
|
29
|
+
export {};
|