@monolith-forensics/monolith-ui 1.9.3-dev.0 → 1.9.3-dev.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/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/FieldLabel/FieldLabel.js +3 -18
- package/dist/RichTextEditor/Extensions/getSlashCommand.d.ts +23 -3
- package/dist/RichTextEditor/Extensions/getSlashCommand.js +14 -6
- package/dist/RichTextEditor/Extensions/getTiptapExtensions.d.ts +5 -2
- package/dist/RichTextEditor/Extensions/getTiptapExtensions.js +3 -1
- package/dist/RichTextEditor/RichTextEditor.d.ts +6 -3
- package/dist/RichTextEditor/RichTextEditor.js +6 -6
- package/dist/SegmentedControl/SegmentedControl.js +1 -1
- package/dist/SegmentedControl/SegmentedControl.styles.d.ts +1 -0
- package/dist/SegmentedControl/SegmentedControl.styles.js +30 -14
- package/dist/SegmentedControl/SegmentedControl.utils.d.ts +1 -0
- package/dist/SegmentedControl/SegmentedControl.utils.js +5 -2
- package/dist/Table/Table.js +4 -3
- package/dist/Table/TableComponents.d.ts +3 -0
- package/dist/Table/TableComponents.js +47 -0
- package/dist/Table/TableHeader.js +1 -1
- package/dist/Table/TableMenu/TableMenu.js +4 -3
- package/dist/Table/TableProvider.js +39 -0
- package/dist/Table/TableRow.js +1 -1
- package/dist/Table/types.d.ts +6 -0
- package/dist/Utilities/getImageTextContent.d.ts +78 -0
- package/dist/Utilities/getImageTextContent.js +222 -0
- package/dist/core/controlSizes.js +9 -9
- package/package.json +1 -1
- package/dist/RichTextEditor/Components/TableCornerMenu.d.ts +0 -16
- package/dist/RichTextEditor/Components/TableCornerMenu.js +0 -202
- package/dist/RichTextEditor/Components/TableTools.d.ts +0 -44
- package/dist/RichTextEditor/Components/TableTools.js +0 -790
|
@@ -23,15 +23,16 @@ import { scaleBand, scaleLinear } from "d3-scale";
|
|
|
23
23
|
import { forwardRef, useEffect, useId, useImperativeHandle, 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 { clamp, easeOutCubic, formatDefaultValue, getBandPadding, getBarKey, getCategoryKey, getGradientColor, getGradientColorFromStops, getGradientStops, getRoundedBarPath, getSeriesKey, getSeriesLabelText, getValueDomain, mergeChartMargin, normalizeTickValue, useThemeColors, } from "./BarChart.lib";
|
|
28
28
|
import { StyledAxisLine, StyledAxisText, StyledBar, StyledChartActions, StyledChartFrame, StyledChartScroller, StyledContainer, StyledEmptyState, StyledGridLine, StyledLegend, StyledLegendItem, StyledLegendLabel, StyledLegendValue, StyledSvg, StyledSwatch, StyledTooltip, StyledTooltipHeader, StyledTooltipLabel, StyledTooltipList, StyledTooltipMeta, StyledTooltipRow, StyledTooltipSwatch, StyledTooltipValue, StyledValueLabel, } from "./BarChart.styled";
|
|
29
29
|
const BarChartInner = (_a, ref) => {
|
|
30
30
|
var _b, _c, _d;
|
|
31
|
-
var { data, series, width =
|
|
31
|
+
var { data, series, width, height, responsive = false, aspectRatio, minWidth = 180, minHeight = 180, orientation = "vertical", seriesLayout = "grouped", margin, barGap = 10, groupBarGap, maxBarThickness, barRadius = 3, colors, colorGradient, barOpacity = 1, barBorderColor, barBorderWidth = 1, barBorderOpacity = 1, minValue, maxValue, valueTickCount = 5, showGridLines = true, showAxisLines = true, showCategoryAxisLabels = true, showValueAxisLabels = true, showLegend = false, showLegendSwatches = true, showLegendLabels = true, showLegendValues = true, showLabels = false, emptyLabel = "No data", ariaLabel = "Bar chart", animateOnRender = false, animationDuration = 520, animationStagger = 35, showExportButton = false, exportFileName = "bar-chart", exportFormats = DEFAULT_CHART_EXPORT_FORMATS, exportScale = 2, exportBackgroundColor, showTooltips = false, valueFormatter, categoryLabelFormatter, tickFormatter, labelFormatter, tooltipFormatter, onBarClick, onLegendItemClick, onSeriesLegendItemClick, className } = _a, props = __rest(_a, ["data", "series", "width", "height", "responsive", "aspectRatio", "minWidth", "minHeight", "orientation", "seriesLayout", "margin", "barGap", "groupBarGap", "maxBarThickness", "barRadius", "colors", "colorGradient", "barOpacity", "barBorderColor", "barBorderWidth", "barBorderOpacity", "minValue", "maxValue", "valueTickCount", "showGridLines", "showAxisLines", "showCategoryAxisLabels", "showValueAxisLabels", "showLegend", "showLegendSwatches", "showLegendLabels", "showLegendValues", "showLabels", "emptyLabel", "ariaLabel", "animateOnRender", "animationDuration", "animationStagger", "showExportButton", "exportFileName", "exportFormats", "exportScale", "exportBackgroundColor", "showTooltips", "valueFormatter", "categoryLabelFormatter", "tickFormatter", "labelFormatter", "tooltipFormatter", "onBarClick", "onLegendItemClick", "onSeriesLegendItemClick", "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 chartFrameRef = useRef(null);
|
|
36
37
|
const svgRef = useRef(null);
|
|
37
38
|
const tooltipRef = useRef(null);
|
|
@@ -69,8 +70,18 @@ const BarChartInner = (_a, ref) => {
|
|
|
69
70
|
},
|
|
70
71
|
];
|
|
71
72
|
}, [data, series]);
|
|
72
|
-
const
|
|
73
|
-
|
|
73
|
+
const chartSize = useChartResponsiveSize(chartSizeRef, {
|
|
74
|
+
width,
|
|
75
|
+
height,
|
|
76
|
+
responsive,
|
|
77
|
+
aspectRatio,
|
|
78
|
+
defaultWidth: 640,
|
|
79
|
+
defaultHeight: 320,
|
|
80
|
+
minWidth: Math.max(minWidth, 1),
|
|
81
|
+
minHeight: Math.max(minHeight, 1),
|
|
82
|
+
});
|
|
83
|
+
const safeWidth = chartSize.width;
|
|
84
|
+
const safeHeight = chartSize.height;
|
|
74
85
|
const safeBarRadius = Math.max(barRadius, 0);
|
|
75
86
|
const safeBarGap = Math.max(barGap, 0);
|
|
76
87
|
const safeGroupBarGap = Math.max(groupBarGap !== null && groupBarGap !== void 0 ? groupBarGap : barGap, 0);
|
|
@@ -286,8 +297,7 @@ const BarChartInner = (_a, ref) => {
|
|
|
286
297
|
}, [categories, isMultiSeries, seriesLayout]);
|
|
287
298
|
const safeAnimationDuration = Math.max(animationDuration, 0);
|
|
288
299
|
const safeAnimationStagger = Math.max(animationStagger, 0);
|
|
289
|
-
const totalAnimationDuration = safeAnimationDuration +
|
|
290
|
-
Math.max(bars.length - 1, 0) * safeAnimationStagger;
|
|
300
|
+
const totalAnimationDuration = safeAnimationDuration + Math.max(bars.length - 1, 0) * safeAnimationStagger;
|
|
291
301
|
useEffect(() => {
|
|
292
302
|
var _a;
|
|
293
303
|
if (!animateOnRender || bars.length === 0) {
|
|
@@ -329,7 +339,10 @@ const BarChartInner = (_a, ref) => {
|
|
|
329
339
|
const elapsed = animationElapsed - index * safeAnimationStagger;
|
|
330
340
|
return easeOutCubic(clamp(elapsed / safeAnimationDuration, 0, 1));
|
|
331
341
|
};
|
|
332
|
-
const formatValue = (datum, sourceSeries) => {
|
|
342
|
+
const formatValue = (datum, sourceSeries) => {
|
|
343
|
+
var _a;
|
|
344
|
+
return (_a = valueFormatter === null || valueFormatter === void 0 ? void 0 : valueFormatter(datum.value, datum, sourceSeries)) !== null && _a !== void 0 ? _a : formatDefaultValue(datum.value);
|
|
345
|
+
};
|
|
333
346
|
const formatCategoryLabel = (category) => {
|
|
334
347
|
var _a, _b;
|
|
335
348
|
return (_b = categoryLabelFormatter === null || categoryLabelFormatter === void 0 ? void 0 : categoryLabelFormatter(category.representativeDatum, category.index, (_a = category.bars[0]) === null || _a === void 0 ? void 0 : _a.sourceSeries)) !== null && _b !== void 0 ? _b : category.label;
|
|
@@ -354,10 +367,10 @@ const BarChartInner = (_a, ref) => {
|
|
|
354
367
|
});
|
|
355
368
|
};
|
|
356
369
|
const activeTooltipBar = showTooltips && activeTooltip
|
|
357
|
-
? (_c = bars.find((bar) => bar.key === activeTooltip.barKey)) !== null && _c !== void 0 ? _c : null
|
|
370
|
+
? ((_c = bars.find((bar) => bar.key === activeTooltip.barKey)) !== null && _c !== void 0 ? _c : null)
|
|
358
371
|
: null;
|
|
359
372
|
const activeTooltipCategory = isMultiSeries && activeTooltipBar
|
|
360
|
-
? (_d = categories.find((category) => category.key === activeTooltipBar.categoryKey)) !== null && _d !== void 0 ? _d : null
|
|
373
|
+
? ((_d = categories.find((category) => category.key === activeTooltipBar.categoryKey)) !== null && _d !== void 0 ? _d : null)
|
|
361
374
|
: null;
|
|
362
375
|
const tooltipStyle = useMemo(() => {
|
|
363
376
|
if (!activeTooltip ||
|
|
@@ -410,7 +423,7 @@ const BarChartInner = (_a, ref) => {
|
|
|
410
423
|
height: tooltipRef.current.offsetHeight,
|
|
411
424
|
});
|
|
412
425
|
}, [activeTooltipBar, activeTooltipCategory, isMultiSeries]);
|
|
413
|
-
return (_jsxs(StyledContainer, Object.assign({ ref: containerRef, className: className }, props, { children: [bars.length === 0 ? (_jsx(StyledEmptyState, { "$width": safeWidth, "$height": safeHeight, children: emptyLabel })) : (
|
|
426
|
+
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: bars.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 }), showGridLines &&
|
|
414
427
|
tickValues.map((tick) => {
|
|
415
428
|
const tickPosition = valueScale(tick);
|
|
416
429
|
return orientation === "vertical" ? (_jsx(StyledGridLine, { x1: resolvedMargin.left, x2: resolvedMargin.left + plotWidth, y1: resolvedMargin.top + tickPosition, y2: resolvedMargin.top + tickPosition }, `grid-${tick}`)) : (_jsx(StyledGridLine, { x1: resolvedMargin.left + tickPosition, x2: resolvedMargin.left + tickPosition, y1: resolvedMargin.top, y2: resolvedMargin.top + plotHeight }, `grid-${tick}`));
|
|
@@ -434,7 +447,8 @@ const BarChartInner = (_a, ref) => {
|
|
|
434
447
|
const endPosition = valueScale(bar.valueEnd);
|
|
435
448
|
const animatedStartPosition = zeroPosition +
|
|
436
449
|
(startPosition - zeroPosition) * animationProgress;
|
|
437
|
-
const animatedEndPosition = zeroPosition +
|
|
450
|
+
const animatedEndPosition = zeroPosition +
|
|
451
|
+
(endPosition - zeroPosition) * animationProgress;
|
|
438
452
|
const x = orientation === "vertical"
|
|
439
453
|
? resolvedMargin.left +
|
|
440
454
|
categoryBandStart +
|
|
@@ -528,7 +542,7 @@ const BarChartInner = (_a, ref) => {
|
|
|
528
542
|
categoryScale.bandwidth() / 2, y: resolvedMargin.top + plotHeight + 20, textAnchor: "middle", children: formatCategoryLabel(category) }, `category-${category.key}`)) : (_jsx(StyledAxisText, { x: resolvedMargin.left - 10, y: resolvedMargin.top +
|
|
529
543
|
((_b = categoryScale(category.key)) !== null && _b !== void 0 ? _b : 0) +
|
|
530
544
|
categoryScale.bandwidth() / 2, textAnchor: "end", dominantBaseline: "middle", children: formatCategoryLabel(category) }, `category-${category.key}`));
|
|
531
|
-
})] })] }) })
|
|
545
|
+
})] })] })) }), activeTooltip && activeTooltipBar && tooltipStyle && (_jsx(StyledTooltip, { ref: tooltipRef, style: tooltipStyle, children: tooltipFormatter ? (tooltipFormatter(activeTooltipBar, activeTooltipBar.index, activeTooltipBar.sourceSeries)) : isMultiSeries && activeTooltipCategory ? (_jsxs(_Fragment, { children: [_jsx(StyledTooltipHeader, { children: _jsx(StyledTooltipLabel, { children: activeTooltipCategory.label }) }), _jsxs(StyledTooltipMeta, { children: [formatDefaultValue(activeTooltipCategory.bars.reduce((sum, bar) => sum + bar.value, 0)), " ", "total"] }), _jsx(StyledTooltipList, { children: activeTooltipCategory.bars.map((bar) => (_jsxs(StyledTooltipRow, { children: [_jsx(StyledTooltipSwatch, { "$color": bar.color }), _jsx(StyledTooltipLabel, { children: bar.seriesLabel }), _jsx(StyledTooltipValue, { children: formatValue(bar, bar.sourceSeries) })] }, `tooltip-${bar.key}`))) })] })) : (_jsxs(_Fragment, { children: [_jsxs(StyledTooltipHeader, { children: [_jsx(StyledTooltipSwatch, { "$color": activeTooltipBar.color }), _jsx(StyledTooltipLabel, { children: activeTooltipBar.label })] }), _jsx(StyledTooltipMeta, { children: formatValue(activeTooltipBar, activeTooltipBar.sourceSeries) })] })) })), shouldShowLegend && (_jsx(StyledLegend, { children: isMultiSeries
|
|
532
546
|
? resolvedSeries.map((seriesEntry) => (_jsxs(StyledLegendItem, { "$active": activeSeriesKey === seriesEntry.key, "$showSwatch": showLegendSwatches, "$showLabel": showLegendLabels, "$showValue": showLegendValues, tabIndex: 0, onMouseEnter: () => setActiveSeriesKey(seriesEntry.key), onMouseLeave: () => setActiveSeriesKey(null), onFocus: () => setActiveSeriesKey(seriesEntry.key), onBlur: () => setActiveSeriesKey(null), onClick: (event) => seriesEntry.sourceSeries &&
|
|
533
547
|
(onSeriesLegendItemClick === null || onSeriesLegendItemClick === void 0 ? void 0 : onSeriesLegendItemClick(event, seriesEntry.sourceSeries)), onKeyDown: (event) => {
|
|
534
548
|
if (event.key !== "Enter" && event.key !== " ")
|
|
@@ -537,13 +551,13 @@ const BarChartInner = (_a, ref) => {
|
|
|
537
551
|
if (seriesEntry.sourceSeries) {
|
|
538
552
|
onSeriesLegendItemClick === null || onSeriesLegendItemClick === void 0 ? void 0 : onSeriesLegendItemClick(event, seriesEntry.sourceSeries);
|
|
539
553
|
}
|
|
540
|
-
}, children: [showLegendSwatches && _jsx(StyledSwatch, { "$color": seriesEntry.color }), showLegendLabels && (_jsx(StyledLegendLabel, { children: seriesEntry.label })), showLegendValues && (_jsx(StyledLegendValue, { children: formatSeriesValue(seriesEntry) }))] }, `legend-${seriesEntry.key}`)))
|
|
554
|
+
}, children: [showLegendSwatches && (_jsx(StyledSwatch, { "$color": seriesEntry.color })), showLegendLabels && (_jsx(StyledLegendLabel, { children: seriesEntry.label })), showLegendValues && (_jsx(StyledLegendValue, { children: formatSeriesValue(seriesEntry) }))] }, `legend-${seriesEntry.key}`)))
|
|
541
555
|
: bars.map((bar) => (_jsxs(StyledLegendItem, { "$active": activeBarKey === bar.key, "$showSwatch": showLegendSwatches, "$showLabel": showLegendLabels, "$showValue": showLegendValues, tabIndex: 0, onMouseEnter: () => setActiveBarKey(bar.key), onMouseLeave: () => setActiveBarKey(null), onFocus: () => setActiveBarKey(bar.key), onBlur: () => setActiveBarKey(null), onClick: (event) => onLegendItemClick === null || onLegendItemClick === void 0 ? void 0 : onLegendItemClick(event, bar), onKeyDown: (event) => {
|
|
542
556
|
if (event.key !== "Enter" && event.key !== " ")
|
|
543
557
|
return;
|
|
544
558
|
event.preventDefault();
|
|
545
559
|
onLegendItemClick === null || onLegendItemClick === void 0 ? void 0 : onLegendItemClick(event, bar);
|
|
546
|
-
}, children: [showLegendSwatches && _jsx(StyledSwatch, { "$color": bar.color }), showLegendLabels && _jsx(StyledLegendLabel, { children: bar.label }), showLegendValues && (_jsx(StyledLegendValue, { children: formatValue(bar, bar.sourceSeries) }))] }, bar.key))) }))] })));
|
|
560
|
+
}, children: [showLegendSwatches && _jsx(StyledSwatch, { "$color": bar.color }), showLegendLabels && (_jsx(StyledLegendLabel, { children: bar.label })), showLegendValues && (_jsx(StyledLegendValue, { children: formatValue(bar, bar.sourceSeries) }))] }, bar.key))) }))] })));
|
|
547
561
|
};
|
|
548
562
|
export const BarChart = forwardRef(BarChartInner);
|
|
549
563
|
export default BarChart;
|
|
@@ -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;
|
|
@@ -11,7 +11,7 @@ export const StyledContainer = styled.div `
|
|
|
11
11
|
align-items: flex-start;
|
|
12
12
|
flex-wrap: wrap;
|
|
13
13
|
gap: 20px;
|
|
14
|
-
width: fit-content;
|
|
14
|
+
width: ${({ $fillAvailableWidth }) => $fillAvailableWidth ? "100%" : "fit-content"};
|
|
15
15
|
max-width: 100%;
|
|
16
16
|
color: ${({ theme }) => theme.palette.text.primary};
|
|
17
17
|
box-sizing: border-box;
|
|
@@ -19,10 +19,13 @@ export const StyledContainer = styled.div `
|
|
|
19
19
|
`;
|
|
20
20
|
export const StyledChartScroller = styled.div `
|
|
21
21
|
display: flex;
|
|
22
|
+
width: ${({ $width }) => $width !== null && $width !== void 0 ? $width : "auto"};
|
|
23
|
+
height: ${({ $height }) => $height !== null && $height !== void 0 ? $height : "auto"};
|
|
22
24
|
max-width: 100%;
|
|
23
25
|
overflow-x: auto;
|
|
24
26
|
overflow-y: visible;
|
|
25
27
|
padding-bottom: 2px;
|
|
28
|
+
box-sizing: border-box;
|
|
26
29
|
`;
|
|
27
30
|
export const StyledChartFrame = styled.div `
|
|
28
31
|
position: relative;
|
|
@@ -93,6 +96,7 @@ export const StyledEmptyState = styled.div `
|
|
|
93
96
|
justify-content: center;
|
|
94
97
|
width: ${({ $width }) => $width}px;
|
|
95
98
|
height: ${({ $height }) => $height}px;
|
|
99
|
+
box-sizing: border-box;
|
|
96
100
|
border: 1px dashed ${({ theme }) => theme.palette.divider};
|
|
97
101
|
border-radius: 8px;
|
|
98
102
|
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 BarChartDatum<TData = unknown> = {
|
|
4
4
|
/** Stable identifier for the bar. Falls back to label and index when omitted. */
|
|
5
5
|
id?: string | number;
|
|
@@ -86,10 +86,18 @@ export type BarChartProps<TData = unknown> = HTMLAttributes<HTMLDivElement> & Ch
|
|
|
86
86
|
data?: BarChartDatum<TData>[];
|
|
87
87
|
/** Multi-series bar data. Takes precedence over data when provided. */
|
|
88
88
|
series?: BarChartSeries<TData>[];
|
|
89
|
-
/** SVG width in pixels. Defaults to 640. */
|
|
90
|
-
width?:
|
|
91
|
-
/** SVG height in pixels. Defaults to 320. */
|
|
92
|
-
height?:
|
|
89
|
+
/** SVG width in pixels or any CSS length measured from the chart frame. Defaults to 640. */
|
|
90
|
+
width?: ChartDimension;
|
|
91
|
+
/** SVG height in pixels or any CSS length measured from the chart frame. Defaults to 320. */
|
|
92
|
+
height?: ChartDimension;
|
|
93
|
+
/** Measures the chart frame and fits the SVG width to its available space. Defaults to false. */
|
|
94
|
+
responsive?: boolean;
|
|
95
|
+
/** Calculates height from resolved width when height is omitted. */
|
|
96
|
+
aspectRatio?: number;
|
|
97
|
+
/** Minimum rendered SVG width in pixels. Defaults to 180. */
|
|
98
|
+
minWidth?: number;
|
|
99
|
+
/** Minimum rendered SVG height in pixels. Defaults to 180. */
|
|
100
|
+
minHeight?: number;
|
|
93
101
|
/** Bar layout direction. Defaults to "vertical". */
|
|
94
102
|
orientation?: BarChartOrientation;
|
|
95
103
|
/** Multi-series layout mode. Defaults to "grouped". */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
export type ChartDimension = number | string;
|
|
3
|
+
export type ChartResponsiveSizeOptions = {
|
|
4
|
+
width?: ChartDimension;
|
|
5
|
+
height?: ChartDimension;
|
|
6
|
+
responsive?: boolean;
|
|
7
|
+
aspectRatio?: number;
|
|
8
|
+
defaultWidth: number;
|
|
9
|
+
defaultHeight: number;
|
|
10
|
+
minWidth: number;
|
|
11
|
+
minHeight: number;
|
|
12
|
+
};
|
|
13
|
+
export type ResolvedChartSize = {
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
widthStyle?: string;
|
|
17
|
+
heightStyle?: string;
|
|
18
|
+
fillAvailableWidth: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare const useChartResponsiveSize: (ref: RefObject<HTMLElement | null>, { width, height, responsive, aspectRatio, defaultWidth, defaultHeight, minWidth, minHeight, }: ChartResponsiveSizeOptions) => ResolvedChartSize;
|
|
@@ -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. */
|