flikkui 0.1.0-beta.4 → 0.1.0-beta.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/dist/components/charts/AreaChart/AreaChart.js +434 -0
- package/dist/components/charts/AreaChart/AreaChart.types.js +7 -0
- package/dist/components/charts/BarChart/BarChart.js +402 -0
- package/dist/components/charts/BarChart/BarChart.types.js +7 -0
- package/dist/components/charts/ChartContainer.js +38 -0
- package/dist/components/charts/Heatmap/Heatmap.js +153 -0
- package/dist/components/charts/Heatmap/HeatmapCell.js +100 -0
- package/dist/components/charts/Heatmap/HeatmapLegend.js +20 -0
- package/dist/components/charts/Heatmap/utils/heatmapUtils.js +174 -0
- package/dist/components/charts/LineChart/LineChart.js +396 -0
- package/dist/components/charts/LineChart/LineChart.types.js +7 -0
- package/dist/components/charts/hooks/useChartAccessibility.js +127 -0
- package/dist/components/charts/hooks/useChartTheme.js +86 -0
- package/dist/components/charts/hooks/useChartValidation.js +59 -0
- package/dist/components/charts/hooks/useTooltipPosition.js +292 -0
- package/dist/components/charts/shared/ChartAxis/XAxis.js +30 -0
- package/dist/components/charts/shared/ChartAxis/YAxis.js +97 -0
- package/dist/components/charts/shared/ChartCrosshair/ChartCrosshair.js +35 -0
- package/dist/components/charts/shared/ChartCrosshair/ChartCrosshair.theme.js +11 -0
- package/dist/components/charts/shared/ChartErrorBoundary/ChartErrorBoundary.js +66 -0
- package/dist/components/charts/shared/ChartGrid/HorizontalGrid.js +22 -0
- package/dist/components/charts/shared/ChartLegend/ChartLegend.js +30 -0
- package/dist/components/charts/shared/ChartLegend/ChartLegendContent.js +22 -0
- package/dist/components/charts/shared/ChartMarker/ChartMarker.js +25 -0
- package/dist/components/charts/shared/ChartMarker/ChartMarker.theme.js +9 -0
- package/dist/components/charts/shared/ChartText/ChartText.js +33 -0
- package/dist/components/charts/shared/ChartText/ChartText.theme.js +9 -0
- package/dist/components/charts/shared/ChartTooltip/ChartTooltip.js +62 -0
- package/dist/components/charts/theme/chart.theme.js +73 -0
- package/dist/components/charts/types/chart.types.js +29 -0
- package/dist/components/charts/utils/chart-validation.js +292 -0
- package/dist/components/charts/utils/color-utils.js +175 -0
- package/dist/components/core/Accordion/Accordion.animations.js +45 -0
- package/dist/components/core/Accordion/Accordion.js +52 -0
- package/dist/components/core/Accordion/Accordion.theme.js +8 -0
- package/dist/components/core/Accordion/AccordionContent.js +25 -0
- package/dist/components/core/Accordion/AccordionItem.js +56 -0
- package/dist/components/core/Accordion/AccordionTrigger.js +32 -0
- package/dist/components/core/Accordion/index.js +5 -0
- package/dist/components/core/Avatar/Avatar.js +94 -0
- package/dist/components/core/Avatar/Avatar.theme.js +25 -0
- package/dist/components/core/AvatarGroup/AvatarGroup.animations.js +79 -0
- package/dist/components/core/AvatarGroup/AvatarGroup.js +67 -0
- package/dist/components/core/AvatarGroup/AvatarGroup.theme.js +23 -0
- package/dist/components/core/Badge/Badge.animations.js +109 -0
- package/dist/components/core/Badge/Badge.js +101 -0
- package/dist/components/core/Badge/Badge.theme.js +41 -0
- package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +8 -8
- package/dist/components/core/Button/Button.theme.js +5 -5
- package/dist/components/core/Card/Card.js +46 -0
- package/dist/components/core/Card/Card.theme.js +5 -0
- package/dist/components/core/Divider/Divider.js +21 -0
- package/dist/components/core/Divider/Divider.theme.js +19 -0
- package/dist/components/core/Pagination/Pagination.js +113 -0
- package/dist/components/core/Pagination/Pagination.theme.js +27 -0
- package/dist/components/core/Segmented/Segmented.js +69 -0
- package/dist/components/core/Segmented/Segmented.theme.js +40 -0
- package/dist/components/core/Segmented/SegmentedContext.js +8 -0
- package/dist/components/core/Segmented/SegmentedItem.js +30 -0
- package/dist/components/core/Stepper/Stepper.js +57 -0
- package/dist/components/core/Stepper/Stepper.theme.js +9 -0
- package/dist/components/core/Stepper/components/ConnectorLine.js +42 -0
- package/dist/components/core/Stepper/components/IconCircle.js +44 -0
- package/dist/components/core/Stepper/components/ProgressIndicator.js +12 -0
- package/dist/components/core/Stepper/components/StepContent.js +36 -0
- package/dist/components/core/Stepper/components/StepperItem.js +22 -0
- package/dist/components/core/Tabs/Tabs.theme.js +2 -2
- package/dist/components/core/Tooltip/Tooltip.animations.js +46 -0
- package/dist/components/core/Tooltip/Tooltip.js +85 -0
- package/dist/components/core/Tooltip/Tooltip.theme.js +11 -0
- package/dist/components/core/Tooltip/useTooltipPositioning.js +59 -0
- package/dist/components/core/Tree/Tree.animations.js +38 -0
- package/dist/components/core/Tree/Tree.js +177 -0
- package/dist/components/core/Tree/Tree.theme.js +11 -0
- package/dist/components/data-display/Table/Table.js +177 -0
- package/dist/components/data-display/Table/Table.theme.js +28 -0
- package/dist/components/data-display/Table/Table.utils.js +28 -0
- package/dist/components/data-display/Table/components/DeclarativeComponents.js +123 -0
- package/dist/components/data-display/Table/components/TableActions/TableActions.js +56 -0
- package/dist/components/data-display/Table/components/TableActions/TableActionsMenu.js +29 -0
- package/dist/components/data-display/Table/components/TableColumnManager/TableColumnManager.js +85 -0
- package/dist/components/data-display/Table/components/TableColumnManager/TableColumnManager.theme.js +21 -0
- package/dist/components/data-display/Table/components/TablePagination/TablePagination.js +51 -0
- package/dist/components/data-display/Table/components/TableSelectionHeader/TableSelectionHeader.js +29 -0
- package/dist/components/data-display/Table/components/core/TableBody.js +32 -0
- package/dist/components/data-display/Table/components/core/TableCell.js +47 -0
- package/dist/components/data-display/Table/components/core/TableHeader.js +77 -0
- package/dist/components/data-display/Table/components/core/TableRow.js +46 -0
- package/dist/components/data-display/Table/index.js +20 -0
- package/dist/components/feedback/Alert/Alert.js +36 -0
- package/dist/components/feedback/Alert/Alert.theme.js +17 -0
- package/dist/components/feedback/ChatMessage/ChatMessage.js +26 -0
- package/dist/components/feedback/ChatMessage/ChatMessage.theme.js +16 -0
- package/dist/components/feedback/Empty/Empty.js +26 -0
- package/dist/components/feedback/Empty/Empty.theme.js +13 -0
- package/dist/components/feedback/Notification/Notification.js +41 -0
- package/dist/components/feedback/Notification/Notification.theme.js +49 -0
- package/dist/components/feedback/Spinner/Spinner.theme.js +3 -3
- package/dist/components/feedback/Toast/Toast.animations.js +58 -0
- package/dist/components/feedback/Toast/Toast.js +67 -0
- package/dist/components/feedback/Toast/Toast.theme.js +18 -0
- package/dist/components/feedback/Toast/ToastProvider.js +73 -0
- package/dist/components/feedback/Toast/useToast.js +91 -0
- package/dist/components/forms/Checkbox/Checkbox.theme.js +1 -1
- package/dist/components/forms/FormLabel/FormLabel.theme.js +2 -2
- package/dist/components/forms/Input/Input.theme.js +4 -4
- package/dist/components/forms/Radio/Radio.theme.js +2 -2
- package/dist/components/forms/Select/Select.js +1 -1
- package/dist/components/forms/Select/Select.theme.js +5 -5
- package/dist/components/forms/Switch/Switch.theme.js +1 -1
- package/dist/components/forms/TimePicker/TimePicker.theme.js +19 -19
- package/dist/components/forms/forms.theme.js +8 -8
- package/dist/components/navigation/NavItem/NavItem.js +93 -0
- package/dist/components/navigation/NavItem/NavItem.theme.js +27 -0
- package/dist/components/navigation/Sidebar/Sidebar.js +28 -0
- package/dist/components/navigation/Sidebar/Sidebar.theme.js +16 -0
- package/dist/components/navigation/Sidebar/SidebarContent.js +12 -0
- package/dist/components/navigation/Sidebar/SidebarContext.js +38 -0
- package/dist/components/navigation/Sidebar/SidebarFooter.js +11 -0
- package/dist/components/navigation/Sidebar/SidebarHeader.js +22 -0
- package/dist/components/navigation/Sidebar/SidebarNav.js +11 -0
- package/dist/components/navigation/Sidebar/SidebarNavGroup.js +19 -0
- package/dist/components/navigation/Sidebar/SidebarToggle.js +26 -0
- package/dist/icons/core/TickIcon.js +3 -1
- package/dist/index.d.ts +29 -4
- package/dist/index.js +64 -4
- package/dist/node_modules/@heroicons/react/20/solid/esm/ChevronDownIcon.js +26 -0
- package/dist/node_modules/@heroicons/react/24/outline/esm/ChevronDoubleLeftIcon.js +28 -0
- package/dist/node_modules/@heroicons/react/24/outline/esm/ChevronDoubleRightIcon.js +28 -0
- package/dist/node_modules/@heroicons/react/24/outline/esm/ChevronLeftIcon.js +28 -0
- package/dist/node_modules/@heroicons/react/24/outline/esm/Cog6ToothIcon.js +32 -0
- package/dist/node_modules/@heroicons/react/24/outline/esm/DocumentIcon.js +28 -0
- package/dist/node_modules/@heroicons/react/24/outline/esm/EllipsisVerticalIcon.js +28 -0
- package/dist/node_modules/@heroicons/react/24/outline/esm/PlusIcon.js +28 -0
- package/dist/node_modules/@heroicons/react/24/solid/esm/ArrowPathIcon.js +26 -0
- package/dist/node_modules/@heroicons/react/24/solid/esm/BellIcon.js +26 -0
- package/dist/node_modules/@heroicons/react/24/solid/esm/CheckCircleIcon.js +26 -0
- package/dist/node_modules/@heroicons/react/24/solid/esm/ExclamationTriangleIcon.js +26 -0
- package/dist/node_modules/@heroicons/react/24/solid/esm/InformationCircleIcon.js +26 -0
- package/dist/node_modules/@heroicons/react/24/solid/esm/XCircleIcon.js +26 -0
- package/dist/node_modules/@heroicons/react/24/solid/esm/XMarkIcon.js +26 -0
- package/dist/node_modules/tslib/tslib.es6.js +15 -1
- package/dist/utils/dateUtils.js +32 -0
- package/dist/utils/debounce.js +21 -0
- package/package.json +1 -1
- package/dist/styles.css +0 -2
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useMemo, useCallback } from 'react';
|
|
2
|
+
import { validateChart, sanitizeChartData, calculateSafeScaleRange, SafeMath } from '../utils/chart-validation.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook for comprehensive chart validation and error handling
|
|
6
|
+
*/
|
|
7
|
+
function useChartValidation(data, config, options) {
|
|
8
|
+
if (options === void 0) { options = {}; }
|
|
9
|
+
var _a = options.autoSanitize, autoSanitize = _a === void 0 ? true : _a, _b = options.logWarnings, logWarnings = _b === void 0 ? process.env.NODE_ENV === 'development' : _b, onValidationError = options.onValidationError, onValidationWarning = options.onValidationWarning;
|
|
10
|
+
// Memoized validation result
|
|
11
|
+
var validation = useMemo(function () {
|
|
12
|
+
var result = validateChart(data, config);
|
|
13
|
+
// Handle errors
|
|
14
|
+
if (result.errors.length > 0 && onValidationError) {
|
|
15
|
+
onValidationError(result.errors);
|
|
16
|
+
}
|
|
17
|
+
// Handle warnings
|
|
18
|
+
if (result.warnings.length > 0) {
|
|
19
|
+
if (logWarnings) {
|
|
20
|
+
console.warn('Chart validation warnings:', result.warnings);
|
|
21
|
+
}
|
|
22
|
+
if (onValidationWarning) {
|
|
23
|
+
onValidationWarning(result.warnings);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}, [data, config, onValidationError, onValidationWarning, logWarnings]);
|
|
28
|
+
// Sanitized data
|
|
29
|
+
var sanitizedData = useMemo(function () {
|
|
30
|
+
if (!autoSanitize || !Array.isArray(data)) {
|
|
31
|
+
return Array.isArray(data) ? data : [];
|
|
32
|
+
}
|
|
33
|
+
return sanitizeChartData(data);
|
|
34
|
+
}, [data, autoSanitize]);
|
|
35
|
+
// Safe scale calculation
|
|
36
|
+
var safeScale = useMemo(function () { return ({
|
|
37
|
+
calculateRange: function (options) {
|
|
38
|
+
var validData = autoSanitize ? sanitizedData : (Array.isArray(data) ? data : []);
|
|
39
|
+
var validConfig = (config && typeof config === 'object') ? config : {};
|
|
40
|
+
return calculateSafeScaleRange(validData, validConfig, options);
|
|
41
|
+
}
|
|
42
|
+
}); }, [sanitizedData, data, config, autoSanitize]);
|
|
43
|
+
// Manual revalidation trigger
|
|
44
|
+
var revalidate = useCallback(function () {
|
|
45
|
+
// This will trigger re-computation of the validation memoized value
|
|
46
|
+
// by updating a dependency (though in this case, we rely on the data/config changes)
|
|
47
|
+
}, []);
|
|
48
|
+
return {
|
|
49
|
+
validation: validation,
|
|
50
|
+
sanitizedData: sanitizedData,
|
|
51
|
+
isValid: validation.isValid,
|
|
52
|
+
hasWarnings: validation.warnings.length > 0,
|
|
53
|
+
safeScale: safeScale,
|
|
54
|
+
safeMath: SafeMath,
|
|
55
|
+
revalidate: revalidate,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { useChartValidation };
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { __assign } from '../../../node_modules/tslib/tslib.es6.js';
|
|
2
|
+
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
3
|
+
|
|
4
|
+
// Optimized animation frame throttle for smooth movement
|
|
5
|
+
function rafThrottle(func) {
|
|
6
|
+
var rafId = null;
|
|
7
|
+
var latestArgs = null;
|
|
8
|
+
var throttledFn = function () {
|
|
9
|
+
var args = [];
|
|
10
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
11
|
+
args[_i] = arguments[_i];
|
|
12
|
+
}
|
|
13
|
+
latestArgs = args;
|
|
14
|
+
if (rafId === null) {
|
|
15
|
+
rafId = requestAnimationFrame(function () {
|
|
16
|
+
if (latestArgs) {
|
|
17
|
+
func.apply(void 0, latestArgs);
|
|
18
|
+
}
|
|
19
|
+
rafId = null;
|
|
20
|
+
latestArgs = null;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
// Add cleanup method
|
|
25
|
+
throttledFn.cancel = function () {
|
|
26
|
+
if (rafId !== null) {
|
|
27
|
+
cancelAnimationFrame(rafId);
|
|
28
|
+
rafId = null;
|
|
29
|
+
latestArgs = null;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
return throttledFn;
|
|
33
|
+
}
|
|
34
|
+
function useTooltipPosition(_a) {
|
|
35
|
+
var containerRef = _a.containerRef, _b = _a.padding, padding = _b === void 0 ? 10 : _b, _c = _a.offset, offset = _c === void 0 ? 15 : _c, _d = _a.isMobile, isMobile = _d === void 0 ? false : _d, _e = _a.animation, animation = _e === void 0 ? {
|
|
36
|
+
duration: 0.08,
|
|
37
|
+
ease: "easeOut",
|
|
38
|
+
enabled: true,
|
|
39
|
+
} : _e;
|
|
40
|
+
var _f = useState(null), tooltipData = _f[0], setTooltipData = _f[1];
|
|
41
|
+
var tooltipRef = useRef(null);
|
|
42
|
+
var isUnmountedRef = useRef(false);
|
|
43
|
+
// Track component mount status to prevent state updates after unmount
|
|
44
|
+
useEffect(function () {
|
|
45
|
+
isUnmountedRef.current = false;
|
|
46
|
+
return function () {
|
|
47
|
+
isUnmountedRef.current = true;
|
|
48
|
+
};
|
|
49
|
+
}, []);
|
|
50
|
+
/**
|
|
51
|
+
* Safe state setter that checks if component is still mounted
|
|
52
|
+
* Supports both direct values and function updates like React.setState
|
|
53
|
+
*/
|
|
54
|
+
var safeSetTooltipData = useCallback(function (data) {
|
|
55
|
+
if (!isUnmountedRef.current) {
|
|
56
|
+
setTooltipData(function (prevData) {
|
|
57
|
+
if (typeof data === 'function') {
|
|
58
|
+
return data(prevData);
|
|
59
|
+
}
|
|
60
|
+
return data;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
/**
|
|
65
|
+
* Calculate bounded position within container with simplified logic
|
|
66
|
+
*/
|
|
67
|
+
var calculateBoundedPosition = useCallback(function (x, y, tooltipWidth, tooltipHeight) {
|
|
68
|
+
if (tooltipWidth === void 0) { tooltipWidth = 0; }
|
|
69
|
+
if (tooltipHeight === void 0) { tooltipHeight = 0; }
|
|
70
|
+
if (!containerRef.current)
|
|
71
|
+
return { x: x, y: y };
|
|
72
|
+
try {
|
|
73
|
+
var containerRect = containerRef.current.getBoundingClientRect();
|
|
74
|
+
var viewportWidth = window.innerWidth;
|
|
75
|
+
var viewportHeight = window.innerHeight;
|
|
76
|
+
var boundedX = x;
|
|
77
|
+
var boundedY = y;
|
|
78
|
+
// Simple X positioning: try right, then left, then clamp
|
|
79
|
+
if (boundedX + tooltipWidth + padding > Math.min(containerRect.right, viewportWidth)) {
|
|
80
|
+
// Try positioning to the left of cursor
|
|
81
|
+
boundedX = x - tooltipWidth - offset;
|
|
82
|
+
}
|
|
83
|
+
// Ensure it doesn't go off the left edge
|
|
84
|
+
boundedX = Math.max(Math.max(containerRect.left, 0) + padding, boundedX);
|
|
85
|
+
// Final clamp to viewport
|
|
86
|
+
boundedX = Math.min(boundedX, viewportWidth - tooltipWidth - padding);
|
|
87
|
+
// Simple Y positioning: try below, then above, then clamp
|
|
88
|
+
if (boundedY + tooltipHeight + padding > Math.min(containerRect.bottom, viewportHeight)) {
|
|
89
|
+
// Try positioning above cursor
|
|
90
|
+
boundedY = y - tooltipHeight - offset;
|
|
91
|
+
}
|
|
92
|
+
// Ensure it doesn't go off the top edge
|
|
93
|
+
boundedY = Math.max(Math.max(containerRect.top, 0) + padding, boundedY);
|
|
94
|
+
// Final clamp to viewport
|
|
95
|
+
boundedY = Math.min(boundedY, viewportHeight - tooltipHeight - padding);
|
|
96
|
+
return { x: boundedX, y: boundedY };
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.warn('Error calculating tooltip position:', error);
|
|
100
|
+
return { x: x, y: y };
|
|
101
|
+
}
|
|
102
|
+
}, [containerRef, padding, offset]);
|
|
103
|
+
/**
|
|
104
|
+
* Get tooltip position for mouse events with stable positioning
|
|
105
|
+
*/
|
|
106
|
+
var getMouseTooltipPosition = useCallback(function (event) {
|
|
107
|
+
var _a, _b;
|
|
108
|
+
// Use page coordinates to avoid scroll issues
|
|
109
|
+
var x = event.clientX;
|
|
110
|
+
var y = event.clientY - offset;
|
|
111
|
+
// Get current tooltip dimensions or use estimated defaults
|
|
112
|
+
var tooltipWidth = ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 200; // reasonable default
|
|
113
|
+
var tooltipHeight = ((_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60; // reasonable default
|
|
114
|
+
return calculateBoundedPosition(x, y, tooltipWidth, tooltipHeight);
|
|
115
|
+
}, [calculateBoundedPosition, offset]);
|
|
116
|
+
/**
|
|
117
|
+
* Get tooltip position for SVG elements (mobile/touch)
|
|
118
|
+
*/
|
|
119
|
+
var getSVGTooltipPosition = useCallback(function (event, svgX, svgY, actualDimensions) {
|
|
120
|
+
var _a, _b;
|
|
121
|
+
try {
|
|
122
|
+
var svgElement = event.currentTarget.closest('svg');
|
|
123
|
+
var svgRect = svgElement === null || svgElement === void 0 ? void 0 : svgElement.getBoundingClientRect();
|
|
124
|
+
if (!svgRect || !actualDimensions.width || !actualDimensions.height) {
|
|
125
|
+
console.warn('SVG positioning fallback: missing SVG rect or dimensions');
|
|
126
|
+
return getMouseTooltipPosition(event);
|
|
127
|
+
}
|
|
128
|
+
// Calculate scale factors using actual dimensions
|
|
129
|
+
var scaleX = svgRect.width / actualDimensions.width;
|
|
130
|
+
var scaleY = svgRect.height / actualDimensions.height;
|
|
131
|
+
// Convert SVG coordinates to screen coordinates
|
|
132
|
+
var screenX_1 = svgRect.left + svgX * scaleX;
|
|
133
|
+
var screenY_1 = svgRect.top + svgY * scaleY;
|
|
134
|
+
var x = screenX_1;
|
|
135
|
+
var y = screenY_1 - offset;
|
|
136
|
+
var tooltipWidth = ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 200;
|
|
137
|
+
var tooltipHeight = ((_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
|
|
138
|
+
return calculateBoundedPosition(x, y, tooltipWidth, tooltipHeight);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.warn('Error in SVG tooltip positioning:', error);
|
|
142
|
+
return getMouseTooltipPosition(event);
|
|
143
|
+
}
|
|
144
|
+
}, [calculateBoundedPosition, getMouseTooltipPosition, offset]);
|
|
145
|
+
/**
|
|
146
|
+
* Show tooltip with content and position
|
|
147
|
+
*/
|
|
148
|
+
var showTooltip = useCallback(function (content, position) {
|
|
149
|
+
safeSetTooltipData({
|
|
150
|
+
x: position.x,
|
|
151
|
+
y: position.y,
|
|
152
|
+
content: content,
|
|
153
|
+
});
|
|
154
|
+
}, [safeSetTooltipData]);
|
|
155
|
+
/**
|
|
156
|
+
* Update tooltip position (for mouse move events)
|
|
157
|
+
*/
|
|
158
|
+
var updateTooltipPosition = useCallback(function (position) {
|
|
159
|
+
safeSetTooltipData(function (prev) {
|
|
160
|
+
return prev ? __assign(__assign({}, prev), { x: position.x, y: position.y }) : null;
|
|
161
|
+
});
|
|
162
|
+
}, [safeSetTooltipData]);
|
|
163
|
+
// Create RAF-throttled version of updateTooltipPosition for smooth movement
|
|
164
|
+
var rafThrottledUpdateRef = useRef(null);
|
|
165
|
+
var rafThrottledUpdate = useCallback(function (position) {
|
|
166
|
+
if (!isUnmountedRef.current) {
|
|
167
|
+
updateTooltipPosition(position);
|
|
168
|
+
}
|
|
169
|
+
}, [updateTooltipPosition]);
|
|
170
|
+
// Initialize RAF throttling
|
|
171
|
+
useEffect(function () {
|
|
172
|
+
rafThrottledUpdateRef.current = rafThrottle(rafThrottledUpdate);
|
|
173
|
+
return function () {
|
|
174
|
+
var _a;
|
|
175
|
+
if ((_a = rafThrottledUpdateRef.current) === null || _a === void 0 ? void 0 : _a.cancel) {
|
|
176
|
+
rafThrottledUpdateRef.current.cancel();
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}, [rafThrottledUpdate]);
|
|
180
|
+
/**
|
|
181
|
+
* Hide tooltip and cancel any pending updates
|
|
182
|
+
*/
|
|
183
|
+
var hideTooltip = useCallback(function () {
|
|
184
|
+
var _a;
|
|
185
|
+
// Cancel any pending RAF updates
|
|
186
|
+
if ((_a = rafThrottledUpdateRef.current) === null || _a === void 0 ? void 0 : _a.cancel) {
|
|
187
|
+
rafThrottledUpdateRef.current.cancel();
|
|
188
|
+
}
|
|
189
|
+
safeSetTooltipData(null);
|
|
190
|
+
}, [safeSetTooltipData]);
|
|
191
|
+
/**
|
|
192
|
+
* Handle mouse enter for chart elements
|
|
193
|
+
*/
|
|
194
|
+
var handleMouseEnter = useCallback(function (event, content, svgCoordinates) {
|
|
195
|
+
try {
|
|
196
|
+
var position = void 0;
|
|
197
|
+
if (isMobile && svgCoordinates) {
|
|
198
|
+
position = getSVGTooltipPosition(event, svgCoordinates.x, svgCoordinates.y, svgCoordinates.dimensions);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
position = getMouseTooltipPosition(event);
|
|
202
|
+
}
|
|
203
|
+
showTooltip(content, position);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
console.warn('Error handling mouse enter:', error);
|
|
207
|
+
}
|
|
208
|
+
}, [isMobile, getSVGTooltipPosition, getMouseTooltipPosition, showTooltip]);
|
|
209
|
+
/**
|
|
210
|
+
* Handle mouse move with optimized RAF throttling for smooth movement
|
|
211
|
+
*/
|
|
212
|
+
var handleMouseMove = useCallback(function (event, svgCoordinates) {
|
|
213
|
+
if (!tooltipData)
|
|
214
|
+
return;
|
|
215
|
+
try {
|
|
216
|
+
// Always use mouse position for consistent movement
|
|
217
|
+
var position = getMouseTooltipPosition(event);
|
|
218
|
+
if (rafThrottledUpdateRef.current) {
|
|
219
|
+
rafThrottledUpdateRef.current(position);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// Fallback to direct update
|
|
223
|
+
updateTooltipPosition(position);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
console.warn('Error handling mouse move:', error);
|
|
228
|
+
}
|
|
229
|
+
}, [tooltipData, getMouseTooltipPosition, updateTooltipPosition]);
|
|
230
|
+
/**
|
|
231
|
+
* Handle mouse leave for chart elements
|
|
232
|
+
*/
|
|
233
|
+
var handleMouseLeave = useCallback(function () {
|
|
234
|
+
hideTooltip();
|
|
235
|
+
}, [hideTooltip]);
|
|
236
|
+
// Update tooltip position when container resizes (simplified)
|
|
237
|
+
useEffect(function () {
|
|
238
|
+
if (!tooltipData || !containerRef.current)
|
|
239
|
+
return;
|
|
240
|
+
var handleResize = function () {
|
|
241
|
+
if (tooltipData && tooltipRef.current && !isUnmountedRef.current) {
|
|
242
|
+
try {
|
|
243
|
+
var tooltipWidth = tooltipRef.current.offsetWidth;
|
|
244
|
+
var tooltipHeight = tooltipRef.current.offsetHeight;
|
|
245
|
+
var newPosition = calculateBoundedPosition(tooltipData.x, tooltipData.y, tooltipWidth, tooltipHeight);
|
|
246
|
+
// Use direct update for resize, not RAF throttled
|
|
247
|
+
updateTooltipPosition(newPosition);
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
console.warn('Error updating tooltip position on resize:', error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
// Use window resize instead of ResizeObserver for better performance
|
|
255
|
+
window.addEventListener('resize', handleResize);
|
|
256
|
+
return function () {
|
|
257
|
+
window.removeEventListener('resize', handleResize);
|
|
258
|
+
};
|
|
259
|
+
}, [tooltipData, containerRef, calculateBoundedPosition, updateTooltipPosition]);
|
|
260
|
+
return {
|
|
261
|
+
tooltipData: tooltipData,
|
|
262
|
+
tooltipRef: tooltipRef,
|
|
263
|
+
showTooltip: showTooltip,
|
|
264
|
+
hideTooltip: hideTooltip,
|
|
265
|
+
updateTooltipPosition: updateTooltipPosition,
|
|
266
|
+
handleMouseEnter: handleMouseEnter,
|
|
267
|
+
handleMouseMove: handleMouseMove,
|
|
268
|
+
handleMouseLeave: handleMouseLeave,
|
|
269
|
+
getMouseTooltipPosition: getMouseTooltipPosition,
|
|
270
|
+
getSVGTooltipPosition: getSVGTooltipPosition,
|
|
271
|
+
// Animation configuration for the consuming component
|
|
272
|
+
animationConfig: {
|
|
273
|
+
animate: tooltipData ? { x: tooltipData.x, y: tooltipData.y, opacity: 1 } : { opacity: 0 },
|
|
274
|
+
transition: animation.enabled ? {
|
|
275
|
+
duration: animation.duration,
|
|
276
|
+
ease: animation.ease,
|
|
277
|
+
// Reduce layout thrashing by using transform instead of changing x/y directly
|
|
278
|
+
type: "tween",
|
|
279
|
+
} : { duration: 0 },
|
|
280
|
+
initial: { opacity: 0 },
|
|
281
|
+
style: tooltipData ? {
|
|
282
|
+
position: 'fixed',
|
|
283
|
+
left: 0,
|
|
284
|
+
top: 0,
|
|
285
|
+
transform: "translate(".concat(tooltipData.x, "px, ").concat(tooltipData.y, "px)"),
|
|
286
|
+
willChange: 'transform, opacity', // Optimize for animations
|
|
287
|
+
} : {},
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export { useTooltipPosition };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { cn } from '../../../../utils/cn.js';
|
|
3
|
+
import { ChartText } from '../ChartText/ChartText.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* XAxis component for charts
|
|
7
|
+
* Renders horizontal axis with labels and optional tick marks
|
|
8
|
+
*/
|
|
9
|
+
var XAxis = function (_a) {
|
|
10
|
+
var data = _a.data, x = _a.x, y = _a.y, width = _a.width, categoryWidth = _a.categoryWidth, _b = _a.categoryGap, categoryGap = _b === void 0 ? 0 : _b, _c = _a.show, show = _c === void 0 ? true : _c, className = _a.className, _d = _a.color, color = _d === void 0 ? 'currentColor' : _d, _e = _a.showTicks, showTicks = _e === void 0 ? true : _e, _f = _a.tickLength, tickLength = _f === void 0 ? 6 : _f, _g = _a.tickPadding, tickPadding = _g === void 0 ? 12 : _g, _h = _a.textAnchor, textAnchor = _h === void 0 ? 'middle' : _h, _j = _a.labelRotation, labelRotation = _j === void 0 ? 0 : _j, labelFormatter = _a.labelFormatter, _k = _a.maxLabelWidth, maxLabelWidth = _k === void 0 ? 100 : _k;
|
|
11
|
+
if (!show)
|
|
12
|
+
return null;
|
|
13
|
+
var formatLabel = function (item, index) {
|
|
14
|
+
if (labelFormatter) {
|
|
15
|
+
return labelFormatter(item, index);
|
|
16
|
+
}
|
|
17
|
+
return item.name || item.label || String(index);
|
|
18
|
+
};
|
|
19
|
+
return (React__default.createElement("g", { className: cn('chart-x-axis', className) },
|
|
20
|
+
React__default.createElement("line", { x1: x, y1: y, x2: x + width, y2: y, stroke: color, className: "opacity-20", strokeWidth: 1 }),
|
|
21
|
+
data.map(function (item, index) {
|
|
22
|
+
var tickX = x + index * (categoryWidth + categoryGap) + categoryWidth / 2;
|
|
23
|
+
var label = formatLabel(item, index);
|
|
24
|
+
return (React__default.createElement("g", { key: index },
|
|
25
|
+
showTicks && (React__default.createElement("line", { x1: tickX, y1: y, x2: tickX, y2: y + tickLength, stroke: color, className: "opacity-40", strokeWidth: 1 })),
|
|
26
|
+
React__default.createElement(ChartText, { x: tickX, y: y + tickLength + tickPadding, textAnchor: textAnchor, maxWidth: maxLabelWidth, truncate: !!maxLabelWidth, rotation: labelRotation }, label)));
|
|
27
|
+
})));
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { XAxis };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { cn } from '../../../../utils/cn.js';
|
|
3
|
+
import { ChartText } from '../ChartText/ChartText.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* YAxis component for charts
|
|
7
|
+
* Renders vertical axis with labels, optional tick marks, and grid lines
|
|
8
|
+
*/
|
|
9
|
+
var YAxis = function (_a) {
|
|
10
|
+
var min = _a.min, max = _a.max, _b = _a.tickCount, tickCount = _b === void 0 ? 5 : _b, x = _a.x, y = _a.y, height = _a.height, _c = _a.show, show = _c === void 0 ? true : _c, className = _a.className, _d = _a.color, color = _d === void 0 ? 'currentColor' : _d, _e = _a.showTicks, showTicks = _e === void 0 ? true : _e, _f = _a.tickLength, tickLength = _f === void 0 ? 6 : _f, _g = _a.tickPadding, tickPadding = _g === void 0 ? 8 : _g, _h = _a.textAnchor, textAnchor = _h === void 0 ? 'end' : _h, tickFormatter = _a.tickFormatter, _j = _a.showGrid, showGrid = _j === void 0 ? false : _j, _k = _a.gridWidth, gridWidth = _k === void 0 ? 0 : _k, customTicks = _a.ticks;
|
|
11
|
+
if (!show)
|
|
12
|
+
return null;
|
|
13
|
+
// Generate tick values
|
|
14
|
+
var generateTicks = function () {
|
|
15
|
+
if (customTicks)
|
|
16
|
+
return customTicks;
|
|
17
|
+
if (tickCount <= 1)
|
|
18
|
+
return [min];
|
|
19
|
+
var range = max - min;
|
|
20
|
+
// For small ranges (like 0-100), use round numbers
|
|
21
|
+
if (range <= 100) {
|
|
22
|
+
var step_1 = Math.ceil(range / (tickCount - 1) / 5) * 5; // Round to nearest 5
|
|
23
|
+
var ticks_1 = [];
|
|
24
|
+
for (var i = 0; i < tickCount; i++) {
|
|
25
|
+
var value = min + i * step_1;
|
|
26
|
+
if (value <= max) {
|
|
27
|
+
ticks_1.push(value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Always include max if it's not already included
|
|
31
|
+
if (ticks_1[ticks_1.length - 1] < max) {
|
|
32
|
+
ticks_1.push(max);
|
|
33
|
+
}
|
|
34
|
+
return ticks_1;
|
|
35
|
+
}
|
|
36
|
+
// For larger ranges, use smarter step calculation
|
|
37
|
+
var roughStep = range / (tickCount - 1);
|
|
38
|
+
var step;
|
|
39
|
+
if (roughStep >= 1000) {
|
|
40
|
+
step = Math.ceil(roughStep / 1000) * 1000;
|
|
41
|
+
}
|
|
42
|
+
else if (roughStep >= 100) {
|
|
43
|
+
step = Math.ceil(roughStep / 100) * 100;
|
|
44
|
+
}
|
|
45
|
+
else if (roughStep >= 10) {
|
|
46
|
+
step = Math.ceil(roughStep / 10) * 10;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
step = Math.ceil(roughStep);
|
|
50
|
+
}
|
|
51
|
+
var ticks = [];
|
|
52
|
+
for (var i = 0; i <= tickCount; i++) {
|
|
53
|
+
var value = min + i * step;
|
|
54
|
+
if (value <= max) {
|
|
55
|
+
ticks.push(value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return ticks;
|
|
59
|
+
};
|
|
60
|
+
var ticks = generateTicks();
|
|
61
|
+
var formatTick = function (value) {
|
|
62
|
+
if (tickFormatter) {
|
|
63
|
+
return tickFormatter(value);
|
|
64
|
+
}
|
|
65
|
+
// Default formatting - prioritize whole numbers
|
|
66
|
+
if (Math.abs(value) >= 1000000) {
|
|
67
|
+
return "".concat(Math.round(value / 1000000), "M");
|
|
68
|
+
}
|
|
69
|
+
else if (Math.abs(value) >= 1000) {
|
|
70
|
+
return "".concat(Math.round(value / 1000), "K");
|
|
71
|
+
}
|
|
72
|
+
else if (Number.isInteger(value) || Math.abs(value - Math.round(value)) < 0.01) {
|
|
73
|
+
return Math.round(value).toString();
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return value.toFixed(1);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var getTickY = function (value) {
|
|
80
|
+
if (max === min) {
|
|
81
|
+
return y + height / 2; // Center position when no range
|
|
82
|
+
}
|
|
83
|
+
var ratio = (value - min) / (max - min);
|
|
84
|
+
return y + height - (ratio * height);
|
|
85
|
+
};
|
|
86
|
+
return (React__default.createElement("g", { className: cn('chart-y-axis', className) },
|
|
87
|
+
React__default.createElement("line", { x1: x, y1: y, x2: x, y2: y + height, stroke: color, className: "opacity-10", strokeWidth: 1 }),
|
|
88
|
+
ticks.map(function (tick, index) {
|
|
89
|
+
var tickY = getTickY(tick);
|
|
90
|
+
return (React__default.createElement("g", { key: index },
|
|
91
|
+
showGrid && gridWidth > 0 && (React__default.createElement("line", { x1: x, y1: tickY, x2: x + gridWidth, y2: tickY, stroke: color, className: "opacity-10", strokeWidth: 1 })),
|
|
92
|
+
showTicks && (React__default.createElement("line", { x1: x - tickLength, y1: tickY, x2: x, y2: tickY, stroke: color, className: "opacity-40", strokeWidth: 1 })),
|
|
93
|
+
React__default.createElement(ChartText, { x: x - tickLength - tickPadding, y: tickY, textAnchor: textAnchor, dominantBaseline: "middle" }, formatTick(tick))));
|
|
94
|
+
})));
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export { YAxis };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { cn } from '../../../../utils/cn.js';
|
|
3
|
+
import { chartCrosshairTheme } from './ChartCrosshair.theme.js';
|
|
4
|
+
import { AnimatePresence } from '../../../../node_modules/framer-motion/dist/es/components/AnimatePresence/index.js';
|
|
5
|
+
import { motion } from '../../../../node_modules/framer-motion/dist/es/render/components/motion/proxy.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ChartCrosshair component for rendering crosshair lines in charts
|
|
9
|
+
* Supports both vertical and horizontal lines with smooth Framer Motion transitions
|
|
10
|
+
*/
|
|
11
|
+
var ChartCrosshair = function (_a) {
|
|
12
|
+
var show = _a.show, x = _a.x, y = _a.y, margin = _a.margin, innerWidth = _a.innerWidth, innerHeight = _a.innerHeight, _b = _a.showHorizontal, showHorizontal = _b === void 0 ? false : _b, _c = _a.strokeColor, strokeColor = _c === void 0 ? "#6b7280" : _c, _d = _a.strokeWidth, strokeWidth = _d === void 0 ? 1 : _d, _e = _a.strokeDasharray, strokeDasharray = _e === void 0 ? "4 4" : _e, _f = _a.opacity, opacity = _f === void 0 ? 0.4 : _f, className = _a.className;
|
|
13
|
+
var theme = chartCrosshairTheme;
|
|
14
|
+
var baseClasses = cn(theme.baseStyle, className);
|
|
15
|
+
return (React__default.createElement(AnimatePresence, null, show && (React__default.createElement(motion.g, { className: "chart-crosshair", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: {
|
|
16
|
+
duration: 0.3,
|
|
17
|
+
ease: "easeInOut"
|
|
18
|
+
} },
|
|
19
|
+
React__default.createElement(motion.line, { x1: x, y1: margin.top, x2: x, y2: margin.top + innerHeight, stroke: strokeColor, strokeWidth: strokeWidth, strokeDasharray: strokeDasharray, opacity: opacity, className: cn(baseClasses, theme.verticalLine), animate: {
|
|
20
|
+
x1: x,
|
|
21
|
+
x2: x
|
|
22
|
+
}, transition: {
|
|
23
|
+
duration: 0.2,
|
|
24
|
+
ease: "easeOut"
|
|
25
|
+
} }),
|
|
26
|
+
showHorizontal && y !== undefined && (React__default.createElement(motion.line, { x1: margin.left, y1: y, x2: margin.left + innerWidth, y2: y, stroke: strokeColor, strokeWidth: strokeWidth, strokeDasharray: strokeDasharray, opacity: opacity, className: cn(baseClasses, theme.horizontalLine), animate: {
|
|
27
|
+
y1: y,
|
|
28
|
+
y2: y
|
|
29
|
+
}, transition: {
|
|
30
|
+
duration: 0.2,
|
|
31
|
+
ease: "easeOut"
|
|
32
|
+
} }))))));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { ChartCrosshair };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default theme for ChartCrosshair component
|
|
3
|
+
* Provides consistent styling for chart crosshair lines with Framer Motion animations
|
|
4
|
+
*/
|
|
5
|
+
var chartCrosshairTheme = {
|
|
6
|
+
baseStyle: "pointer-events-none",
|
|
7
|
+
verticalLine: "stroke-gray-500",
|
|
8
|
+
horizontalLine: "stroke-gray-500",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { chartCrosshairTheme };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { __extends } from '../../../../node_modules/tslib/tslib.es6.js';
|
|
2
|
+
import React__default, { Component } from 'react';
|
|
3
|
+
import { cn } from '../../../../utils/cn.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Error boundary specifically designed for chart components
|
|
7
|
+
* Provides graceful error handling and fallback UI
|
|
8
|
+
*/
|
|
9
|
+
var ChartErrorBoundary = /** @class */ (function (_super) {
|
|
10
|
+
__extends(ChartErrorBoundary, _super);
|
|
11
|
+
function ChartErrorBoundary(props) {
|
|
12
|
+
var _this = _super.call(this, props) || this;
|
|
13
|
+
_this.state = { hasError: false };
|
|
14
|
+
return _this;
|
|
15
|
+
}
|
|
16
|
+
ChartErrorBoundary.getDerivedStateFromError = function (error) {
|
|
17
|
+
return {
|
|
18
|
+
hasError: true,
|
|
19
|
+
error: error,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
ChartErrorBoundary.prototype.componentDidCatch = function (error, errorInfo) {
|
|
23
|
+
this.setState({
|
|
24
|
+
error: error,
|
|
25
|
+
errorInfo: errorInfo,
|
|
26
|
+
});
|
|
27
|
+
// Call optional error handler
|
|
28
|
+
if (this.props.onError) {
|
|
29
|
+
this.props.onError(error, errorInfo);
|
|
30
|
+
}
|
|
31
|
+
// Log error in development
|
|
32
|
+
if (process.env.NODE_ENV === 'development') {
|
|
33
|
+
console.error('Chart Error Boundary caught an error:', error, errorInfo);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
ChartErrorBoundary.prototype.render = function () {
|
|
37
|
+
var _this = this;
|
|
38
|
+
var _a;
|
|
39
|
+
if (this.state.hasError) {
|
|
40
|
+
// Use custom fallback if provided
|
|
41
|
+
if (this.props.fallback) {
|
|
42
|
+
return this.props.fallback;
|
|
43
|
+
}
|
|
44
|
+
// Default error UI
|
|
45
|
+
return (React__default.createElement("div", { className: cn("flex flex-col items-center justify-center p-6 border border-danger-200 bg-danger-50 rounded-lg text-center", this.props.className), role: "alert", "aria-live": "polite" },
|
|
46
|
+
React__default.createElement("div", { className: "flex items-center gap-2 mb-2" },
|
|
47
|
+
React__default.createElement("svg", { className: "w-5 h-5 text-danger-500", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" },
|
|
48
|
+
React__default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" })),
|
|
49
|
+
React__default.createElement("h3", { className: "text-sm font-medium text-danger-800" }, "Chart Error")),
|
|
50
|
+
React__default.createElement("p", { className: "text-sm text-danger-600 mb-3" }, "Unable to render chart due to an error"),
|
|
51
|
+
this.props.showErrorDetails && this.state.error && (React__default.createElement("details", { className: "w-full" },
|
|
52
|
+
React__default.createElement("summary", { className: "text-xs text-danger-500 cursor-pointer hover:text-danger-700 mb-2" }, "Show error details"),
|
|
53
|
+
React__default.createElement("div", { className: "text-left bg-danger-100 p-3 rounded border text-xs font-mono text-danger-800 overflow-auto max-h-32" },
|
|
54
|
+
React__default.createElement("div", { className: "font-semibold mb-1" }, "Error:"),
|
|
55
|
+
React__default.createElement("div", { className: "mb-2" }, this.state.error.message),
|
|
56
|
+
((_a = this.state.errorInfo) === null || _a === void 0 ? void 0 : _a.componentStack) && (React__default.createElement(React__default.Fragment, null,
|
|
57
|
+
React__default.createElement("div", { className: "font-semibold mb-1" }, "Component Stack:"),
|
|
58
|
+
React__default.createElement("pre", { className: "whitespace-pre-wrap text-xs" }, this.state.errorInfo.componentStack)))))),
|
|
59
|
+
React__default.createElement("button", { onClick: function () { return _this.setState({ hasError: false, error: undefined, errorInfo: undefined }); }, className: "mt-3 px-3 py-1 text-xs bg-danger-600 text-white rounded hover:bg-danger-700 transition-colors" }, "Try Again")));
|
|
60
|
+
}
|
|
61
|
+
return this.props.children;
|
|
62
|
+
};
|
|
63
|
+
return ChartErrorBoundary;
|
|
64
|
+
}(Component));
|
|
65
|
+
|
|
66
|
+
export { ChartErrorBoundary };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { cn } from '../../../../utils/cn.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HorizontalGrid component for charts
|
|
6
|
+
* Renders horizontal grid lines at specified intervals
|
|
7
|
+
*/
|
|
8
|
+
var HorizontalGrid = function (_a) {
|
|
9
|
+
var x = _a.x, y = _a.y, width = _a.width, height = _a.height, _b = _a.lineCount, lineCount = _b === void 0 ? 5 : _b, _c = _a.show, show = _c === void 0 ? true : _c, _d = _a.color, color = _d === void 0 ? 'currentColor' : _d, className = _a.className, tickPositions = _a.tickPositions;
|
|
10
|
+
if (!show)
|
|
11
|
+
return null;
|
|
12
|
+
// Generate grid line positions
|
|
13
|
+
var positions = tickPositions ||
|
|
14
|
+
Array.from({ length: lineCount }, function (_, i) {
|
|
15
|
+
if (lineCount <= 1)
|
|
16
|
+
return y;
|
|
17
|
+
return y + (i * height) / (lineCount - 1);
|
|
18
|
+
});
|
|
19
|
+
return (React__default.createElement("g", { className: cn('chart-horizontal-grid', className) }, positions.map(function (lineY, index) { return (React__default.createElement("line", { key: index, x1: x, y1: lineY, x2: x + width, y2: lineY, stroke: color, className: "opacity-10", strokeWidth: 1 })); })));
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { HorizontalGrid };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { __rest, __assign } from '../../../../node_modules/tslib/tslib.es6.js';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Basic ChartLegend component - minimal implementation
|
|
6
|
+
* TODO: Enhance with full legend functionality when needed
|
|
7
|
+
*/
|
|
8
|
+
var ChartLegend = function (_a) {
|
|
9
|
+
var content = _a.content, className = _a.className, wrapperStyle = _a.wrapperStyle, _b = _a.layout, layout = _b === void 0 ? 'horizontal' : _b, _c = _a.align, align = _c === void 0 ? 'center' : _c, _d = _a.verticalAlign, verticalAlign = _d === void 0 ? 'bottom' : _d, props = __rest(_a, ["content", "className", "wrapperStyle", "layout", "align", "verticalAlign"]);
|
|
10
|
+
if (!content) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
var alignClasses = {
|
|
14
|
+
left: 'justify-start',
|
|
15
|
+
center: 'justify-center',
|
|
16
|
+
right: 'justify-end',
|
|
17
|
+
};
|
|
18
|
+
var verticalAlignClasses = {
|
|
19
|
+
top: 'items-start',
|
|
20
|
+
middle: 'items-center',
|
|
21
|
+
bottom: 'items-end',
|
|
22
|
+
};
|
|
23
|
+
var layoutClasses = {
|
|
24
|
+
horizontal: 'flex-row',
|
|
25
|
+
vertical: 'flex-col',
|
|
26
|
+
};
|
|
27
|
+
return (React__default.createElement("div", __assign({ className: "flex ".concat(layoutClasses[layout], " ").concat(alignClasses[align], " ").concat(verticalAlignClasses[verticalAlign], " ").concat(className || ''), style: wrapperStyle }, props), content));
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { ChartLegend };
|