tekivex-ui 2.3.0 → 2.5.2

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 (93) hide show
  1. package/README.md +436 -83
  2. package/dist/TkxForm-BWK4LqY3.js +1461 -0
  3. package/dist/TkxForm-ljQjX7KD.cjs +15 -0
  4. package/dist/charts.cjs +1 -0
  5. package/dist/charts.js +480 -0
  6. package/dist/headless.cjs +1 -0
  7. package/dist/headless.js +258 -0
  8. package/dist/index-BINBzXuY.cjs +2 -0
  9. package/dist/index-eT_U4qB2.js +512 -0
  10. package/dist/index.cjs +20 -32
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +7942 -8903
  14. package/dist/src/charts/TkxAreaChart.d.ts +29 -0
  15. package/dist/src/charts/TkxAreaChart.d.ts.map +1 -0
  16. package/dist/src/charts/TkxBarChart.d.ts +28 -0
  17. package/dist/src/charts/TkxBarChart.d.ts.map +1 -0
  18. package/dist/src/charts/TkxDonutChart.d.ts +23 -0
  19. package/dist/src/charts/TkxDonutChart.d.ts.map +1 -0
  20. package/dist/src/charts/TkxLineChart.d.ts +35 -0
  21. package/dist/src/charts/TkxLineChart.d.ts.map +1 -0
  22. package/dist/src/charts/TkxPieChart.d.ts +19 -0
  23. package/dist/src/charts/TkxPieChart.d.ts.map +1 -0
  24. package/dist/src/charts/TkxRadarChart.d.ts +20 -0
  25. package/dist/src/charts/TkxRadarChart.d.ts.map +1 -0
  26. package/dist/src/charts/TkxScatterChart.d.ts +28 -0
  27. package/dist/src/charts/TkxScatterChart.d.ts.map +1 -0
  28. package/dist/src/charts/index.d.ts +15 -0
  29. package/dist/src/charts/index.d.ts.map +1 -0
  30. package/dist/src/charts/shared.d.ts +33 -0
  31. package/dist/src/charts/shared.d.ts.map +1 -0
  32. package/dist/src/components/TkxDataGrid.d.ts +16 -2
  33. package/dist/src/components/TkxDataGrid.d.ts.map +1 -1
  34. package/dist/src/components/TkxForm.d.ts +33 -3
  35. package/dist/src/components/TkxForm.d.ts.map +1 -1
  36. package/dist/src/components/TkxImage.d.ts.map +1 -1
  37. package/dist/src/components/TkxTypography.d.ts +1 -1
  38. package/dist/src/components/TkxTypography.d.ts.map +1 -1
  39. package/dist/src/engine/tkx.d.ts.map +1 -1
  40. package/dist/src/headless/index.d.ts +18 -0
  41. package/dist/src/headless/index.d.ts.map +1 -0
  42. package/dist/src/headless/useControllable.d.ts +20 -0
  43. package/dist/src/headless/useControllable.d.ts.map +1 -0
  44. package/dist/src/headless/useDebounce.d.ts +14 -0
  45. package/dist/src/headless/useDebounce.d.ts.map +1 -0
  46. package/dist/src/headless/useDisclosure.d.ts +20 -0
  47. package/dist/src/headless/useDisclosure.d.ts.map +1 -0
  48. package/dist/src/headless/useFormState.d.ts +44 -0
  49. package/dist/src/headless/useFormState.d.ts.map +1 -0
  50. package/dist/src/headless/useIntersectionObserver.d.ts +23 -0
  51. package/dist/src/headless/useIntersectionObserver.d.ts.map +1 -0
  52. package/dist/src/headless/useListSelection.d.ts +29 -0
  53. package/dist/src/headless/useListSelection.d.ts.map +1 -0
  54. package/dist/src/headless/useLocalStorage.d.ts +9 -0
  55. package/dist/src/headless/useLocalStorage.d.ts.map +1 -0
  56. package/dist/src/headless/useMediaQuery.d.ts +21 -0
  57. package/dist/src/headless/useMediaQuery.d.ts.map +1 -0
  58. package/dist/src/headless/useRovingTabIndex.d.ts +33 -0
  59. package/dist/src/headless/useRovingTabIndex.d.ts.map +1 -0
  60. package/dist/src/headless/useThrottle.d.ts +9 -0
  61. package/dist/src/headless/useThrottle.d.ts.map +1 -0
  62. package/dist/src/i18n/index.d.ts +47 -2
  63. package/dist/src/i18n/index.d.ts.map +1 -1
  64. package/dist/src/themes/index.d.ts.map +1 -1
  65. package/package.json +61 -7
  66. package/src/charts/TkxAreaChart.tsx +119 -0
  67. package/src/charts/TkxBarChart.tsx +115 -0
  68. package/src/charts/TkxDonutChart.tsx +145 -0
  69. package/src/charts/TkxLineChart.tsx +135 -0
  70. package/src/charts/TkxPieChart.tsx +82 -0
  71. package/src/charts/TkxRadarChart.tsx +90 -0
  72. package/src/charts/TkxScatterChart.tsx +102 -0
  73. package/src/charts/index.ts +20 -0
  74. package/src/charts/shared.ts +45 -0
  75. package/src/components/TkxDataGrid.tsx +532 -268
  76. package/src/components/TkxForm.tsx +67 -15
  77. package/src/components/TkxImage.tsx +1 -1
  78. package/src/components/TkxTypography.tsx +4 -2
  79. package/src/engine/tkx.ts +60 -3
  80. package/src/headless/index.ts +44 -0
  81. package/src/headless/useControllable.ts +40 -0
  82. package/src/headless/useDebounce.ts +35 -0
  83. package/src/headless/useDisclosure.ts +28 -0
  84. package/src/headless/useFormState.ts +111 -0
  85. package/src/headless/useIntersectionObserver.ts +51 -0
  86. package/src/headless/useListSelection.ts +101 -0
  87. package/src/headless/useLocalStorage.ts +46 -0
  88. package/src/headless/useMediaQuery.ts +37 -0
  89. package/src/headless/useRovingTabIndex.ts +84 -0
  90. package/src/headless/useThrottle.ts +46 -0
  91. package/src/i18n/I18nProvider.tsx +1 -1
  92. package/src/i18n/index.ts +678 -38
  93. package/src/themes/index.ts +31 -4
@@ -0,0 +1,145 @@
1
+ import {
2
+ ResponsiveContainer,
3
+ PieChart,
4
+ Pie,
5
+ Cell,
6
+ Tooltip,
7
+ Legend,
8
+ } from 'recharts';
9
+ import { useTheme } from '../themes';
10
+ import { getDefaultColors, tooltipStyle } from './shared';
11
+
12
+ export interface TkxDonutChartSlice {
13
+ name: string;
14
+ value: number;
15
+ color?: string;
16
+ }
17
+
18
+ export interface TkxDonutChartProps {
19
+ data: TkxDonutChartSlice[];
20
+ height?: number;
21
+ showLegend?: boolean;
22
+ showTooltip?: boolean;
23
+ /** Center label — large text (e.g. total value) */
24
+ centerLabel?: string;
25
+ /** Center sublabel — small text below centerLabel */
26
+ centerSublabel?: string;
27
+ /** Inner radius as number or percentage string. Default: '55%' */
28
+ innerRadius?: number | string;
29
+ /** Outer radius as number or percentage string. Default: '75%' */
30
+ outerRadius?: number | string;
31
+ startAngle?: number;
32
+ ariaLabel?: string;
33
+ }
34
+
35
+ function CenterLabel({
36
+ cx, cy, label, sublabel, theme,
37
+ }: {
38
+ cx: number; cy: number;
39
+ label?: string; sublabel?: string;
40
+ theme: any;
41
+ }) {
42
+ if (!label && !sublabel) return null;
43
+ return (
44
+ <>
45
+ {label && (
46
+ <text x={cx} y={cy - (sublabel ? 8 : 0)} textAnchor="middle" dominantBaseline="middle"
47
+ fill={theme.text} fontSize={22} fontWeight={700} fontFamily="inherit">
48
+ {label}
49
+ </text>
50
+ )}
51
+ {sublabel && (
52
+ <text x={cx} y={cy + (label ? 18 : 0)} textAnchor="middle" dominantBaseline="middle"
53
+ fill={theme.textMuted} fontSize={13} fontFamily="inherit">
54
+ {sublabel}
55
+ </text>
56
+ )}
57
+ </>
58
+ );
59
+ }
60
+
61
+ export function TkxDonutChart({
62
+ data,
63
+ height = 300,
64
+ showLegend = true,
65
+ showTooltip = true,
66
+ centerLabel,
67
+ centerSublabel,
68
+ innerRadius = '55%',
69
+ outerRadius = '75%',
70
+ startAngle = 90,
71
+ ariaLabel = 'Donut chart',
72
+ }: TkxDonutChartProps) {
73
+ const theme = useTheme();
74
+ const colors = getDefaultColors(theme);
75
+ const tt = tooltipStyle(theme);
76
+
77
+ return (
78
+ <div role="img" aria-label={ariaLabel} style={{ width: '100%', height }}>
79
+ <ResponsiveContainer width="100%" height="100%">
80
+ <PieChart>
81
+ {showTooltip && (
82
+ <Tooltip
83
+ contentStyle={tt.contentStyle}
84
+ labelStyle={tt.labelStyle}
85
+ itemStyle={tt.itemStyle}
86
+ />
87
+ )}
88
+ {showLegend && (
89
+ <Legend wrapperStyle={{ fontSize: 13, color: theme.textMuted }} />
90
+ )}
91
+ <Pie
92
+ data={data}
93
+ dataKey="value"
94
+ nameKey="name"
95
+ innerRadius={innerRadius}
96
+ outerRadius={outerRadius}
97
+ startAngle={startAngle}
98
+ endAngle={startAngle - 360}
99
+ strokeWidth={3}
100
+ stroke={theme.bg}
101
+ label={false}
102
+ labelLine={false}
103
+ >
104
+ {data.map((entry, i) => (
105
+ <Cell key={entry.name} fill={entry.color ?? colors[i % colors.length]} />
106
+ ))}
107
+ {/* Center text via customized label — recharts passes cx/cy to label */}
108
+ </Pie>
109
+ {/* SVG center label rendered as a separate layer */}
110
+ {(centerLabel || centerSublabel) && (
111
+ <text>
112
+ {/* This renders nothing — actual center text needs PieChart customization */}
113
+ </text>
114
+ )}
115
+ </PieChart>
116
+ </ResponsiveContainer>
117
+ {/* Overlay center label using absolute positioning */}
118
+ {(centerLabel || centerSublabel) && (
119
+ <div
120
+ style={{
121
+ position: 'absolute',
122
+ inset: 0,
123
+ display: 'flex',
124
+ flexDirection: 'column',
125
+ alignItems: 'center',
126
+ justifyContent: 'center',
127
+ pointerEvents: 'none',
128
+ marginTop: showLegend ? -24 : 0,
129
+ }}
130
+ >
131
+ {centerLabel && (
132
+ <span style={{ fontSize: 22, fontWeight: 700, color: theme.text, lineHeight: 1 }}>
133
+ {centerLabel}
134
+ </span>
135
+ )}
136
+ {centerSublabel && (
137
+ <span style={{ fontSize: 13, color: theme.textMuted, marginTop: 4 }}>
138
+ {centerSublabel}
139
+ </span>
140
+ )}
141
+ </div>
142
+ )}
143
+ </div>
144
+ );
145
+ }
@@ -0,0 +1,135 @@
1
+ import {
2
+ ResponsiveContainer,
3
+ LineChart,
4
+ Line,
5
+ XAxis,
6
+ YAxis,
7
+ CartesianGrid,
8
+ Tooltip,
9
+ Legend,
10
+ ReferenceLine,
11
+ } from 'recharts';
12
+ import { useTheme } from '../themes';
13
+ import { getDefaultColors, tooltipStyle, DEFAULT_MARGIN, type ChartMargin } from './shared';
14
+
15
+ export interface TkxLineChartSeries {
16
+ key: string;
17
+ label?: string;
18
+ color?: string;
19
+ strokeWidth?: number;
20
+ dashed?: boolean;
21
+ dot?: boolean;
22
+ }
23
+
24
+ export interface TkxReferenceLineConfig {
25
+ y?: number;
26
+ x?: number | string;
27
+ label?: string;
28
+ color?: string;
29
+ dashed?: boolean;
30
+ }
31
+
32
+ export interface TkxLineChartProps {
33
+ data: Record<string, any>[];
34
+ series: TkxLineChartSeries[];
35
+ xKey: string;
36
+ height?: number;
37
+ margin?: ChartMargin;
38
+ showGrid?: boolean;
39
+ showLegend?: boolean;
40
+ showTooltip?: boolean;
41
+ smooth?: boolean;
42
+ referenceLines?: TkxReferenceLineConfig[];
43
+ xTickFormatter?: (value: any) => string;
44
+ yTickFormatter?: (value: any) => string;
45
+ yDomain?: [number | 'auto' | 'dataMin' | 'dataMax', number | 'auto' | 'dataMin' | 'dataMax'];
46
+ connectNulls?: boolean;
47
+ ariaLabel?: string;
48
+ }
49
+
50
+ export function TkxLineChart({
51
+ data,
52
+ series,
53
+ xKey,
54
+ height = 300,
55
+ margin = DEFAULT_MARGIN,
56
+ showGrid = true,
57
+ showLegend = true,
58
+ showTooltip = true,
59
+ smooth = true,
60
+ referenceLines = [],
61
+ xTickFormatter,
62
+ yTickFormatter,
63
+ yDomain,
64
+ connectNulls = false,
65
+ ariaLabel = 'Line chart',
66
+ }: TkxLineChartProps) {
67
+ const theme = useTheme();
68
+ const colors = getDefaultColors(theme);
69
+ const tt = tooltipStyle(theme);
70
+ const tickStyle = { fill: theme.textMuted, fontSize: 12 };
71
+
72
+ return (
73
+ <div role="img" aria-label={ariaLabel} style={{ width: '100%', height }}>
74
+ <ResponsiveContainer width="100%" height="100%">
75
+ <LineChart data={data} margin={margin}>
76
+ {showGrid && (
77
+ <CartesianGrid strokeDasharray="3 3" stroke={theme.border} vertical={false} />
78
+ )}
79
+ <XAxis
80
+ dataKey={xKey}
81
+ tick={tickStyle}
82
+ axisLine={{ stroke: theme.border }}
83
+ tickLine={false}
84
+ tickFormatter={xTickFormatter}
85
+ />
86
+ <YAxis
87
+ tick={tickStyle}
88
+ axisLine={false}
89
+ tickLine={false}
90
+ tickFormatter={yTickFormatter}
91
+ domain={yDomain}
92
+ />
93
+ {showTooltip && (
94
+ <Tooltip
95
+ contentStyle={tt.contentStyle}
96
+ labelStyle={tt.labelStyle}
97
+ itemStyle={tt.itemStyle}
98
+ cursor={{ stroke: theme.border, strokeWidth: 1 }}
99
+ />
100
+ )}
101
+ {showLegend && (
102
+ <Legend wrapperStyle={{ fontSize: 13, color: theme.textMuted, paddingTop: 8 }} />
103
+ )}
104
+ {referenceLines.map((rl, i) => (
105
+ <ReferenceLine
106
+ key={i}
107
+ y={rl.y}
108
+ x={rl.x}
109
+ label={rl.label ? { value: rl.label, fill: theme.textMuted, fontSize: 11 } : undefined}
110
+ stroke={rl.color ?? theme.border}
111
+ strokeDasharray={rl.dashed ? '4 4' : undefined}
112
+ />
113
+ ))}
114
+ {series.map((s, i) => {
115
+ const color = s.color ?? colors[i % colors.length];
116
+ return (
117
+ <Line
118
+ key={s.key}
119
+ type={smooth ? 'monotone' : 'linear'}
120
+ dataKey={s.key}
121
+ name={s.label ?? s.key}
122
+ stroke={color}
123
+ strokeWidth={s.strokeWidth ?? 2}
124
+ strokeDasharray={s.dashed ? '6 3' : undefined}
125
+ dot={s.dot ?? false}
126
+ activeDot={{ r: 5, strokeWidth: 0, fill: color }}
127
+ connectNulls={connectNulls}
128
+ />
129
+ );
130
+ })}
131
+ </LineChart>
132
+ </ResponsiveContainer>
133
+ </div>
134
+ );
135
+ }
@@ -0,0 +1,82 @@
1
+ import {
2
+ ResponsiveContainer,
3
+ PieChart,
4
+ Pie,
5
+ Cell,
6
+ Tooltip,
7
+ Legend,
8
+ } from 'recharts';
9
+ import { useTheme } from '../themes';
10
+ import { getDefaultColors, tooltipStyle } from './shared';
11
+
12
+ export interface TkxPieChartSlice {
13
+ name: string;
14
+ value: number;
15
+ color?: string;
16
+ }
17
+
18
+ export interface TkxPieChartProps {
19
+ data: TkxPieChartSlice[];
20
+ height?: number;
21
+ showLegend?: boolean;
22
+ showTooltip?: boolean;
23
+ showLabels?: boolean;
24
+ /** Outer radius as a number (px) or percentage string. Default: '70%' */
25
+ outerRadius?: number | string;
26
+ /** Start angle in degrees. Default: 90 (12 o'clock) */
27
+ startAngle?: number;
28
+ ariaLabel?: string;
29
+ }
30
+
31
+ export function TkxPieChart({
32
+ data,
33
+ height = 300,
34
+ showLegend = true,
35
+ showTooltip = true,
36
+ showLabels = false,
37
+ outerRadius = '70%',
38
+ startAngle = 90,
39
+ ariaLabel = 'Pie chart',
40
+ }: TkxPieChartProps) {
41
+ const theme = useTheme();
42
+ const colors = getDefaultColors(theme);
43
+ const tt = tooltipStyle(theme);
44
+
45
+ return (
46
+ <div role="img" aria-label={ariaLabel} style={{ width: '100%', height }}>
47
+ <ResponsiveContainer width="100%" height="100%">
48
+ <PieChart>
49
+ {showTooltip && (
50
+ <Tooltip
51
+ contentStyle={tt.contentStyle}
52
+ labelStyle={tt.labelStyle}
53
+ itemStyle={tt.itemStyle}
54
+ />
55
+ )}
56
+ {showLegend && (
57
+ <Legend wrapperStyle={{ fontSize: 13, color: theme.textMuted }} />
58
+ )}
59
+ <Pie
60
+ data={data}
61
+ dataKey="value"
62
+ nameKey="name"
63
+ outerRadius={outerRadius}
64
+ startAngle={startAngle}
65
+ endAngle={startAngle - 360}
66
+ label={showLabels ? ({ name, percent }) => `${name} (${(percent * 100).toFixed(0)}%)` : undefined}
67
+ labelLine={showLabels}
68
+ strokeWidth={2}
69
+ stroke={theme.bg}
70
+ >
71
+ {data.map((entry, i) => (
72
+ <Cell
73
+ key={entry.name}
74
+ fill={entry.color ?? colors[i % colors.length]}
75
+ />
76
+ ))}
77
+ </Pie>
78
+ </PieChart>
79
+ </ResponsiveContainer>
80
+ </div>
81
+ );
82
+ }
@@ -0,0 +1,90 @@
1
+ import {
2
+ ResponsiveContainer,
3
+ RadarChart,
4
+ PolarGrid,
5
+ PolarAngleAxis,
6
+ PolarRadiusAxis,
7
+ Radar,
8
+ Legend,
9
+ Tooltip,
10
+ } from 'recharts';
11
+ import { useTheme } from '../themes';
12
+ import { getDefaultColors, tooltipStyle } from './shared';
13
+
14
+ export interface TkxRadarSeries {
15
+ key: string;
16
+ label?: string;
17
+ color?: string;
18
+ fillOpacity?: number;
19
+ }
20
+
21
+ export interface TkxRadarChartProps {
22
+ data: Record<string, any>[];
23
+ series: TkxRadarSeries[];
24
+ /** Key in data for the axis labels (e.g. 'subject', 'metric') */
25
+ angleKey: string;
26
+ height?: number;
27
+ showLegend?: boolean;
28
+ showTooltip?: boolean;
29
+ /** Outer radius as percentage string or number. Default: '70%' */
30
+ outerRadius?: string | number;
31
+ ariaLabel?: string;
32
+ }
33
+
34
+ export function TkxRadarChart({
35
+ data,
36
+ series,
37
+ angleKey,
38
+ height = 300,
39
+ showLegend = true,
40
+ showTooltip = true,
41
+ outerRadius = '70%',
42
+ ariaLabel = 'Radar chart',
43
+ }: TkxRadarChartProps) {
44
+ const theme = useTheme();
45
+ const colors = getDefaultColors(theme);
46
+ const tt = tooltipStyle(theme);
47
+
48
+ return (
49
+ <div role="img" aria-label={ariaLabel} style={{ width: '100%', height }}>
50
+ <ResponsiveContainer width="100%" height="100%">
51
+ <RadarChart data={data} outerRadius={outerRadius}>
52
+ <PolarGrid stroke={theme.border} />
53
+ <PolarAngleAxis
54
+ dataKey={angleKey}
55
+ tick={{ fill: theme.textMuted, fontSize: 12 }}
56
+ />
57
+ <PolarRadiusAxis
58
+ tick={{ fill: theme.textMuted, fontSize: 10 }}
59
+ axisLine={false}
60
+ tickLine={false}
61
+ />
62
+ {showTooltip && (
63
+ <Tooltip
64
+ contentStyle={tt.contentStyle}
65
+ labelStyle={tt.labelStyle}
66
+ itemStyle={tt.itemStyle}
67
+ />
68
+ )}
69
+ {showLegend && (
70
+ <Legend wrapperStyle={{ fontSize: 13, color: theme.textMuted }} />
71
+ )}
72
+ {series.map((s, i) => {
73
+ const color = s.color ?? colors[i % colors.length];
74
+ return (
75
+ <Radar
76
+ key={s.key}
77
+ name={s.label ?? s.key}
78
+ dataKey={s.key}
79
+ stroke={color}
80
+ fill={color}
81
+ fillOpacity={s.fillOpacity ?? 0.2}
82
+ strokeWidth={2}
83
+ />
84
+ );
85
+ })}
86
+ </RadarChart>
87
+ </ResponsiveContainer>
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,102 @@
1
+ import {
2
+ ResponsiveContainer,
3
+ ScatterChart,
4
+ Scatter,
5
+ XAxis,
6
+ YAxis,
7
+ ZAxis,
8
+ CartesianGrid,
9
+ Tooltip,
10
+ Legend,
11
+ } from 'recharts';
12
+ import { useTheme } from '../themes';
13
+ import { getDefaultColors, tooltipStyle, DEFAULT_MARGIN, type ChartMargin } from './shared';
14
+
15
+ export interface TkxScatterSeries {
16
+ data: { x: number; y: number; z?: number; label?: string }[];
17
+ name?: string;
18
+ color?: string;
19
+ }
20
+
21
+ export interface TkxScatterChartProps {
22
+ series: TkxScatterSeries[];
23
+ height?: number;
24
+ margin?: ChartMargin;
25
+ showGrid?: boolean;
26
+ showLegend?: boolean;
27
+ showTooltip?: boolean;
28
+ xLabel?: string;
29
+ yLabel?: string;
30
+ xTickFormatter?: (value: any) => string;
31
+ yTickFormatter?: (value: any) => string;
32
+ /** Z-axis range (bubble size). Default: [20, 400] */
33
+ zRange?: [number, number];
34
+ ariaLabel?: string;
35
+ }
36
+
37
+ export function TkxScatterChart({
38
+ series,
39
+ height = 300,
40
+ margin = DEFAULT_MARGIN,
41
+ showGrid = true,
42
+ showLegend = true,
43
+ showTooltip = true,
44
+ xTickFormatter,
45
+ yTickFormatter,
46
+ zRange = [20, 400],
47
+ ariaLabel = 'Scatter chart',
48
+ }: TkxScatterChartProps) {
49
+ const theme = useTheme();
50
+ const colors = getDefaultColors(theme);
51
+ const tt = tooltipStyle(theme);
52
+ const tickStyle = { fill: theme.textMuted, fontSize: 12 };
53
+
54
+ return (
55
+ <div role="img" aria-label={ariaLabel} style={{ width: '100%', height }}>
56
+ <ResponsiveContainer width="100%" height="100%">
57
+ <ScatterChart margin={margin}>
58
+ {showGrid && (
59
+ <CartesianGrid strokeDasharray="3 3" stroke={theme.border} />
60
+ )}
61
+ <XAxis
62
+ type="number"
63
+ dataKey="x"
64
+ tick={tickStyle}
65
+ axisLine={{ stroke: theme.border }}
66
+ tickLine={false}
67
+ tickFormatter={xTickFormatter}
68
+ />
69
+ <YAxis
70
+ type="number"
71
+ dataKey="y"
72
+ tick={tickStyle}
73
+ axisLine={false}
74
+ tickLine={false}
75
+ tickFormatter={yTickFormatter}
76
+ />
77
+ <ZAxis type="number" dataKey="z" range={zRange} />
78
+ {showTooltip && (
79
+ <Tooltip
80
+ contentStyle={tt.contentStyle}
81
+ labelStyle={tt.labelStyle}
82
+ itemStyle={tt.itemStyle}
83
+ cursor={{ strokeDasharray: '3 3' }}
84
+ />
85
+ )}
86
+ {showLegend && (
87
+ <Legend wrapperStyle={{ fontSize: 13, color: theme.textMuted, paddingTop: 8 }} />
88
+ )}
89
+ {series.map((s, i) => (
90
+ <Scatter
91
+ key={s.name ?? i}
92
+ name={s.name}
93
+ data={s.data}
94
+ fill={s.color ?? colors[i % colors.length]}
95
+ fillOpacity={0.8}
96
+ />
97
+ ))}
98
+ </ScatterChart>
99
+ </ResponsiveContainer>
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,20 @@
1
+ // ── @tekivex/ui/charts ───────────────────────────────────────────────────────
2
+ // Theme-aware chart components built on Recharts.
3
+ // Import from '@tekivex/ui/charts' — zero impact on the main bundle.
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+
6
+ export { TkxAreaChart } from './TkxAreaChart';
7
+ export { TkxBarChart } from './TkxBarChart';
8
+ export { TkxLineChart } from './TkxLineChart';
9
+ export { TkxPieChart } from './TkxPieChart';
10
+ export { TkxDonutChart } from './TkxDonutChart';
11
+ export { TkxScatterChart } from './TkxScatterChart';
12
+ export { TkxRadarChart } from './TkxRadarChart';
13
+
14
+ export type { TkxAreaChartProps } from './TkxAreaChart';
15
+ export type { TkxBarChartProps } from './TkxBarChart';
16
+ export type { TkxLineChartProps } from './TkxLineChart';
17
+ export type { TkxPieChartProps } from './TkxPieChart';
18
+ export type { TkxDonutChartProps } from './TkxDonutChart';
19
+ export type { TkxScatterChartProps } from './TkxScatterChart';
20
+ export type { TkxRadarChartProps } from './TkxRadarChart';
@@ -0,0 +1,45 @@
1
+ // ── Shared chart utilities ───────────────────────────────────────────────────
2
+
3
+ import type { ThemeTokens } from '../themes';
4
+
5
+ /** Default palette: uses theme tokens then falls back to categorical colors */
6
+ export function getDefaultColors(theme: ThemeTokens): string[] {
7
+ return [
8
+ theme.primary,
9
+ theme.secondary,
10
+ theme.info,
11
+ theme.success,
12
+ theme.warning,
13
+ theme.danger,
14
+ '#a855f7',
15
+ '#f97316',
16
+ '#14b8a6',
17
+ '#e879f9',
18
+ ];
19
+ }
20
+
21
+ export interface ChartMargin {
22
+ top?: number;
23
+ right?: number;
24
+ bottom?: number;
25
+ left?: number;
26
+ }
27
+
28
+ export const DEFAULT_MARGIN: ChartMargin = { top: 10, right: 30, bottom: 10, left: 0 };
29
+
30
+ /** Common recharts tooltip style that matches TekiVex theme */
31
+ export function tooltipStyle(theme: ThemeTokens) {
32
+ return {
33
+ contentStyle: {
34
+ backgroundColor: theme.surface,
35
+ border: `1px solid ${theme.border}`,
36
+ borderRadius: 8,
37
+ boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
38
+ color: theme.text,
39
+ fontSize: 13,
40
+ },
41
+ labelStyle: { color: theme.textMuted, fontWeight: 600, marginBottom: 4 },
42
+ itemStyle: { color: theme.text },
43
+ cursor: { fill: `${theme.primary}15` },
44
+ };
45
+ }