@shohojdhara/atomix 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/atomix.css +1266 -1412
- package/dist/atomix.min.css +3 -3
- package/dist/index.d.ts +1232 -876
- package/dist/index.esm.js +16212 -26364
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +15652 -22298
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/themes/applemix.css +15008 -0
- package/dist/themes/applemix.min.css +72 -0
- package/dist/themes/boomdevs.css +1266 -1413
- package/dist/themes/boomdevs.min.css +3 -3
- package/dist/themes/esrar.css +1267 -1413
- package/dist/themes/esrar.min.css +3 -3
- package/dist/themes/flashtrade.css +15159 -0
- package/dist/themes/flashtrade.min.css +86 -0
- package/dist/themes/mashroom.css +1264 -1410
- package/dist/themes/mashroom.min.css +5 -5
- package/dist/themes/shaj-default.css +1266 -1412
- package/dist/themes/shaj-default.min.css +3 -3
- package/package.json +6 -17
- package/src/components/Accordion/Accordion.stories.tsx +4 -26
- package/src/components/Accordion/Accordion.tsx +21 -12
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +106 -72
- package/src/components/AtomixGlass/AtomixGlass.tsx +487 -1215
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +400 -0
- package/src/components/AtomixGlass/GlassFilter.tsx +156 -0
- package/src/components/AtomixGlass/README.md +124 -2
- package/src/components/AtomixGlass/atomixGLass.old.tsx +1266 -0
- package/src/components/AtomixGlass/glass-utils.ts +263 -0
- package/src/components/AtomixGlass/shader-utils.ts +404 -236
- package/src/components/AtomixGlass/{AtomixGlass.stories.tsx → stories/AtomixGlass.stories.tsx} +55 -35
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +57 -89
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +149 -149
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +95 -32
- package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +0 -2
- package/src/components/AtomixGlass/stories/shared-components.tsx +9 -18
- package/src/components/AtomixGlass/utils.ts +3 -3
- package/src/components/Avatar/Avatar.tsx +3 -0
- package/src/components/Avatar/AvatarGroup.tsx +2 -1
- package/src/components/Badge/Badge.stories.tsx +74 -54
- package/src/components/Badge/Badge.tsx +8 -12
- package/src/components/Breadcrumb/Breadcrumb.tsx +23 -4
- package/src/components/Button/Button.tsx +3 -5
- package/src/components/Callout/Callout.stories.tsx +86 -35
- package/src/components/Callout/Callout.tsx +4 -0
- package/src/components/Card/Card.stories.tsx +89 -85
- package/src/components/Card/Card.tsx +15 -4
- package/src/components/Card/ElevationCard.tsx +2 -0
- package/src/components/Chart/AnimatedChart.tsx +179 -156
- package/src/components/Chart/AreaChart.tsx +123 -12
- package/src/components/Chart/BarChart.tsx +91 -100
- package/src/components/Chart/BaseChart.tsx +80 -0
- package/src/components/Chart/BubbleChart.tsx +114 -290
- package/src/components/Chart/CandlestickChart.tsx +282 -622
- package/src/components/Chart/Chart.stories.tsx +576 -179
- package/src/components/Chart/Chart.tsx +374 -75
- package/src/components/Chart/ChartRenderer.tsx +371 -220
- package/src/components/Chart/ChartToolbar.tsx +372 -61
- package/src/components/Chart/ChartTooltip.tsx +33 -18
- package/src/components/Chart/DonutChart.tsx +172 -254
- package/src/components/Chart/FunnelChart.tsx +169 -240
- package/src/components/Chart/GaugeChart.tsx +224 -392
- package/src/components/Chart/HeatmapChart.tsx +302 -440
- package/src/components/Chart/LineChart.tsx +148 -103
- package/src/components/Chart/MultiAxisChart.tsx +267 -395
- package/src/components/Chart/PieChart.tsx +114 -64
- package/src/components/Chart/RadarChart.tsx +202 -218
- package/src/components/Chart/ScatterChart.tsx +111 -97
- package/src/components/Chart/TreemapChart.tsx +147 -222
- package/src/components/Chart/WaterfallChart.tsx +253 -291
- package/src/components/Chart/index.ts +11 -9
- package/src/components/Chart/types.ts +85 -9
- package/src/components/Chart/utils.ts +66 -0
- package/src/components/ColorModeToggle/ColorModeToggle.tsx +6 -3
- package/src/components/Countdown/Countdown.tsx +4 -0
- package/src/components/DataTable/DataTable.tsx +2 -1
- package/src/components/DatePicker/DatePicker.stories.tsx +0 -11
- package/src/components/DatePicker/DatePicker.tsx +3 -9
- package/src/components/DatePicker/types.ts +5 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +32 -25
- package/src/components/Dropdown/Dropdown.tsx +26 -28
- package/src/components/EdgePanel/EdgePanel.stories.tsx +13 -15
- package/src/components/EdgePanel/EdgePanel.tsx +20 -5
- package/src/components/Footer/Footer.stories.tsx +187 -60
- package/src/components/Footer/Footer.test.tsx +134 -0
- package/src/components/Footer/Footer.tsx +133 -34
- package/src/components/Footer/FooterLink.tsx +1 -1
- package/src/components/Footer/FooterSection.tsx +53 -36
- package/src/components/Footer/FooterSocialLink.tsx +32 -29
- package/src/components/Footer/README.md +82 -3
- package/src/components/Footer/index.ts +1 -1
- package/src/components/Form/Checkbox.stories.tsx +13 -5
- package/src/components/Form/Checkbox.tsx +3 -6
- package/src/components/Form/Form.stories.tsx +10 -3
- package/src/components/Form/Form.tsx +2 -0
- package/src/components/Form/FormGroup.tsx +2 -1
- package/src/components/Form/Input.stories.tsx +12 -11
- package/src/components/Form/Input.tsx +97 -95
- package/src/components/Form/Radio.stories.tsx +22 -7
- package/src/components/Form/Radio.tsx +3 -6
- package/src/components/Form/Select.stories.tsx +21 -6
- package/src/components/Form/Select.tsx +3 -5
- package/src/components/Form/Textarea.stories.tsx +13 -11
- package/src/components/Form/Textarea.tsx +88 -86
- package/src/components/Hero/Hero.stories.tsx +2 -3
- package/src/components/Hero/Hero.tsx +5 -6
- package/src/components/Icon/Icon.tsx +12 -1
- package/src/components/List/List.tsx +2 -1
- package/src/components/List/ListGroup.tsx +2 -1
- package/src/components/Messages/Messages.tsx +3 -2
- package/src/components/Modal/Modal.stories.tsx +48 -34
- package/src/components/Modal/Modal.tsx +19 -23
- package/src/components/Navigation/Menu/MegaMenu.tsx +2 -2
- package/src/components/Navigation/Menu/Menu.tsx +2 -2
- package/src/components/Navigation/Nav/Nav.tsx +6 -1
- package/src/components/Navigation/Nav/NavDropdown.tsx +10 -1
- package/src/components/Navigation/Navbar/Navbar.tsx +4 -1
- package/src/components/Navigation/SideMenu/SideMenu.tsx +3 -2
- package/src/components/Pagination/Pagination.stories.tsx +13 -6
- package/src/components/Pagination/Pagination.tsx +7 -6
- package/src/components/PhotoViewer/PhotoViewer.tsx +2 -1
- package/src/components/Popover/Popover.stories.tsx +32 -24
- package/src/components/Popover/Popover.tsx +4 -1
- package/src/components/ProductReview/ProductReview.tsx +8 -2
- package/src/components/Progress/Progress.tsx +2 -1
- package/src/components/Rating/Rating.stories.tsx +11 -6
- package/src/components/Rating/Rating.tsx +3 -5
- package/src/components/River/River.tsx +5 -5
- package/src/components/SectionIntro/SectionIntro.tsx +8 -2
- package/src/components/Slider/Slider.stories.tsx +4 -4
- package/src/components/Slider/Slider.tsx +4 -3
- package/src/components/Spinner/Spinner.tsx +2 -1
- package/src/components/Steps/Steps.stories.tsx +5 -4
- package/src/components/Steps/Steps.tsx +8 -5
- package/src/components/Tab/Tab.stories.tsx +4 -3
- package/src/components/Tab/Tab.tsx +8 -6
- package/src/components/Testimonial/Testimonial.tsx +8 -2
- package/src/components/Todo/Todo.tsx +2 -1
- package/src/components/Toggle/Toggle.stories.tsx +5 -4
- package/src/components/Toggle/Toggle.tsx +8 -5
- package/src/components/Tooltip/Tooltip.stories.tsx +40 -30
- package/src/components/Tooltip/Tooltip.tsx +9 -2
- package/src/components/Upload/Upload.stories.tsx +252 -0
- package/src/components/Upload/Upload.tsx +92 -53
- package/src/components/VideoPlayer/VideoPlayer.tsx +3 -1
- package/src/components/index.ts +0 -4
- package/src/layouts/Grid/Grid.stories.tsx +10 -23
- package/src/layouts/Grid/Grid.tsx +20 -1
- package/src/layouts/Grid/GridCol.tsx +76 -48
- package/src/lib/composables/useAtomixGlass.ts +861 -44
- package/src/lib/composables/useBarChart.ts +13 -6
- package/src/lib/composables/useChart.ts +17 -13
- package/src/lib/composables/useChartExport.ts +19 -78
- package/src/lib/composables/useChartToolbar.ts +0 -1
- package/src/lib/composables/useEdgePanel.ts +111 -103
- package/src/lib/composables/useFooter.ts +3 -3
- package/src/lib/composables/useGlassContainer.ts +16 -7
- package/src/lib/composables/useLineChart.ts +8 -1
- package/src/lib/composables/useRiver.ts +5 -0
- package/src/lib/composables/useSlider.ts +62 -24
- package/src/lib/composables/useVideoPlayer.ts +60 -63
- package/src/lib/constants/components.ts +146 -32
- package/src/lib/types/components.ts +258 -10
- package/src/lib/utils/displacement-generator.ts +55 -49
- package/src/lib/utils/icons.ts +1 -1
- package/src/lib/utils/index.ts +16 -10
- package/src/styles/01-settings/_settings.accordion.scss +19 -19
- package/src/styles/01-settings/_settings.animations.scss +5 -5
- package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
- package/src/styles/01-settings/_settings.avatar.scss +17 -17
- package/src/styles/01-settings/_settings.background.scss +1 -4
- package/src/styles/01-settings/_settings.badge.scss +1 -1
- package/src/styles/01-settings/_settings.breadcrumb.scss +1 -1
- package/src/styles/01-settings/_settings.card.scss +1 -1
- package/src/styles/01-settings/_settings.chart.scss +65 -2
- package/src/styles/01-settings/_settings.dropdown.scss +1 -1
- package/src/styles/01-settings/_settings.footer.scss +35 -42
- package/src/styles/01-settings/_settings.input.scss +1 -1
- package/src/styles/01-settings/_settings.list.scss +1 -1
- package/src/styles/01-settings/_settings.rating.scss +1 -1
- package/src/styles/01-settings/_settings.tabs.scss +1 -1
- package/src/styles/01-settings/_settings.upload.scss +6 -5
- package/src/styles/02-tools/_tools.animations.scss +4 -5
- package/src/styles/02-tools/_tools.background.scss +1 -13
- package/src/styles/02-tools/_tools.glass.scss +0 -1
- package/src/styles/02-tools/_tools.utility-api.scss +42 -34
- package/src/styles/03-generic/_generic.root.scss +1 -4
- package/src/styles/04-elements/_elements.body.scss +0 -1
- package/src/styles/06-components/_components.atomix-glass.scss +216 -39
- package/src/styles/06-components/_components.badge.scss +6 -8
- package/src/styles/06-components/_components.button.scss +8 -3
- package/src/styles/06-components/_components.card.scss +2 -14
- package/src/styles/06-components/_components.chart.scss +969 -1449
- package/src/styles/06-components/_components.dropdown.scss +19 -7
- package/src/styles/06-components/_components.edge-panel.scss +4 -2
- package/src/styles/06-components/_components.footer.scss +166 -85
- package/src/styles/06-components/_components.input.scss +8 -9
- package/src/styles/06-components/_components.list.scss +1 -0
- package/src/styles/06-components/_components.modal.scss +5 -3
- package/src/styles/06-components/_components.skeleton.scss +8 -6
- package/src/styles/06-components/_components.upload.scss +219 -4
- package/src/styles/06-components/old.chart.styles.scss +1 -30
- package/src/styles/99-utilities/_utilities.opacity.scss +1 -1
- package/src/styles/99-utilities/_utilities.scss +1 -1
- package/src/components/Chart/AdvancedChart.tsx +0 -624
- package/src/components/Chart/LineChartNew.tsx +0 -167
- package/src/components/Chart/RealTimeChart.tsx +0 -436
- 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 (
|
|
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 (
|
|
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
|
-
}, [
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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
|
-
}, [
|
|
521
|
+
}, [effectiveDefaults, onSettings, showSettingsMenu]);
|
|
313
522
|
|
|
314
|
-
//
|
|
523
|
+
// Use provided groups if available, otherwise generate defaults
|
|
315
524
|
const allGroups =
|
|
316
525
|
groups && groups.length > 0
|
|
317
526
|
? groups
|
|
318
|
-
:
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
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
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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=
|
|
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
|
-
|
|
605
|
+
ref={exportMenuRef}
|
|
606
|
+
className={`${CHART.EXPORT_DROPDOWN_CLASS}`}
|
|
607
|
+
role="menu"
|
|
608
|
+
aria-label="Export formats"
|
|
357
609
|
>
|
|
358
|
-
<div className=
|
|
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}
|
|
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
|
-
|
|
384
|
-
|
|
637
|
+
ref={settingsMenuRef}
|
|
638
|
+
className={`${CHART.SETTINGS_MENU_CLASS}`}
|
|
639
|
+
role="menu"
|
|
640
|
+
aria-label="Chart settings"
|
|
385
641
|
>
|
|
386
|
-
<div className=
|
|
387
|
-
<div className=
|
|
388
|
-
{
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
<
|
|
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=
|
|
397
|
-
<span className=
|
|
398
|
-
<span className=
|
|
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}
|
|
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=
|
|
722
|
+
<div key={group.id} className={`${CHART.TOOLBAR_CLASS}-group`}>
|
|
412
723
|
{group.separator && groupIndex > 0 && (
|
|
413
|
-
<div className=
|
|
724
|
+
<div className={`${CHART.TOOLBAR_CLASS}-separator`} />
|
|
414
725
|
)}
|
|
415
726
|
|
|
416
727
|
{group.label && size === 'lg' && (
|
|
417
|
-
<span className=
|
|
728
|
+
<span className={`${CHART.TOOLBAR_CLASS}-group-label`}>{group.label}</span>
|
|
418
729
|
)}
|
|
419
730
|
|
|
420
|
-
<div className=
|
|
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
|
-
|
|
35
|
-
let
|
|
35
|
+
// Start with the provided position
|
|
36
|
+
let newX = position.x;
|
|
37
|
+
let newY = position.y;
|
|
36
38
|
|
|
37
|
-
// Adjust
|
|
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 -
|
|
41
|
+
newX = position.x - rect.width - 12;
|
|
42
|
+
} else {
|
|
43
|
+
newX = position.x + 12;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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(
|
|
49
|
-
newY = Math.max(
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
);
|