@monolith-forensics/monolith-ui 1.8.1-dev.4 → 1.8.1
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/Button/Button.js +58 -9
- package/dist/Calendar/Calendar.d.ts +2 -7
- package/dist/Calendar/Calendar.js +49 -226
- package/dist/Calendar/CalendarStyles.d.ts +2 -6
- package/dist/Calendar/CalendarStyles.js +33 -153
- package/dist/Calendar/calendarHelpers.d.ts +2 -6
- package/dist/Calendar/calendarHelpers.js +5 -13
- package/dist/Charts/BarChart/BarChart.js +28 -14
- package/dist/Charts/BarChart/BarChart.styled.d.ts +7 -2
- package/dist/Charts/BarChart/BarChart.styled.js +5 -1
- package/dist/Charts/BarChart/BarChart.types.d.ts +13 -5
- package/dist/Charts/ChartUtils/chartSizing.d.ts +20 -0
- package/dist/Charts/ChartUtils/chartSizing.js +83 -0
- package/dist/Charts/ChartUtils/index.d.ts +1 -0
- package/dist/Charts/ChartUtils/index.js +1 -0
- package/dist/Charts/HeatMap/HeatMap.js +28 -7
- package/dist/Charts/HeatMap/HeatMap.styled.d.ts +6 -2
- package/dist/Charts/HeatMap/HeatMap.styled.js +3 -0
- package/dist/Charts/HeatMap/HeatMap.types.d.ts +7 -1
- package/dist/Charts/LineChart/LineChart.js +34 -15
- package/dist/Charts/LineChart/LineChart.styled.d.ts +7 -2
- package/dist/Charts/LineChart/LineChart.styled.js +5 -1
- package/dist/Charts/LineChart/LineChart.types.d.ts +13 -5
- package/dist/Charts/PieChart/PieChart.js +48 -33
- package/dist/Charts/PieChart/PieChart.styled.d.ts +7 -2
- package/dist/Charts/PieChart/PieChart.styled.js +6 -1
- package/dist/Charts/PieChart/PieChart.types.d.ts +7 -3
- package/dist/CheckBox/CheckBox.js +19 -36
- package/dist/DateInput/DateInput.js +143 -198
- package/dist/DropDownMenu/DropDownMenu.js +15 -25
- package/dist/DropDownMenu/components/MenuComponent.js +2 -8
- package/dist/DropDownMenu/components/MenuItem.d.ts +0 -2
- package/dist/DropDownMenu/components/MenuItem.js +21 -25
- package/dist/DropDownMenu/components/MenuItemList.d.ts +0 -3
- package/dist/DropDownMenu/components/MenuItemList.js +86 -192
- package/dist/DropDownMenu/components/StyledContent.js +2 -1
- package/dist/DropDownMenu/components/StyledFloatContainer.js +1 -1
- package/dist/DropDownMenu/types.d.ts +0 -3
- package/dist/FieldLabel/FieldLabel.js +12 -4
- package/dist/FileInputField/FileInputField.js +23 -4
- package/dist/FileViewer/viewers/ImageViewer.js +18 -75
- package/dist/FormSection/FormSection.js +25 -5
- package/dist/IconButton/IconButton.js +16 -2
- package/dist/Input/Input.js +56 -7
- package/dist/MonolithUIProvider/MonolithUIProvider.d.ts +4 -1
- package/dist/Pill/Pill.js +79 -8
- package/dist/Popover/Popover.context.d.ts +1 -2
- package/dist/Popover/Popover.js +2 -5
- package/dist/Popover/Popover.styles.d.ts +6 -1
- package/dist/Popover/Popover.styles.js +28 -11
- package/dist/Popover/Popover.transitions.d.ts +2 -4
- package/dist/Popover/Popover.transitions.js +49 -23
- package/dist/Popover/PopoverDropdown.js +8 -6
- package/dist/Popover/PopoverTarget.js +3 -6
- package/dist/QueryFilter/DefaultOperators.d.ts +76 -0
- package/dist/QueryFilter/DefaultOperators.js +21 -0
- package/dist/QueryFilter/QueryFilter.d.ts +1 -1
- package/dist/QueryFilter/QueryFilter.js +303 -3
- package/dist/QueryFilter/index.d.ts +2 -3
- package/dist/QueryFilter/index.js +2 -3
- package/dist/QueryFilter/types.d.ts +52 -0
- package/dist/QueryFilter/types.js +1 -0
- package/dist/QueryFilter/useQueryFilter.d.ts +1 -1
- package/dist/QueryFilter/useQueryFilter.js +19 -23
- package/dist/RichTextEditor/Components/CodeBlockBaseButton.d.ts +18 -0
- package/dist/RichTextEditor/Components/CodeBlockBaseButton.js +6 -0
- package/dist/RichTextEditor/Components/CodeBlockCopyButton.d.ts +9 -0
- package/dist/RichTextEditor/Components/CodeBlockCopyButton.js +42 -0
- package/dist/RichTextEditor/Components/CodeBlockFormatButton.d.ts +10 -0
- package/dist/RichTextEditor/Components/CodeBlockFormatButton.js +60 -0
- package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.d.ts +9 -0
- package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.js +30 -0
- package/dist/RichTextEditor/Components/CodeBlockNodeView.d.ts +3 -0
- package/dist/RichTextEditor/Components/CodeBlockNodeView.js +28 -0
- package/dist/RichTextEditor/Components/CodeBlockWrapButton.d.ts +10 -0
- package/dist/RichTextEditor/Components/CodeBlockWrapButton.js +17 -0
- package/dist/RichTextEditor/Components/LinkEditor.d.ts +8 -0
- package/dist/RichTextEditor/Components/LinkEditor.js +94 -0
- package/dist/RichTextEditor/Components/TableTools/TableCornerMenu.d.ts +2 -0
- package/dist/RichTextEditor/Components/TableTools/TableCornerMenu.js +19 -0
- package/dist/RichTextEditor/Components/TableTools/TableInsertControls.d.ts +2 -0
- package/dist/RichTextEditor/Components/TableTools/TableInsertControls.js +24 -0
- package/dist/RichTextEditor/Components/TableTools/TableRails.d.ts +2 -0
- package/dist/RichTextEditor/Components/TableTools/TableRails.js +180 -0
- package/dist/RichTextEditor/Components/TableTools/TableToolMenu.d.ts +5 -0
- package/dist/RichTextEditor/Components/TableTools/TableToolMenu.js +6 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.actions.d.ts +5 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.actions.js +183 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.commands.d.ts +16 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.commands.js +217 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.constants.d.ts +8 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.constants.js +11 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.d.ts +3 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.geometry.d.ts +23 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.geometry.js +75 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.js +3 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.selectors.d.ts +16 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.selectors.js +53 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.styled.d.ts +40 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.styled.js +167 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.types.d.ts +76 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.types.js +1 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.utils.d.ts +4 -0
- package/dist/RichTextEditor/Components/TableTools/TableTools.utils.js +4 -0
- package/dist/RichTextEditor/Components/TableTools/TableToolsPopover.d.ts +2 -0
- package/dist/RichTextEditor/Components/TableTools/TableToolsPopover.js +12 -0
- package/dist/RichTextEditor/Components/TableTools/index.d.ts +3 -0
- package/dist/RichTextEditor/Components/TableTools/index.js +2 -0
- package/dist/RichTextEditor/Enums/HighlightColors.d.ts +9 -0
- package/dist/RichTextEditor/Enums/HighlightColors.js +10 -0
- package/dist/RichTextEditor/Extensions/getTiptapExtensions.js +15 -5
- package/dist/RichTextEditor/Plugins/ImageActionsPlugin.js +4 -7
- package/dist/RichTextEditor/Plugins/UploadImagesPlugin.d.ts +0 -15
- package/dist/RichTextEditor/Plugins/UploadImagesPlugin.js +51 -115
- package/dist/RichTextEditor/Plugins/index.d.ts +0 -1
- package/dist/RichTextEditor/Plugins/index.js +0 -1
- package/dist/RichTextEditor/RichTextEditor.d.ts +2 -3
- package/dist/RichTextEditor/RichTextEditor.js +35 -309
- package/dist/RichTextEditor/Toolbar/Toolbar.js +2 -14
- package/dist/RichTextEditor/Utils/codeBlockUtils.d.ts +20 -0
- package/dist/RichTextEditor/Utils/codeBlockUtils.js +137 -0
- package/dist/RichTextEditor/Utils/codeUtils.d.ts +3 -0
- package/dist/RichTextEditor/Utils/codeUtils.js +12 -0
- package/dist/RichTextEditor/Utils/linkUtils.d.ts +19 -0
- package/dist/RichTextEditor/Utils/linkUtils.js +57 -0
- package/dist/RichTextEditor/Utils/tableUtils.d.ts +1 -0
- package/dist/RichTextEditor/Utils/tableUtils.js +1 -0
- package/dist/SegmentedControl/SegmentedControl.utils.d.ts +2 -2
- package/dist/SegmentedControl/SegmentedControl.utils.js +30 -3
- package/dist/SelectBox/SelectBox.js +5 -5
- package/dist/SelectBox/select-box.styled-components.d.ts +1 -4
- package/dist/SelectBox/select-box.styled-components.js +48 -11
- package/dist/SelectBox/types.d.ts +0 -1
- package/dist/Switch/Switch.d.ts +2 -2
- package/dist/Switch/Switch.js +83 -18
- package/dist/Table/ColumnResizer.d.ts +9 -6
- package/dist/Table/ColumnResizer.js +10 -30
- package/dist/Table/StateStorage.d.ts +0 -4
- package/dist/Table/StateStorage.js +0 -13
- package/dist/Table/Table.js +12 -160
- package/dist/Table/TableComponents.d.ts +0 -10
- package/dist/Table/TableComponents.js +10 -71
- package/dist/Table/TableDefaults.d.ts +0 -7
- package/dist/Table/TableDefaults.js +0 -7
- package/dist/Table/TableHeader.js +16 -31
- package/dist/Table/TableMenu/TableMenu.js +1 -1
- package/dist/Table/TableProvider.js +75 -354
- package/dist/Table/TableRow.js +16 -28
- package/dist/Table/Utils/index.d.ts +1 -0
- package/dist/Table/Utils/index.js +1 -0
- package/dist/Table/Utils/resizeHandler.d.ts +3 -0
- package/dist/Table/Utils/resizeHandler.js +84 -0
- package/dist/Table/types.d.ts +19 -70
- package/dist/TagBox/TagBox.d.ts +1 -1
- package/dist/TagBox/TagBox.js +80 -22
- package/dist/TagBox/types.d.ts +0 -1
- package/dist/TextArea/TextArea.js +23 -9
- package/dist/TextInput/TextInput.js +6 -12
- package/dist/Utilities/parseTimestamp.js +6 -11
- package/dist/core/ArrowButton.d.ts +0 -2
- package/dist/core/ArrowButton.js +3 -7
- package/dist/core/ClearButton.d.ts +0 -2
- package/dist/core/ClearButton.js +3 -7
- package/dist/core/controlSizes.js +9 -9
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -2
- package/dist/theme/variants.js +8 -2
- package/package.json +18 -26
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
const toDimensionStyle = (dimension) => {
|
|
3
|
+
if (dimension == null || typeof dimension === "number")
|
|
4
|
+
return undefined;
|
|
5
|
+
return dimension;
|
|
6
|
+
};
|
|
7
|
+
const toNumericDimension = (dimension, fallback) => typeof dimension === "number" && Number.isFinite(dimension)
|
|
8
|
+
? dimension
|
|
9
|
+
: fallback;
|
|
10
|
+
const getElementSize = (element) => {
|
|
11
|
+
const rect = element.getBoundingClientRect();
|
|
12
|
+
return {
|
|
13
|
+
width: Math.max(Math.round(rect.width || element.clientWidth || 0), 0),
|
|
14
|
+
height: Math.max(Math.round(rect.height || element.clientHeight || 0), 0),
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export const useChartResponsiveSize = (ref, { width, height, responsive = false, aspectRatio, defaultWidth, defaultHeight, minWidth, minHeight, }) => {
|
|
18
|
+
const resolvedWidthInput = width !== null && width !== void 0 ? width : (responsive ? "100%" : defaultWidth);
|
|
19
|
+
const resolvedHeightInput = height !== null && height !== void 0 ? height : defaultHeight;
|
|
20
|
+
const shouldMeasureWidth = responsive || typeof resolvedWidthInput === "string";
|
|
21
|
+
const shouldMeasureHeight = typeof resolvedHeightInput === "string";
|
|
22
|
+
const shouldMeasure = shouldMeasureWidth || shouldMeasureHeight;
|
|
23
|
+
const [measuredSize, setMeasuredSize] = useState({ width: 0, height: 0 });
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!shouldMeasure)
|
|
26
|
+
return;
|
|
27
|
+
const element = ref.current;
|
|
28
|
+
if (!element)
|
|
29
|
+
return;
|
|
30
|
+
const updateSize = () => {
|
|
31
|
+
const nextSize = getElementSize(element);
|
|
32
|
+
setMeasuredSize((currentSize) => currentSize.width === nextSize.width &&
|
|
33
|
+
currentSize.height === nextSize.height
|
|
34
|
+
? currentSize
|
|
35
|
+
: nextSize);
|
|
36
|
+
};
|
|
37
|
+
updateSize();
|
|
38
|
+
if (typeof ResizeObserver === "undefined") {
|
|
39
|
+
window.addEventListener("resize", updateSize);
|
|
40
|
+
return () => window.removeEventListener("resize", updateSize);
|
|
41
|
+
}
|
|
42
|
+
const observer = new ResizeObserver(updateSize);
|
|
43
|
+
observer.observe(element);
|
|
44
|
+
return () => observer.disconnect();
|
|
45
|
+
}, [ref, shouldMeasure]);
|
|
46
|
+
return useMemo(() => {
|
|
47
|
+
const fallbackWidth = toNumericDimension(resolvedWidthInput, defaultWidth);
|
|
48
|
+
const fallbackHeight = toNumericDimension(resolvedHeightInput, defaultHeight);
|
|
49
|
+
const measuredWidth = shouldMeasureWidth && measuredSize.width > 0
|
|
50
|
+
? measuredSize.width
|
|
51
|
+
: fallbackWidth;
|
|
52
|
+
const safeWidth = Math.max(measuredWidth, minWidth);
|
|
53
|
+
const resolvedAspectRatio = aspectRatio != null && Number.isFinite(aspectRatio) && aspectRatio > 0
|
|
54
|
+
? aspectRatio
|
|
55
|
+
: null;
|
|
56
|
+
const measuredHeight = height == null && resolvedAspectRatio != null
|
|
57
|
+
? safeWidth / resolvedAspectRatio
|
|
58
|
+
: shouldMeasureHeight && measuredSize.height > 0
|
|
59
|
+
? measuredSize.height
|
|
60
|
+
: fallbackHeight;
|
|
61
|
+
return {
|
|
62
|
+
width: Math.max(Math.round(safeWidth), minWidth),
|
|
63
|
+
height: Math.max(Math.round(measuredHeight), minHeight),
|
|
64
|
+
widthStyle: toDimensionStyle(resolvedWidthInput),
|
|
65
|
+
heightStyle: toDimensionStyle(resolvedHeightInput),
|
|
66
|
+
fillAvailableWidth: responsive || typeof resolvedWidthInput === "string",
|
|
67
|
+
};
|
|
68
|
+
}, [
|
|
69
|
+
aspectRatio,
|
|
70
|
+
defaultHeight,
|
|
71
|
+
defaultWidth,
|
|
72
|
+
height,
|
|
73
|
+
measuredSize.height,
|
|
74
|
+
measuredSize.width,
|
|
75
|
+
minHeight,
|
|
76
|
+
minWidth,
|
|
77
|
+
resolvedHeightInput,
|
|
78
|
+
resolvedWidthInput,
|
|
79
|
+
responsive,
|
|
80
|
+
shouldMeasureHeight,
|
|
81
|
+
shouldMeasureWidth,
|
|
82
|
+
]);
|
|
83
|
+
};
|
|
@@ -22,14 +22,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
22
22
|
import { forwardRef, useEffect, useId, useImperativeHandle, useMemo, useRef, useState, } from "react";
|
|
23
23
|
import { useTheme } from "styled-components";
|
|
24
24
|
import { ChartExportControl } from "../ChartPrimitives";
|
|
25
|
-
import { DEFAULT_CHART_EXPORT_FORMATS, copyChartImage, downloadChartImage, } from "../ChartUtils";
|
|
25
|
+
import { DEFAULT_CHART_EXPORT_FORMATS, copyChartImage, downloadChartImage, useChartResponsiveSize, } from "../ChartUtils";
|
|
26
26
|
import { buildHeatMapCells, clamp, easeOutCubic, formatDefaultValue, formatDefaultWeekdayLabel, getHeatMapColor, getHeatMapDateRange, getMonthLabels, } from "./HeatMap.lib";
|
|
27
27
|
import { StyledCell, StyledChartActions, StyledChartFrame, StyledChartScroller, StyledContainer, StyledLegend, StyledLegendCell, StyledLegendScale, StyledMonthLabel, StyledSvg, StyledTooltip, StyledTooltipHeader, StyledTooltipMeta, StyledTooltipSwatch, StyledWeekdayLabel, } from "./HeatMap.styled";
|
|
28
28
|
const HeatMapInner = (_a, ref) => {
|
|
29
|
-
var { data, startDate, endDate, cellSize = 12, cellGap = 4, cellRadius = 2, emptyColor, colors, minValue = 0, maxValue, weekStartsOn = 0, showMonthLabels = true, showWeekdayLabels = true, showLegend = true, animateOnRender = false, animationDuration = 350, animationStagger = 1, showExportButton = false, exportFileName = "heat-map", exportFormats = DEFAULT_CHART_EXPORT_FORMATS, exportScale = 2, exportBackgroundColor, showTooltips = false, ariaLabel = "Heat map", valueFormatter, monthLabelFormatter, weekdayLabelFormatter, tooltipFormatter, onCellClick, className } = _a, props = __rest(_a, ["data", "startDate", "endDate", "cellSize", "cellGap", "cellRadius", "emptyColor", "colors", "minValue", "maxValue", "weekStartsOn", "showMonthLabels", "showWeekdayLabels", "showLegend", "animateOnRender", "animationDuration", "animationStagger", "showExportButton", "exportFileName", "exportFormats", "exportScale", "exportBackgroundColor", "showTooltips", "ariaLabel", "valueFormatter", "monthLabelFormatter", "weekdayLabelFormatter", "tooltipFormatter", "onCellClick", "className"]);
|
|
29
|
+
var { data, width, responsive = false, startDate, endDate, cellSize = 12, minCellSize = 6, cellGap = 4, cellRadius = 2, emptyColor, colors, minValue = 0, maxValue, weekStartsOn = 0, showMonthLabels = true, showWeekdayLabels = true, showLegend = true, animateOnRender = false, animationDuration = 350, animationStagger = 1, showExportButton = false, exportFileName = "heat-map", exportFormats = DEFAULT_CHART_EXPORT_FORMATS, exportScale = 2, exportBackgroundColor, showTooltips = false, ariaLabel = "Heat map", valueFormatter, monthLabelFormatter, weekdayLabelFormatter, tooltipFormatter, onCellClick, className } = _a, props = __rest(_a, ["data", "width", "responsive", "startDate", "endDate", "cellSize", "minCellSize", "cellGap", "cellRadius", "emptyColor", "colors", "minValue", "maxValue", "weekStartsOn", "showMonthLabels", "showWeekdayLabels", "showLegend", "animateOnRender", "animationDuration", "animationStagger", "showExportButton", "exportFileName", "exportFormats", "exportScale", "exportBackgroundColor", "showTooltips", "ariaLabel", "valueFormatter", "monthLabelFormatter", "weekdayLabelFormatter", "tooltipFormatter", "onCellClick", "className"]);
|
|
30
30
|
const descriptionId = useId();
|
|
31
31
|
const theme = useTheme();
|
|
32
32
|
const containerRef = useRef(null);
|
|
33
|
+
const chartSizeRef = useRef(null);
|
|
33
34
|
const svgRef = useRef(null);
|
|
34
35
|
const [activeCellKey, setActiveCellKey] = useState(null);
|
|
35
36
|
const [activeTooltip, setActiveTooltip] = useState(null);
|
|
@@ -73,12 +74,12 @@ const HeatMapInner = (_a, ref) => {
|
|
|
73
74
|
.map((datum) => datum.value)
|
|
74
75
|
.filter((value) => Number.isFinite(value));
|
|
75
76
|
const resolvedMaxValue = maxValue !== null && maxValue !== void 0 ? maxValue : Math.max(...values, minValue, 1);
|
|
76
|
-
const
|
|
77
|
+
const preferredCellSize = Math.max(cellSize, 1);
|
|
78
|
+
const safeMinCellSize = Math.max(minCellSize, 1);
|
|
77
79
|
const safeCellGap = Math.max(cellGap, 0);
|
|
78
80
|
const safeCellRadius = Math.max(cellRadius, 0);
|
|
79
81
|
const labelWidth = showWeekdayLabels ? 28 : 0;
|
|
80
82
|
const monthLabelHeight = showMonthLabels ? 18 : 0;
|
|
81
|
-
const step = safeCellSize + safeCellGap;
|
|
82
83
|
const cells = useMemo(() => buildHeatMapCells({
|
|
83
84
|
data,
|
|
84
85
|
startDate: resolvedStartDate,
|
|
@@ -100,8 +101,28 @@ const HeatMapInner = (_a, ref) => {
|
|
|
100
101
|
weekStartsOn,
|
|
101
102
|
]);
|
|
102
103
|
const weekCount = cells.length > 0 ? Math.max(...cells.map((cell) => cell.weekIndex)) + 1 : 1;
|
|
103
|
-
const
|
|
104
|
-
const
|
|
104
|
+
const preferredStep = preferredCellSize + safeCellGap;
|
|
105
|
+
const preferredWidth = labelWidth + weekCount * preferredStep - safeCellGap;
|
|
106
|
+
const preferredHeight = monthLabelHeight + 7 * preferredStep - safeCellGap;
|
|
107
|
+
const chartSize = useChartResponsiveSize(chartSizeRef, {
|
|
108
|
+
width,
|
|
109
|
+
responsive,
|
|
110
|
+
defaultWidth: preferredWidth,
|
|
111
|
+
defaultHeight: preferredHeight,
|
|
112
|
+
minWidth: 1,
|
|
113
|
+
minHeight: 1,
|
|
114
|
+
});
|
|
115
|
+
const shouldFitWidth = responsive || width != null;
|
|
116
|
+
const targetCellSize = (chartSize.width - labelWidth + safeCellGap) / weekCount - safeCellGap;
|
|
117
|
+
const safeCellSize = shouldFitWidth
|
|
118
|
+
? Math.max(targetCellSize, safeMinCellSize)
|
|
119
|
+
: preferredCellSize;
|
|
120
|
+
const step = safeCellSize + safeCellGap;
|
|
121
|
+
const chartWidth = labelWidth + weekCount * step - safeCellGap;
|
|
122
|
+
const chartHeight = monthLabelHeight + 7 * step - safeCellGap;
|
|
123
|
+
const chartWidthStyle = typeof width === "number" && Number.isFinite(width)
|
|
124
|
+
? `${chartSize.width}px`
|
|
125
|
+
: chartSize.widthStyle;
|
|
105
126
|
const formatValue = (cell) => { var _a; return (_a = valueFormatter === null || valueFormatter === void 0 ? void 0 : valueFormatter(cell.value, cell.datum)) !== null && _a !== void 0 ? _a : formatDefaultValue(cell.value); };
|
|
106
127
|
const getCellFill = (cell) => {
|
|
107
128
|
if (!cell.datum)
|
|
@@ -172,7 +193,7 @@ const HeatMapInner = (_a, ref) => {
|
|
|
172
193
|
const elapsed = animationElapsed - index * safeAnimationStagger;
|
|
173
194
|
return easeOutCubic(clamp(elapsed / safeAnimationDuration, 0, 1));
|
|
174
195
|
};
|
|
175
|
-
return (_jsxs(StyledContainer, Object.assign({ ref: containerRef, className: className }, props, { children: [_jsx(StyledChartScroller, { children: _jsxs(StyledChartFrame, { children: [showExportButton && exportFormats.length > 0 && (_jsx(StyledChartActions, { "data-chart-export-ignore": "true", children: _jsx(ChartExportControl, { rootRef: containerRef, svgRef: svgRef, fileName: exportFileName, formats: exportFormats, scale: exportScale, backgroundColor: resolvedExportBackgroundColor }) })), _jsxs(StyledSvg, { ref: svgRef, width:
|
|
196
|
+
return (_jsxs(StyledContainer, Object.assign({ ref: containerRef, className: className, "$fillAvailableWidth": chartSize.fillAvailableWidth }, props, { children: [_jsx(StyledChartScroller, { ref: chartSizeRef, "$width": chartWidthStyle, children: _jsxs(StyledChartFrame, { children: [showExportButton && exportFormats.length > 0 && (_jsx(StyledChartActions, { "data-chart-export-ignore": "true", children: _jsx(ChartExportControl, { rootRef: containerRef, svgRef: svgRef, fileName: exportFileName, formats: exportFormats, scale: exportScale, backgroundColor: resolvedExportBackgroundColor }) })), _jsxs(StyledSvg, { ref: svgRef, width: chartWidth, height: chartHeight, viewBox: `0 0 ${chartWidth} ${chartHeight}`, role: "img", "aria-label": ariaLabel, "aria-describedby": descriptionId, children: [_jsx("desc", { id: descriptionId, children: description }), showMonthLabels &&
|
|
176
197
|
monthLabels.map((monthLabel) => (_jsx(StyledMonthLabel, { x: labelWidth + monthLabel.weekIndex * step, y: 10, children: monthLabel.label }, `${monthLabel.label}-${monthLabel.weekIndex}`))), showWeekdayLabels &&
|
|
177
198
|
Array.from({ length: 7 }, (_, dayIndex) => {
|
|
178
199
|
var _a;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { StyledChartActions } from "../ChartPrimitives";
|
|
2
|
-
export declare const StyledContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").
|
|
3
|
-
|
|
2
|
+
export declare const StyledContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
3
|
+
$fillAvailableWidth: boolean;
|
|
4
|
+
}>> & string;
|
|
5
|
+
export declare const StyledChartScroller: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
6
|
+
$width?: string;
|
|
7
|
+
}>> & string;
|
|
4
8
|
export declare const StyledChartFrame: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
5
9
|
export { StyledChartActions };
|
|
6
10
|
export declare const StyledSvg: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").SVGProps<SVGSVGElement>, never>> & string;
|
|
@@ -9,16 +9,19 @@ export const StyledContainer = styled.div `
|
|
|
9
9
|
display: inline-flex;
|
|
10
10
|
flex-direction: column;
|
|
11
11
|
gap: 10px;
|
|
12
|
+
width: ${({ $fillAvailableWidth }) => $fillAvailableWidth ? "100%" : "fit-content"};
|
|
12
13
|
max-width: 100%;
|
|
13
14
|
color: ${({ theme }) => theme.palette.text.primary};
|
|
14
15
|
overflow: visible;
|
|
15
16
|
`;
|
|
16
17
|
export const StyledChartScroller = styled.div `
|
|
17
18
|
display: flex;
|
|
19
|
+
width: ${({ $width }) => $width !== null && $width !== void 0 ? $width : "auto"};
|
|
18
20
|
max-width: 100%;
|
|
19
21
|
overflow-x: auto;
|
|
20
22
|
overflow-y: visible;
|
|
21
23
|
padding-bottom: 2px;
|
|
24
|
+
box-sizing: border-box;
|
|
22
25
|
`;
|
|
23
26
|
export const StyledChartFrame = styled.div `
|
|
24
27
|
position: relative;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { HTMLAttributes } from "react";
|
|
2
|
-
import type { ChartExportOptions } from "../ChartUtils";
|
|
2
|
+
import type { ChartDimension, ChartExportOptions } from "../ChartUtils";
|
|
3
3
|
export type HeatMapDatum<TData = unknown> = {
|
|
4
4
|
/** Date represented by this cell. ISO yyyy-mm-dd strings are recommended. */
|
|
5
5
|
date: Date | string;
|
|
@@ -31,12 +31,18 @@ export type HeatMapTooltipState = {
|
|
|
31
31
|
export type HeatMapProps<TData = unknown> = HTMLAttributes<HTMLDivElement> & ChartExportOptions & {
|
|
32
32
|
/** Values rendered by the heatmap. Missing dates render as empty cells. */
|
|
33
33
|
data: HeatMapDatum<TData>[];
|
|
34
|
+
/** Target heatmap width in pixels or any CSS length measured from the chart frame. */
|
|
35
|
+
width?: ChartDimension;
|
|
36
|
+
/** Measures the chart frame and resizes cells to fit the available width. Defaults to false. */
|
|
37
|
+
responsive?: boolean;
|
|
34
38
|
/** First date to render. Defaults to the earliest date in data. */
|
|
35
39
|
startDate?: Date | string;
|
|
36
40
|
/** Last date to render. Defaults to the latest date in data. */
|
|
37
41
|
endDate?: Date | string;
|
|
38
42
|
/** Size of each square cell in pixels. Defaults to 12. */
|
|
39
43
|
cellSize?: number;
|
|
44
|
+
/** Minimum rendered cell size in pixels when responsive sizing is active. Defaults to 6. */
|
|
45
|
+
minCellSize?: number;
|
|
40
46
|
/** Gap between cells in pixels. Defaults to 4. */
|
|
41
47
|
cellGap?: number;
|
|
42
48
|
/** Cell corner radius in pixels. Defaults to 2. */
|
|
@@ -23,16 +23,17 @@ import { scaleLinear, scalePoint, scaleTime } from "d3-scale";
|
|
|
23
23
|
import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
24
24
|
import { useTheme } from "styled-components";
|
|
25
25
|
import { ChartExportControl } from "../ChartPrimitives";
|
|
26
|
-
import { DEFAULT_CHART_EXPORT_FORMATS, copyChartImage, downloadChartImage, } from "../ChartUtils";
|
|
26
|
+
import { DEFAULT_CHART_EXPORT_FORMATS, copyChartImage, downloadChartImage, useChartResponsiveSize, } from "../ChartUtils";
|
|
27
27
|
import { buildAreaPath, buildLinePath, clamp, easeOutCubic, formatDefaultValue, getGradientStops, getPointKey, getSeriesKey, getSeriesLabelText, getValueDomain, measureSvgPath, mergeChartMargin, normalizeTickValue, parseLineChartXValue, resolveXAxisType, useThemeColor, useThemeColors, } from "./LineChart.lib";
|
|
28
28
|
import { StyledArea, StyledAxisLine, StyledAxisText, StyledChartActions, StyledChartFrame, StyledChartScroller, StyledContainer, StyledEmptyState, StyledGridLine, StyledHoverTarget, StyledLegend, StyledLegendItem, StyledLegendLabel, StyledLegendLine, StyledLegendValue, StyledLine, StyledPoint, StyledSvg, StyledTooltip, StyledTooltipHeader, StyledTooltipLabel, StyledTooltipMeta, StyledTooltipSwatch, StyledValueLabel, } from "./LineChart.styled";
|
|
29
29
|
const LineChartInner = (_a, ref) => {
|
|
30
30
|
var _b, _c, _d;
|
|
31
|
-
var { data, series, seriesLabel = "Series", width =
|
|
31
|
+
var { data, series, seriesLabel = "Series", width, height, responsive = false, aspectRatio, minWidth = 240, minHeight = 200, margin, xAxisType = "auto", curve = "monotone", lineColor, colors, colorGradient, lineWidth = 2.5, lineOpacity = 1, lineDasharray, showArea = false, areaColor, areaOpacity = 0.14, showPoints = false, pointRadius = 3, activePointRadius = 4, pointColor, pointBorderColor, pointBorderWidth = 1.5, pointOpacity = 1, yMin, yMax, xTickCount = 6, yTickCount = 5, showGridLines = true, showAxisLines = true, showXAxisLabels = true, showYAxisLabels = true, showLegend = false, showLabels = false, emptyLabel = "No data", ariaLabel = "Line chart", animateOnRender = false, animationDuration = 720, showExportButton = false, exportFileName = "line-chart", exportFormats = DEFAULT_CHART_EXPORT_FORMATS, exportScale = 2, exportBackgroundColor, showTooltips = false, valueFormatter, xValueFormatter, xTickFormatter, yTickFormatter, labelFormatter, tooltipFormatter, onPointClick, className } = _a, props = __rest(_a, ["data", "series", "seriesLabel", "width", "height", "responsive", "aspectRatio", "minWidth", "minHeight", "margin", "xAxisType", "curve", "lineColor", "colors", "colorGradient", "lineWidth", "lineOpacity", "lineDasharray", "showArea", "areaColor", "areaOpacity", "showPoints", "pointRadius", "activePointRadius", "pointColor", "pointBorderColor", "pointBorderWidth", "pointOpacity", "yMin", "yMax", "xTickCount", "yTickCount", "showGridLines", "showAxisLines", "showXAxisLabels", "showYAxisLabels", "showLegend", "showLabels", "emptyLabel", "ariaLabel", "animateOnRender", "animationDuration", "showExportButton", "exportFileName", "exportFormats", "exportScale", "exportBackgroundColor", "showTooltips", "valueFormatter", "xValueFormatter", "xTickFormatter", "yTickFormatter", "labelFormatter", "tooltipFormatter", "onPointClick", "className"]);
|
|
32
32
|
const descriptionId = useId();
|
|
33
33
|
const gradientBaseId = useId();
|
|
34
34
|
const theme = useTheme();
|
|
35
35
|
const containerRef = useRef(null);
|
|
36
|
+
const chartSizeRef = useRef(null);
|
|
36
37
|
const chartFrameRef = useRef(null);
|
|
37
38
|
const svgRef = useRef(null);
|
|
38
39
|
const tooltipRef = useRef(null);
|
|
@@ -46,8 +47,18 @@ const LineChartInner = (_a, ref) => {
|
|
|
46
47
|
const themeLineColor = useThemeColor(lineColor);
|
|
47
48
|
const themeColors = useThemeColors(colors);
|
|
48
49
|
const resolvedMargin = mergeChartMargin(margin, showXAxisLabels, showYAxisLabels, showLabels);
|
|
49
|
-
const
|
|
50
|
-
|
|
50
|
+
const chartSize = useChartResponsiveSize(chartSizeRef, {
|
|
51
|
+
width,
|
|
52
|
+
height,
|
|
53
|
+
responsive,
|
|
54
|
+
aspectRatio,
|
|
55
|
+
defaultWidth: 720,
|
|
56
|
+
defaultHeight: 320,
|
|
57
|
+
minWidth: Math.max(minWidth, 1),
|
|
58
|
+
minHeight: Math.max(minHeight, 1),
|
|
59
|
+
});
|
|
60
|
+
const safeWidth = chartSize.width;
|
|
61
|
+
const safeHeight = chartSize.height;
|
|
51
62
|
const plotWidth = Math.max(safeWidth - resolvedMargin.left - resolvedMargin.right, 1);
|
|
52
63
|
const plotHeight = Math.max(safeHeight - resolvedMargin.top - resolvedMargin.bottom, 1);
|
|
53
64
|
const resolvedGlobalLineWidth = Math.max(lineWidth, 1);
|
|
@@ -207,7 +218,7 @@ const LineChartInner = (_a, ref) => {
|
|
|
207
218
|
if (resolvedXAxisType !== "time")
|
|
208
219
|
return null;
|
|
209
220
|
const timeValues = allPoints
|
|
210
|
-
.map((point) =>
|
|
221
|
+
.map((point) => point.parsedX instanceof Date ? point.parsedX.getTime() : null)
|
|
211
222
|
.filter((value) => value != null);
|
|
212
223
|
const min = Math.min(...timeValues);
|
|
213
224
|
const max = Math.max(...timeValues);
|
|
@@ -289,7 +300,8 @@ const LineChartInner = (_a, ref) => {
|
|
|
289
300
|
}, [renderedSeries, renderedSeriesKey]);
|
|
290
301
|
useLayoutEffect(() => {
|
|
291
302
|
var _a;
|
|
292
|
-
if (!animateOnRender ||
|
|
303
|
+
if (!animateOnRender ||
|
|
304
|
+
renderedSeries.every((seriesEntry) => !seriesEntry.linePath)) {
|
|
293
305
|
setAnimationProgress(1);
|
|
294
306
|
return;
|
|
295
307
|
}
|
|
@@ -307,7 +319,9 @@ const LineChartInner = (_a, ref) => {
|
|
|
307
319
|
if (startTime == null)
|
|
308
320
|
startTime = timestamp;
|
|
309
321
|
const elapsed = timestamp - startTime;
|
|
310
|
-
const progress = safeDuration === 0
|
|
322
|
+
const progress = safeDuration === 0
|
|
323
|
+
? 1
|
|
324
|
+
: easeOutCubic(clamp(elapsed / safeDuration, 0, 1));
|
|
311
325
|
setAnimationProgress(progress);
|
|
312
326
|
if (progress < 1) {
|
|
313
327
|
animationFrame = window.requestAnimationFrame(runAnimation);
|
|
@@ -337,7 +351,10 @@ const LineChartInner = (_a, ref) => {
|
|
|
337
351
|
const yTicks = useMemo(() => Array.from(new Set(yScale
|
|
338
352
|
.ticks(Math.max(yTickCount, 2))
|
|
339
353
|
.map((tick) => normalizeTickValue(tick)))), [yScale, yTickCount]);
|
|
340
|
-
const formatValue = (datum, sourceSeries) => {
|
|
354
|
+
const formatValue = (datum, sourceSeries) => {
|
|
355
|
+
var _a;
|
|
356
|
+
return (_a = valueFormatter === null || valueFormatter === void 0 ? void 0 : valueFormatter(datum.y, datum, sourceSeries)) !== null && _a !== void 0 ? _a : formatDefaultValue(datum.y);
|
|
357
|
+
};
|
|
341
358
|
const formatXValue = (datum, sourceSeries) => {
|
|
342
359
|
var _a;
|
|
343
360
|
return (_a = xValueFormatter === null || xValueFormatter === void 0 ? void 0 : xValueFormatter(datum.x, datum, sourceSeries)) !== null && _a !== void 0 ? _a : (datum.x instanceof Date ? datum.x.toLocaleDateString() : String(datum.x));
|
|
@@ -428,7 +445,7 @@ const LineChartInner = (_a, ref) => {
|
|
|
428
445
|
.join(", ");
|
|
429
446
|
const shouldAnimateStroke = animateOnRender && animationProgress < 1;
|
|
430
447
|
const shouldShowDataLabels = showLabels && allPoints.length <= 24;
|
|
431
|
-
return (_jsxs(StyledContainer, Object.assign({ ref: containerRef, className: className }, props, { children: [allPoints.length === 0 ? (_jsx(StyledEmptyState, { "$width": safeWidth, "$height": safeHeight, children: emptyLabel })) : (
|
|
448
|
+
return (_jsxs(StyledContainer, Object.assign({ ref: containerRef, className: className, "$fillAvailableWidth": chartSize.fillAvailableWidth }, props, { children: [_jsx(StyledChartScroller, { ref: chartSizeRef, "$width": chartSize.widthStyle, "$height": chartSize.heightStyle, children: allPoints.length === 0 ? (_jsx(StyledEmptyState, { "$width": safeWidth, "$height": safeHeight, children: emptyLabel })) : (_jsxs(StyledChartFrame, { ref: chartFrameRef, children: [showExportButton && exportFormats.length > 0 && (_jsx(StyledChartActions, { "data-chart-export-ignore": "true", children: _jsx(ChartExportControl, { rootRef: containerRef, svgRef: svgRef, fileName: exportFileName, formats: exportFormats, scale: exportScale, backgroundColor: resolvedExportBackgroundColor }) })), _jsxs(StyledSvg, { ref: svgRef, width: safeWidth, height: safeHeight, viewBox: `0 0 ${safeWidth} ${safeHeight}`, role: "img", "aria-label": ariaLabel, "aria-describedby": descriptionId, children: [_jsx("desc", { id: descriptionId, children: description }), _jsx("defs", { children: renderedSeries
|
|
432
449
|
.filter((seriesEntry) => { var _a; return (_a = seriesEntry.gradientStops) === null || _a === void 0 ? void 0 : _a.length; })
|
|
433
450
|
.map((seriesEntry) => {
|
|
434
451
|
var _a;
|
|
@@ -437,7 +454,8 @@ const LineChartInner = (_a, ref) => {
|
|
|
437
454
|
return (_jsx("stop", { offset: `${((_a = seriesEntry.gradientStops) !== null && _a !== void 0 ? _a : []).length === 1
|
|
438
455
|
? 100
|
|
439
456
|
: (index /
|
|
440
|
-
(((_b = seriesEntry.gradientStops) !== null && _b !== void 0 ? _b : []).length -
|
|
457
|
+
(((_b = seriesEntry.gradientStops) !== null && _b !== void 0 ? _b : []).length -
|
|
458
|
+
1)) *
|
|
441
459
|
100}%`, stopColor: stop }, `${stop}-${index}`));
|
|
442
460
|
}) }, seriesEntry.gradientId));
|
|
443
461
|
}) }), showGridLines &&
|
|
@@ -446,10 +464,10 @@ const LineChartInner = (_a, ref) => {
|
|
|
446
464
|
xTicks.map((tick, index) => {
|
|
447
465
|
var _a, _b, _c;
|
|
448
466
|
const x = resolvedXAxisType === "time"
|
|
449
|
-
? (_a = timeScale === null || timeScale === void 0 ? void 0 : timeScale(tick)) !== null && _a !== void 0 ? _a : 0
|
|
467
|
+
? ((_a = timeScale === null || timeScale === void 0 ? void 0 : timeScale(tick)) !== null && _a !== void 0 ? _a : 0)
|
|
450
468
|
: resolvedXAxisType === "linear"
|
|
451
|
-
? (_b = linearScale === null || linearScale === void 0 ? void 0 : linearScale(tick)) !== null && _b !== void 0 ? _b : 0
|
|
452
|
-
: (_c = pointScale === null || pointScale === void 0 ? void 0 : pointScale(String(tick))) !== null && _c !== void 0 ? _c : 0;
|
|
469
|
+
? ((_b = linearScale === null || linearScale === void 0 ? void 0 : linearScale(tick)) !== null && _b !== void 0 ? _b : 0)
|
|
470
|
+
: ((_c = pointScale === null || pointScale === void 0 ? void 0 : pointScale(String(tick))) !== null && _c !== void 0 ? _c : 0);
|
|
453
471
|
return (_jsx(StyledAxisText, { x: resolvedMargin.left + x, y: resolvedMargin.top + plotHeight + 20, textAnchor: "middle", children: formatXTick(tick) }, `tick-x-${index}`));
|
|
454
472
|
}), _jsxs("g", { transform: `translate(${resolvedMargin.left}, ${resolvedMargin.top})`, children: [_jsx(StyledHoverTarget, { x: 0, y: 0, width: plotWidth, height: plotHeight, onMouseEnter: (event) => {
|
|
455
473
|
if (!showTooltips && !showPoints && !onPointClick)
|
|
@@ -488,7 +506,8 @@ const LineChartInner = (_a, ref) => {
|
|
|
488
506
|
: undefined,
|
|
489
507
|
opacity: isSeriesDimmed ? 0.7 : 1,
|
|
490
508
|
} })), seriesEntry.linePath && (_jsx(StyledLine, { "$active": isSeriesActive, "$dimmed": isSeriesDimmed, ref: (node) => {
|
|
491
|
-
linePathRefs.current[String(seriesEntry.key)] =
|
|
509
|
+
linePathRefs.current[String(seriesEntry.key)] =
|
|
510
|
+
node;
|
|
492
511
|
}, d: seriesEntry.linePath, stroke: gradientReference, strokeWidth: isSeriesActive
|
|
493
512
|
? seriesEntry.lineWidth + 0.8
|
|
494
513
|
: seriesEntry.lineWidth, strokeOpacity: seriesEntry.lineOpacity, strokeDasharray: shouldAnimateStroke && lineLength > 0
|
|
@@ -518,7 +537,7 @@ const LineChartInner = (_a, ref) => {
|
|
|
518
537
|
renderedSeries.map((seriesEntry) => seriesEntry.points.map((point) => {
|
|
519
538
|
var _a;
|
|
520
539
|
return (_jsx(StyledValueLabel, { x: getPointX(point), y: getPointY(point) - 10, textAnchor: "middle", children: (_a = labelFormatter === null || labelFormatter === void 0 ? void 0 : labelFormatter(point, point.index, seriesEntry.sourceSeries)) !== null && _a !== void 0 ? _a : formatValue(point, seriesEntry.sourceSeries) }, `label-${point.key}`));
|
|
521
|
-
}))] })] })] }) })
|
|
540
|
+
}))] })] })] })) }), activeTooltip && activePoint && activeSeries && tooltipStyle && (_jsx(StyledTooltip, { ref: tooltipRef, style: tooltipStyle, children: tooltipFormatter ? (tooltipFormatter(activePoint, activePoint.index, activeSeries.sourceSeries)) : (_jsxs(_Fragment, { children: [_jsxs(StyledTooltipHeader, { children: [_jsx(StyledTooltipSwatch, { "$color": (_d = activePoint.color) !== null && _d !== void 0 ? _d : activeSeries.pointColor }), _jsx(StyledTooltipLabel, { children: formatXValue(activePoint, activeSeries.sourceSeries) })] }), _jsxs(StyledTooltipMeta, { children: [_jsx("span", { children: activePoint.seriesLabel }), _jsx("span", { children: formatValue(activePoint, activeSeries.sourceSeries) })] })] })) })), showLegend && (_jsx(StyledLegend, { children: renderedSeries.map((seriesEntry) => {
|
|
522
541
|
const latestPoint = seriesEntry.points[seriesEntry.points.length - 1];
|
|
523
542
|
if (!latestPoint)
|
|
524
543
|
return null;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { StyledChartActions } from "../ChartPrimitives";
|
|
2
|
-
export declare const StyledContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").
|
|
3
|
-
|
|
2
|
+
export declare const StyledContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
3
|
+
$fillAvailableWidth: boolean;
|
|
4
|
+
}>> & string;
|
|
5
|
+
export declare const StyledChartScroller: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
6
|
+
$width?: string;
|
|
7
|
+
$height?: string;
|
|
8
|
+
}>> & string;
|
|
4
9
|
export declare const StyledChartFrame: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
5
10
|
export { StyledChartActions };
|
|
6
11
|
export declare const StyledSvg: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").SVGProps<SVGSVGElement>, never>> & string;
|
|
@@ -10,7 +10,7 @@ export const StyledContainer = styled.div `
|
|
|
10
10
|
align-items: flex-start;
|
|
11
11
|
flex-wrap: wrap;
|
|
12
12
|
gap: 20px;
|
|
13
|
-
width: fit-content;
|
|
13
|
+
width: ${({ $fillAvailableWidth }) => $fillAvailableWidth ? "100%" : "fit-content"};
|
|
14
14
|
max-width: 100%;
|
|
15
15
|
color: ${({ theme }) => theme.palette.text.primary};
|
|
16
16
|
box-sizing: border-box;
|
|
@@ -18,10 +18,13 @@ export const StyledContainer = styled.div `
|
|
|
18
18
|
`;
|
|
19
19
|
export const StyledChartScroller = styled.div `
|
|
20
20
|
display: flex;
|
|
21
|
+
width: ${({ $width }) => $width !== null && $width !== void 0 ? $width : "auto"};
|
|
22
|
+
height: ${({ $height }) => $height !== null && $height !== void 0 ? $height : "auto"};
|
|
21
23
|
max-width: 100%;
|
|
22
24
|
overflow-x: auto;
|
|
23
25
|
overflow-y: visible;
|
|
24
26
|
padding-bottom: 2px;
|
|
27
|
+
box-sizing: border-box;
|
|
25
28
|
`;
|
|
26
29
|
export const StyledChartFrame = styled.div `
|
|
27
30
|
position: relative;
|
|
@@ -120,6 +123,7 @@ export const StyledEmptyState = styled.div `
|
|
|
120
123
|
justify-content: center;
|
|
121
124
|
width: ${({ $width }) => $width}px;
|
|
122
125
|
height: ${({ $height }) => $height}px;
|
|
126
|
+
box-sizing: border-box;
|
|
123
127
|
border: 1px dashed ${({ theme }) => theme.palette.divider};
|
|
124
128
|
border-radius: 8px;
|
|
125
129
|
background: linear-gradient(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { HTMLAttributes } from "react";
|
|
2
|
-
import type { ChartExportOptions } from "../ChartUtils";
|
|
2
|
+
import type { ChartDimension, ChartExportOptions } from "../ChartUtils";
|
|
3
3
|
export type LineChartDatum<TData = unknown> = {
|
|
4
4
|
/** Stable identifier for the point. Falls back to x and index when omitted. */
|
|
5
5
|
id?: string | number;
|
|
@@ -104,10 +104,18 @@ export type LineChartProps<TData = unknown> = HTMLAttributes<HTMLDivElement> & C
|
|
|
104
104
|
series?: LineChartSeries<TData>[];
|
|
105
105
|
/** Label used for the single-line variant in legend and tooltip context. */
|
|
106
106
|
seriesLabel?: React.ReactNode;
|
|
107
|
-
/** SVG width in pixels. Defaults to 720. */
|
|
108
|
-
width?:
|
|
109
|
-
/** SVG height in pixels. Defaults to 320. */
|
|
110
|
-
height?:
|
|
107
|
+
/** SVG width in pixels or any CSS length measured from the chart frame. Defaults to 720. */
|
|
108
|
+
width?: ChartDimension;
|
|
109
|
+
/** SVG height in pixels or any CSS length measured from the chart frame. Defaults to 320. */
|
|
110
|
+
height?: ChartDimension;
|
|
111
|
+
/** Measures the chart frame and fits the SVG width to its available space. Defaults to false. */
|
|
112
|
+
responsive?: boolean;
|
|
113
|
+
/** Calculates height from resolved width when height is omitted. */
|
|
114
|
+
aspectRatio?: number;
|
|
115
|
+
/** Minimum rendered SVG width in pixels. Defaults to 240. */
|
|
116
|
+
minWidth?: number;
|
|
117
|
+
/** Minimum rendered SVG height in pixels. Defaults to 200. */
|
|
118
|
+
minHeight?: number;
|
|
111
119
|
/** Partial chart margin overrides. Defaults are based on visible labels. */
|
|
112
120
|
margin?: Partial<LineChartMargin>;
|
|
113
121
|
/** X-axis scale type. Defaults to "auto". */
|
|
@@ -23,15 +23,16 @@ import { forwardRef, useEffect, useId, useImperativeHandle, useMemo, useRef, use
|
|
|
23
23
|
import { arc, pie } from "d3-shape";
|
|
24
24
|
import { useTheme } from "styled-components";
|
|
25
25
|
import { ChartExportControl } from "../ChartPrimitives";
|
|
26
|
-
import { DEFAULT_CHART_EXPORT_FORMATS, copyChartImage, downloadChartImage, } from "../ChartUtils";
|
|
26
|
+
import { DEFAULT_CHART_EXPORT_FORMATS, copyChartImage, downloadChartImage, useChartResponsiveSize, } from "../ChartUtils";
|
|
27
27
|
import { clamp, easeOutCubic, formatDefaultValue, getGradientColor, getSliceKey, useThemeColors, } from "./PieChart.lib";
|
|
28
28
|
import { StyledCenter, StyledCenterLabel, StyledCenterPanel, StyledCenterValue, StyledChartActions, StyledChartWrap, StyledContainer, StyledEmptyState, StyledLabel, StyledLegend, StyledLegendItem, StyledLegendLabel, StyledLegendMeta, StyledLegendPercent, StyledLegendValue, StyledSlice, StyledSvg, StyledSwatch, StyledTooltip, StyledTooltipHeader, StyledTooltipLabel, StyledTooltipMeta, StyledTooltipSwatch, } from "./PieChart.styled";
|
|
29
29
|
const PieChartInner = (_a, ref) => {
|
|
30
30
|
var _b, _c;
|
|
31
|
-
var { data, size =
|
|
31
|
+
var { data, size, responsive = false, minSize = 120, innerRadius, outerRadius, cornerRadius = 1, padAngle = 0.004, colors, colorGradient, sliceOpacity = 1, sliceBorderColor, sliceBorderWidth = 1, sliceBorderOpacity = 1, sliceBorderLineJoin = "round", showLegend = true, showLegendSwatches = true, showLegendLabels = true, showLegendValues = true, showLegendPercentages = true, showLabels = false, centerLabel, centerValue, emptyLabel = "No data", ariaLabel = "Pie chart", animateOnRender = false, animationDuration = 520, animationStagger = 35, showExportButton = false, exportFileName = "pie-chart", exportFormats = DEFAULT_CHART_EXPORT_FORMATS, exportScale = 2, exportBackgroundColor, showTooltips = false, valueFormatter, labelFormatter, tooltipFormatter, onSliceClick, onLegendItemClick, className } = _a, props = __rest(_a, ["data", "size", "responsive", "minSize", "innerRadius", "outerRadius", "cornerRadius", "padAngle", "colors", "colorGradient", "sliceOpacity", "sliceBorderColor", "sliceBorderWidth", "sliceBorderOpacity", "sliceBorderLineJoin", "showLegend", "showLegendSwatches", "showLegendLabels", "showLegendValues", "showLegendPercentages", "showLabels", "centerLabel", "centerValue", "emptyLabel", "ariaLabel", "animateOnRender", "animationDuration", "animationStagger", "showExportButton", "exportFileName", "exportFormats", "exportScale", "exportBackgroundColor", "showTooltips", "valueFormatter", "labelFormatter", "tooltipFormatter", "onSliceClick", "onLegendItemClick", "className"]);
|
|
32
32
|
const descriptionId = useId();
|
|
33
33
|
const theme = useTheme();
|
|
34
34
|
const containerRef = useRef(null);
|
|
35
|
+
const chartSizeRef = useRef(null);
|
|
35
36
|
const svgRef = useRef(null);
|
|
36
37
|
const [activeSliceKey, setActiveSliceKey] = useState(null);
|
|
37
38
|
const [activeTooltip, setActiveTooltip] = useState(null);
|
|
@@ -39,7 +40,21 @@ const PieChartInner = (_a, ref) => {
|
|
|
39
40
|
const themeColors = useThemeColors(colors);
|
|
40
41
|
const validData = useMemo(() => data.filter((datum) => Number.isFinite(datum.value) && datum.value > 0), [data]);
|
|
41
42
|
const total = useMemo(() => validData.reduce((sum, datum) => sum + datum.value, 0), [validData]);
|
|
42
|
-
const
|
|
43
|
+
const chartSize = useChartResponsiveSize(chartSizeRef, {
|
|
44
|
+
width: size,
|
|
45
|
+
responsive,
|
|
46
|
+
aspectRatio: 1,
|
|
47
|
+
defaultWidth: 220,
|
|
48
|
+
defaultHeight: 220,
|
|
49
|
+
minWidth: Math.max(minSize, 1),
|
|
50
|
+
minHeight: Math.max(minSize, 1),
|
|
51
|
+
});
|
|
52
|
+
const safeSize = Math.min(chartSize.width, chartSize.height);
|
|
53
|
+
const radius = outerRadius !== null && outerRadius !== void 0 ? outerRadius : Math.max(safeSize / 2 - 6, 0);
|
|
54
|
+
const shouldScaleDefaultInnerRadius = innerRadius == null && (responsive || typeof size === "string");
|
|
55
|
+
const defaultInnerRadius = shouldScaleDefaultInnerRadius
|
|
56
|
+
? Math.max(radius * (58 / 104), 0)
|
|
57
|
+
: 58;
|
|
43
58
|
const resolvedSliceOpacity = clamp(sliceOpacity, 0, 1);
|
|
44
59
|
const resolvedSliceBorderWidth = Math.max(sliceBorderWidth, 0);
|
|
45
60
|
const resolvedSliceBorderOpacity = clamp(sliceBorderOpacity, 0, 1);
|
|
@@ -69,7 +84,7 @@ const PieChartInner = (_a, ref) => {
|
|
|
69
84
|
});
|
|
70
85
|
}),
|
|
71
86
|
}), [exportFileName, exportScale, resolvedExportBackgroundColor]);
|
|
72
|
-
const resolvedInnerRadius = Math.min(innerRadius, radius - 1);
|
|
87
|
+
const resolvedInnerRadius = Math.max(Math.min(innerRadius !== null && innerRadius !== void 0 ? innerRadius : defaultInnerRadius, radius - 1), 0);
|
|
73
88
|
const centerPanelDiameter = Math.max(resolvedInnerRadius * 1.62, 52);
|
|
74
89
|
const labelRadius = resolvedInnerRadius > 0
|
|
75
90
|
? resolvedInnerRadius + (radius - resolvedInnerRadius) / 2
|
|
@@ -155,35 +170,35 @@ const PieChartInner = (_a, ref) => {
|
|
|
155
170
|
const activeTooltipSlice = showTooltips && activeTooltip
|
|
156
171
|
? slices.find((slice, index) => getSliceKey(slice.data, index) === activeTooltip.sliceKey)
|
|
157
172
|
: null;
|
|
158
|
-
return (_jsxs(StyledContainer, Object.assign({ ref: containerRef, className: className }, props, { children: [slices.length === 0 ? (_jsx(StyledEmptyState, { "$size":
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
173
|
+
return (_jsxs(StyledContainer, Object.assign({ ref: containerRef, className: className, "$fillAvailableWidth": chartSize.fillAvailableWidth }, props, { children: [_jsx(StyledChartWrap, { ref: chartSizeRef, "$width": chartSize.widthStyle, "$height": chartSize.heightStyle, children: slices.length === 0 ? (_jsx(StyledEmptyState, { "$size": safeSize, children: emptyLabel })) : (_jsxs(_Fragment, { children: [showExportButton && exportFormats.length > 0 && (_jsx(StyledChartActions, { "data-chart-export-ignore": "true", children: _jsx(ChartExportControl, { rootRef: containerRef, svgRef: svgRef, fileName: exportFileName, formats: exportFormats, scale: exportScale, backgroundColor: resolvedExportBackgroundColor }) })), _jsxs(StyledSvg, { ref: svgRef, width: safeSize, height: safeSize, viewBox: `0 0 ${safeSize} ${safeSize}`, role: "img", "aria-label": ariaLabel, "aria-describedby": descriptionId, children: [_jsx("desc", { id: descriptionId, children: slices
|
|
174
|
+
.map((slice) => `${slice.data.label}: ${formatDefaultValue(slice.data.value)}`)
|
|
175
|
+
.join(", ") }), _jsx("g", { transform: `translate(${safeSize / 2}, ${safeSize / 2})`, children: slices.map((slice, index) => {
|
|
176
|
+
var _a;
|
|
177
|
+
const sliceKey = getSliceKey(slice.data, index);
|
|
178
|
+
const sliceAnimationProgress = getSliceAnimationProgress(index);
|
|
179
|
+
const animatedSlice = Object.assign(Object.assign({}, slice), { startAngle: animationStartAngle +
|
|
180
|
+
(slice.startAngle - animationStartAngle) *
|
|
181
|
+
sliceAnimationProgress, endAngle: animationStartAngle +
|
|
182
|
+
(slice.endAngle - animationStartAngle) *
|
|
183
|
+
sliceAnimationProgress });
|
|
184
|
+
const path = arcGenerator(animatedSlice);
|
|
185
|
+
const labelPosition = labelArcGenerator.centroid(slice);
|
|
186
|
+
const percent = Math.round(slice.percent * 100);
|
|
187
|
+
return (_jsxs("g", { children: [_jsx(StyledSlice, { "$active": activeSliceKey === sliceKey, d: path !== null && path !== void 0 ? path : undefined, fill: slice.color, fillOpacity: resolvedSliceOpacity, stroke: resolvedSliceBorderColor, strokeWidth: resolvedSliceBorderWidth, strokeOpacity: resolvedSliceBorderOpacity, strokeLinejoin: sliceBorderLineJoin, tabIndex: 0, onFocus: () => setActiveSliceKey(sliceKey), onBlur: () => setActiveSliceKey(null), onMouseEnter: (event) => {
|
|
188
|
+
setActiveSliceKey(sliceKey);
|
|
189
|
+
updateTooltipPosition(event, sliceKey);
|
|
190
|
+
}, onMouseMove: (event) => updateTooltipPosition(event, sliceKey), onMouseLeave: () => {
|
|
191
|
+
setActiveSliceKey(null);
|
|
192
|
+
setActiveTooltip(null);
|
|
193
|
+
}, onClick: (event) => onSliceClick === null || onSliceClick === void 0 ? void 0 : onSliceClick(event, slice.data), onKeyDown: (event) => {
|
|
194
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
195
|
+
return;
|
|
196
|
+
event.preventDefault();
|
|
197
|
+
onSliceClick === null || onSliceClick === void 0 ? void 0 : onSliceClick(event, slice.data);
|
|
198
|
+
}, "aria-label": `${slice.data.label}: ${formatDefaultValue(slice.data.value)}, ${percent}%` }), showLabels &&
|
|
199
|
+
slice.percent >= 0.05 &&
|
|
200
|
+
sliceAnimationProgress >= 0.92 && (_jsx(StyledLabel, { x: labelPosition[0], y: labelPosition[1], textAnchor: "middle", dominantBaseline: "central", children: (_a = labelFormatter === null || labelFormatter === void 0 ? void 0 : labelFormatter(slice.data, slice.percent)) !== null && _a !== void 0 ? _a : `${percent}%` }))] }, sliceKey));
|
|
201
|
+
}) })] }), (centerLabel != null || centerValue != null) && (_jsx(StyledCenter, { children: _jsxs(StyledCenterPanel, { "$diameter": centerPanelDiameter, children: [centerValue != null && (_jsx(StyledCenterValue, { children: centerValue })), centerLabel != null && (_jsx(StyledCenterLabel, { children: centerLabel }))] }) }))] })) }), shouldShowLegend && (_jsx(StyledLegend, { children: slices.map((slice, index) => {
|
|
187
202
|
const sliceKey = getSliceKey(slice.data, index);
|
|
188
203
|
return (_jsxs(StyledLegendItem, { "$active": activeSliceKey === sliceKey, "$showSwatch": showLegendSwatches, "$showLabel": showLegendLabels, "$showMeta": showLegendMeta, tabIndex: 0, onMouseEnter: () => setActiveSliceKey(sliceKey), onMouseLeave: () => setActiveSliceKey(null), onFocus: () => setActiveSliceKey(sliceKey), onBlur: () => setActiveSliceKey(null), onClick: (event) => onLegendItemClick === null || onLegendItemClick === void 0 ? void 0 : onLegendItemClick(event, slice.data), onKeyDown: (event) => {
|
|
189
204
|
if (event.key !== "Enter" && event.key !== " ")
|