@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, useMemo, useState } from 'react';
1
+ import { forwardRef, memo } from 'react';
2
2
  import { CHART } from '../../lib/constants/components';
3
- import Chart from './Chart';
3
+ import BaseChart from './BaseChart';
4
4
  import ChartTooltip from './ChartTooltip';
5
- import { ChartProps } from './types';
5
+ import { ChartProps, ChartDataPoint, ChartRenderContentParams } from './types';
6
6
 
7
7
  interface CandlestickDataPoint {
8
8
  /**
@@ -41,7 +41,7 @@ interface CandlestickDataPoint {
41
41
  metadata?: Record<string, any>;
42
42
  }
43
43
 
44
- interface CandlestickChartProps extends Omit<ChartProps, 'type' | 'datasets'> {
44
+ interface CandlestickChartProps extends Omit<ChartProps, 'type' | 'datasets' | 'data'> {
45
45
  /**
46
46
  * Candlestick chart data
47
47
  */
@@ -52,709 +52,369 @@ interface CandlestickChartProps extends Omit<ChartProps, 'type' | 'datasets'> {
52
52
  */
53
53
  candlestickOptions?: {
54
54
  /**
55
- * Color for bullish (rising) candles
55
+ * Whether to show volume bars
56
56
  */
57
- bullishColor?: string;
58
-
57
+ showVolume?: boolean;
59
58
  /**
60
- * Color for bearish (falling) candles
59
+ * Volume bar height ratio (0-1)
61
60
  */
62
- bearishColor?: string;
63
-
61
+ volumeHeightRatio?: number;
64
62
  /**
65
- * Candle width as percentage of available space
63
+ * Up color (when close > open)
66
64
  */
67
- candleWidth?: number;
68
-
65
+ upColor?: string;
69
66
  /**
70
- * Whether to show volume bars
67
+ * Down color (when close < open)
71
68
  */
72
- showVolume?: boolean;
73
-
69
+ downColor?: string;
74
70
  /**
75
- * Volume bar height ratio
71
+ * Wick color
76
72
  */
77
- volumeHeightRatio?: number;
78
-
73
+ wickColor?: string;
74
+ /**
75
+ * Border color
76
+ */
77
+ borderColor?: string;
79
78
  /**
80
79
  * Whether to show moving averages
81
80
  */
82
81
  showMovingAverages?: boolean;
83
-
84
82
  /**
85
83
  * Moving average periods
86
84
  */
87
85
  movingAveragePeriods?: number[];
88
-
89
86
  /**
90
87
  * Moving average colors
91
88
  */
92
89
  movingAverageColors?: string[];
93
-
94
90
  /**
95
- * Whether to show trend lines
91
+ * Date format
96
92
  */
97
- showTrendLines?: boolean;
98
-
93
+ dateFormat?: 'short' | 'medium' | 'long' | 'numeric' | 'custom';
99
94
  /**
100
- * Whether to enable crosshair
95
+ * Custom date formatter function
101
96
  */
102
- enableCrosshair?: boolean;
103
-
97
+ dateFormatter?: (date: string | Date) => string;
104
98
  /**
105
- * Whether to show OHLC tooltip
99
+ * Whether to show grid lines
106
100
  */
107
- showOHLCTooltip?: boolean;
108
-
101
+ showGrid?: boolean;
109
102
  /**
110
- * Date format for x-axis labels
103
+ * Grid color
111
104
  */
112
- dateFormat?: 'short' | 'medium' | 'long' | 'numeric';
113
-
105
+ gridColor?: string;
114
106
  /**
115
- * Price precision (decimal places)
107
+ * Whether to show tooltips
116
108
  */
117
- pricePrecision?: number;
118
-
119
- /**
120
- * Whether to enable zoom and pan
121
- */
122
- enableZoomPan?: boolean;
109
+ showTooltips?: boolean;
123
110
  };
124
111
  }
125
112
 
126
113
  const CandlestickChart = memo(
127
114
  forwardRef<HTMLDivElement, CandlestickChartProps>(
128
115
  (
129
- {
130
- candlestickData = [],
131
- config = {},
132
- candlestickOptions = {
133
- bullishColor: '#4DFF9F',
134
- bearishColor: '#FF6B6B',
135
- candleWidth: 0.8,
136
- showVolume: false,
137
- volumeHeightRatio: 0.3,
138
- showMovingAverages: false,
139
- movingAveragePeriods: [20, 50],
140
- movingAverageColors: ['#FFD93D', '#6BCF7F'],
141
- showTrendLines: false,
142
- enableCrosshair: true,
143
- showOHLCTooltip: true,
144
- dateFormat: 'short',
145
- pricePrecision: 2,
146
- enableZoomPan: false,
147
- },
148
- onDataPointClick,
149
- ...props
150
- },
116
+ { candlestickData = [], config = {}, candlestickOptions = {}, onDataPointClick, ...props },
151
117
  ref
152
118
  ) => {
153
- const [hoveredCandle, setHoveredCandle] = useState<{
154
- index: number;
155
- x: number;
156
- y: number;
157
- data: CandlestickDataPoint;
158
- } | null>(null);
159
-
160
- const [crosshair, setCrosshair] = useState<{ x: number; y: number } | null>(null);
161
- const [zoom, setZoom] = useState({ scale: 1, translateX: 0, translateY: 0 });
119
+ const {
120
+ showVolume = true,
121
+ volumeHeightRatio = 0.2,
122
+ upColor = 'var(--atomix-success-bg-subtle)',
123
+ downColor = 'var(--atomix-error-bg-subtle)',
124
+ wickColor = 'var(--atomix-brand-border-subtle)',
125
+ borderColor = 'var(--atomix-primary-border-subtle)',
126
+ showMovingAverages = false,
127
+ movingAveragePeriods = [7, 21],
128
+ movingAverageColors = ['var(--atomix-warning-bg-subtle)', 'var(--atomix-warning-border-subtle)'],
129
+ dateFormat = 'short',
130
+ dateFormatter,
131
+ showGrid = true,
132
+ gridColor = 'var(--atomix-brand-text-emphasis)',
133
+ showTooltips = true,
134
+ } = candlestickOptions;
162
135
 
163
136
  // Calculate moving averages
164
- const calculateMovingAverage = useCallback((data: CandlestickDataPoint[], period: number) => {
137
+ const calculateMovingAverage = (data: CandlestickDataPoint[], period: number): number[] => {
165
138
  const result: number[] = [];
166
-
167
139
  for (let i = 0; i < data.length; i++) {
168
140
  if (i < period - 1) {
169
141
  result.push(NaN);
170
- } else {
171
- const sum = data
172
- .slice(i - period + 1, i + 1)
173
- .reduce((acc, candle) => acc + candle.close, 0);
174
- result.push(sum / period);
142
+ continue;
175
143
  }
176
- }
177
144
 
145
+ const sum = data.slice(i - period + 1, i + 1).reduce((acc, item) => acc + item.close, 0);
146
+ result.push(sum / period);
147
+ }
178
148
  return result;
179
- }, []);
149
+ };
180
150
 
181
151
  // Format date for display
182
- const formatDate = useCallback(
183
- (date: string | Date) => {
184
- const dateObj = typeof date === 'string' ? new Date(date) : date;
185
-
186
- switch (candlestickOptions.dateFormat) {
187
- case 'short':
188
- return dateObj.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
189
- case 'medium':
190
- return dateObj.toLocaleDateString('en-US', {
191
- month: 'short',
192
- day: 'numeric',
193
- year: '2-digit',
194
- });
195
- case 'long':
196
- return dateObj.toLocaleDateString('en-US', {
197
- month: 'long',
198
- day: 'numeric',
199
- year: 'numeric',
200
- });
201
- case 'numeric':
202
- return dateObj.toLocaleDateString('en-US');
203
- default:
204
- return dateObj.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
205
- }
206
- },
207
- [candlestickOptions.dateFormat]
208
- );
152
+ const formatDate = (date: string | Date) => {
153
+ if (dateFormatter) {
154
+ return dateFormatter(date);
155
+ }
209
156
 
210
- // Chart content calculation
211
- const chartContent = useMemo(() => {
157
+ const dateObj = typeof date === 'string' ? new Date(date) : date;
158
+
159
+ switch (dateFormat) {
160
+ case 'short':
161
+ return dateObj.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
162
+ case 'medium':
163
+ return dateObj.toLocaleDateString('en-US', {
164
+ month: 'short',
165
+ day: 'numeric',
166
+ year: '2-digit',
167
+ });
168
+ case 'long':
169
+ return dateObj.toLocaleDateString('en-US', {
170
+ month: 'long',
171
+ day: 'numeric',
172
+ year: 'numeric',
173
+ });
174
+ case 'numeric':
175
+ return dateObj.toLocaleDateString('en-US');
176
+ default:
177
+ return dateObj.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
178
+ }
179
+ };
180
+
181
+ const renderContent = ({
182
+ scales,
183
+ colors,
184
+ datasets: renderedDatasets,
185
+ handlers,
186
+ hoveredPoint,
187
+ toolbarState,
188
+ config: renderConfig,
189
+ }: ChartRenderContentParams) => {
212
190
  if (!candlestickData.length) return null;
213
191
 
214
- const width = 800;
215
- const height = candlestickOptions.showVolume ? 500 : 400;
216
- const padding = { top: 40, right: 70, bottom: 60, left: 70 };
217
- const chartHeight = candlestickOptions.showVolume
218
- ? height * (1 - candlestickOptions.volumeHeightRatio!)
219
- : height - padding.top - padding.bottom;
220
- const volumeHeight = candlestickOptions.showVolume
221
- ? height * candlestickOptions.volumeHeightRatio!
222
- : 0;
223
- const innerWidth = width - padding.left - padding.right;
224
-
225
- // Calculate price scales
226
- const allPrices = candlestickData.flatMap(candle => [
227
- candle.open,
228
- candle.high,
229
- candle.low,
230
- candle.close,
231
- ]);
232
- const minPrice = config.yAxis?.min ?? Math.min(...allPrices);
233
- const maxPrice = config.yAxis?.max ?? Math.max(...allPrices);
234
-
235
- // Handle case where all prices are the same to avoid division by zero
236
- const priceRange = maxPrice !== minPrice ? maxPrice - minPrice : 1;
237
-
238
- // Calculate volume scale if needed
239
- const candlesWithVolume = candlestickData.filter(d => d.volume);
240
- const maxVolume =
241
- candlestickOptions.showVolume && candlesWithVolume.length > 0
242
- ? Math.max(...candlesWithVolume.map(d => d.volume!))
243
- : 0;
244
- // Ensure maxVolume is at least 1 to avoid division by zero
245
- const safeMaxVolume = maxVolume > 0 ? maxVolume : 1;
246
-
247
- const xScale = (i: number) => {
248
- // Handle case where there's only one data point to avoid division by zero
249
- const denominator = candlestickData.length > 1 ? candlestickData.length - 1 : 1;
250
- const baseX = padding.left + (i / denominator) * innerWidth;
251
- return baseX * zoom.scale + zoom.translateX;
252
- };
253
-
254
- const priceScale = (price: number) => {
255
- const baseY = padding.top + chartHeight - ((price - minPrice) / priceRange) * chartHeight;
256
- return baseY * zoom.scale + zoom.translateY;
257
- };
258
-
259
- const volumeScale = (volume: number) => {
260
- // Use safeMaxVolume to avoid division by zero
261
- return (
262
- chartHeight +
263
- padding.top +
264
- 10 +
265
- ((safeMaxVolume - volume) / safeMaxVolume) * (volumeHeight - 20)
266
- );
267
- };
268
-
269
- // Ensure we have at least one data point to avoid division by zero
270
- const safeDataLength = Math.max(candlestickData.length, 1);
271
- const candleSpacing = innerWidth / safeDataLength;
272
- const candleWidth = candleSpacing * (candlestickOptions.candleWidth || 0.8);
273
-
274
- // Generate chart elements
275
- const chartElements = [];
276
-
277
- // Volume bars (if enabled)
278
- if (candlestickOptions.showVolume && candlesWithVolume.length > 0) {
279
- candlestickData.forEach((candle, i) => {
280
- if (!candle.volume) return;
281
-
282
- const x = xScale(i);
283
- const isBullish = candle.close >= candle.open;
284
- const volumeColor = isBullish
285
- ? candlestickOptions.bullishColor
286
- : candlestickOptions.bearishColor;
287
-
288
- // Ensure all values are valid numbers before creating the rect element
289
- const xPos = isNaN(x) ? 0 : x;
290
- const candleWidthQuarter = isNaN(candleWidth / 4) ? 0 : candleWidth / 4;
291
- const volScale = volumeScale(candle.volume);
292
- const volHeight = chartHeight + padding.top + 10 + volumeHeight - 20 - volScale;
293
-
294
- chartElements.push(
295
- <rect
296
- key={`volume-${i}`}
297
- x={xPos - candleWidthQuarter}
298
- y={isNaN(volScale) ? 0 : volScale}
299
- width={isNaN(candleWidth / 2) ? 0 : candleWidth / 2}
300
- height={isNaN(volHeight) ? 0 : volHeight}
301
- fill={volumeColor}
302
- opacity={0.3}
192
+ // Use toolbar state if available, fallback to config for backward compatibility
193
+ const showTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? candlestickOptions.showTooltips ?? true;
194
+
195
+ const padding = 40;
196
+ const chartWidth = scales.width - padding * 2;
197
+ const chartHeight = scales.height - padding * 2;
198
+ const volumeHeight = showVolume ? chartHeight * volumeHeightRatio : 0;
199
+ const priceHeight = chartHeight - volumeHeight;
200
+
201
+ // Calculate price scale
202
+ const allHighs = candlestickData.map(d => d.high);
203
+ const allLows = candlestickData.map(d => d.low);
204
+ const priceMin = Math.min(...allLows);
205
+ const priceMax = Math.max(...allHighs);
206
+ const priceRange = priceMax - priceMin || 1;
207
+
208
+ // Calculate volume scale
209
+ const volumes = candlestickData.map(d => d.volume || 0);
210
+ const volumeMax = Math.max(...volumes);
211
+ const volumeRange = volumeMax || 1;
212
+
213
+ // Draw grid
214
+ const gridLines: React.ReactNode[] = [];
215
+ if (showGrid) {
216
+ // Horizontal grid lines for price
217
+ for (let i = 0; i <= 5; i++) {
218
+ const y = padding + (i / 5) * priceHeight;
219
+ gridLines.push(
220
+ <line
221
+ key={`price-grid-${i}`}
222
+ x1={padding}
223
+ y1={y}
224
+ x2={padding + chartWidth}
225
+ y2={y}
226
+ stroke={gridColor}
227
+ strokeWidth="0.5"
228
+ strokeDasharray="4 2"
303
229
  />
304
230
  );
305
- });
231
+ }
306
232
 
307
- // Volume section separator
308
- chartElements.push(
309
- <line
310
- key="volume-separator"
311
- x1={padding.left}
312
- y1={chartHeight + padding.top + 5}
313
- x2={width - padding.right}
314
- y2={chartHeight + padding.top + 5}
315
- stroke="#e5e7eb"
316
- strokeWidth={1}
317
- />
318
- );
233
+ // Vertical grid lines for time
234
+ const step = Math.max(1, Math.floor(candlestickData.length / 10));
235
+ for (let i = 0; i < candlestickData.length; i += step) {
236
+ const x = padding + (i / (candlestickData.length - 1)) * chartWidth;
237
+ gridLines.push(
238
+ <line
239
+ key={`time-grid-${i}`}
240
+ x1={x}
241
+ y1={padding}
242
+ x2={x}
243
+ y2={padding + priceHeight}
244
+ stroke={gridColor}
245
+ strokeWidth="0.5"
246
+ strokeDasharray="4 2"
247
+ />
248
+ );
249
+ }
319
250
  }
320
251
 
321
- // Candlesticks
322
- candlestickData.forEach((candle, i) => {
323
- const x = xScale(i);
324
- const openY = priceScale(candle.open);
325
- const highY = priceScale(candle.high);
326
- const lowY = priceScale(candle.low);
327
- const closeY = priceScale(candle.close);
328
-
329
- const isBullish = candle.close >= candle.open;
330
- const candleColor = isBullish
331
- ? candlestickOptions.bullishColor
332
- : candlestickOptions.bearishColor;
333
-
334
- const bodyTop = Math.min(openY, closeY);
335
- const bodyBottom = Math.max(openY, closeY);
336
- const bodyHeight = Math.abs(closeY - openY);
337
-
338
- const isHovered = hoveredCandle?.index === i;
339
-
340
- // Ensure all values are valid numbers before creating elements
341
- const xPos = isNaN(x) ? 0 : x;
342
- const candleWidthHalf = isNaN(candleWidth / 2) ? 0 : candleWidth / 2;
343
- const safeBodyTop = isNaN(bodyTop) ? 0 : bodyTop;
344
- const safeBodyHeight = isNaN(bodyHeight) || bodyHeight === 0 ? 1 : Math.abs(bodyHeight);
345
-
346
- chartElements.push(
347
- <g key={`candle-${i}`}>
348
- {/* High-Low line (wick) */}
252
+ // Draw candles
253
+ const candles = candlestickData.map((candle, index) => {
254
+ const isUp = candle.close >= candle.open;
255
+ const color = isUp ? upColor : downColor;
256
+
257
+ // Calculate coordinates
258
+ const x = padding + (index / (candlestickData.length - 1)) * chartWidth;
259
+ const highY = padding + ((priceMax - candle.high) / priceRange) * priceHeight;
260
+ const lowY = padding + ((priceMax - candle.low) / priceRange) * priceHeight;
261
+ const openY = padding + ((priceMax - candle.open) / priceRange) * priceHeight;
262
+ const closeY = padding + ((priceMax - candle.close) / priceRange) * priceHeight;
263
+
264
+ const candleTop = Math.min(openY, closeY);
265
+ const candleHeight = Math.abs(openY - closeY);
266
+ const candleWidth = Math.max(1, (chartWidth / candlestickData.length) * 0.8);
267
+
268
+ return (
269
+ <g key={`candle-${index}`}>
270
+ {/* Wick */}
349
271
  <line
350
- x1={isNaN(xPos) ? 0 : xPos}
351
- y1={isNaN(highY) ? 0 : highY}
352
- x2={isNaN(xPos) ? 0 : xPos}
353
- y2={isNaN(lowY) ? 0 : lowY}
354
- stroke={candleColor}
355
- className={`c-chart__wick ${isHovered ? 'c-chart__wick--hovered' : ''}`}
272
+ x1={x}
273
+ y1={highY}
274
+ x2={x}
275
+ y2={lowY}
276
+ stroke={wickColor}
277
+ strokeWidth="1"
278
+ className="c-chart__candlestick-wick"
356
279
  />
357
-
358
280
  {/* Candle body */}
359
281
  <rect
360
- x={xPos - candleWidthHalf}
361
- y={safeBodyTop}
362
- width={isNaN(candleWidth) ? 0 : candleWidth}
363
- height={safeBodyHeight}
364
- fill={isBullish ? candleColor : candleColor}
365
- stroke={candleColor}
366
- className={`c-chart__candlestick ${isBullish ? 'c-chart__candlestick--bullish' : 'c-chart__candlestick--bearish'}`}
282
+ x={x - candleWidth / 2}
283
+ y={candleTop}
284
+ width={candleWidth}
285
+ height={candleHeight || 1}
286
+ fill={color}
287
+ stroke={borderColor}
288
+ strokeWidth="1"
289
+ className="c-chart__candlestick-candle"
367
290
  onMouseEnter={e => {
368
- const rect = e.currentTarget.ownerSVGElement?.getBoundingClientRect();
369
- const clientX = rect ? rect.left + xPos : e.clientX;
370
- const clientY = rect ? rect.top + safeBodyTop : e.clientY;
371
- setHoveredCandle({ index: i, x: clientX, y: clientY, data: candle });
291
+ const rect = e.currentTarget.getBoundingClientRect();
292
+ handlers.onPointHover(
293
+ 0,
294
+ index,
295
+ x,
296
+ highY,
297
+ rect.left + rect.width / 2,
298
+ rect.top + rect.height / 2
299
+ );
372
300
  }}
373
- onMouseLeave={() => setHoveredCandle(null)}
374
- onClick={() => onDataPointClick?.(candle as any, 0, i)}
301
+ onMouseLeave={handlers.onPointLeave}
302
+ onClick={() => handlers.onDataPointClick?.(candle as unknown as ChartDataPoint, 0, index)}
375
303
  />
376
-
377
- {/* Hover highlight */}
378
- {isHovered && (
379
- <rect
380
- x={xPos - candleWidthHalf - 2}
381
- y={safeBodyTop - 2}
382
- width={isNaN(candleWidth + 4) ? 0 : candleWidth + 4}
383
- height={isNaN(safeBodyHeight + 4) ? 5 : Math.max(safeBodyHeight + 4, 5)}
384
- fill="none"
385
- stroke={candleColor}
386
- className="c-chart__candlestick-highlight"
387
- />
388
- )}
389
304
  </g>
390
305
  );
391
306
  });
392
307
 
393
- // Moving averages
394
- if (candlestickOptions.showMovingAverages && candlestickOptions.movingAveragePeriods) {
395
- candlestickOptions.movingAveragePeriods.forEach((period, periodIndex) => {
396
- const movingAverage = calculateMovingAverage(candlestickData, period);
397
- const color = candlestickOptions.movingAverageColors?.[periodIndex] || '#FFD93D';
308
+ // Draw volume bars
309
+ const volumeBars: React.ReactNode[] = [];
310
+ if (showVolume) {
311
+ const volumeY = padding + priceHeight + 20;
398
312
 
399
- const pathData = movingAverage
400
- .map((value, i) => {
401
- if (isNaN(value)) return '';
402
- const x = xScale(i);
403
- const y = priceScale(value);
404
- if (i === 0) return `M ${isNaN(x) ? 0 : x},${isNaN(y) ? 0 : y}`;
405
- const prevValue = movingAverage[i - 1];
406
- return prevValue !== undefined && isNaN(prevValue)
407
- ? `M ${isNaN(x) ? 0 : x},${isNaN(y) ? 0 : y}`
408
- : `L ${isNaN(x) ? 0 : x},${isNaN(y) ? 0 : y}`;
409
- })
410
- .join(' ');
411
-
412
- chartElements.push(
413
- <path
414
- key={`ma-${period}`}
415
- d={pathData}
416
- stroke={color}
417
- fill="none"
418
- className="c-chart__moving-average"
313
+ candlestickData.forEach((candle, index) => {
314
+ if (!candle.volume) return;
315
+
316
+ const isUp = candle.close >= candle.open;
317
+ const color = isUp ? upColor : downColor;
318
+
319
+ const x = padding + (index / (candlestickData.length - 1)) * chartWidth;
320
+ const barHeight = (candle.volume / volumeRange) * (volumeHeight - 20);
321
+ const barWidth = Math.max(1, (chartWidth / candlestickData.length) * 0.6);
322
+
323
+ volumeBars.push(
324
+ <rect
325
+ key={`volume-${index}`}
326
+ x={x - barWidth / 2}
327
+ y={volumeY + volumeHeight - barHeight}
328
+ width={barWidth}
329
+ height={barHeight}
330
+ fill={color}
331
+ fillOpacity="0.7"
332
+ className="c-chart__candlestick-volume"
419
333
  />
420
334
  );
421
335
  });
422
336
  }
423
337
 
424
- // Crosshair
425
- if (crosshair && candlestickOptions.enableCrosshair) {
426
- chartElements.push(
427
- <g key="crosshair" className="c-chart__crosshair">
428
- <line
429
- x1={isNaN(crosshair.x) ? 0 : crosshair.x}
430
- y1={padding.top}
431
- x2={isNaN(crosshair.x) ? 0 : crosshair.x}
432
- y2={chartHeight + padding.top}
433
- className="c-chart__crosshair-line c-chart__crosshair-line--vertical"
434
- />
435
- <line
436
- x1={padding.left}
437
- y1={isNaN(crosshair.y) ? 0 : crosshair.y}
438
- x2={width - padding.right}
439
- y2={isNaN(crosshair.y) ? 0 : crosshair.y}
440
- className="c-chart__crosshair-line c-chart__crosshair-line--horizontal"
441
- />
442
- </g>
443
- );
444
- }
338
+ // Draw moving averages
339
+ const movingAverages: React.ReactNode[] = [];
340
+ if (showMovingAverages) {
341
+ movingAveragePeriods.forEach((period, periodIndex) => {
342
+ const movingAverage = calculateMovingAverage(candlestickData, period);
343
+ const color = movingAverageColors?.[periodIndex] || 'var(--atomix-warning)';
445
344
 
446
- // Grid
447
- const grid = (
448
- <g className={CHART.GRID_CLASS}>
449
- {/* Horizontal price grid lines */}
450
- {config.yAxis?.showGrid &&
451
- Array.from({ length: 6 }).map((_, i) => {
452
- const price = minPrice + (priceRange * i) / 5;
453
- const yPos = priceScale(price);
454
- return (
455
- <line
456
- key={`price-grid-${i}`}
457
- x1={padding.left}
458
- y1={isNaN(yPos) ? 0 : yPos}
459
- x2={width - padding.right}
460
- y2={isNaN(yPos) ? 0 : yPos}
461
- stroke="#e5e7eb"
462
- strokeWidth={1}
463
- strokeDasharray="2,2"
464
- opacity={0.2}
465
- />
466
- );
467
- })}
468
-
469
- {/* Vertical time grid lines */}
470
- {config.xAxis?.showGrid &&
471
- candlestickData.map((_, i) => {
472
- if (i % Math.ceil(candlestickData.length / 10) !== 0) return null;
473
- const xPos = xScale(i);
474
- return (
475
- <line
476
- key={`time-grid-${i}`}
477
- x1={isNaN(xPos) ? 0 : xPos}
478
- y1={padding.top}
479
- x2={isNaN(xPos) ? 0 : xPos}
480
- y2={chartHeight + padding.top}
481
- stroke="#e5e7eb"
482
- strokeWidth={1}
483
- strokeDasharray="2,2"
484
- opacity={0.2}
485
- />
486
- );
487
- })}
488
- </g>
489
- );
345
+ const points = movingAverage
346
+ .map((value, i) => {
347
+ if (isNaN(value)) return null;
348
+ const x = padding + (i / (candlestickData.length - 1)) * chartWidth;
349
+ const y = padding + ((priceMax - value) / priceRange) * priceHeight;
350
+ return { x, y };
351
+ })
352
+ .filter(Boolean) as { x: number; y: number }[];
353
+
354
+ if (points.length > 1) {
355
+ const path = `M ${points.map(p => `${p.x},${p.y}`).join(' L ')}`;
356
+ movingAverages.push(
357
+ <path
358
+ key={`ma-${period}`}
359
+ d={path}
360
+ stroke={color}
361
+ strokeWidth="1"
362
+ fill="none"
363
+ strokeDasharray="5,5"
364
+ />
365
+ );
366
+ }
367
+ });
368
+ }
490
369
 
491
- // Axes
492
- const axes = (
370
+ return (
493
371
  <>
494
- {/* Price axis (Y-axis) */}
495
- <g className={`${CHART.AXIS_CLASS} ${CHART.AXIS_CLASS}--y`}>
496
- <line
497
- x1={padding.left}
498
- y1={padding.top}
499
- x2={padding.left}
500
- y2={chartHeight + padding.top}
501
- stroke="#e5e7eb"
502
- strokeWidth={1}
503
- />
504
- {Array.from({ length: 6 }).map((_, i) => {
505
- const price = minPrice + (priceRange * i) / 5;
506
- const yPos = priceScale(price);
507
- return (
508
- <g key={`price-axis-${i}`}>
509
- <line
510
- x1={padding.left - 5}
511
- y1={isNaN(yPos) ? 0 : yPos}
512
- x2={padding.left}
513
- y2={isNaN(yPos) ? 0 : yPos}
514
- stroke="#e5e7eb"
515
- strokeWidth={1}
516
- />
517
- <text
518
- x={padding.left - 10}
519
- y={isNaN(yPos) ? 0 : yPos}
520
- textAnchor="end"
521
- dominantBaseline="middle"
522
- fontSize="12"
523
- fill="#374151"
524
- >
525
- ${price.toFixed(candlestickOptions.pricePrecision)}
526
- </text>
527
- </g>
528
- );
529
- })}
530
- </g>
531
-
532
- {/* Time axis (X-axis) */}
533
- <g className={`${CHART.AXIS_CLASS} ${CHART.AXIS_CLASS}--x`}>
534
- <line
535
- x1={padding.left}
536
- y1={chartHeight + padding.top}
537
- x2={width - padding.right}
538
- y2={chartHeight + padding.top}
539
- stroke="#e5e7eb"
540
- strokeWidth={1}
541
- />
542
- {candlestickData.map((candle, i) => {
543
- if (i % Math.ceil(candlestickData.length / 8) !== 0) return null;
544
- const xPos = xScale(i);
545
- return (
546
- <g key={`time-axis-${i}`}>
547
- <line
548
- x1={isNaN(xPos) ? 0 : xPos}
549
- y1={chartHeight + padding.top}
550
- x2={isNaN(xPos) ? 0 : xPos}
551
- y2={chartHeight + padding.top + 5}
552
- stroke="#e5e7eb"
553
- strokeWidth={1}
554
- />
555
- <text
556
- x={isNaN(xPos) ? 0 : xPos}
557
- y={chartHeight + padding.top + 20}
558
- textAnchor="middle"
559
- fontSize="12"
560
- fill="#374151"
561
- >
562
- {formatDate(candle.date)}
563
- </text>
564
- </g>
565
- );
566
- })}
567
- </g>
568
-
569
- {/* Volume axis (if enabled) */}
570
- {candlestickOptions.showVolume && candlesWithVolume.length > 0 && (
571
- <g className={`${CHART.AXIS_CLASS} ${CHART.AXIS_CLASS}--volume`}>
572
- <line
573
- x1={width - padding.right}
574
- y1={chartHeight + padding.top + 10}
575
- x2={width - padding.right}
576
- y2={height - padding.bottom}
577
- stroke="#e5e7eb"
578
- strokeWidth={1}
372
+ {gridLines}
373
+ {candles}
374
+ {volumeBars}
375
+ {movingAverages}
376
+ {showTooltips &&
377
+ hoveredPoint &&
378
+ candlestickData[hoveredPoint.pointIndex] && (
379
+ <ChartTooltip
380
+ dataPoint={candlestickData[hoveredPoint.pointIndex] as unknown as ChartDataPoint}
381
+ datasetLabel="Candlestick"
382
+ position={{
383
+ x: hoveredPoint.clientX,
384
+ y: hoveredPoint.clientY,
385
+ }}
386
+ visible={true}
579
387
  />
580
- {Array.from({ length: 3 }).map((_, i) => {
581
- const volume = (safeMaxVolume * (i + 1)) / 3;
582
- const yPos = volumeScale(volume);
583
- return (
584
- <g key={`volume-axis-${i}`}>
585
- <line
586
- x1={width - padding.right}
587
- y1={isNaN(yPos) ? 0 : yPos}
588
- x2={width - padding.right + 5}
589
- y2={isNaN(yPos) ? 0 : yPos}
590
- stroke="#e5e7eb"
591
- strokeWidth={1}
592
- />
593
- <text
594
- x={width - padding.right + 10}
595
- y={isNaN(yPos) ? 0 : yPos}
596
- textAnchor="start"
597
- dominantBaseline="middle"
598
- fontSize="10"
599
- fill="#374151"
600
- >
601
- {volume > 1000000
602
- ? `${(volume / 1000000).toFixed(1)}M`
603
- : volume > 1000
604
- ? `${(volume / 1000).toFixed(0)}K`
605
- : `${Math.round(volume)}`}
606
- </text>
607
- </g>
608
- );
609
- })}
610
- </g>
611
- )}
388
+ )}
612
389
  </>
613
390
  );
614
-
615
- return (
616
- <svg
617
- width="100%"
618
- height="100%"
619
- viewBox={`0 0 ${width} ${height}`}
620
- preserveAspectRatio="xMidYMid meet"
621
- onMouseMove={e => {
622
- if (!candlestickOptions.enableCrosshair) return;
623
- const rect = e.currentTarget.getBoundingClientRect();
624
- const x = e.clientX - rect.left;
625
- const y = e.clientY - rect.top;
626
- setCrosshair({ x, y });
627
- }}
628
- onMouseLeave={() => setCrosshair(null)}
629
- style={{ cursor: 'crosshair' }}
630
- >
631
- {grid}
632
- {axes}
633
- {chartElements}
634
- </svg>
635
- );
636
- }, [
637
- candlestickData,
638
- config,
639
- candlestickOptions,
640
- hoveredCandle,
641
- crosshair,
642
- zoom,
643
- calculateMovingAverage,
644
- formatDate,
645
- onDataPointClick,
646
- ]);
647
-
648
- // OHLC Tooltip custom renderer
649
- const renderOHLCTooltip = useCallback(
650
- (dataPoint: any) => {
651
- if (!hoveredCandle) return null;
652
-
653
- const { data } = hoveredCandle;
654
- const isBullish = data.close >= data.open;
655
- const change = data.close - data.open;
656
- const changePercent = (change / data.open) * 100;
657
-
658
- return (
659
- <div>
660
- <div style={{ fontWeight: 'bold', marginBottom: '0.5rem' }}>
661
- {formatDate(data.date)}
662
- </div>
663
- <div
664
- style={{
665
- display: 'grid',
666
- gridTemplateColumns: '1fr 1fr',
667
- gap: '0.25rem',
668
- fontSize: '0.75rem',
669
- }}
670
- >
671
- <div>
672
- Open: <strong>${data.open.toFixed(candlestickOptions.pricePrecision)}</strong>
673
- </div>
674
- <div>
675
- High: <strong>${data.high.toFixed(candlestickOptions.pricePrecision)}</strong>
676
- </div>
677
- <div>
678
- Low: <strong>${data.low.toFixed(candlestickOptions.pricePrecision)}</strong>
679
- </div>
680
- <div>
681
- Close: <strong>${data.close.toFixed(candlestickOptions.pricePrecision)}</strong>
682
- </div>
683
- </div>
684
- <div
685
- style={{
686
- marginTop: '0.5rem',
687
- paddingTop: '0.5rem',
688
- borderTop: '1px solid var(--atomix-gray-3)',
689
- color: isBullish
690
- ? candlestickOptions.bullishColor
691
- : candlestickOptions.bearishColor,
692
- fontWeight: 'bold',
693
- }}
694
- >
695
- {isBullish ? '+' : ''}
696
- {change.toFixed(candlestickOptions.pricePrecision)} ({changePercent.toFixed(2)}%)
697
- </div>
698
- {data.volume && (
699
- <div style={{ marginTop: '0.25rem', fontSize: '0.75rem' }}>
700
- Volume: {data.volume.toLocaleString()}
701
- </div>
702
- )}
703
- </div>
704
- );
705
- },
706
- [candlestickOptions, hoveredCandle, formatDate]
707
- );
391
+ };
708
392
 
709
393
  return (
710
- <Chart ref={ref} type="candlestick" datasets={[]} config={config} {...props}>
711
- {chartContent}
712
- {candlestickOptions.showOHLCTooltip && hoveredCandle && (
713
- <ChartTooltip
714
- dataPoint={{
715
- label: formatDate(hoveredCandle.data.date),
716
- value: hoveredCandle.data.close,
394
+ <BaseChart
395
+ ref={ref}
396
+ type="candlestick"
397
+ datasets={[
398
+ {
399
+ label: 'Candlestick Data',
400
+ data: candlestickData.map(candle => ({
401
+ label: candle.date.toString(),
402
+ value: candle.close,
717
403
  metadata: {
718
- open: hoveredCandle.data.open,
719
- high: hoveredCandle.data.high,
720
- low: hoveredCandle.data.low,
721
- close: hoveredCandle.data.close,
722
- volume: hoveredCandle.data.volume,
404
+ open: candle.open,
405
+ high: candle.high,
406
+ low: candle.low,
407
+ close: candle.close,
408
+ volume: candle.volume,
723
409
  },
724
- }}
725
- datasetLabel="OHLC"
726
- position={{ x: hoveredCandle.x, y: hoveredCandle.y }}
727
- visible={true}
728
- customRenderer={renderOHLCTooltip}
729
- />
730
- )}
731
- {candlestickOptions.showMovingAverages && candlestickOptions.movingAveragePeriods && (
732
- <div
733
- className={CHART.LEGEND_CLASS}
734
- style={{
735
- display: 'flex',
736
- gap: '0.75rem',
737
- marginTop: '0.5rem',
738
- fontSize: '0.875rem',
739
- }}
740
- >
741
- {candlestickOptions.movingAveragePeriods.map((period, i) => (
742
- <div key={period} style={{ display: 'flex', alignItems: 'center' }}>
743
- <div
744
- className={CHART.LEGEND_COLOR_CLASS}
745
- style={{
746
- width: '12px',
747
- height: '2px',
748
- backgroundColor: candlestickOptions.movingAverageColors?.[i] || '#FFD93D',
749
- marginRight: '0.25rem',
750
- }}
751
- />
752
- <span className={CHART.LEGEND_LABEL_CLASS}>MA{period}</span>
753
- </div>
754
- ))}
755
- </div>
756
- )}
757
- </Chart>
410
+ })),
411
+ },
412
+ ]}
413
+ config={config}
414
+ renderContent={renderContent}
415
+ onDataPointClick={onDataPointClick}
416
+ {...props}
417
+ />
758
418
  );
759
419
  }
760
420
  )