@shohojdhara/atomix 0.2.4 → 0.2.5

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 (211) hide show
  1. package/README.md +19 -0
  2. package/dist/atomix.css +1266 -1412
  3. package/dist/atomix.min.css +3 -3
  4. package/dist/index.d.ts +1232 -876
  5. package/dist/index.esm.js +16212 -26364
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +15652 -22298
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.js +1 -1
  10. package/dist/index.min.js.map +1 -1
  11. package/dist/themes/applemix.css +15008 -0
  12. package/dist/themes/applemix.min.css +72 -0
  13. package/dist/themes/boomdevs.css +1266 -1413
  14. package/dist/themes/boomdevs.min.css +3 -3
  15. package/dist/themes/esrar.css +1267 -1413
  16. package/dist/themes/esrar.min.css +3 -3
  17. package/dist/themes/flashtrade.css +15159 -0
  18. package/dist/themes/flashtrade.min.css +86 -0
  19. package/dist/themes/mashroom.css +1264 -1410
  20. package/dist/themes/mashroom.min.css +5 -5
  21. package/dist/themes/shaj-default.css +1266 -1412
  22. package/dist/themes/shaj-default.min.css +3 -3
  23. package/package.json +6 -17
  24. package/src/components/Accordion/Accordion.stories.tsx +4 -26
  25. package/src/components/Accordion/Accordion.tsx +21 -12
  26. package/src/components/AtomixGlass/AtomixGlass.test.tsx +106 -72
  27. package/src/components/AtomixGlass/AtomixGlass.tsx +487 -1215
  28. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +400 -0
  29. package/src/components/AtomixGlass/GlassFilter.tsx +156 -0
  30. package/src/components/AtomixGlass/README.md +124 -2
  31. package/src/components/AtomixGlass/atomixGLass.old.tsx +1266 -0
  32. package/src/components/AtomixGlass/glass-utils.ts +263 -0
  33. package/src/components/AtomixGlass/shader-utils.ts +404 -236
  34. package/src/components/AtomixGlass/{AtomixGlass.stories.tsx → stories/AtomixGlass.stories.tsx} +55 -35
  35. package/src/components/AtomixGlass/stories/Examples.stories.tsx +57 -89
  36. package/src/components/AtomixGlass/stories/Modes.stories.tsx +149 -149
  37. package/src/components/AtomixGlass/stories/Playground.stories.tsx +95 -32
  38. package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +0 -2
  39. package/src/components/AtomixGlass/stories/shared-components.tsx +9 -18
  40. package/src/components/AtomixGlass/utils.ts +3 -3
  41. package/src/components/Avatar/Avatar.tsx +3 -0
  42. package/src/components/Avatar/AvatarGroup.tsx +2 -1
  43. package/src/components/Badge/Badge.stories.tsx +74 -54
  44. package/src/components/Badge/Badge.tsx +8 -12
  45. package/src/components/Breadcrumb/Breadcrumb.tsx +23 -4
  46. package/src/components/Button/Button.tsx +3 -5
  47. package/src/components/Callout/Callout.stories.tsx +86 -35
  48. package/src/components/Callout/Callout.tsx +4 -0
  49. package/src/components/Card/Card.stories.tsx +89 -85
  50. package/src/components/Card/Card.tsx +15 -4
  51. package/src/components/Card/ElevationCard.tsx +2 -0
  52. package/src/components/Chart/AnimatedChart.tsx +179 -156
  53. package/src/components/Chart/AreaChart.tsx +123 -12
  54. package/src/components/Chart/BarChart.tsx +91 -100
  55. package/src/components/Chart/BaseChart.tsx +80 -0
  56. package/src/components/Chart/BubbleChart.tsx +114 -290
  57. package/src/components/Chart/CandlestickChart.tsx +282 -622
  58. package/src/components/Chart/Chart.stories.tsx +576 -179
  59. package/src/components/Chart/Chart.tsx +374 -75
  60. package/src/components/Chart/ChartRenderer.tsx +371 -220
  61. package/src/components/Chart/ChartToolbar.tsx +372 -61
  62. package/src/components/Chart/ChartTooltip.tsx +33 -18
  63. package/src/components/Chart/DonutChart.tsx +172 -254
  64. package/src/components/Chart/FunnelChart.tsx +169 -240
  65. package/src/components/Chart/GaugeChart.tsx +224 -392
  66. package/src/components/Chart/HeatmapChart.tsx +302 -440
  67. package/src/components/Chart/LineChart.tsx +148 -103
  68. package/src/components/Chart/MultiAxisChart.tsx +267 -395
  69. package/src/components/Chart/PieChart.tsx +114 -64
  70. package/src/components/Chart/RadarChart.tsx +202 -218
  71. package/src/components/Chart/ScatterChart.tsx +111 -97
  72. package/src/components/Chart/TreemapChart.tsx +147 -222
  73. package/src/components/Chart/WaterfallChart.tsx +253 -291
  74. package/src/components/Chart/index.ts +11 -9
  75. package/src/components/Chart/types.ts +85 -9
  76. package/src/components/Chart/utils.ts +66 -0
  77. package/src/components/ColorModeToggle/ColorModeToggle.tsx +6 -3
  78. package/src/components/Countdown/Countdown.tsx +4 -0
  79. package/src/components/DataTable/DataTable.tsx +2 -1
  80. package/src/components/DatePicker/DatePicker.stories.tsx +0 -11
  81. package/src/components/DatePicker/DatePicker.tsx +3 -9
  82. package/src/components/DatePicker/types.ts +5 -0
  83. package/src/components/Dropdown/Dropdown.stories.tsx +32 -25
  84. package/src/components/Dropdown/Dropdown.tsx +26 -28
  85. package/src/components/EdgePanel/EdgePanel.stories.tsx +13 -15
  86. package/src/components/EdgePanel/EdgePanel.tsx +20 -5
  87. package/src/components/Footer/Footer.stories.tsx +187 -60
  88. package/src/components/Footer/Footer.test.tsx +134 -0
  89. package/src/components/Footer/Footer.tsx +133 -34
  90. package/src/components/Footer/FooterLink.tsx +1 -1
  91. package/src/components/Footer/FooterSection.tsx +53 -36
  92. package/src/components/Footer/FooterSocialLink.tsx +32 -29
  93. package/src/components/Footer/README.md +82 -3
  94. package/src/components/Footer/index.ts +1 -1
  95. package/src/components/Form/Checkbox.stories.tsx +13 -5
  96. package/src/components/Form/Checkbox.tsx +3 -6
  97. package/src/components/Form/Form.stories.tsx +10 -3
  98. package/src/components/Form/Form.tsx +2 -0
  99. package/src/components/Form/FormGroup.tsx +2 -1
  100. package/src/components/Form/Input.stories.tsx +12 -11
  101. package/src/components/Form/Input.tsx +97 -95
  102. package/src/components/Form/Radio.stories.tsx +22 -7
  103. package/src/components/Form/Radio.tsx +3 -6
  104. package/src/components/Form/Select.stories.tsx +21 -6
  105. package/src/components/Form/Select.tsx +3 -5
  106. package/src/components/Form/Textarea.stories.tsx +13 -11
  107. package/src/components/Form/Textarea.tsx +88 -86
  108. package/src/components/Hero/Hero.stories.tsx +2 -3
  109. package/src/components/Hero/Hero.tsx +5 -6
  110. package/src/components/Icon/Icon.tsx +12 -1
  111. package/src/components/List/List.tsx +2 -1
  112. package/src/components/List/ListGroup.tsx +2 -1
  113. package/src/components/Messages/Messages.tsx +3 -2
  114. package/src/components/Modal/Modal.stories.tsx +48 -34
  115. package/src/components/Modal/Modal.tsx +19 -23
  116. package/src/components/Navigation/Menu/MegaMenu.tsx +2 -2
  117. package/src/components/Navigation/Menu/Menu.tsx +2 -2
  118. package/src/components/Navigation/Nav/Nav.tsx +6 -1
  119. package/src/components/Navigation/Nav/NavDropdown.tsx +10 -1
  120. package/src/components/Navigation/Navbar/Navbar.tsx +4 -1
  121. package/src/components/Navigation/SideMenu/SideMenu.tsx +3 -2
  122. package/src/components/Pagination/Pagination.stories.tsx +13 -6
  123. package/src/components/Pagination/Pagination.tsx +7 -6
  124. package/src/components/PhotoViewer/PhotoViewer.tsx +2 -1
  125. package/src/components/Popover/Popover.stories.tsx +32 -24
  126. package/src/components/Popover/Popover.tsx +4 -1
  127. package/src/components/ProductReview/ProductReview.tsx +8 -2
  128. package/src/components/Progress/Progress.tsx +2 -1
  129. package/src/components/Rating/Rating.stories.tsx +11 -6
  130. package/src/components/Rating/Rating.tsx +3 -5
  131. package/src/components/River/River.tsx +5 -5
  132. package/src/components/SectionIntro/SectionIntro.tsx +8 -2
  133. package/src/components/Slider/Slider.stories.tsx +4 -4
  134. package/src/components/Slider/Slider.tsx +4 -3
  135. package/src/components/Spinner/Spinner.tsx +2 -1
  136. package/src/components/Steps/Steps.stories.tsx +5 -4
  137. package/src/components/Steps/Steps.tsx +8 -5
  138. package/src/components/Tab/Tab.stories.tsx +4 -3
  139. package/src/components/Tab/Tab.tsx +8 -6
  140. package/src/components/Testimonial/Testimonial.tsx +8 -2
  141. package/src/components/Todo/Todo.tsx +2 -1
  142. package/src/components/Toggle/Toggle.stories.tsx +5 -4
  143. package/src/components/Toggle/Toggle.tsx +8 -5
  144. package/src/components/Tooltip/Tooltip.stories.tsx +40 -30
  145. package/src/components/Tooltip/Tooltip.tsx +9 -2
  146. package/src/components/Upload/Upload.stories.tsx +252 -0
  147. package/src/components/Upload/Upload.tsx +92 -53
  148. package/src/components/VideoPlayer/VideoPlayer.tsx +3 -1
  149. package/src/components/index.ts +0 -4
  150. package/src/layouts/Grid/Grid.stories.tsx +10 -23
  151. package/src/layouts/Grid/Grid.tsx +20 -1
  152. package/src/layouts/Grid/GridCol.tsx +76 -48
  153. package/src/lib/composables/useAtomixGlass.ts +861 -44
  154. package/src/lib/composables/useBarChart.ts +13 -6
  155. package/src/lib/composables/useChart.ts +17 -13
  156. package/src/lib/composables/useChartExport.ts +19 -78
  157. package/src/lib/composables/useChartToolbar.ts +0 -1
  158. package/src/lib/composables/useEdgePanel.ts +111 -103
  159. package/src/lib/composables/useFooter.ts +3 -3
  160. package/src/lib/composables/useGlassContainer.ts +16 -7
  161. package/src/lib/composables/useLineChart.ts +8 -1
  162. package/src/lib/composables/useRiver.ts +5 -0
  163. package/src/lib/composables/useSlider.ts +62 -24
  164. package/src/lib/composables/useVideoPlayer.ts +60 -63
  165. package/src/lib/constants/components.ts +146 -32
  166. package/src/lib/types/components.ts +258 -10
  167. package/src/lib/utils/displacement-generator.ts +55 -49
  168. package/src/lib/utils/icons.ts +1 -1
  169. package/src/lib/utils/index.ts +16 -10
  170. package/src/styles/01-settings/_settings.accordion.scss +19 -19
  171. package/src/styles/01-settings/_settings.animations.scss +5 -5
  172. package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
  173. package/src/styles/01-settings/_settings.avatar.scss +17 -17
  174. package/src/styles/01-settings/_settings.background.scss +1 -4
  175. package/src/styles/01-settings/_settings.badge.scss +1 -1
  176. package/src/styles/01-settings/_settings.breadcrumb.scss +1 -1
  177. package/src/styles/01-settings/_settings.card.scss +1 -1
  178. package/src/styles/01-settings/_settings.chart.scss +65 -2
  179. package/src/styles/01-settings/_settings.dropdown.scss +1 -1
  180. package/src/styles/01-settings/_settings.footer.scss +35 -42
  181. package/src/styles/01-settings/_settings.input.scss +1 -1
  182. package/src/styles/01-settings/_settings.list.scss +1 -1
  183. package/src/styles/01-settings/_settings.rating.scss +1 -1
  184. package/src/styles/01-settings/_settings.tabs.scss +1 -1
  185. package/src/styles/01-settings/_settings.upload.scss +6 -5
  186. package/src/styles/02-tools/_tools.animations.scss +4 -5
  187. package/src/styles/02-tools/_tools.background.scss +1 -13
  188. package/src/styles/02-tools/_tools.glass.scss +0 -1
  189. package/src/styles/02-tools/_tools.utility-api.scss +42 -34
  190. package/src/styles/03-generic/_generic.root.scss +1 -4
  191. package/src/styles/04-elements/_elements.body.scss +0 -1
  192. package/src/styles/06-components/_components.atomix-glass.scss +216 -39
  193. package/src/styles/06-components/_components.badge.scss +6 -8
  194. package/src/styles/06-components/_components.button.scss +8 -3
  195. package/src/styles/06-components/_components.card.scss +2 -14
  196. package/src/styles/06-components/_components.chart.scss +969 -1449
  197. package/src/styles/06-components/_components.dropdown.scss +19 -7
  198. package/src/styles/06-components/_components.edge-panel.scss +4 -2
  199. package/src/styles/06-components/_components.footer.scss +166 -85
  200. package/src/styles/06-components/_components.input.scss +8 -9
  201. package/src/styles/06-components/_components.list.scss +1 -0
  202. package/src/styles/06-components/_components.modal.scss +5 -3
  203. package/src/styles/06-components/_components.skeleton.scss +8 -6
  204. package/src/styles/06-components/_components.upload.scss +219 -4
  205. package/src/styles/06-components/old.chart.styles.scss +1 -30
  206. package/src/styles/99-utilities/_utilities.opacity.scss +1 -1
  207. package/src/styles/99-utilities/_utilities.scss +1 -1
  208. package/src/components/Chart/AdvancedChart.tsx +0 -624
  209. package/src/components/Chart/LineChartNew.tsx +0 -167
  210. package/src/components/Chart/RealTimeChart.tsx +0 -436
  211. package/src/components/DatePicker/DatePicker copy.tsx +0 -551
@@ -1,9 +1,8 @@
1
- import { forwardRef, memo, useMemo, useState } from 'react';
2
- import { CHART } from '../../lib/constants/components';
3
- import Chart from './Chart';
1
+ import { forwardRef, memo, useMemo } from 'react';
2
+ import BaseChart from './BaseChart';
4
3
  import ChartTooltip from './ChartTooltip';
5
4
  import { PieChartProps } from './PieChart';
6
- import { ChartDataPoint } from './types';
5
+ import { ChartDataPoint, ChartRenderContentParams } from './types';
7
6
 
8
7
  interface DonutChartProps extends Omit<PieChartProps, 'type'> {
9
8
  /**
@@ -65,14 +64,9 @@ const DonutChart = memo(
65
64
  ) => {
66
65
  // Use the first dataset for donut chart
67
66
  const dataset = datasets.length > 0 ? datasets[0] : { label: '', data: [] };
68
- const [hoveredSlice, setHoveredSlice] = useState<{
69
- index: number;
70
- clientX: number;
71
- clientY: number;
72
- } | null>(null);
73
67
 
74
- // Calculate dimensions and generate donut slices
75
- const chartContent = useMemo(() => {
68
+ // Prepare data for donut chart (calculations will be done in renderContent with actual dimensions)
69
+ const chartData = useMemo(() => {
76
70
  if (!dataset?.data?.length) return null;
77
71
 
78
72
  // Filter out invalid data points
@@ -86,280 +80,204 @@ const DonutChart = memo(
86
80
 
87
81
  if (!validDataPoints.length) return null;
88
82
 
89
- // Calculate chart dimensions
90
- const width = 800;
91
- const height = 400;
83
+ return { validDataPoints };
84
+ }, [dataset]);
85
+
86
+ const renderContent = ({
87
+ scales,
88
+ colors,
89
+ datasets: renderedDatasets,
90
+ handlers,
91
+ hoveredPoint,
92
+ toolbarState,
93
+ config: renderConfig,
94
+ }: ChartRenderContentParams) => {
95
+ if (!chartData) return null;
96
+
97
+ // Use actual container dimensions from scales
98
+ const width = scales.width;
99
+ const height = scales.height;
92
100
  const outerRadius = (Math.min(width, height) / 2) * 0.8;
93
101
  const innerRadius = outerRadius * (donutOptions.innerRadiusRatio ?? 0.6);
94
102
  const centerX = width / 2;
95
103
  const centerY = height / 2;
96
104
 
97
105
  // Generate colors if not provided
106
+ // Using primary color variations for consistent theming
98
107
  const defaultColors = [
99
- '#7AFFD7',
100
- '#1AFFD2',
101
- '#00E6C3',
102
- '#4DFF9F',
103
- '#1AFF85',
104
- '#00E66B',
105
- '#DD6061',
106
- '#FF1A1A',
107
- '#E60000',
108
- '#FFCC00',
109
- '#E6B800',
110
- '#B38F00',
108
+ 'var(--atomix-primary-2)',
109
+ 'var(--atomix-primary-3)',
110
+ 'var(--atomix-primary-4)',
111
+ 'var(--atomix-primary-5)',
112
+ 'var(--atomix-primary-6)',
113
+ 'var(--atomix-primary-7)',
114
+ 'var(--atomix-primary-8)',
115
+ 'var(--atomix-primary-9)',
111
116
  ];
112
117
 
113
- // Sort data points if needed
114
- let dataPoints = [...validDataPoints];
115
- if (pieOptions.sortByValue) {
116
- dataPoints.sort((a, b) => b.value - a.value);
117
- }
118
+ const chartColors = dataset?.color
119
+ ? [dataset.color]
120
+ : dataset?.data?.map((_, i) => defaultColors[i % defaultColors.length]) || defaultColors;
118
121
 
119
122
  // Calculate total value
120
- const total = dataPoints.reduce((sum, point) => sum + point.value, 0);
121
-
122
- // Prevent division by zero
123
- if (total <= 0 || !isFinite(total)) return null;
123
+ const total = chartData.validDataPoints.reduce((sum, point) => sum + point.value, 0);
124
124
 
125
125
  // Calculate angles for each slice
126
- const slices: Array<{
127
- dataPoint: ChartDataPoint;
128
- index: number;
129
- startAngle: number;
130
- endAngle: number;
131
- color: string;
132
- percentage: number;
133
- }> = [];
134
-
135
- let currentAngle = ((pieOptions.startAngle ?? 0) * Math.PI) / 180;
136
-
137
- dataPoints.forEach((point, i) => {
126
+ const padAngleRad = ((pieOptions.padAngle || 1) * Math.PI) / 180;
127
+ let currentAngle = ((pieOptions.startAngle || 0) * Math.PI) / 180;
128
+
129
+ const slices = chartData.validDataPoints.map((point, index) => {
138
130
  const percentage = point.value / total;
139
-
140
- // Validate percentage calculation
141
- if (!isFinite(percentage) || percentage < 0) return;
142
-
143
- const angle = percentage * 2 * Math.PI - ((pieOptions.padAngle ?? 1) * Math.PI) / 180;
144
-
145
- // Validate angle calculation
146
- if (!isFinite(angle) || angle < 0) return;
147
-
148
- const endAngle = currentAngle + angle;
149
-
150
- // Validate angles before adding to slices
151
- if (!isFinite(currentAngle) || !isFinite(endAngle)) return;
152
-
153
- slices.push({
154
- dataPoint: point,
155
- index: i,
156
- startAngle: currentAngle,
157
- endAngle: endAngle,
158
- color: (point.color || defaultColors[i % defaultColors.length]) as string,
159
- percentage,
160
- });
161
-
162
- currentAngle = endAngle + ((pieOptions.padAngle ?? 1) * Math.PI) / 180;
163
- });
164
-
165
- // Generate SVG arc path for each slice
166
- const donutSlices = slices.map(slice => {
167
- const { startAngle, endAngle, color, dataPoint, index, percentage } = slice;
168
-
169
- // Calculate outer arc points
170
- const outerStartX = centerX + outerRadius * Math.cos(startAngle);
171
- const outerStartY = centerY + outerRadius * Math.sin(startAngle);
172
- const outerEndX = centerX + outerRadius * Math.cos(endAngle);
173
- const outerEndY = centerY + outerRadius * Math.sin(endAngle);
174
-
175
- // Calculate inner arc points
176
- const innerStartX = centerX + innerRadius * Math.cos(endAngle);
177
- const innerStartY = centerY + innerRadius * Math.sin(endAngle);
178
- const innerEndX = centerX + innerRadius * Math.cos(startAngle);
179
- const innerEndY = centerY + innerRadius * Math.sin(startAngle);
180
-
181
- const largeArcFlag = endAngle - startAngle > Math.PI ? 1 : 0;
182
-
183
- // Create donut segment path
184
- const pathData = [
185
- `M ${outerStartX},${outerStartY}`,
186
- `A ${outerRadius},${outerRadius} 0 ${largeArcFlag},1 ${outerEndX},${outerEndY}`,
187
- `L ${innerStartX},${innerStartY}`,
188
- `A ${innerRadius},${innerRadius} 0 ${largeArcFlag},0 ${innerEndX},${innerEndY}`,
131
+ const sliceAngle = percentage * (2 * Math.PI) - padAngleRad;
132
+ const startAngle = currentAngle;
133
+ const endAngle = currentAngle + sliceAngle;
134
+ const midAngle = (startAngle + endAngle) / 2;
135
+
136
+ // Calculate label position
137
+ const labelRadius = outerRadius * 0.75;
138
+ const labelX = centerX + Math.cos(midAngle) * labelRadius;
139
+ const labelY = centerY + Math.sin(midAngle) * labelRadius;
140
+
141
+ // Calculate slice path
142
+ const x1 = centerX + innerRadius * Math.cos(startAngle);
143
+ const y1 = centerY + innerRadius * Math.sin(startAngle);
144
+ const x2 = centerX + outerRadius * Math.cos(startAngle);
145
+ const y2 = centerY + outerRadius * Math.sin(startAngle);
146
+ const x3 = centerX + outerRadius * Math.cos(endAngle);
147
+ const y3 = centerY + outerRadius * Math.sin(endAngle);
148
+ const x4 = centerX + innerRadius * Math.cos(endAngle);
149
+ const y4 = centerY + innerRadius * Math.sin(endAngle);
150
+
151
+ // Large arc flag (1 if arc is > 180 degrees, 0 otherwise)
152
+ const largeArcFlag = sliceAngle > Math.PI ? 1 : 0;
153
+
154
+ const path = [
155
+ `M ${x1} ${y1}`,
156
+ `L ${x2} ${y2}`,
157
+ `A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${x3} ${y3}`,
158
+ `L ${x4} ${y4}`,
159
+ `A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${x1} ${y1}`,
189
160
  'Z',
190
161
  ].join(' ');
191
162
 
192
- // Calculate position for labels/values
193
- const midAngle = startAngle + (endAngle - startAngle) / 2;
194
- const labelRadius = (outerRadius + innerRadius) / 2;
195
- const labelX = centerX + labelRadius * Math.cos(midAngle);
196
- const labelY = centerY + labelRadius * Math.sin(midAngle);
197
-
198
- // Format percentage
199
- const percentageText = `${Math.round(percentage * 100)}%`;
163
+ currentAngle = endAngle + padAngleRad;
200
164
 
201
- return (
202
- <g key={`slice-${index}`}>
203
- <path
204
- d={pathData}
205
- fill={color}
206
- className="c-chart__donut-slice"
207
- onClick={() => onDataPointClick?.(dataPoint, 0, index)}
208
- onMouseEnter={e => {
209
- const rect = e.currentTarget.ownerSVGElement?.getBoundingClientRect();
210
- const clientX = rect ? rect.left + labelX : e.clientX;
211
- const clientY = rect ? rect.top + labelY : e.clientY;
212
- setHoveredSlice({ index, clientX, clientY });
213
- }}
214
- onMouseLeave={() => setHoveredSlice(null)}
215
- data-tooltip={`${dataPoint.label}: ${dataPoint.value} (${percentageText})`}
216
- />
217
-
218
- {pieOptions.showValues && (
219
- <text
220
- x={labelX}
221
- y={labelY}
222
- textAnchor="middle"
223
- dominantBaseline="middle"
224
- className="c-chart__donut-label"
225
- >
226
- {pieOptions.showPercentages ? percentageText : dataPoint.value}
227
- </text>
228
- )}
229
- </g>
230
- );
165
+ return {
166
+ path,
167
+ color: point.color || chartColors[index],
168
+ labelPosition: { x: labelX, y: labelY },
169
+ dataPoint: point,
170
+ value: point.value,
171
+ percentage: (point.value / total) * 100,
172
+ };
231
173
  });
232
174
 
233
- // Center content
234
- const centerContent = donutOptions.showTotal && (
235
- <g className="c-chart__donut-center">
236
- <circle
237
- cx={centerX}
238
- cy={centerY}
239
- r={innerRadius}
240
- className="c-chart__donut-center-bg"
241
- />
242
- {donutOptions.centerLabel && (
243
- <text
244
- x={centerX}
245
- y={centerY - 15}
246
- textAnchor="middle"
247
- dominantBaseline="middle"
248
- className="c-chart__donut-center-label"
249
- >
250
- {donutOptions.centerLabel}
251
- </text>
252
- )}
253
- <text
254
- x={centerX}
255
- y={centerY + (donutOptions.centerLabel ? 15 : 0)}
256
- textAnchor="middle"
257
- dominantBaseline="middle"
258
- className="c-chart__donut-center-value"
259
- >
260
- {donutOptions.centerValue !== undefined ? donutOptions.centerValue : total}
261
- </text>
262
- </g>
263
- );
264
-
265
- return (
266
- <svg
267
- width="100%"
268
- height="100%"
269
- viewBox={`0 0 ${width} ${height}`}
270
- preserveAspectRatio="xMidYMid meet"
271
- >
272
- <g>
273
- {donutSlices}
274
- {centerContent}
275
- </g>
276
- </svg>
277
- );
278
- }, [dataset, pieOptions, donutOptions, onDataPointClick]);
279
-
280
- // Render legend if enabled
281
- const legend = useMemo(() => {
282
- if (!config.showLegend || !dataset?.data?.length) return null;
283
-
284
- // Filter out invalid data points (same as chart content)
285
- const validDataPoints = dataset?.data?.filter(
286
- point =>
287
- typeof point.value === 'number' &&
288
- !isNaN(point.value) &&
289
- isFinite(point.value) &&
290
- point.value > 0
291
- );
292
-
293
- if (!validDataPoints.length) return null;
294
-
295
- // Generate colors if not provided
296
- const defaultColors = [
297
- '#7AFFD7',
298
- '#1AFFD2',
299
- '#00E6C3',
300
- '#4DFF9F',
301
- '#1AFF85',
302
- '#00E66B',
303
- '#DD6061',
304
- '#FF1A1A',
305
- '#E60000',
306
- '#FFCC00',
307
- '#E6B800',
308
- '#B38F00',
309
- ];
310
-
311
- // Calculate total for percentages
312
- const total = validDataPoints.reduce((sum, point) => sum + point.value, 0);
313
-
314
- // Prevent division by zero
315
- if (total <= 0 || !isFinite(total)) return null;
175
+ // Use toolbar state if available, fallback to config for backward compatibility
176
+ const showTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? true;
316
177
 
317
178
  return (
318
- <div className={CHART.LEGEND_CLASS}>
319
- {validDataPoints.map((point, i) => {
320
- const percentage = Math.round((point.value / total) * 100);
321
-
322
- // Validate percentage calculation
323
- if (!isFinite(percentage)) return null;
179
+ <>
180
+ {slices.map((slice, index) => {
181
+ const isHovered = hoveredPoint?.pointIndex === index;
324
182
 
325
183
  return (
326
- <div
327
- key={`legend-${i}`}
328
- className={CHART.LEGEND_ITEM_CLASS}
329
- onClick={() => onDataPointClick?.(point, 0, i)}
330
- >
331
- <div
332
- className={`${CHART.LEGEND_COLOR_CLASS} c-chart__legend-color`}
333
- style={{
334
- backgroundColor: point.color || defaultColors[i % defaultColors.length],
184
+ <g key={`slice-${index}`}>
185
+ <path
186
+ d={slice.path}
187
+ fill={slice.color}
188
+ className={`c-chart__donut-slice ${isHovered ? 'c-chart__donut-slice--hovered' : ''}`}
189
+ onClick={() => handlers.onDataPointClick?.(slice.dataPoint, 0, index)}
190
+ onMouseEnter={e => {
191
+ const rect = e.currentTarget.getBoundingClientRect();
192
+ handlers.onPointHover(
193
+ 0,
194
+ index,
195
+ slice.labelPosition.x,
196
+ slice.labelPosition.y,
197
+ rect.left + rect.width / 2,
198
+ rect.top + rect.height / 2
199
+ );
335
200
  }}
201
+ onMouseLeave={handlers.onPointLeave}
336
202
  />
337
- <span className={CHART.LEGEND_LABEL_CLASS}>
338
- {point.label} {pieOptions.showPercentages && `(${percentage}%)`}
339
- </span>
340
- </div>
203
+ {pieOptions.showLabels && (
204
+ <text
205
+ x={slice.labelPosition.x}
206
+ y={slice.labelPosition.y}
207
+ textAnchor="middle"
208
+ className="c-chart__donut-label"
209
+ >
210
+ {slice.dataPoint.label}
211
+ </text>
212
+ )}
213
+ {pieOptions.showPercentages && (
214
+ <text
215
+ x={slice.labelPosition.x}
216
+ y={slice.labelPosition.y + 20}
217
+ textAnchor="middle"
218
+ className="c-chart__donut-percentage"
219
+ >
220
+ {slice.percentage.toFixed(1)}%
221
+ </text>
222
+ )}
223
+ </g>
341
224
  );
342
225
  })}
343
- </div>
226
+
227
+ {/* Center label and value */}
228
+ {donutOptions.showTotal && (
229
+ <g>
230
+ <text
231
+ x={centerX}
232
+ y={centerY - 10}
233
+ textAnchor="middle"
234
+ dominantBaseline="middle"
235
+ className="c-chart__donut-center-label"
236
+ >
237
+ {donutOptions.centerLabel}
238
+ </text>
239
+ <text
240
+ x={centerX}
241
+ y={centerY + 20}
242
+ textAnchor="middle"
243
+ dominantBaseline="middle"
244
+ className="c-chart__donut-center-value"
245
+ >
246
+ {donutOptions.centerValue !== undefined
247
+ ? donutOptions.centerValue
248
+ : total.toLocaleString()}
249
+ </text>
250
+ </g>
251
+ )}
252
+ {showTooltips &&
253
+ hoveredPoint &&
254
+ hoveredPoint.pointIndex < slices.length &&
255
+ slices[hoveredPoint.pointIndex] && (
256
+ <ChartTooltip
257
+ dataPoint={slices[hoveredPoint.pointIndex]!.dataPoint}
258
+ datasetLabel={dataset?.label}
259
+ datasetColor={slices[hoveredPoint.pointIndex]?.color}
260
+ position={{
261
+ x: hoveredPoint.clientX,
262
+ y: hoveredPoint.clientY,
263
+ }}
264
+ visible={true}
265
+ />
266
+ )}
267
+ </>
344
268
  );
345
- }, [dataset, config.showLegend, pieOptions.showPercentages, onDataPointClick]);
269
+ };
346
270
 
347
271
  return (
348
- <Chart ref={ref} type="donut" datasets={datasets} config={config} {...props}>
349
- <div className={CHART.CANVAS_CLASS}>
350
- {chartContent}
351
- {hoveredSlice && dataset?.data?.[hoveredSlice.index] && (
352
- <ChartTooltip
353
- dataPoint={dataset.data[hoveredSlice.index]!}
354
- datasetLabel={dataset.label}
355
- datasetColor={dataset.data[hoveredSlice.index]!.color}
356
- position={{ x: hoveredSlice.clientX, y: hoveredSlice.clientY }}
357
- visible={true}
358
- />
359
- )}
360
- </div>
361
- {legend}
362
- </Chart>
272
+ <BaseChart
273
+ ref={ref}
274
+ type="donut"
275
+ datasets={datasets}
276
+ config={config}
277
+ renderContent={renderContent}
278
+ onDataPointClick={onDataPointClick}
279
+ {...props}
280
+ />
363
281
  );
364
282
  }
365
283
  )