tekivex-ui 2.2.0 → 2.5.1

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 (129) hide show
  1. package/dist/TkxForm-BWK4LqY3.js +1461 -0
  2. package/dist/TkxForm-ljQjX7KD.cjs +15 -0
  3. package/dist/charts.cjs +1 -0
  4. package/dist/charts.js +480 -0
  5. package/dist/headless.cjs +1 -0
  6. package/dist/headless.js +258 -0
  7. package/dist/index-BINBzXuY.cjs +2 -0
  8. package/dist/index-eT_U4qB2.js +512 -0
  9. package/dist/index.cjs +63 -14
  10. package/dist/index.d.ts +33 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +11396 -6336
  13. package/dist/src/charts/TkxAreaChart.d.ts +29 -0
  14. package/dist/src/charts/TkxAreaChart.d.ts.map +1 -0
  15. package/dist/src/charts/TkxBarChart.d.ts +28 -0
  16. package/dist/src/charts/TkxBarChart.d.ts.map +1 -0
  17. package/dist/src/charts/TkxDonutChart.d.ts +23 -0
  18. package/dist/src/charts/TkxDonutChart.d.ts.map +1 -0
  19. package/dist/src/charts/TkxLineChart.d.ts +35 -0
  20. package/dist/src/charts/TkxLineChart.d.ts.map +1 -0
  21. package/dist/src/charts/TkxPieChart.d.ts +19 -0
  22. package/dist/src/charts/TkxPieChart.d.ts.map +1 -0
  23. package/dist/src/charts/TkxRadarChart.d.ts +20 -0
  24. package/dist/src/charts/TkxRadarChart.d.ts.map +1 -0
  25. package/dist/src/charts/TkxScatterChart.d.ts +28 -0
  26. package/dist/src/charts/TkxScatterChart.d.ts.map +1 -0
  27. package/dist/src/charts/index.d.ts +15 -0
  28. package/dist/src/charts/index.d.ts.map +1 -0
  29. package/dist/src/charts/shared.d.ts +33 -0
  30. package/dist/src/charts/shared.d.ts.map +1 -0
  31. package/dist/src/components/TkxAffix.d.ts +10 -0
  32. package/dist/src/components/TkxAffix.d.ts.map +1 -0
  33. package/dist/src/components/TkxAnchor.d.ts +14 -0
  34. package/dist/src/components/TkxAnchor.d.ts.map +1 -0
  35. package/dist/src/components/TkxCascader.d.ts +16 -0
  36. package/dist/src/components/TkxCascader.d.ts.map +1 -0
  37. package/dist/src/components/TkxDataGrid.d.ts +19 -1
  38. package/dist/src/components/TkxDataGrid.d.ts.map +1 -1
  39. package/dist/src/components/TkxForm.d.ts +33 -3
  40. package/dist/src/components/TkxForm.d.ts.map +1 -1
  41. package/dist/src/components/TkxImage.d.ts.map +1 -1
  42. package/dist/src/components/TkxList.d.ts +24 -0
  43. package/dist/src/components/TkxList.d.ts.map +1 -0
  44. package/dist/src/components/TkxMentions.d.ts +15 -0
  45. package/dist/src/components/TkxMentions.d.ts.map +1 -0
  46. package/dist/src/components/TkxQRCode.d.ts +11 -0
  47. package/dist/src/components/TkxQRCode.d.ts.map +1 -0
  48. package/dist/src/components/TkxResult.d.ts +11 -0
  49. package/dist/src/components/TkxResult.d.ts.map +1 -0
  50. package/dist/src/components/TkxSegmented.d.ts +16 -0
  51. package/dist/src/components/TkxSegmented.d.ts.map +1 -0
  52. package/dist/src/components/TkxSelect.d.ts +5 -1
  53. package/dist/src/components/TkxSelect.d.ts.map +1 -1
  54. package/dist/src/components/TkxTour.d.ts +15 -0
  55. package/dist/src/components/TkxTour.d.ts.map +1 -0
  56. package/dist/src/components/TkxTypography.d.ts +1 -1
  57. package/dist/src/components/TkxTypography.d.ts.map +1 -1
  58. package/dist/src/components/TkxWatermark.d.ts +12 -0
  59. package/dist/src/components/TkxWatermark.d.ts.map +1 -0
  60. package/dist/src/components/index.d.ts +10 -0
  61. package/dist/src/components/index.d.ts.map +1 -1
  62. package/dist/src/engine/tkx.d.ts +38 -0
  63. package/dist/src/engine/tkx.d.ts.map +1 -1
  64. package/dist/src/headless/index.d.ts +18 -0
  65. package/dist/src/headless/index.d.ts.map +1 -0
  66. package/dist/src/headless/useControllable.d.ts +20 -0
  67. package/dist/src/headless/useControllable.d.ts.map +1 -0
  68. package/dist/src/headless/useDebounce.d.ts +14 -0
  69. package/dist/src/headless/useDebounce.d.ts.map +1 -0
  70. package/dist/src/headless/useDisclosure.d.ts +20 -0
  71. package/dist/src/headless/useDisclosure.d.ts.map +1 -0
  72. package/dist/src/headless/useFormState.d.ts +44 -0
  73. package/dist/src/headless/useFormState.d.ts.map +1 -0
  74. package/dist/src/headless/useIntersectionObserver.d.ts +23 -0
  75. package/dist/src/headless/useIntersectionObserver.d.ts.map +1 -0
  76. package/dist/src/headless/useListSelection.d.ts +29 -0
  77. package/dist/src/headless/useListSelection.d.ts.map +1 -0
  78. package/dist/src/headless/useLocalStorage.d.ts +9 -0
  79. package/dist/src/headless/useLocalStorage.d.ts.map +1 -0
  80. package/dist/src/headless/useMediaQuery.d.ts +21 -0
  81. package/dist/src/headless/useMediaQuery.d.ts.map +1 -0
  82. package/dist/src/headless/useRovingTabIndex.d.ts +33 -0
  83. package/dist/src/headless/useRovingTabIndex.d.ts.map +1 -0
  84. package/dist/src/headless/useThrottle.d.ts +9 -0
  85. package/dist/src/headless/useThrottle.d.ts.map +1 -0
  86. package/dist/src/i18n/index.d.ts +47 -2
  87. package/dist/src/i18n/index.d.ts.map +1 -1
  88. package/dist/src/themes/index.d.ts.map +1 -1
  89. package/package.json +61 -7
  90. package/src/charts/TkxAreaChart.tsx +119 -0
  91. package/src/charts/TkxBarChart.tsx +115 -0
  92. package/src/charts/TkxDonutChart.tsx +145 -0
  93. package/src/charts/TkxLineChart.tsx +135 -0
  94. package/src/charts/TkxPieChart.tsx +82 -0
  95. package/src/charts/TkxRadarChart.tsx +90 -0
  96. package/src/charts/TkxScatterChart.tsx +102 -0
  97. package/src/charts/index.ts +20 -0
  98. package/src/charts/shared.ts +45 -0
  99. package/src/components/TkxAffix.tsx +138 -0
  100. package/src/components/TkxAnchor.tsx +193 -0
  101. package/src/components/TkxCascader.tsx +276 -0
  102. package/src/components/TkxDataGrid.tsx +557 -230
  103. package/src/components/TkxForm.tsx +67 -15
  104. package/src/components/TkxImage.tsx +1 -1
  105. package/src/components/TkxList.tsx +242 -0
  106. package/src/components/TkxMentions.tsx +210 -0
  107. package/src/components/TkxQRCode.tsx +174 -0
  108. package/src/components/TkxResult.tsx +128 -0
  109. package/src/components/TkxSegmented.tsx +169 -0
  110. package/src/components/TkxSelect.tsx +209 -6
  111. package/src/components/TkxTour.tsx +239 -0
  112. package/src/components/TkxTypography.tsx +4 -2
  113. package/src/components/TkxWatermark.tsx +143 -0
  114. package/src/components/index.ts +10 -0
  115. package/src/engine/tkx.ts +122 -3
  116. package/src/headless/index.ts +44 -0
  117. package/src/headless/useControllable.ts +40 -0
  118. package/src/headless/useDebounce.ts +35 -0
  119. package/src/headless/useDisclosure.ts +28 -0
  120. package/src/headless/useFormState.ts +111 -0
  121. package/src/headless/useIntersectionObserver.ts +51 -0
  122. package/src/headless/useListSelection.ts +101 -0
  123. package/src/headless/useLocalStorage.ts +46 -0
  124. package/src/headless/useMediaQuery.ts +37 -0
  125. package/src/headless/useRovingTabIndex.ts +84 -0
  126. package/src/headless/useThrottle.ts +46 -0
  127. package/src/i18n/I18nProvider.tsx +1 -1
  128. package/src/i18n/index.ts +678 -38
  129. package/src/themes/index.ts +31 -4
@@ -0,0 +1,119 @@
1
+ import {
2
+ ResponsiveContainer,
3
+ AreaChart,
4
+ Area,
5
+ XAxis,
6
+ YAxis,
7
+ CartesianGrid,
8
+ Tooltip,
9
+ Legend,
10
+ } from 'recharts';
11
+ import { useTheme } from '../themes';
12
+ import { getDefaultColors, tooltipStyle, DEFAULT_MARGIN, type ChartMargin } from './shared';
13
+
14
+ export interface TkxAreaChartSeries {
15
+ key: string;
16
+ label?: string;
17
+ color?: string;
18
+ /** Fill opacity. Default: 0.2 */
19
+ fillOpacity?: number;
20
+ /** Whether to stack this series. Default: false */
21
+ stacked?: boolean;
22
+ }
23
+
24
+ export interface TkxAreaChartProps {
25
+ data: Record<string, any>[];
26
+ series: TkxAreaChartSeries[];
27
+ xKey: string;
28
+ height?: number;
29
+ margin?: ChartMargin;
30
+ showGrid?: boolean;
31
+ showLegend?: boolean;
32
+ showTooltip?: boolean;
33
+ /** Smooth curves. Default: true */
34
+ smooth?: boolean;
35
+ xTickFormatter?: (value: any) => string;
36
+ yTickFormatter?: (value: any) => string;
37
+ yDomain?: [number | 'auto' | 'dataMin' | 'dataMax', number | 'auto' | 'dataMin' | 'dataMax'];
38
+ /** aria-label for the chart container */
39
+ ariaLabel?: string;
40
+ }
41
+
42
+ export function TkxAreaChart({
43
+ data,
44
+ series,
45
+ xKey,
46
+ height = 300,
47
+ margin = DEFAULT_MARGIN,
48
+ showGrid = true,
49
+ showLegend = true,
50
+ showTooltip = true,
51
+ smooth = true,
52
+ xTickFormatter,
53
+ yTickFormatter,
54
+ yDomain,
55
+ ariaLabel = 'Area chart',
56
+ }: TkxAreaChartProps) {
57
+ const theme = useTheme();
58
+ const colors = getDefaultColors(theme);
59
+ const tt = tooltipStyle(theme);
60
+
61
+ const tickStyle = { fill: theme.textMuted, fontSize: 12 };
62
+
63
+ return (
64
+ <div role="img" aria-label={ariaLabel} style={{ width: '100%', height }}>
65
+ <ResponsiveContainer width="100%" height="100%">
66
+ <AreaChart data={data} margin={margin}>
67
+ {showGrid && (
68
+ <CartesianGrid strokeDasharray="3 3" stroke={theme.border} vertical={false} />
69
+ )}
70
+ <XAxis
71
+ dataKey={xKey}
72
+ tick={tickStyle}
73
+ axisLine={{ stroke: theme.border }}
74
+ tickLine={false}
75
+ tickFormatter={xTickFormatter}
76
+ />
77
+ <YAxis
78
+ tick={tickStyle}
79
+ axisLine={false}
80
+ tickLine={false}
81
+ tickFormatter={yTickFormatter}
82
+ domain={yDomain}
83
+ />
84
+ {showTooltip && (
85
+ <Tooltip
86
+ contentStyle={tt.contentStyle}
87
+ labelStyle={tt.labelStyle}
88
+ itemStyle={tt.itemStyle}
89
+ cursor={tt.cursor}
90
+ />
91
+ )}
92
+ {showLegend && (
93
+ <Legend
94
+ wrapperStyle={{ fontSize: 13, color: theme.textMuted, paddingTop: 8 }}
95
+ />
96
+ )}
97
+ {series.map((s, i) => {
98
+ const color = s.color ?? colors[i % colors.length];
99
+ return (
100
+ <Area
101
+ key={s.key}
102
+ type={smooth ? 'monotone' : 'linear'}
103
+ dataKey={s.key}
104
+ name={s.label ?? s.key}
105
+ stroke={color}
106
+ strokeWidth={2}
107
+ fill={color}
108
+ fillOpacity={s.fillOpacity ?? 0.2}
109
+ stackId={s.stacked ? 'stack' : undefined}
110
+ dot={false}
111
+ activeDot={{ r: 5, strokeWidth: 0 }}
112
+ />
113
+ );
114
+ })}
115
+ </AreaChart>
116
+ </ResponsiveContainer>
117
+ </div>
118
+ );
119
+ }
@@ -0,0 +1,115 @@
1
+ import {
2
+ ResponsiveContainer,
3
+ BarChart,
4
+ Bar,
5
+ XAxis,
6
+ YAxis,
7
+ CartesianGrid,
8
+ Tooltip,
9
+ Legend,
10
+ Cell,
11
+ } from 'recharts';
12
+ import { useTheme } from '../themes';
13
+ import { getDefaultColors, tooltipStyle, DEFAULT_MARGIN, type ChartMargin } from './shared';
14
+
15
+ export interface TkxBarChartSeries {
16
+ key: string;
17
+ label?: string;
18
+ color?: string;
19
+ /** Stack ID — bars with the same stackId are stacked. */
20
+ stackId?: string;
21
+ radius?: number | [number, number, number, number];
22
+ }
23
+
24
+ export interface TkxBarChartProps {
25
+ data: Record<string, any>[];
26
+ series: TkxBarChartSeries[];
27
+ xKey: string;
28
+ height?: number;
29
+ margin?: ChartMargin;
30
+ showGrid?: boolean;
31
+ showLegend?: boolean;
32
+ showTooltip?: boolean;
33
+ layout?: 'vertical' | 'horizontal';
34
+ barSize?: number;
35
+ /** Use gradient fill per series. Default: false */
36
+ gradient?: boolean;
37
+ xTickFormatter?: (value: any) => string;
38
+ yTickFormatter?: (value: any) => string;
39
+ ariaLabel?: string;
40
+ }
41
+
42
+ export function TkxBarChart({
43
+ data,
44
+ series,
45
+ xKey,
46
+ height = 300,
47
+ margin = DEFAULT_MARGIN,
48
+ showGrid = true,
49
+ showLegend = true,
50
+ showTooltip = true,
51
+ layout = 'horizontal',
52
+ barSize,
53
+ xTickFormatter,
54
+ yTickFormatter,
55
+ ariaLabel = 'Bar chart',
56
+ }: TkxBarChartProps) {
57
+ const theme = useTheme();
58
+ const colors = getDefaultColors(theme);
59
+ const tt = tooltipStyle(theme);
60
+ const tickStyle = { fill: theme.textMuted, fontSize: 12 };
61
+ const isVertical = layout === 'vertical';
62
+
63
+ return (
64
+ <div role="img" aria-label={ariaLabel} style={{ width: '100%', height }}>
65
+ <ResponsiveContainer width="100%" height="100%">
66
+ <BarChart data={data} margin={margin} layout={layout}>
67
+ {showGrid && (
68
+ <CartesianGrid
69
+ strokeDasharray="3 3"
70
+ stroke={theme.border}
71
+ vertical={isVertical}
72
+ horizontal={!isVertical}
73
+ />
74
+ )}
75
+ {isVertical ? (
76
+ <>
77
+ <YAxis dataKey={xKey} type="category" tick={tickStyle} axisLine={false} tickLine={false} tickFormatter={xTickFormatter} width={100} />
78
+ <XAxis type="number" tick={tickStyle} axisLine={{ stroke: theme.border }} tickLine={false} tickFormatter={yTickFormatter} />
79
+ </>
80
+ ) : (
81
+ <>
82
+ <XAxis dataKey={xKey} tick={tickStyle} axisLine={{ stroke: theme.border }} tickLine={false} tickFormatter={xTickFormatter} />
83
+ <YAxis tick={tickStyle} axisLine={false} tickLine={false} tickFormatter={yTickFormatter} />
84
+ </>
85
+ )}
86
+ {showTooltip && (
87
+ <Tooltip
88
+ contentStyle={tt.contentStyle}
89
+ labelStyle={tt.labelStyle}
90
+ itemStyle={tt.itemStyle}
91
+ cursor={{ fill: `${theme.surfaceAlt}` }}
92
+ />
93
+ )}
94
+ {showLegend && (
95
+ <Legend wrapperStyle={{ fontSize: 13, color: theme.textMuted, paddingTop: 8 }} />
96
+ )}
97
+ {series.map((s, i) => {
98
+ const color = s.color ?? colors[i % colors.length];
99
+ return (
100
+ <Bar
101
+ key={s.key}
102
+ dataKey={s.key}
103
+ name={s.label ?? s.key}
104
+ fill={color}
105
+ stackId={s.stackId}
106
+ maxBarSize={barSize ?? 40}
107
+ radius={s.radius ?? [4, 4, 0, 0]}
108
+ />
109
+ );
110
+ })}
111
+ </BarChart>
112
+ </ResponsiveContainer>
113
+ </div>
114
+ );
115
+ }
@@ -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
+ }