@shohojdhara/atomix 0.2.3 → 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 (225) hide show
  1. package/README.md +19 -0
  2. package/dist/atomix.css +1703 -1544
  3. package/dist/atomix.min.css +4 -4
  4. package/dist/index.d.ts +1465 -963
  5. package/dist/index.esm.js +16289 -25908
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +15650 -21780
  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 +1608 -1450
  14. package/dist/themes/boomdevs.min.css +5 -5
  15. package/dist/themes/esrar.css +1702 -1543
  16. package/dist/themes/esrar.min.css +4 -4
  17. package/dist/themes/flashtrade.css +15159 -0
  18. package/dist/themes/flashtrade.min.css +86 -0
  19. package/dist/themes/mashroom.css +1699 -1540
  20. package/dist/themes/mashroom.min.css +7 -7
  21. package/dist/themes/shaj-default.css +1693 -1534
  22. package/dist/themes/shaj-default.min.css +4 -4
  23. package/package.json +6 -17
  24. package/src/components/Accordion/Accordion.stories.tsx +662 -21
  25. package/src/components/Accordion/Accordion.tsx +21 -14
  26. package/src/components/AtomixGlass/AtomixGlass.test.tsx +106 -72
  27. package/src/components/AtomixGlass/AtomixGlass.tsx +529 -1195
  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 +792 -68
  34. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1250 -0
  35. package/src/components/AtomixGlass/stories/Examples.stories.tsx +5768 -0
  36. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1065 -0
  37. package/src/components/AtomixGlass/stories/Playground.stories.tsx +1129 -0
  38. package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +395 -0
  39. package/src/components/AtomixGlass/stories/shared-components.tsx +301 -0
  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 +76 -55
  44. package/src/components/Badge/Badge.tsx +12 -14
  45. package/src/components/Breadcrumb/Breadcrumb.tsx +23 -4
  46. package/src/components/Button/Button.stories.tsx +501 -20
  47. package/src/components/Button/Button.tsx +5 -8
  48. package/src/components/Callout/Callout.stories.tsx +86 -35
  49. package/src/components/Callout/Callout.tsx +31 -9
  50. package/src/components/Card/Card.stories.tsx +565 -2
  51. package/src/components/Card/Card.tsx +15 -4
  52. package/src/components/Card/ElevationCard.tsx +2 -0
  53. package/src/components/Chart/AnimatedChart.tsx +179 -156
  54. package/src/components/Chart/AreaChart.tsx +123 -12
  55. package/src/components/Chart/BarChart.tsx +91 -100
  56. package/src/components/Chart/BaseChart.tsx +80 -0
  57. package/src/components/Chart/BubbleChart.tsx +114 -290
  58. package/src/components/Chart/CandlestickChart.tsx +282 -622
  59. package/src/components/Chart/Chart.stories.tsx +576 -179
  60. package/src/components/Chart/Chart.tsx +374 -75
  61. package/src/components/Chart/ChartRenderer.tsx +371 -220
  62. package/src/components/Chart/ChartToolbar.tsx +372 -61
  63. package/src/components/Chart/ChartTooltip.tsx +33 -18
  64. package/src/components/Chart/DonutChart.tsx +172 -254
  65. package/src/components/Chart/FunnelChart.tsx +169 -240
  66. package/src/components/Chart/GaugeChart.tsx +224 -392
  67. package/src/components/Chart/HeatmapChart.tsx +302 -440
  68. package/src/components/Chart/LineChart.tsx +148 -103
  69. package/src/components/Chart/MultiAxisChart.tsx +267 -395
  70. package/src/components/Chart/PieChart.tsx +114 -64
  71. package/src/components/Chart/RadarChart.tsx +202 -218
  72. package/src/components/Chart/ScatterChart.tsx +111 -97
  73. package/src/components/Chart/TreemapChart.tsx +147 -222
  74. package/src/components/Chart/WaterfallChart.tsx +253 -291
  75. package/src/components/Chart/index.ts +11 -9
  76. package/src/components/Chart/types.ts +85 -9
  77. package/src/components/Chart/utils.ts +66 -0
  78. package/src/components/ColorModeToggle/ColorModeToggle.tsx +6 -3
  79. package/src/components/Countdown/Countdown.tsx +4 -0
  80. package/src/components/DataTable/DataTable.tsx +2 -1
  81. package/src/components/DatePicker/DatePicker.stories.tsx +689 -12
  82. package/src/components/DatePicker/DatePicker.tsx +3 -9
  83. package/src/components/DatePicker/types.ts +5 -0
  84. package/src/components/Dropdown/Dropdown.stories.tsx +32 -25
  85. package/src/components/Dropdown/Dropdown.tsx +26 -28
  86. package/src/components/EdgePanel/EdgePanel.stories.tsx +473 -2
  87. package/src/components/EdgePanel/EdgePanel.tsx +101 -13
  88. package/src/components/Footer/Footer.stories.tsx +187 -60
  89. package/src/components/Footer/Footer.test.tsx +134 -0
  90. package/src/components/Footer/Footer.tsx +133 -34
  91. package/src/components/Footer/FooterLink.tsx +1 -1
  92. package/src/components/Footer/FooterSection.tsx +53 -36
  93. package/src/components/Footer/FooterSocialLink.tsx +32 -29
  94. package/src/components/Footer/README.md +82 -3
  95. package/src/components/Footer/index.ts +1 -1
  96. package/src/components/Form/Checkbox.stories.tsx +13 -5
  97. package/src/components/Form/Checkbox.tsx +3 -6
  98. package/src/components/Form/Form.stories.tsx +10 -3
  99. package/src/components/Form/Form.tsx +2 -0
  100. package/src/components/Form/FormGroup.tsx +2 -1
  101. package/src/components/Form/Input.stories.tsx +12 -11
  102. package/src/components/Form/Input.tsx +97 -95
  103. package/src/components/Form/Radio.stories.tsx +22 -7
  104. package/src/components/Form/Radio.tsx +3 -6
  105. package/src/components/Form/Select.stories.tsx +21 -6
  106. package/src/components/Form/Select.tsx +3 -5
  107. package/src/components/Form/Textarea.stories.tsx +13 -11
  108. package/src/components/Form/Textarea.tsx +88 -86
  109. package/src/components/Hero/Hero.stories.tsx +2 -3
  110. package/src/components/Hero/Hero.tsx +5 -6
  111. package/src/components/Icon/Icon.tsx +12 -1
  112. package/src/components/List/List.tsx +2 -1
  113. package/src/components/List/ListGroup.tsx +2 -1
  114. package/src/components/Messages/Messages.stories.tsx +113 -0
  115. package/src/components/Messages/Messages.tsx +52 -9
  116. package/src/components/Modal/Modal.stories.tsx +48 -32
  117. package/src/components/Modal/Modal.tsx +19 -24
  118. package/src/components/Navigation/Menu/MegaMenu.tsx +2 -2
  119. package/src/components/Navigation/Menu/Menu.tsx +2 -2
  120. package/src/components/Navigation/Nav/Nav.stories.tsx +469 -0
  121. package/src/components/Navigation/Nav/Nav.tsx +22 -4
  122. package/src/components/Navigation/Nav/NavDropdown.tsx +10 -1
  123. package/src/components/Navigation/Navbar/Navbar.stories.tsx +413 -0
  124. package/src/components/Navigation/Navbar/Navbar.tsx +70 -29
  125. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +340 -0
  126. package/src/components/Navigation/SideMenu/SideMenu.tsx +29 -2
  127. package/src/components/Pagination/Pagination.stories.tsx +13 -6
  128. package/src/components/Pagination/Pagination.tsx +7 -6
  129. package/src/components/PhotoViewer/PhotoViewer.tsx +2 -1
  130. package/src/components/Popover/Popover.stories.tsx +32 -24
  131. package/src/components/Popover/Popover.tsx +4 -1
  132. package/src/components/ProductReview/ProductReview.tsx +8 -2
  133. package/src/components/Progress/Progress.tsx +19 -3
  134. package/src/components/Rating/Rating.stories.tsx +11 -6
  135. package/src/components/Rating/Rating.tsx +3 -5
  136. package/src/components/River/River.tsx +5 -5
  137. package/src/components/SectionIntro/SectionIntro.tsx +8 -2
  138. package/src/components/Slider/Slider.stories.tsx +4 -4
  139. package/src/components/Slider/Slider.tsx +4 -3
  140. package/src/components/Spinner/Spinner.tsx +19 -3
  141. package/src/components/Steps/Steps.stories.tsx +5 -4
  142. package/src/components/Steps/Steps.tsx +8 -5
  143. package/src/components/Tab/Tab.stories.tsx +4 -3
  144. package/src/components/Tab/Tab.tsx +8 -6
  145. package/src/components/Testimonial/Testimonial.tsx +8 -2
  146. package/src/components/Todo/Todo.tsx +2 -1
  147. package/src/components/Toggle/Toggle.stories.tsx +5 -4
  148. package/src/components/Toggle/Toggle.tsx +8 -5
  149. package/src/components/Tooltip/Tooltip.stories.tsx +40 -30
  150. package/src/components/Tooltip/Tooltip.tsx +9 -2
  151. package/src/components/Upload/Upload.stories.tsx +252 -0
  152. package/src/components/Upload/Upload.tsx +92 -53
  153. package/src/components/VideoPlayer/VideoPlayer.tsx +3 -1
  154. package/src/components/index.ts +0 -4
  155. package/src/layouts/Grid/Grid.stories.tsx +10 -23
  156. package/src/layouts/Grid/Grid.tsx +20 -1
  157. package/src/layouts/Grid/GridCol.tsx +76 -48
  158. package/src/lib/composables/useAtomixGlass.ts +861 -44
  159. package/src/lib/composables/useBarChart.ts +21 -4
  160. package/src/lib/composables/useChart.ts +227 -370
  161. package/src/lib/composables/useChartExport.ts +19 -78
  162. package/src/lib/composables/useChartToolbar.ts +11 -21
  163. package/src/lib/composables/useEdgePanel.ts +125 -71
  164. package/src/lib/composables/useFooter.ts +3 -3
  165. package/src/lib/composables/useGlassContainer.ts +16 -7
  166. package/src/lib/composables/useLineChart.ts +11 -2
  167. package/src/lib/composables/usePieChart.ts +4 -14
  168. package/src/lib/composables/useRiver.ts +5 -0
  169. package/src/lib/composables/useSlider.ts +62 -24
  170. package/src/lib/composables/useVideoPlayer.ts +60 -63
  171. package/src/lib/constants/components.ts +147 -32
  172. package/src/lib/types/components.ts +355 -25
  173. package/src/lib/utils/displacement-generator.ts +55 -49
  174. package/src/lib/utils/icons.ts +1 -1
  175. package/src/lib/utils/index.ts +16 -10
  176. package/src/styles/01-settings/_settings.accordion.scss +19 -19
  177. package/src/styles/01-settings/_settings.animations.scss +5 -5
  178. package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
  179. package/src/styles/01-settings/_settings.avatar.scss +17 -17
  180. package/src/styles/01-settings/_settings.background.scss +0 -3
  181. package/src/styles/01-settings/_settings.badge.scss +1 -1
  182. package/src/styles/01-settings/_settings.breadcrumb.scss +1 -1
  183. package/src/styles/01-settings/_settings.card.scss +1 -1
  184. package/src/styles/01-settings/_settings.chart.scss +65 -2
  185. package/src/styles/01-settings/_settings.dropdown.scss +1 -1
  186. package/src/styles/01-settings/_settings.edge-panel.scss +1 -1
  187. package/src/styles/01-settings/_settings.footer.scss +35 -42
  188. package/src/styles/01-settings/_settings.input.scss +1 -1
  189. package/src/styles/01-settings/_settings.list.scss +1 -1
  190. package/src/styles/01-settings/_settings.rating.scss +1 -1
  191. package/src/styles/01-settings/_settings.tabs.scss +1 -1
  192. package/src/styles/01-settings/_settings.upload.scss +6 -5
  193. package/src/styles/02-tools/_tools.animations.scss +4 -5
  194. package/src/styles/02-tools/_tools.background.scss +1 -13
  195. package/src/styles/02-tools/_tools.glass.scss +0 -1
  196. package/src/styles/02-tools/_tools.utility-api.scss +91 -48
  197. package/src/styles/03-generic/_generic.root.scss +1 -4
  198. package/src/styles/04-elements/_elements.body.scss +0 -1
  199. package/src/styles/06-components/_components.atomix-glass.scss +249 -0
  200. package/src/styles/06-components/_components.badge.scss +8 -23
  201. package/src/styles/06-components/_components.button.scss +8 -3
  202. package/src/styles/06-components/_components.callout.scss +10 -5
  203. package/src/styles/06-components/_components.card.scss +2 -14
  204. package/src/styles/06-components/_components.chart.scss +969 -1449
  205. package/src/styles/06-components/_components.dropdown.scss +19 -7
  206. package/src/styles/06-components/_components.edge-panel.scss +103 -0
  207. package/src/styles/06-components/_components.footer.scss +166 -85
  208. package/src/styles/06-components/_components.input.scss +8 -9
  209. package/src/styles/06-components/_components.list.scss +1 -0
  210. package/src/styles/06-components/_components.messages.scss +176 -0
  211. package/src/styles/06-components/_components.modal.scss +16 -4
  212. package/src/styles/06-components/_components.navbar.scss +12 -1
  213. package/src/styles/06-components/_components.side-menu.scss +5 -0
  214. package/src/styles/06-components/_components.skeleton.scss +8 -6
  215. package/src/styles/06-components/_components.upload.scss +219 -4
  216. package/src/styles/06-components/old.chart.styles.scss +1 -30
  217. package/src/styles/99-utilities/_index.scss +1 -0
  218. package/src/styles/99-utilities/_utilities.glass-fixes.scss +1 -0
  219. package/src/styles/99-utilities/_utilities.scss +1 -1
  220. package/src/components/AtomixGlass/AtomixGlass.stories.tsx +0 -3011
  221. package/src/components/AtomixGlass/AtomixGlassComprehensivePreview.stories.tsx +0 -1369
  222. package/src/components/Chart/AdvancedChart.tsx +0 -624
  223. package/src/components/Chart/LineChartNew.tsx +0 -167
  224. package/src/components/Chart/RealTimeChart.tsx +0 -436
  225. package/src/components/DatePicker/DatePicker copy.tsx +0 -551
@@ -1,8 +1,8 @@
1
- import { forwardRef, memo, useCallback } from 'react';
1
+ import { forwardRef, memo } from 'react';
2
2
  import { PieChartOptions, usePieChart } from '../../lib/composables/usePieChart';
3
- import Chart from './Chart';
3
+ import BaseChart from './BaseChart';
4
4
  import ChartTooltip from './ChartTooltip';
5
- import { ChartProps } from './types';
5
+ import { ChartDataPoint, ChartProps, ChartRenderContentParams } from './types';
6
6
 
7
7
  interface PieChartProps extends Omit<ChartProps, 'type'> {
8
8
  /**
@@ -25,74 +25,124 @@ const PieChart = memo(
25
25
  selectedSlices,
26
26
  } = usePieChart(data, pieOptions);
27
27
 
28
- const renderContent = useCallback(() => {
28
+ const renderContent = ({
29
+ scales,
30
+ colors,
31
+ datasets: renderedDatasets,
32
+ handlers,
33
+ hoveredPoint,
34
+ toolbarState,
35
+ config: renderConfig,
36
+ }: ChartRenderContentParams) => {
29
37
  if (!slices.length) return null;
30
38
 
31
- return slices.map((slice, index) => {
32
- const isHovered = hoveredSlice === index;
33
- const isSelected = selectedSlices.has(index);
39
+ // Use actual container dimensions from scales
40
+ const width = scales.width;
41
+ const height = scales.height;
42
+ const centerX = width / 2;
43
+ const centerY = height / 2;
44
+ const outerRadius = (Math.min(width, height) / 2) * 0.8;
34
45
 
35
- return (
36
- <g key={`slice-${index}`}>
37
- <path
38
- d={slice.path}
39
- fill={slice.color}
40
- className={`c-chart__pie-slice ${isHovered ? 'c-chart__pie-slice--hovered' : ''} ${isSelected ? 'c-chart__pie-slice--selected' : ''}`}
41
- onClick={() => {
42
- handleSliceClick(index);
43
- onDataPointClick?.(slice.dataPoint, 0, index);
44
- }}
45
- onMouseEnter={e => {
46
- const rect = e.currentTarget.ownerSVGElement?.getBoundingClientRect();
47
- const clientX = rect ? rect.left + slice.labelPosition.x : e.clientX;
48
- const clientY = rect ? rect.top + slice.labelPosition.y : e.clientY;
49
- handleSliceHover(index, clientX, clientY);
46
+ // Recalculate slices with actual dimensions
47
+ const recalculatedSlices = slices.map(slice => {
48
+ // Recalculate path with actual center and radius
49
+ const outerStartX = centerX + outerRadius * Math.cos(slice.startAngle);
50
+ const outerStartY = centerY + outerRadius * Math.sin(slice.startAngle);
51
+ const outerEndX = centerX + outerRadius * Math.cos(slice.endAngle);
52
+ const outerEndY = centerY + outerRadius * Math.sin(slice.endAngle);
53
+
54
+ const angle = slice.endAngle - slice.startAngle;
55
+ const largeArcFlag = angle > Math.PI ? 1 : 0;
56
+
57
+ const path = [
58
+ `M ${centerX},${centerY}`,
59
+ `L ${outerStartX},${outerStartY}`,
60
+ `A ${outerRadius},${outerRadius} 0 ${largeArcFlag},1 ${outerEndX},${outerEndY}`,
61
+ 'Z',
62
+ ].join(' ');
63
+
64
+ // Recalculate label position
65
+ const labelRadius = outerRadius * 0.7;
66
+ const labelX = centerX + labelRadius * Math.cos(slice.midAngle);
67
+ const labelY = centerY + labelRadius * Math.sin(slice.midAngle);
68
+
69
+ return {
70
+ ...slice,
71
+ path,
72
+ labelPosition: { x: labelX, y: labelY },
73
+ };
74
+ });
75
+
76
+ // Use toolbar state if available, fallback to config for backward compatibility
77
+ const showTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? true;
78
+
79
+ return (
80
+ <>
81
+ {recalculatedSlices.map((slice, index) => {
82
+ const isHovered = hoveredPoint?.pointIndex === index;
83
+
84
+ return (
85
+ <g key={`slice-${index}`}>
86
+ <path
87
+ d={slice.path}
88
+ fill={slice.color}
89
+ className={`c-chart__pie-slice ${isHovered ? 'c-chart__pie-slice--hovered' : ''}`}
90
+ onClick={() => {
91
+ handleSliceClick(index);
92
+ handlers.onDataPointClick?.(slice.dataPoint, 0, index);
93
+ }}
94
+ onMouseEnter={e => {
95
+ const rect = e.currentTarget.getBoundingClientRect();
96
+ handlers.onPointHover(
97
+ 0,
98
+ index,
99
+ slice.labelPosition.x,
100
+ slice.labelPosition.y,
101
+ rect.left + rect.width / 2,
102
+ rect.top + rect.height / 2
103
+ );
104
+ }}
105
+ onMouseLeave={handlers.onPointLeave}
106
+ />
107
+ {pieOptions.showLabels && (
108
+ <text
109
+ x={slice.labelPosition.x}
110
+ y={slice.labelPosition.y}
111
+ textAnchor="middle"
112
+ className="c-chart__pie-label"
113
+ >
114
+ {formatLabel(slice)}
115
+ </text>
116
+ )}
117
+ </g>
118
+ );
119
+ })}
120
+ {showTooltips && hoveredPoint && data[hoveredPoint.pointIndex] && (
121
+ <ChartTooltip
122
+ dataPoint={data[hoveredPoint.pointIndex] as ChartDataPoint}
123
+ datasetLabel={renderedDatasets[0]?.label}
124
+ datasetColor={slices[hoveredPoint.pointIndex]?.color}
125
+ position={{
126
+ x: hoveredPoint.clientX,
127
+ y: hoveredPoint.clientY,
50
128
  }}
51
- onMouseLeave={handleSliceLeave}
129
+ visible={true}
52
130
  />
53
- {pieOptions.showLabels && (
54
- <text
55
- x={slice.labelPosition.x}
56
- y={slice.labelPosition.y}
57
- textAnchor="middle"
58
- className="c-chart__pie-label"
59
- >
60
- {formatLabel(slice)}
61
- </text>
62
- )}
63
- </g>
64
- );
65
- });
66
- }, [
67
- slices,
68
- hoveredSlice,
69
- selectedSlices,
70
- pieOptions.showLabels,
71
- handleSliceClick,
72
- handleSliceHover,
73
- handleSliceLeave,
74
- formatLabel,
75
- onDataPointClick,
76
- ]);
131
+ )}
132
+ </>
133
+ );
134
+ };
77
135
 
78
136
  return (
79
- <Chart ref={ref} type="pie" datasets={datasets} config={config} {...props}>
80
- <svg width="100%" height="100%" viewBox="0 0 800 400">
81
- {renderContent()}
82
- </svg>
83
- {hoveredSlice !== null && data[hoveredSlice] && (
84
- <ChartTooltip
85
- dataPoint={data[hoveredSlice]}
86
- datasetLabel={datasets[0]?.label}
87
- datasetColor={slices[hoveredSlice]?.color}
88
- position={{
89
- x: slices[hoveredSlice]?.clientX || 0,
90
- y: slices[hoveredSlice]?.clientY || 0,
91
- }}
92
- visible={true}
93
- />
94
- )}
95
- </Chart>
137
+ <BaseChart
138
+ ref={ref}
139
+ type="pie"
140
+ datasets={datasets}
141
+ config={config}
142
+ renderContent={renderContent}
143
+ onDataPointClick={onDataPointClick}
144
+ {...props}
145
+ />
96
146
  );
97
147
  }
98
148
  )
@@ -1,8 +1,8 @@
1
- import { forwardRef, memo, ReactElement, useCallback, useState } from 'react';
2
- import { ChartProps } from '../../lib/types/components';
3
- import Chart from './Chart';
4
- import ChartRenderer from './ChartRenderer';
1
+ import { forwardRef, memo, useState } from 'react';
2
+ import BaseChart from './BaseChart';
5
3
  import ChartTooltip from './ChartTooltip';
4
+ import { ChartProps } from '../../lib/types/components';
5
+ import { ChartRenderContentParams, ChartDataset, ChartDataPoint } from './types';
6
6
 
7
7
  export interface RadarChartProps extends Omit<ChartProps, 'type'> {
8
8
  /**
@@ -78,251 +78,235 @@ const RadarChart = memo(
78
78
  scaleMax,
79
79
  } = radarOptions;
80
80
 
81
- const [hoveredPoint, setHoveredPoint] = useState<{
82
- datasetIndex: number;
83
- pointIndex: number;
84
- clientX: number;
85
- clientY: number;
86
- } | null>(null);
81
+ const renderContent = ({
82
+ scales,
83
+ colors,
84
+ datasets: renderedDatasets,
85
+ handlers,
86
+ hoveredPoint,
87
+ toolbarState,
88
+ config: renderConfig,
89
+ }: ChartRenderContentParams) => {
90
+ if (!renderedDatasets.length) return null;
87
91
 
88
- const renderContent = useCallback(
89
- ({
90
- scales,
91
- colors,
92
- datasets: renderedDatasets,
93
- handlers,
94
- }: {
95
- scales: any;
96
- colors: any;
97
- datasets: any;
98
- handlers: any;
99
- }) => {
100
- if (!renderedDatasets.length) return null;
92
+ // Use toolbar state if available, fallback to config for backward compatibility
93
+ const showTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? true;
101
94
 
102
- const centerX = scales.width / 2;
103
- const centerY = scales.height / 2;
104
- const radius = Math.min(centerX, centerY) * 0.8;
95
+ const centerX = scales.width / 2;
96
+ const centerY = scales.height / 2;
97
+ const radius = Math.min(centerX, centerY) * 0.8;
105
98
 
106
- const firstDataset = renderedDatasets[0];
107
- const dataPoints = firstDataset.data || [];
108
- const angleStep = (2 * Math.PI) / dataPoints.length;
99
+ const firstDataset = renderedDatasets[0];
100
+ const dataPoints = firstDataset.data || [];
101
+ const angleStep = (2 * Math.PI) / dataPoints.length;
109
102
 
110
- // Calculate scale
111
- const maxValue =
112
- scaleMax ||
113
- Math.max(
114
- ...renderedDatasets.flatMap((d: any) => d.data?.map((p: any) => p.value) || [])
115
- );
116
- const minValue = scaleMin;
117
- const valueRange = maxValue - minValue;
103
+ // Calculate value bounds
104
+ let minValue = scaleMin;
105
+ let maxValue = scaleMax;
118
106
 
119
- // Generate grid levels
120
- const gridElements = [];
121
- if (showGrid) {
122
- for (let level = 1; level <= gridLevels; level++) {
123
- const levelRadius = (radius * level) / gridLevels;
124
- const points = dataPoints.map((_: any, i: number) => {
125
- const angle = i * angleStep - Math.PI / 2;
126
- return {
127
- x: centerX + Math.cos(angle) * levelRadius,
128
- y: centerY + Math.sin(angle) * levelRadius,
129
- };
130
- });
107
+ if (minValue === undefined || maxValue === undefined) {
108
+ const allValues = renderedDatasets.flatMap(
109
+ dataset => dataset.data?.map((d: any) => d.value) || []
110
+ );
111
+ if (minValue === undefined) minValue = Math.min(scaleMin, ...allValues);
112
+ if (maxValue === undefined) maxValue = Math.max(scaleMax || 0, ...allValues);
113
+ }
131
114
 
132
- const pathData = `M ${points.map((p: any) => `${p.x},${p.y}`).join(' L ')} Z`;
115
+ const valueRange = maxValue - minValue;
133
116
 
134
- gridElements.push(
135
- <path
136
- key={`grid-${level}`}
137
- d={pathData}
138
- fill="none"
139
- className="c-chart__radar-grid"
140
- />
141
- );
142
- }
117
+ // Generate grid lines
118
+ const gridLines = [];
119
+ if (showGrid) {
120
+ // Concentric circles
121
+ for (let i = 1; i <= gridLevels; i++) {
122
+ const r = (radius * i) / gridLevels;
123
+ gridLines.push(
124
+ <circle
125
+ key={`grid-circle-${i}`}
126
+ cx={centerX}
127
+ cy={centerY}
128
+ r={r}
129
+ className="c-chart__radar-grid-line"
130
+ fill="none"
131
+ stroke="var(--atomix-border-color)"
132
+ strokeWidth="1"
133
+ />
134
+ );
135
+ }
143
136
 
144
- // Add axis lines
145
- dataPoints.forEach((_: any, i: number) => {
146
- const angle = i * angleStep - Math.PI / 2;
147
- const endX = centerX + Math.cos(angle) * radius;
148
- const endY = centerY + Math.sin(angle) * radius;
137
+ // Radial lines
138
+ for (let i = 0; i < dataPoints.length; i++) {
139
+ const angle = i * angleStep - Math.PI / 2;
140
+ const x = centerX + radius * Math.cos(angle);
141
+ const y = centerY + radius * Math.sin(angle);
149
142
 
150
- gridElements.push(
151
- <line
152
- key={`axis-${i}`}
153
- x1={centerX}
154
- y1={centerY}
155
- x2={endX}
156
- y2={endY}
157
- className="c-chart__radar-axis"
158
- />
159
- );
160
- });
143
+ gridLines.push(
144
+ <line
145
+ key={`grid-radial-${i}`}
146
+ x1={centerX}
147
+ y1={centerY}
148
+ x2={x}
149
+ y2={y}
150
+ className="c-chart__radar-grid-line"
151
+ stroke="var(--atomix-border-color)"
152
+ strokeWidth="1"
153
+ />
154
+ );
161
155
  }
156
+ }
162
157
 
163
- // Generate axis labels
164
- const labelElements: ReactElement[] = [];
165
- if (showAxisLabels) {
166
- dataPoints.forEach((point: any, i: number) => {
167
- const angle = i * angleStep - Math.PI / 2;
168
- const labelRadius = radius + 20;
169
- const labelX = centerX + Math.cos(angle) * labelRadius;
170
- const labelY = centerY + Math.sin(angle) * labelRadius;
158
+ // Generate axis labels
159
+ const axisLabels = [];
160
+ if (showAxisLabels) {
161
+ for (let i = 0; i < dataPoints.length; i++) {
162
+ const angle = i * angleStep - Math.PI / 2;
163
+ const x = centerX + (radius + 20) * Math.cos(angle);
164
+ const y = centerY + (radius + 20) * Math.sin(angle);
171
165
 
172
- labelElements.push(
173
- <text
174
- key={`label-${i}`}
175
- x={labelX}
176
- y={labelY}
177
- textAnchor="middle"
178
- dominantBaseline="middle"
179
- className="c-chart__radar-label"
180
- >
181
- {point.label}
182
- </text>
183
- );
184
- });
166
+ axisLabels.push(
167
+ <text
168
+ key={`label-${i}`}
169
+ x={x}
170
+ y={y}
171
+ textAnchor="middle"
172
+ dominantBaseline="middle"
173
+ className="c-chart__radar-axis-label"
174
+ >
175
+ {dataPoints[i]?.label}
176
+ </text>
177
+ );
185
178
  }
179
+ }
180
+
181
+ // Generate data paths
182
+ const dataPaths = renderedDatasets.map((dataset: ChartDataset, datasetIndex: number) => {
183
+ const color = dataset.color || colors[datasetIndex % colors.length];
184
+ const points = [];
186
185
 
187
- // Generate data paths
188
- const dataElements = renderedDatasets.map((dataset: any, datasetIndex: number) => {
189
- const color = dataset.color || colors[datasetIndex];
190
- const points =
191
- dataset.data?.map((point: any, i: number) => {
192
- const angle = i * angleStep - Math.PI / 2;
193
- const normalizedValue = (point.value - minValue) / valueRange;
194
- const pointRadius = radius * normalizedValue;
195
- return {
196
- x: centerX + Math.cos(angle) * pointRadius,
197
- y: centerY + Math.sin(angle) * pointRadius,
198
- originalPoint: point,
199
- angle,
200
- radius: pointRadius,
201
- };
202
- }) || [];
186
+ // Calculate points
187
+ for (let i = 0; i < dataset.data?.length; i++) {
188
+ const value = dataset.data[i]?.value || 0;
189
+ const normalizedValue = valueRange > 0 ? (value - minValue) / valueRange : 0;
190
+ const r = radius * normalizedValue;
191
+ const angle = i * angleStep - Math.PI / 2;
192
+ const x = centerX + r * Math.cos(angle);
193
+ const y = centerY + r * Math.sin(angle);
203
194
 
204
- const pathData = smooth
205
- ? generateSmoothRadarPath(points)
206
- : `M ${points.map((p: any) => `${p.x},${p.y}`).join(' L ')} Z`;
195
+ points.push({ x, y, value, point: dataset.data[i] });
196
+ }
207
197
 
208
- const elements = [];
198
+ if (points.length === 0) return null;
209
199
 
210
- // Fill area
211
- if (fillArea) {
212
- elements.push(
200
+ // Generate path
201
+ let path = '';
202
+ if (smooth && points.length > 2) {
203
+ // For smooth curves, we would implement a more complex algorithm
204
+ // For now, we'll just connect the points with straight lines
205
+ path = `M ${points[0].x},${points[0].y}`;
206
+ for (let i = 1; i < points.length; i++) {
207
+ path += ` L ${points[i].x},${points[i].y}`;
208
+ }
209
+ path += ` L ${points[0].x},${points[0].y} Z`;
210
+ } else {
211
+ path = `M ${points[0].x},${points[0].y}`;
212
+ for (let i = 1; i < points.length; i++) {
213
+ path += ` L ${points[i].x},${points[i].y}`;
214
+ }
215
+ path += ` L ${points[0].x},${points[0].y} Z`;
216
+ }
217
+
218
+ return (
219
+ <g key={`dataset-${datasetIndex}`}>
220
+ {fillArea && (
213
221
  <path
214
- key={`fill-${datasetIndex}`}
215
- d={pathData}
222
+ d={path}
216
223
  fill={color}
217
- className="c-chart__radar-fill"
218
- style={{ opacity: fillOpacity }}
224
+ fillOpacity={fillOpacity}
225
+ className="c-chart__radar-area"
219
226
  />
220
- );
221
- }
222
-
223
- // Line
224
- elements.push(
227
+ )}
225
228
  <path
226
- key={`line-${datasetIndex}`}
227
- d={pathData}
229
+ d={path}
228
230
  fill="none"
229
231
  stroke={color}
232
+ strokeWidth={lineWidth}
230
233
  className="c-chart__radar-line"
231
- style={{ strokeWidth: lineWidth }}
232
234
  />
233
- );
235
+ {showDataPoints &&
236
+ points.map((point, pointIndex) => {
237
+ const isHovered =
238
+ hoveredPoint?.datasetIndex === datasetIndex &&
239
+ hoveredPoint?.pointIndex === pointIndex;
234
240
 
235
- // Data points
236
- if (showDataPoints) {
237
- points.forEach((point: any, i: number) => {
238
- elements.push(
239
- <circle
240
- key={`point-${datasetIndex}-${i}`}
241
- cx={point.x}
242
- cy={point.y}
243
- r={pointRadius}
244
- fill={color}
245
- className="c-chart__radar-point"
246
- onClick={() =>
247
- handlers.onDataPointClick?.(point.originalPoint, datasetIndex, i)
248
- }
249
- onMouseEnter={e => {
250
- const rect = e.currentTarget.ownerSVGElement?.getBoundingClientRect();
251
- const clientX = rect ? rect.left + point.x : e.clientX;
252
- const clientY = rect ? rect.top + point.y : e.clientY;
253
- setHoveredPoint({ datasetIndex, pointIndex: i, clientX, clientY });
254
- }}
255
- onMouseLeave={() => setHoveredPoint(null)}
256
- />
257
- );
258
- });
259
- }
260
-
261
- return <g key={`dataset-${datasetIndex}`}>{elements}</g>;
262
- });
263
-
264
- return (
265
- <g>
266
- {gridElements}
267
- {dataElements}
268
- {labelElements}
241
+ return (
242
+ <g key={`point-${datasetIndex}-${pointIndex}`}>
243
+ <circle
244
+ cx={point.x}
245
+ cy={point.y}
246
+ r={isHovered ? pointRadius * 1.5 : pointRadius}
247
+ fill={color}
248
+ className={`c-chart__radar-point ${isHovered ? 'c-chart__radar-point--hovered' : ''}`}
249
+ onClick={() =>
250
+ handlers.onDataPointClick?.(point.point, datasetIndex, pointIndex)
251
+ }
252
+ onMouseEnter={e => {
253
+ const rect = e.currentTarget.getBoundingClientRect();
254
+ handlers.onPointHover(
255
+ datasetIndex,
256
+ pointIndex,
257
+ point.x,
258
+ point.y,
259
+ rect.left + rect.width / 2,
260
+ rect.top + rect.height / 2
261
+ );
262
+ }}
263
+ onMouseLeave={handlers.onPointLeave}
264
+ />
265
+ </g>
266
+ );
267
+ })}
269
268
  </g>
270
269
  );
271
- },
272
- [
273
- gridLevels,
274
- showGrid,
275
- showAxisLabels,
276
- fillArea,
277
- fillOpacity,
278
- showDataPoints,
279
- pointRadius,
280
- lineWidth,
281
- smooth,
282
- scaleMin,
283
- scaleMax,
284
- ]
285
- );
286
-
287
- const generateSmoothRadarPath = useCallback((points: any[]) => {
288
- if (points.length < 3) return `M ${points.map(p => `${p.x},${p.y}`).join(' L ')} Z`;
289
-
290
- let path = `M ${points[0].x},${points[0].y}`;
291
-
292
- for (let i = 0; i < points.length; i++) {
293
- const current = points[i];
294
- const next = points[(i + 1) % points.length];
295
- const prev = points[i === 0 ? points.length - 1 : i - 1];
296
-
297
- const cp1x = current.x + (next.x - prev.x) * 0.1;
298
- const cp1y = current.y + (next.y - prev.y) * 0.1;
299
- const cp2x = next.x - (points[(i + 2) % points.length].x - current.x) * 0.1;
300
- const cp2y = next.y - (points[(i + 2) % points.length].y - current.y) * 0.1;
270
+ });
301
271
 
302
- path += ` C ${cp1x},${cp1y} ${cp2x},${cp2y} ${next.x},${next.y}`;
303
- }
304
-
305
- return path + ' Z';
306
- }, []);
272
+ return (
273
+ <>
274
+ <g>
275
+ {gridLines}
276
+ {dataPaths}
277
+ {axisLabels}
278
+ </g>
279
+ {showTooltips && hoveredPoint && (
280
+ <ChartTooltip
281
+ dataPoint={
282
+ renderedDatasets[hoveredPoint.datasetIndex]?.data?.[hoveredPoint.pointIndex]
283
+ }
284
+ datasetLabel={renderedDatasets[hoveredPoint.datasetIndex]?.label}
285
+ datasetColor={
286
+ renderedDatasets[hoveredPoint.datasetIndex]?.color ||
287
+ colors[hoveredPoint.datasetIndex]
288
+ }
289
+ position={{
290
+ x: hoveredPoint.clientX,
291
+ y: hoveredPoint.clientY,
292
+ }}
293
+ visible={true}
294
+ />
295
+ )}
296
+ </>
297
+ );
298
+ };
307
299
 
308
300
  return (
309
- <Chart ref={ref} type="radar" datasets={datasets} config={config} {...props}>
310
- <ChartRenderer
311
- datasets={datasets}
312
- config={config}
313
- onDataPointClick={onDataPointClick}
314
- renderContent={renderContent}
315
- />
316
- {hoveredPoint && (
317
- <ChartTooltip
318
- dataPoint={datasets[hoveredPoint.datasetIndex]?.data?.[hoveredPoint.pointIndex]!}
319
- datasetLabel={datasets[hoveredPoint.datasetIndex]?.label}
320
- datasetColor={datasets[hoveredPoint.datasetIndex]?.color}
321
- position={{ x: hoveredPoint.clientX, y: hoveredPoint.clientY }}
322
- visible={true}
323
- />
324
- )}
325
- </Chart>
301
+ <BaseChart
302
+ ref={ref}
303
+ type="radar"
304
+ datasets={datasets}
305
+ config={config}
306
+ renderContent={renderContent}
307
+ onDataPointClick={onDataPointClick}
308
+ {...props}
309
+ />
326
310
  );
327
311
  }
328
312
  )