@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,7 @@
1
- import { forwardRef, memo, useCallback, useMemo } from 'react';
1
+ import { forwardRef, memo } from 'react';
2
2
  import { ChartDataset, ChartProps } from '../../lib/types/components';
3
- import Chart from './Chart';
4
- import ChartRenderer from './ChartRenderer';
5
- import { ChartDataPoint } from './types';
3
+ import BaseChart from './BaseChart';
4
+ import { ChartDataPoint, ChartRenderContentParams } from './types';
6
5
 
7
6
  interface AxisConfig {
8
7
  /**
@@ -49,36 +48,80 @@ interface MultiAxisDataset extends ChartDataset {
49
48
  */
50
49
  yAxisId?: string;
51
50
  /**
52
- * Chart type for this dataset
51
+ * X-axis ID this dataset should use
53
52
  */
54
- type?: 'line' | 'bar' | 'area';
53
+ xAxisId?: string;
55
54
  }
56
55
 
57
- interface MultiAxisChartProps extends Omit<ChartProps, 'type' | 'datasets'> {
56
+ export interface MultiAxisChartProps extends Omit<ChartProps, 'type'> {
58
57
  /**
59
- * Multi-axis datasets
58
+ * Multi-axis chart datasets
60
59
  */
61
60
  datasets: MultiAxisDataset[];
62
61
 
63
62
  /**
64
63
  * Y-axis configurations
65
64
  */
66
- yAxes: AxisConfig[];
65
+ yAxes?: AxisConfig[];
67
66
 
68
67
  /**
69
- * X-axis configuration
68
+ * X-axis configurations
70
69
  */
71
- xAxis?: AxisConfig;
70
+ xAxes?: AxisConfig[];
72
71
 
73
72
  /**
74
- * Whether to sync zoom across axes
73
+ * Multi-axis chart specific options
75
74
  */
76
- syncZoom?: boolean;
77
-
78
- /**
79
- * Whether to show crosshair across all axes
80
- */
81
- showCrosshair?: boolean;
75
+ multiAxisOptions?: {
76
+ /**
77
+ * Whether to show legend
78
+ */
79
+ showLegend?: boolean;
80
+ /**
81
+ * Legend position
82
+ */
83
+ legendPosition?: 'top' | 'bottom' | 'left' | 'right';
84
+ /**
85
+ * Whether to synchronize axis ranges
86
+ */
87
+ syncAxes?: boolean;
88
+ /**
89
+ * Padding between axes
90
+ */
91
+ axisPadding?: number;
92
+ /**
93
+ * Whether to show tooltips
94
+ */
95
+ showTooltips?: boolean;
96
+ /**
97
+ * Tooltip position
98
+ */
99
+ tooltipPosition?: 'auto' | 'nearest' | 'average';
100
+ /**
101
+ * Interpolation method for line charts
102
+ */
103
+ interpolation?: 'linear' | 'step' | 'natural' | 'monotone';
104
+ /**
105
+ * Whether to show area under lines
106
+ */
107
+ showArea?: boolean;
108
+ /**
109
+ * Area opacity (0-1)
110
+ */
111
+ areaOpacity?: number;
112
+ /**
113
+ * Whether to show data points
114
+ */
115
+ showDataPoints?: boolean;
116
+ /**
117
+ * Data point radius
118
+ */
119
+ pointRadius?: number;
120
+ /**
121
+ * Whether to connect points across null values
122
+ */
123
+ spanGaps?: boolean;
124
+ };
82
125
  }
83
126
 
84
127
  const MultiAxisChart = memo(
@@ -86,408 +129,238 @@ const MultiAxisChart = memo(
86
129
  (
87
130
  {
88
131
  datasets = [],
89
- yAxes = [],
90
- xAxis,
91
132
  config = {},
92
- syncZoom = true,
93
- showCrosshair = true,
133
+ yAxes = [],
134
+ xAxes = [],
135
+ multiAxisOptions = {},
136
+ onDataPointClick,
94
137
  ...props
95
138
  },
96
139
  ref
97
140
  ) => {
98
- // Calculate scales for each axis
99
- const axisScales = useMemo(() => {
100
- const scales: Record<string, any> = {};
101
-
102
- // Default dimensions
103
- const width = 800;
104
- const height = 400;
105
- const leftAxisWidth = 60;
106
- const rightAxisWidth = 60;
107
- const topAxisHeight = 40;
108
- const bottomAxisHeight = 60;
109
-
110
- // Calculate available space
111
- const leftAxes = yAxes.filter(axis => axis.position === 'left');
112
- const rightAxes = yAxes.filter(axis => axis.position === 'right');
113
-
114
- const totalLeftWidth = leftAxes.length * leftAxisWidth;
115
- const totalRightWidth = rightAxes.length * rightAxisWidth;
116
-
117
- const plotAreaLeft = totalLeftWidth;
118
- const plotAreaRight = width - totalRightWidth;
119
- const plotAreaTop = topAxisHeight;
120
- const plotAreaBottom = height - bottomAxisHeight;
121
- const plotAreaWidth = plotAreaRight - plotAreaLeft;
122
- const plotAreaHeight = plotAreaBottom - plotAreaTop;
123
-
124
- // Create scales for each Y-axis
125
- yAxes.forEach((axis, index) => {
126
- // Find datasets using this axis
127
- const axisDatasets = datasets.filter(d => d.yAxisId === axis.id);
128
-
129
- if (axisDatasets.length === 0) return;
130
-
131
- // Calculate value range
132
- const allValues = axisDatasets.flatMap(
133
- dataset => dataset.data?.map(d => d.value).filter(v => typeof v === 'number') || []
134
- );
135
-
136
- const minValue = axis.min ?? Math.min(0, ...allValues);
137
- const maxValue = axis.max ?? Math.max(...allValues, 1);
138
- const valueRange = maxValue - minValue;
139
-
140
- // Create scale function
141
- const yScale = (value: number) => {
142
- if (valueRange === 0) return plotAreaTop + plotAreaHeight / 2;
143
- return (
144
- plotAreaTop + plotAreaHeight - ((value - minValue) / valueRange) * plotAreaHeight
145
- );
146
- };
147
-
148
- // Calculate axis position
149
- let axisX;
150
- if (axis.position === 'left') {
151
- const leftIndex = leftAxes.findIndex(a => a.id === axis.id);
152
- axisX = leftIndex * leftAxisWidth + leftAxisWidth / 2;
153
- } else {
154
- const rightIndex = rightAxes.findIndex(a => a.id === axis.id);
155
- axisX = plotAreaRight + rightIndex * rightAxisWidth + rightAxisWidth / 2;
141
+ const {
142
+ showLegend = true,
143
+ legendPosition = 'top',
144
+ syncAxes = false,
145
+ axisPadding = 20,
146
+ showTooltips = true,
147
+ tooltipPosition = 'nearest',
148
+ interpolation = 'linear',
149
+ showArea = false,
150
+ areaOpacity = 0.3,
151
+ showDataPoints = true,
152
+ pointRadius = 4,
153
+ spanGaps = false,
154
+ } = multiAxisOptions;
155
+
156
+ const renderContent = ({
157
+ scales,
158
+ colors,
159
+ datasets: renderedDatasets,
160
+ handlers,
161
+ hoveredPoint,
162
+ toolbarState,
163
+ config: renderConfig,
164
+ }: ChartRenderContentParams) => {
165
+ if (!datasets.length) return null;
166
+
167
+ // Use toolbar state if available, fallback to config for backward compatibility
168
+ const effectiveShowTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? showTooltips ?? true;
169
+ const effectiveShowGrid = toolbarState?.showGrid ?? true; // Grid visibility from toolbar
170
+
171
+ const padding = 60;
172
+ const chartWidth = scales.width - padding * 2;
173
+ const chartHeight = scales.height - padding * 2;
174
+
175
+ // Create axis configurations
176
+ const yAxisConfigs: AxisConfig[] = yAxes.length
177
+ ? yAxes
178
+ : [
179
+ {
180
+ id: 'y-axis-1',
181
+ position: 'left',
182
+ label: 'Y Axis',
183
+ },
184
+ ];
185
+
186
+ const xAxisConfigs: AxisConfig[] = xAxes.length
187
+ ? xAxes
188
+ : [
189
+ {
190
+ id: 'x-axis-1',
191
+ position: 'bottom',
192
+ label: 'X Axis',
193
+ },
194
+ ];
195
+
196
+ // Group datasets by axis
197
+ const datasetsByYAxis: Record<string, any[]> = {};
198
+ datasets.forEach((dataset, index) => {
199
+ const axisId = dataset.yAxisId || yAxisConfigs[0]?.id || 'y-axis-1';
200
+ if (!datasetsByYAxis[axisId]) {
201
+ datasetsByYAxis[axisId] = [];
156
202
  }
157
-
158
- scales[axis.id] = {
159
- yScale,
160
- minValue,
161
- maxValue,
162
- valueRange,
163
- axisX,
164
- tickCount: axis.tickCount || 5,
165
- format: axis.format || ((v: number) => v.toFixed(1)),
166
- };
203
+ datasetsByYAxis[axisId].push({ ...dataset, index });
167
204
  });
168
205
 
169
- // X-axis scale
170
- const maxDataLength = Math.max(...datasets.map(d => d.data?.length || 0));
171
- const xScale = (index: number, dataLength?: number) => {
172
- const totalLength = dataLength || maxDataLength;
173
- if (totalLength <= 1) return plotAreaLeft + plotAreaWidth / 2;
174
- return plotAreaLeft + (index / (totalLength - 1)) * plotAreaWidth;
175
- };
176
-
177
- scales.x = {
178
- xScale,
179
- plotAreaLeft,
180
- plotAreaRight,
181
- plotAreaTop,
182
- plotAreaBottom,
183
- plotAreaWidth,
184
- plotAreaHeight,
185
- maxDataLength,
186
- };
187
-
188
- return scales;
189
- }, [datasets, yAxes, xAxis]);
190
-
191
- // Render multi-axis content
192
- const renderContent = useCallback(
193
- ({
194
- scales: _,
195
- colors,
196
- datasets: renderedDatasets,
197
- handlers,
198
- }: {
199
- scales: any;
200
- colors: string[];
201
- datasets: MultiAxisDataset[];
202
- handlers: {
203
- onDataPointClick?: (
204
- dataPoint: ChartDataPoint,
205
- datasetIndex: number,
206
- pointIndex: number
207
- ) => void;
206
+ // Calculate scales for each axis
207
+ const axisScales: Record<string, { min: number; max: number; scale: number }> = {};
208
+ Object.entries(datasetsByYAxis).forEach(([axisId, axisDatasets]) => {
209
+ const allValues = axisDatasets.flatMap(dataset => dataset.data.map((d: any) => d.value));
210
+ const min = Math.min(...allValues);
211
+ const max = Math.max(...allValues);
212
+ const range = max - min || 1; // Avoid division by zero
213
+ axisScales[axisId] = {
214
+ min,
215
+ max,
216
+ scale: chartHeight / range,
208
217
  };
209
- }) => {
210
- if (!renderedDatasets.length || !axisScales.x) return null;
218
+ });
211
219
 
212
- const {
213
- xScale,
214
- plotAreaLeft,
215
- plotAreaRight,
216
- plotAreaTop,
217
- plotAreaBottom,
218
- plotAreaWidth,
219
- plotAreaHeight,
220
- } = axisScales.x;
220
+ // Generate chart elements
221
+ const elements: React.ReactNode[] = [];
222
+
223
+ // Draw grid lines
224
+ if (effectiveShowGrid) {
225
+ for (let i = 0; i <= 5; i++) {
226
+ const y = padding + (i / 5) * chartHeight;
227
+ elements.push(
228
+ <line
229
+ key={`grid-${i}`}
230
+ x1={padding}
231
+ y1={y}
232
+ x2={padding + chartWidth}
233
+ y2={y}
234
+ className="c-chart__grid"
235
+ />
236
+ );
237
+ }
238
+ }
239
+
240
+ // Draw datasets
241
+ datasets.forEach((dataset, datasetIndex) => {
242
+ const axisId = dataset.yAxisId || yAxisConfigs[0]?.id || 'y-axis-1';
243
+ const axisScale = axisScales[axisId];
244
+ const color = dataset.color || colors[datasetIndex % colors.length];
245
+
246
+ // Generate points
247
+ const points = dataset.data.map((point: ChartDataPoint, pointIndex: number) => ({
248
+ x: padding + (pointIndex / (dataset.data.length - 1)) * chartWidth,
249
+ y: axisScale
250
+ ? padding + chartHeight - (point.value - axisScale.min) * axisScale.scale
251
+ : 0,
252
+ }));
253
+
254
+ // Generate line path
255
+ let linePath = '';
256
+ if (points.length > 0) {
257
+ linePath = `M ${points.map((p) => `${p.x},${p.y}`).join(' L ')}`;
258
+ }
221
259
 
222
- return (
223
- <g>
224
- {/* Plot area background */}
225
- <rect
226
- x={plotAreaLeft}
227
- y={plotAreaTop}
228
- width={plotAreaWidth}
229
- height={plotAreaHeight}
230
- className="c-chart__plot-area"
260
+ // Draw area under line
261
+ if (showArea && linePath) {
262
+ const areaPath = `${linePath} L ${padding + chartWidth},${padding + chartHeight} L ${padding},${padding + chartHeight} Z`;
263
+ elements.push(
264
+ <path
265
+ key={`area-${datasetIndex}`}
266
+ d={areaPath}
267
+ fill={color}
268
+ fillOpacity={areaOpacity}
231
269
  />
270
+ );
271
+ }
232
272
 
233
- {/* Y-axis grids and axes */}
234
- {yAxes.map((axis, axisIndex) => {
235
- const axisScale = axisScales[axis.id];
236
- if (!axisScale) return null;
237
-
238
- const ticks = Array.from({ length: axisScale.tickCount }, (_, i) => {
239
- const value =
240
- axisScale.minValue +
241
- (axisScale.maxValue - axisScale.minValue) * (i / (axisScale.tickCount - 1));
242
- return {
243
- value,
244
- y: axisScale.yScale(value),
245
- label: axisScale.format(value),
246
- };
247
- });
248
-
249
- return (
250
- <g key={`y-axis-${axis.id}`}>
251
- {/* Grid lines */}
252
- {axis.showGrid &&
253
- ticks.map((tick, i) => (
254
- <line
255
- key={`grid-${i}`}
256
- x1={plotAreaLeft}
257
- y1={tick.y}
258
- x2={plotAreaRight}
259
- y2={tick.y}
260
- className="c-chart__grid"
261
- />
262
- ))}
263
-
264
- {/* Axis line */}
265
- <line
266
- x1={axisScale.axisX}
267
- y1={plotAreaTop}
268
- x2={axisScale.axisX}
269
- y2={plotAreaBottom}
270
- stroke={axis.color || 'var(--atomix-secondary-text)'}
271
- className="c-chart__axis-line"
272
- />
273
-
274
- {/* Ticks and labels */}
275
- {ticks.map((tick, i) => (
276
- <g key={`tick-${i}`}>
277
- <line
278
- x1={axisScale.axisX - 5}
279
- y1={tick.y}
280
- x2={axisScale.axisX + 5}
281
- y2={tick.y}
282
- stroke={axis.color || 'var(--atomix-gray-6)'}
283
- strokeWidth="1"
284
- />
285
- <text
286
- x={axis.position === 'left' ? axisScale.axisX - 10 : axisScale.axisX + 10}
287
- y={tick.y}
288
- textAnchor={axis.position === 'left' ? 'end' : 'start'}
289
- dominantBaseline="middle"
290
- className="c-chart__tick-label"
291
- >
292
- {tick.label}
293
- </text>
294
- </g>
295
- ))}
273
+ // Draw line
274
+ elements.push(
275
+ <path
276
+ key={`line-${datasetIndex}`}
277
+ d={linePath}
278
+ stroke={color}
279
+ fill="none"
280
+ className="c-chart__data-line"
281
+ />
282
+ );
296
283
 
297
- {/* Axis label */}
298
- {axis.label && (
299
- <text
300
- x={axisScale.axisX}
301
- y={axis.position === 'left' ? 20 : plotAreaBottom + 40}
302
- textAnchor="middle"
303
- fontSize="14"
304
- fontWeight="bold"
305
- fill={axis.color || 'var(--atomix-gray-8)'}
306
- transform={
307
- axis.position === 'left' ? `rotate(-90, ${axisScale.axisX}, 20)` : ''
308
- }
309
- >
310
- {axis.label}
311
- </text>
312
- )}
313
- </g>
284
+ // Draw data points
285
+ if (showDataPoints) {
286
+ points.forEach((point, pointIndex: number) => {
287
+ const dataPoint = dataset.data[pointIndex];
288
+ if (dataPoint) {
289
+ elements.push(
290
+ <circle
291
+ key={`point-${datasetIndex}-${pointIndex}`}
292
+ cx={point.x}
293
+ cy={point.y}
294
+ r={pointRadius}
295
+ fill={color}
296
+ onClick={() => handlers.onDataPointClick?.(dataPoint, datasetIndex, pointIndex)}
297
+ />
314
298
  );
315
- })}
316
-
317
- {/* X-axis */}
318
- <g>
319
- <line
320
- x1={plotAreaLeft}
321
- y1={plotAreaBottom}
322
- x2={plotAreaRight}
323
- y2={plotAreaBottom}
324
- stroke="var(--atomix-gray-6)"
325
- strokeWidth="2"
326
- />
327
-
328
- {/* X-axis ticks and labels */}
329
- {renderedDatasets[0]?.data?.map((point: ChartDataPoint, i: number) => {
330
- const x = xScale(i, renderedDatasets[0]?.data?.length || 0);
331
- return (
332
- <g key={`x-tick-${i}`}>
333
- <line
334
- x1={x}
335
- y1={plotAreaBottom}
336
- x2={x}
337
- y2={plotAreaBottom + 5}
338
- stroke="var(--atomix-gray-6)"
339
- strokeWidth="1"
340
- />
341
- <text
342
- x={x}
343
- y={plotAreaBottom + 20}
344
- textAnchor="middle"
345
- fontSize="12"
346
- fill="var(--atomix-gray-7)"
347
- >
348
- {point.label}
349
- </text>
350
- </g>
351
- );
352
- })}
353
- </g>
354
-
355
- {/* Data visualization */}
356
- {renderedDatasets.map((dataset: MultiAxisDataset, datasetIndex: number) => {
357
- const axisScale =
358
- axisScales[(dataset as MultiAxisDataset).yAxisId || yAxes[0]?.id || ''];
359
- if (!axisScale) return null;
360
-
361
- const color = dataset.color || colors[datasetIndex];
362
- const chartType = (dataset as MultiAxisDataset).type || 'line';
363
-
364
- if (chartType === 'line' || chartType === 'area') {
365
- const points =
366
- dataset.data?.map((point: ChartDataPoint, i: number) => ({
367
- x: xScale(i, dataset.data?.length),
368
- y: axisScale.yScale(point.value),
369
- })) || [];
370
-
371
- const path =
372
- points.length > 1
373
- ? `M ${points.map((p: { x: number; y: number }) => `${p.x},${p.y}`).join(' L ')}`
374
- : '';
375
-
376
- return (
377
- <g key={`dataset-${datasetIndex}`}>
378
- {/* Area fill */}
379
- {chartType === 'area' && (
380
- <path
381
- d={`${path} L ${points[points.length - 1]?.x || 0},${plotAreaBottom} L ${points[0]?.x || 0},${plotAreaBottom} Z`}
382
- fill={color}
383
- opacity="0.3"
384
- />
385
- )}
386
-
387
- {/* Line */}
388
- <path
389
- d={path}
390
- stroke={color}
391
- fill="none"
392
- strokeWidth="2"
393
- strokeLinecap="round"
394
- strokeLinejoin="round"
395
- />
396
-
397
- {/* Data points */}
398
- {dataset.data?.map((point: ChartDataPoint, i: number) => {
399
- const x = xScale(i, dataset.data?.length);
400
- const y = axisScale.yScale(point.value);
401
-
402
- return (
403
- <circle
404
- key={`point-${i}`}
405
- cx={x}
406
- cy={y}
407
- r="4"
408
- fill={color}
409
- className="c-chart__data-point"
410
- onClick={() => handlers.onDataPointClick?.(point, datasetIndex, i)}
411
- />
412
- );
413
- })}
414
- </g>
415
- );
416
- }
417
-
418
- if (chartType === 'bar') {
419
- const barWidth = (plotAreaWidth / (dataset.data?.length || 1)) * 0.6;
420
-
421
- return (
422
- <g key={`bars-${datasetIndex}`}>
423
- {dataset.data?.map((point: ChartDataPoint, i: number) => {
424
- const x = xScale(i, dataset.data?.length || 0);
425
- const y = axisScale.yScale(point.value);
426
- const barHeight = plotAreaBottom - y;
427
-
428
- return (
429
- <rect
430
- key={`bar-${i}`}
431
- x={x - barWidth / 2}
432
- y={y}
433
- width={barWidth}
434
- height={barHeight}
435
- fill={color}
436
- rx="4"
437
- onClick={() => handlers.onDataPointClick?.(point, datasetIndex, i)}
438
- style={{ cursor: 'pointer' }}
439
- />
440
- );
441
- })}
442
- </g>
443
- );
444
- }
299
+ }
300
+ });
301
+ }
302
+ });
445
303
 
446
- return null;
447
- })}
304
+ // Draw axes
305
+ yAxisConfigs.forEach(axis => {
306
+ elements.push(
307
+ <line
308
+ key={`y-axis-${axis.id}`}
309
+ x1={padding}
310
+ y1={padding}
311
+ x2={padding}
312
+ y2={padding + chartHeight}
313
+ stroke={axis.color || 'var(--atomix-text-primary)'}
314
+ className="c-chart__axis-line"
315
+ />
316
+ );
317
+ });
448
318
 
449
- {/* Legend */}
450
- <g transform={`translate(${plotAreaLeft}, ${plotAreaBottom + 50})`}>
451
- {renderedDatasets.map((dataset: MultiAxisDataset, i: number) => {
452
- const color = dataset.color || colors[i];
453
- const x = i * 120;
319
+ xAxisConfigs.forEach(axis => {
320
+ elements.push(
321
+ <line
322
+ key={`x-axis-${axis.id}`}
323
+ x1={padding}
324
+ y1={padding + chartHeight}
325
+ x2={padding + chartWidth}
326
+ y2={padding + chartHeight}
327
+ stroke={axis.color || 'var(--atomix-text-primary)'}
328
+ className="c-chart__axis-line"
329
+ />
330
+ );
331
+ });
454
332
 
455
- return (
456
- <g key={`legend-${i}`} transform={`translate(${x}, 0)`}>
457
- <rect x="0" y="0" width="12" height="12" fill={color} rx="2" />
458
- <text x="18" y="9" fontSize="12" fill="var(--atomix-gray-8)">
459
- {dataset.label} ({(dataset as MultiAxisDataset).yAxisId})
460
- </text>
461
- </g>
462
- );
463
- })}
333
+ // Draw legend
334
+ if (showLegend) {
335
+ const legendY = legendPosition === 'top' ? 20 : scales.height - 30;
336
+ datasets.forEach((dataset, index) => {
337
+ const color = dataset.color || colors[index % colors.length];
338
+ const legendX = padding + (index * chartWidth) / datasets.length;
339
+
340
+ elements.push(
341
+ <g key={`legend-${index}`}>
342
+ <rect x={legendX} y={legendY} width="12" height="12" fill={color} className="c-chart__legend-item-color" />
343
+ <text x={legendX + 16} y={legendY + 10} className="c-chart__legend-item-text">
344
+ {dataset.label}
345
+ </text>
464
346
  </g>
465
- </g>
466
- );
467
- },
468
- [axisScales, yAxes]
469
- );
347
+ );
348
+ });
349
+ }
350
+
351
+ return <g>{elements}</g>;
352
+ };
470
353
 
471
354
  return (
472
- <Chart
355
+ <BaseChart
473
356
  ref={ref}
474
357
  type="line"
475
358
  datasets={datasets}
476
359
  config={config}
477
- title="Multi-Axis Chart"
478
- showToolbar
360
+ renderContent={renderContent}
361
+ onDataPointClick={onDataPointClick}
479
362
  {...props}
480
- >
481
- <ChartRenderer
482
- datasets={datasets}
483
- config={config}
484
- width={800}
485
- height={500}
486
- renderContent={renderContent}
487
- interactive
488
- enableAccessibility
489
- />
490
- </Chart>
363
+ />
491
364
  );
492
365
  }
493
366
  )
@@ -495,4 +368,3 @@ const MultiAxisChart = memo(
495
368
 
496
369
  MultiAxisChart.displayName = 'MultiAxisChart';
497
370
  export default MultiAxisChart;
498
- export type { AxisConfig, MultiAxisChartProps, MultiAxisDataset };