@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,4 +1,4 @@
1
- import { forwardRef, memo, useCallback, useState } from 'react';
1
+ import { forwardRef, memo, useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { CHART } from '../../lib/constants/components';
3
3
  import { Icon } from '../Icon';
4
4
  import type { PhosphorIconsType } from '../Icon/Icon';
@@ -50,6 +50,10 @@ export interface ChartToolbarProps {
50
50
  zoom?: boolean;
51
51
  pan?: boolean;
52
52
  reset?: boolean;
53
+ grid?: boolean;
54
+ legend?: boolean;
55
+ tooltips?: boolean;
56
+ animations?: boolean;
53
57
  };
54
58
 
55
59
  /**
@@ -145,13 +149,156 @@ const ChartToolbar = memo(
145
149
  ) => {
146
150
  const [showExportMenu, setShowExportMenu] = useState(false);
147
151
  const [showSettingsMenu, setShowSettingsMenu] = useState(false);
152
+ const exportMenuRef = useRef<HTMLDivElement>(null);
153
+ const settingsMenuRef = useRef<HTMLDivElement>(null);
154
+ const exportButtonRef = useRef<HTMLButtonElement>(null);
155
+ const settingsButtonRef = useRef<HTMLButtonElement>(null);
156
+
157
+ // Compute effective defaults based on provided groups
158
+ const effectiveDefaults =
159
+ groups && groups.length > 0
160
+ ? {
161
+ refresh: defaults.refresh ?? true,
162
+ export: defaults.export ?? true,
163
+ fullscreen: defaults.fullscreen ?? true,
164
+ settings: defaults.settings ?? true,
165
+ zoom: groups.some(group =>
166
+ group.actions.some(action => action.id === 'zoom-in' || action.id === 'zoom-out')
167
+ ),
168
+ pan: groups.some(group => group.actions.some(action => action.id === 'pan')),
169
+ reset: groups.some(group => group.actions.some(action => action.id === 'reset')),
170
+ grid: defaults.grid ?? true,
171
+ legend: defaults.legend ?? true,
172
+ tooltips: defaults.tooltips ?? true,
173
+ animations: defaults.animations ?? true,
174
+ }
175
+ : defaults;
176
+
177
+ // Close menus when clicking outside
178
+ useEffect(() => {
179
+ const handleClickOutside = (event: MouseEvent) => {
180
+ if (
181
+ exportMenuRef.current &&
182
+ !exportMenuRef.current.contains(event.target as Node) &&
183
+ exportButtonRef.current &&
184
+ !exportButtonRef.current.contains(event.target as Node)
185
+ ) {
186
+ setShowExportMenu(false);
187
+ }
188
+ if (
189
+ settingsMenuRef.current &&
190
+ !settingsMenuRef.current.contains(event.target as Node) &&
191
+ settingsButtonRef.current &&
192
+ !settingsButtonRef.current.contains(event.target as Node)
193
+ ) {
194
+ setShowSettingsMenu(false);
195
+ }
196
+ };
197
+
198
+ if (showExportMenu || showSettingsMenu) {
199
+ document.addEventListener('mousedown', handleClickOutside);
200
+ return () => {
201
+ document.removeEventListener('mousedown', handleClickOutside);
202
+ };
203
+ }
204
+ }, [showExportMenu, showSettingsMenu]);
205
+
206
+ // Handle keyboard shortcuts
207
+ useEffect(() => {
208
+ const handleKeyDown = (event: KeyboardEvent) => {
209
+ // Prevent shortcuts when typing in inputs
210
+ if (
211
+ event.target instanceof HTMLInputElement ||
212
+ event.target instanceof HTMLTextAreaElement ||
213
+ (event.target instanceof HTMLElement && event.target.isContentEditable)
214
+ ) {
215
+ return;
216
+ }
217
+
218
+ // Ctrl/Cmd + R: Refresh
219
+ if ((event.ctrlKey || event.metaKey) && event.key === 'r') {
220
+ if (effectiveDefaults.refresh && onRefresh) {
221
+ event.preventDefault();
222
+ onRefresh();
223
+ }
224
+ }
225
+
226
+ // Ctrl/Cmd + E: Export
227
+ if ((event.ctrlKey || event.metaKey) && event.key === 'e') {
228
+ if (effectiveDefaults.export && onExport) {
229
+ event.preventDefault();
230
+ setShowExportMenu(!showExportMenu);
231
+ }
232
+ }
233
+
234
+ // F11: Fullscreen
235
+ if (event.key === 'F11') {
236
+ if (effectiveDefaults.fullscreen && onFullscreen) {
237
+ event.preventDefault();
238
+ onFullscreen(!state.isFullscreen);
239
+ }
240
+ }
241
+
242
+ // Space: Pan toggle
243
+ if (event.key === ' ' && effectiveDefaults.pan && onPanToggle) {
244
+ event.preventDefault();
245
+ onPanToggle(!state.panEnabled);
246
+ }
247
+
248
+ // R: Reset
249
+ if (event.key === 'r' || event.key === 'R') {
250
+ if (!event.ctrlKey && !event.metaKey && effectiveDefaults.reset) {
251
+ event.preventDefault();
252
+ onZoomReset?.();
253
+ onReset?.();
254
+ }
255
+ }
256
+
257
+ // +/-: Zoom
258
+ if (event.key === '+' || event.key === '=') {
259
+ if (effectiveDefaults.zoom && onZoomIn) {
260
+ event.preventDefault();
261
+ onZoomIn();
262
+ }
263
+ }
264
+ if (event.key === '-' || event.key === '_') {
265
+ if (effectiveDefaults.zoom && onZoomOut) {
266
+ event.preventDefault();
267
+ onZoomOut();
268
+ }
269
+ }
270
+
271
+ // Escape: Close menus
272
+ if (event.key === 'Escape') {
273
+ setShowExportMenu(false);
274
+ setShowSettingsMenu(false);
275
+ }
276
+ };
277
+
278
+ document.addEventListener('keydown', handleKeyDown);
279
+ return () => {
280
+ document.removeEventListener('keydown', handleKeyDown);
281
+ };
282
+ }, [
283
+ effectiveDefaults,
284
+ onRefresh,
285
+ onExport,
286
+ onFullscreen,
287
+ onPanToggle,
288
+ onZoomReset,
289
+ onReset,
290
+ onZoomIn,
291
+ onZoomOut,
292
+ state,
293
+ showExportMenu,
294
+ ]);
148
295
 
149
296
  // Generate chart-specific default actions
150
297
  const getDefaultActions = useCallback((): ChartToolbarGroup[] => {
151
298
  const actions: ChartToolbarAction[] = [];
152
299
 
153
300
  // Refresh action
154
- if (defaults.refresh && onRefresh) {
301
+ if (effectiveDefaults.refresh && onRefresh) {
155
302
  actions.push({
156
303
  id: 'refresh',
157
304
  label: 'Refresh',
@@ -164,7 +311,7 @@ const ChartToolbar = memo(
164
311
  }
165
312
 
166
313
  // Export actions
167
- if (defaults.export && onExport) {
314
+ if (effectiveDefaults.export && onExport) {
168
315
  actions.push({
169
316
  id: 'export',
170
317
  label: 'Export',
@@ -185,20 +332,14 @@ const ChartToolbar = memo(
185
332
  separator: true,
186
333
  },
187
334
  ];
188
- }, [defaults, onRefresh, onExport, state, showExportMenu]);
335
+ }, [effectiveDefaults, onRefresh, onExport, state, showExportMenu]);
189
336
 
190
337
  // Generate chart-specific view actions
191
338
  const getViewActions = useCallback((): ChartToolbarGroup[] => {
192
339
  const actions: ChartToolbarAction[] = [];
193
340
 
194
- // Zoom actions (for interactive charts)
195
- if (
196
- defaults.zoom &&
197
- (chartType === 'interactive' ||
198
- chartType === 'line' ||
199
- chartType === 'area' ||
200
- chartType === 'bar')
201
- ) {
341
+ // Zoom actions (use configuration from props)
342
+ if (effectiveDefaults.zoom && (onZoomIn || onZoomOut)) {
202
343
  actions.push(
203
344
  {
204
345
  id: 'zoom-in',
@@ -219,11 +360,8 @@ const ChartToolbar = memo(
219
360
  );
220
361
  }
221
362
 
222
- // Pan toggle (for interactive charts)
223
- if (
224
- defaults.pan &&
225
- (chartType === 'interactive' || chartType === 'line' || chartType === 'area')
226
- ) {
363
+ // Pan toggle (use configuration from props)
364
+ if (effectiveDefaults.pan && onPanToggle) {
227
365
  actions.push({
228
366
  id: 'pan',
229
367
  label: 'Pan',
@@ -235,8 +373,8 @@ const ChartToolbar = memo(
235
373
  });
236
374
  }
237
375
 
238
- // Reset view
239
- if (defaults.reset && (onZoomReset || onReset)) {
376
+ // Reset view (use configuration from props)
377
+ if (effectiveDefaults.reset && (onZoomReset || onReset)) {
240
378
  actions.push({
241
379
  id: 'reset',
242
380
  label: 'Reset View',
@@ -250,8 +388,8 @@ const ChartToolbar = memo(
250
388
  });
251
389
  }
252
390
 
253
- // Fullscreen
254
- if (defaults.fullscreen && onFullscreen) {
391
+ // Fullscreen (for all chart types that support it)
392
+ if (effectiveDefaults.fullscreen && onFullscreen) {
255
393
  actions.push({
256
394
  id: 'fullscreen',
257
395
  label: state.isFullscreen ? 'Exit Fullscreen' : 'Fullscreen',
@@ -274,8 +412,7 @@ const ChartToolbar = memo(
274
412
  ]
275
413
  : [];
276
414
  }, [
277
- defaults,
278
- chartType,
415
+ effectiveDefaults,
279
416
  onZoomIn,
280
417
  onZoomOut,
281
418
  onPanToggle,
@@ -285,17 +422,89 @@ const ChartToolbar = memo(
285
422
  state,
286
423
  ]);
287
424
 
425
+ // Generate display/visual actions
426
+ const getDisplayActions = useCallback((): ChartToolbarGroup[] => {
427
+ const actions: ChartToolbarAction[] = [];
428
+
429
+ // Grid toggle
430
+ if (effectiveDefaults.grid && onGridToggle) {
431
+ actions.push({
432
+ id: 'grid',
433
+ label: 'Grid',
434
+ icon: 'GridFour',
435
+ onClick: () => onGridToggle(!state.showGrid),
436
+ active: state.showGrid,
437
+ tooltip: 'Toggle grid lines',
438
+ });
439
+ }
440
+
441
+ // Legend toggle
442
+ if (effectiveDefaults.legend && onLegendToggle) {
443
+ actions.push({
444
+ id: 'legend',
445
+ label: 'Legend',
446
+ icon: 'List',
447
+ onClick: () => onLegendToggle(!state.showLegend),
448
+ active: state.showLegend,
449
+ tooltip: 'Toggle legend',
450
+ });
451
+ }
452
+
453
+ // Tooltips toggle
454
+ if (effectiveDefaults.tooltips && onTooltipsToggle) {
455
+ actions.push({
456
+ id: 'tooltips',
457
+ label: 'Tooltips',
458
+ icon: 'CursorText',
459
+ onClick: () => onTooltipsToggle(!state.showTooltips),
460
+ active: state.showTooltips,
461
+ tooltip: 'Toggle tooltips',
462
+ });
463
+ }
464
+
465
+ // Animations toggle
466
+ if (effectiveDefaults.animations && onAnimationsToggle) {
467
+ actions.push({
468
+ id: 'animations',
469
+ label: 'Animations',
470
+ icon: 'Sparkle',
471
+ onClick: () => onAnimationsToggle(!state.animationsEnabled),
472
+ active: state.animationsEnabled,
473
+ tooltip: 'Toggle animations',
474
+ });
475
+ }
476
+
477
+ return actions.length > 0
478
+ ? [
479
+ {
480
+ id: 'display-actions',
481
+ label: 'Display',
482
+ actions,
483
+ separator: true,
484
+ },
485
+ ]
486
+ : [];
487
+ }, [
488
+ effectiveDefaults,
489
+ onGridToggle,
490
+ onLegendToggle,
491
+ onTooltipsToggle,
492
+ onAnimationsToggle,
493
+ state,
494
+ ]);
495
+
288
496
  // Generate chart-specific tool actions
289
497
  const getToolActions = useCallback((): ChartToolbarGroup[] => {
290
498
  const actions: ChartToolbarAction[] = [];
291
499
 
292
500
  // Settings
293
- if (defaults.settings && onSettings) {
501
+ if (effectiveDefaults.settings && onSettings) {
294
502
  actions.push({
295
503
  id: 'settings',
296
504
  label: 'Settings',
297
505
  icon: 'Gear',
298
506
  onClick: () => setShowSettingsMenu(!showSettingsMenu),
507
+ active: showSettingsMenu,
299
508
  tooltip: 'Chart settings',
300
509
  });
301
510
  }
@@ -309,40 +518,80 @@ const ChartToolbar = memo(
309
518
  },
310
519
  ]
311
520
  : [];
312
- }, [defaults, onSettings, showSettingsMenu]);
521
+ }, [effectiveDefaults, onSettings, showSettingsMenu]);
313
522
 
314
- // Always use provided groups if available, otherwise generate defaults
523
+ // Use provided groups if available, otherwise generate defaults
315
524
  const allGroups =
316
525
  groups && groups.length > 0
317
526
  ? groups
318
- : [
319
- ...(enableDefaults ? getDefaultActions() : []),
320
- ...(enableDefaults ? getViewActions() : []),
321
- ...(enableDefaults ? getToolActions() : []),
322
- ];
323
-
324
- console.log('ChartToolbar: All groups', allGroups);
325
- console.log('ChartToolbar: Groups provided', groups);
326
- console.log('ChartToolbar: Enable defaults', enableDefaults);
527
+ : enableDefaults
528
+ ? [
529
+ ...getDefaultActions(),
530
+ ...getViewActions(),
531
+ ...getDisplayActions(),
532
+ ...getToolActions(),
533
+ ]
534
+ : [];
327
535
 
328
536
  // Render action button
329
537
  const renderAction = (action: ChartToolbarAction) => {
330
- console.log('ChartToolbar: Rendering action', action.id, action);
538
+ // Use the action's onClick handler if available
539
+ const handleClick = () => {
540
+ if (action.onClick) {
541
+ action.onClick();
542
+ } else {
543
+ // Fallback for special cases that need custom handling
544
+ if (action.id === 'export' && onExport) {
545
+ setShowExportMenu(!showExportMenu);
546
+ } else if (action.id === 'settings' && onSettings) {
547
+ setShowSettingsMenu(!showSettingsMenu);
548
+ } else {
549
+ // Try to find the appropriate individual handler
550
+ switch (action.id) {
551
+ case 'zoom-in':
552
+ onZoomIn?.();
553
+ break;
554
+ case 'zoom-out':
555
+ onZoomOut?.();
556
+ break;
557
+ case 'pan':
558
+ onPanToggle?.(!state.panEnabled);
559
+ break;
560
+ case 'reset':
561
+ onZoomReset?.();
562
+ onReset?.();
563
+ break;
564
+ case 'fullscreen':
565
+ onFullscreen?.(!state.isFullscreen);
566
+ break;
567
+ case 'refresh':
568
+ onRefresh?.();
569
+ break;
570
+ default:
571
+ console.warn(`No handler found for action: ${String(action.id).replace(/[\r\n\t]/g, '')}`);
572
+ }
573
+ }
574
+ }
575
+ };
576
+
577
+ const buttonRef =
578
+ action.id === 'export' ? exportButtonRef : action.id === 'settings' ? settingsButtonRef : null;
579
+
331
580
  return (
332
581
  <button
333
582
  key={action.id}
334
- className={`${CHART.ACTION_CLASS} ${action.variant ? `${CHART.ACTION_CLASS}--${action.variant}` : ''} ${action.active ? 'is-active' : ''} u-d-inline-flex u-align-items-center u-gap-1`}
335
- onClick={() => {
336
- console.log('ChartToolbar: Action clicked', action.id);
337
- action.onClick();
338
- }}
583
+ ref={buttonRef}
584
+ className={`${CHART.ACTION_CLASS} ${action.variant ? `${CHART.ACTION_CLASS}--${action.variant}` : ''} ${action.active ? 'is-active' : ''}`}
585
+ onClick={handleClick}
339
586
  disabled={action.disabled}
340
587
  title={action.tooltip}
341
588
  type="button"
342
589
  aria-label={action.label}
590
+ aria-pressed={action.active ? 'true' : 'false'}
591
+ aria-expanded={action.id === 'export' ? showExportMenu : action.id === 'settings' ? showSettingsMenu : undefined}
343
592
  >
344
593
  <Icon name={action.icon} size="sm" />
345
- {size === 'lg' && <span className="u-text-xs">{action.label}</span>}
594
+ {size === 'lg' && <span className={`${CHART.ACTION_CLASS}-label`}>{action.label}</span>}
346
595
  </button>
347
596
  );
348
597
  };
@@ -353,19 +602,24 @@ const ChartToolbar = memo(
353
602
 
354
603
  return (
355
604
  <div
356
- className={`${CHART.EXPORT_DROPDOWN_CLASS} u-position-absolute u-bg-white u-border u-border-radius u-shadow u-p-2 u-z-10`}
605
+ ref={exportMenuRef}
606
+ className={`${CHART.EXPORT_DROPDOWN_CLASS}`}
607
+ role="menu"
608
+ aria-label="Export formats"
357
609
  >
358
- <div className="u-mb-2 u-text-xs u-text-muted u-fw-medium">Export Formats</div>
610
+ <div className={`${CHART.EXPORT_DROPDOWN_CLASS}-title`}>Export Formats</div>
359
611
  {exportFormats.map(format => (
360
612
  <button
361
613
  key={format}
362
- className={`${CHART.EXPORT_OPTION_CLASS} u-d-block u-w-full u-text-start u-p-1 u-border-0 u-bg-transparent u-text-decoration-none u-border-radius-sm`}
614
+ className={`${CHART.EXPORT_OPTION_CLASS}`}
363
615
  onClick={() => {
364
616
  onExport(format);
365
617
  setShowExportMenu(false);
366
618
  }}
367
619
  disabled={state.isExporting}
368
620
  type="button"
621
+ role="menuitem"
622
+ aria-label={`Export as ${format.toUpperCase()}`}
369
623
  >
370
624
  {format.toUpperCase()}
371
625
  </button>
@@ -380,22 +634,79 @@ const ChartToolbar = memo(
380
634
 
381
635
  return (
382
636
  <div
383
- className="u-position-absolute u-bg-white u-border u-border-radius u-shadow u-p-3 u-z-10"
384
- style={{ minWidth: '200px' }}
637
+ ref={settingsMenuRef}
638
+ className={`${CHART.SETTINGS_MENU_CLASS}`}
639
+ role="menu"
640
+ aria-label="Chart settings"
385
641
  >
386
- <div className="u-mb-2 u-text-xs u-text-muted u-fw-medium">Chart Settings</div>
387
- <div className="u-d-flex u-flex-column u-gap-2">
388
- {state.zoomLevel && (
389
- <div className="u-d-flex u-justify-between u-align-items-center">
390
- <span className="u-text-sm">Zoom Level</span>
391
- <span className="u-text-sm u-text-muted">
642
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-title`}>Chart Settings</div>
643
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-content`}>
644
+ {/* Display toggles */}
645
+ {effectiveDefaults.grid && onGridToggle && (
646
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-item`}>
647
+ <label className={`${CHART.SETTINGS_MENU_CLASS}-toggle`}>
648
+ <input
649
+ type="checkbox"
650
+ checked={state.showGrid ?? false}
651
+ onChange={e => onGridToggle(e.target.checked)}
652
+ aria-label="Toggle grid lines"
653
+ />
654
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-label`}>Show Grid</span>
655
+ </label>
656
+ </div>
657
+ )}
658
+ {effectiveDefaults.legend && onLegendToggle && (
659
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-item`}>
660
+ <label className={`${CHART.SETTINGS_MENU_CLASS}-toggle`}>
661
+ <input
662
+ type="checkbox"
663
+ checked={state.showLegend ?? false}
664
+ onChange={e => onLegendToggle(e.target.checked)}
665
+ aria-label="Toggle legend"
666
+ />
667
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-label`}>Show Legend</span>
668
+ </label>
669
+ </div>
670
+ )}
671
+ {effectiveDefaults.tooltips && onTooltipsToggle && (
672
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-item`}>
673
+ <label className={`${CHART.SETTINGS_MENU_CLASS}-toggle`}>
674
+ <input
675
+ type="checkbox"
676
+ checked={state.showTooltips ?? false}
677
+ onChange={e => onTooltipsToggle(e.target.checked)}
678
+ aria-label="Toggle tooltips"
679
+ />
680
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-label`}>Show Tooltips</span>
681
+ </label>
682
+ </div>
683
+ )}
684
+ {effectiveDefaults.animations && onAnimationsToggle && (
685
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-item`}>
686
+ <label className={`${CHART.SETTINGS_MENU_CLASS}-toggle`}>
687
+ <input
688
+ type="checkbox"
689
+ checked={state.animationsEnabled ?? false}
690
+ onChange={e => onAnimationsToggle(e.target.checked)}
691
+ aria-label="Toggle animations"
692
+ />
693
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-label`}>Enable Animations</span>
694
+ </label>
695
+ </div>
696
+ )}
697
+
698
+ {/* Info items */}
699
+ {state.zoomLevel !== undefined && (
700
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-item ${CHART.SETTINGS_MENU_CLASS}-item--info`}>
701
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-label`}>Zoom Level</span>
702
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-value`}>
392
703
  {Math.round((state.zoomLevel || 1) * 100)}%
393
704
  </span>
394
705
  </div>
395
706
  )}
396
- <div className="u-d-flex u-justify-between u-align-items-center">
397
- <span className="u-text-sm">Chart Type</span>
398
- <span className="u-text-sm u-text-muted u-text-capitalize">{chartType}</span>
707
+ <div className={`${CHART.SETTINGS_MENU_CLASS}-item ${CHART.SETTINGS_MENU_CLASS}-item--info`}>
708
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-label`}>Chart Type</span>
709
+ <span className={`${CHART.SETTINGS_MENU_CLASS}-value`}>{chartType}</span>
399
710
  </div>
400
711
  </div>
401
712
  </div>
@@ -403,21 +714,21 @@ const ChartToolbar = memo(
403
714
  };
404
715
 
405
716
  const toolbarClass =
406
- `${CHART.TOOLBAR_CLASS} ${CHART.TOOLBAR_CLASS}--${size} ${CHART.TOOLBAR_CLASS}--${position} u-d-flex u-align-items-center u-gap-2 ${className}`.trim();
717
+ `${CHART.TOOLBAR_CLASS} ${CHART.TOOLBAR_CLASS}--${size} ${CHART.TOOLBAR_CLASS}--${position} ${className}`.trim();
407
718
 
408
719
  return (
409
720
  <div ref={ref} className={toolbarClass} {...props}>
410
721
  {allGroups.map((group, groupIndex) => (
411
- <div key={group.id} className="u-d-flex u-align-items-center u-gap-1">
722
+ <div key={group.id} className={`${CHART.TOOLBAR_CLASS}-group`}>
412
723
  {group.separator && groupIndex > 0 && (
413
- <div className="u-border-start u-h-4 u-mx-1 u-opacity-25" />
724
+ <div className={`${CHART.TOOLBAR_CLASS}-separator`} />
414
725
  )}
415
726
 
416
727
  {group.label && size === 'lg' && (
417
- <span className="u-text-xs u-text-muted u-me-1">{group.label}</span>
728
+ <span className={`${CHART.TOOLBAR_CLASS}-group-label`}>{group.label}</span>
418
729
  )}
419
730
 
420
- <div className="u-d-flex u-align-items-center u-gap-1 u-position-relative">
731
+ <div className={`${CHART.TOOLBAR_CLASS}-actions`}>
421
732
  {group.actions.map(renderAction)}
422
733
 
423
734
  {/* Render contextual menus */}
@@ -1,4 +1,5 @@
1
1
  import { memo, useEffect, useRef, useState } from 'react';
2
+ import { createPortal } from 'react-dom';
2
3
  import { ChartDataPoint } from './types';
3
4
 
4
5
  interface TooltipPosition {
@@ -31,35 +32,46 @@ const ChartTooltip = memo<ChartTooltipProps>(
31
32
  height: window.innerHeight,
32
33
  };
33
34
 
34
- let newX = position.x + 8;
35
- let newY = position.y - rect.height;
35
+ // Start with the provided position
36
+ let newX = position.x;
37
+ let newY = position.y;
36
38
 
37
- // Adjust horizontal position
39
+ // Adjust for tooltip size to keep it in view
38
40
  if (newX + rect.width > viewport.width - 16) {
39
- newX = position.x - rect.width - 8;
41
+ newX = position.x - rect.width - 12;
42
+ } else {
43
+ newX = position.x + 12;
40
44
  }
41
45
 
42
- // Adjust vertical position
43
- if (newY < 8) {
44
- newY = position.y + 8;
46
+ if (newY + rect.height > viewport.height - 16) {
47
+ newY = position.y - rect.height - 12;
48
+ } else {
49
+ newY = position.y - rect.height / 2;
45
50
  }
46
51
 
47
52
  // Ensure tooltip doesn't go off-screen
48
- newX = Math.max(8, Math.min(newX, viewport.width - rect.width - 8));
49
- newY = Math.max(8, Math.min(newY, viewport.height - rect.height - 8));
53
+ newX = Math.max(16, Math.min(newX, viewport.width - rect.width - 16));
54
+ newY = Math.max(16, Math.min(newY, viewport.height - rect.height - 16));
50
55
 
51
56
  setAdjustedPosition({ x: newX, y: newY });
52
57
  }, [position, visible]);
53
58
 
54
- if (!visible) return null;
59
+ if (!visible || !dataPoint) return null;
55
60
 
56
- return (
61
+ return createPortal(
57
62
  <div
58
63
  ref={tooltipRef}
59
64
  className="c-chart__tooltip"
60
65
  style={{
61
- left: adjustedPosition.x,
62
- top: adjustedPosition.y,
66
+ left: `${adjustedPosition.x}px`,
67
+ top: `${adjustedPosition.y}px`,
68
+ opacity: visible ? 1 : 0,
69
+ visibility: visible ? 'visible' : 'hidden',
70
+ transition: 'opacity 0.2s ease, transform 0.2s ease',
71
+ transform: 'translateZ(0)',
72
+ position: 'fixed',
73
+ zIndex: 1000,
74
+ pointerEvents: 'none',
63
75
  }}
64
76
  >
65
77
  {customRenderer ? (
@@ -70,10 +82,12 @@ const ChartTooltip = memo<ChartTooltipProps>(
70
82
  <div className="c-chart__tooltip-content">
71
83
  {datasetLabel && (
72
84
  <div className="c-chart__tooltip-dataset">
73
- <div
74
- className="c-chart__tooltip-color-indicator"
75
- style={{ backgroundColor: datasetColor }}
76
- />
85
+ {datasetColor && (
86
+ <div
87
+ className="c-chart__tooltip-color-indicator"
88
+ style={{ backgroundColor: datasetColor }}
89
+ />
90
+ )}
77
91
  <span className="c-chart__tooltip-dataset-label">{datasetLabel}:</span>
78
92
  <span className="c-chart__tooltip-value">{dataPoint.value}</span>
79
93
  </div>
@@ -91,7 +105,8 @@ const ChartTooltip = memo<ChartTooltipProps>(
91
105
  </div>
92
106
  </>
93
107
  )}
94
- </div>
108
+ </div>,
109
+ document.body
95
110
  );
96
111
  }
97
112
  );