@automattic/charts 4.1.1 → 4.3.0
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/CHANGELOG.md +39 -0
- package/TOKENS.md +1 -1
- package/dist/index.cjs +1335 -348
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +30 -1
- package/dist/index.d.cts +129 -8
- package/dist/index.d.ts +129 -8
- package/dist/index.js +1336 -351
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/charts/area-chart/area-chart.tsx +42 -10
- package/src/charts/area-chart/private/overlays.tsx +1 -2
- package/src/charts/area-chart/private/validate-data.ts +2 -3
- package/src/charts/area-chart/test/area-chart.test.tsx +72 -1
- package/src/charts/bar-chart/bar-chart.tsx +137 -70
- package/src/charts/bar-chart/index.ts +1 -1
- package/src/charts/bar-chart/private/band-highlight.tsx +87 -0
- package/src/charts/bar-chart/private/band-scale.ts +13 -0
- package/src/charts/bar-chart/private/band-tooltip.tsx +138 -0
- package/src/charts/bar-chart/private/comparison-bars.tsx +5 -10
- package/src/charts/bar-chart/private/index.ts +3 -0
- package/src/charts/bar-chart/private/test/band-highlight.test.tsx +135 -0
- package/src/charts/bar-chart/private/test/band-tooltip.test.ts +26 -0
- package/src/charts/bar-chart/private/test/value-domain.test.ts +100 -0
- package/src/charts/bar-chart/private/truncated-tick-component.tsx +1 -1
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +13 -40
- package/src/charts/bar-chart/private/value-domain.ts +90 -0
- package/src/charts/bar-chart/test/bar-chart-pointer-events.test.tsx +11 -23
- package/src/charts/bar-chart/test/bar-chart.test.tsx +1058 -19
- package/src/charts/bar-chart/types.ts +39 -0
- package/src/charts/bar-list-chart/bar-list-chart.tsx +5 -3
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +1 -1
- package/src/charts/conversion-funnel-chart/types.ts +4 -2
- package/src/charts/geo-chart/types.ts +4 -2
- package/src/charts/heatmap-chart/build-calendar-data.ts +5 -11
- package/src/charts/heatmap-chart/build-month-calendar-data.ts +124 -0
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +32 -0
- package/src/charts/heatmap-chart/heatmap-chart.tsx +191 -114
- package/src/charts/heatmap-chart/index.ts +6 -0
- package/src/charts/heatmap-chart/private/civil-day.ts +26 -0
- package/src/charts/heatmap-chart/private/column-groups.ts +71 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +19 -3
- package/src/charts/heatmap-chart/private/index.ts +2 -0
- package/src/charts/heatmap-chart/private/keyboard-navigation.ts +201 -0
- package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +36 -0
- package/src/charts/heatmap-chart/test/build-month-calendar-data.test.ts +194 -0
- package/src/charts/heatmap-chart/test/column-groups.test.ts +83 -0
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +428 -2
- package/src/charts/heatmap-chart/test/keyboard-navigation.test.ts +25 -0
- package/src/charts/heatmap-chart/test/use-month-calendar-heatmap-data.test.tsx +90 -0
- package/src/charts/heatmap-chart/test/zoned-month-calendar-data.test.ts +23 -0
- package/src/charts/heatmap-chart/types.ts +59 -3
- package/src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts +34 -0
- package/src/charts/leaderboard-chart/types.ts +13 -14
- package/src/charts/line-chart/line-chart.tsx +149 -36
- package/src/charts/line-chart/private/index.ts +1 -0
- package/src/charts/line-chart/private/line-chart-annotation.tsx +1 -1
- package/src/charts/line-chart/private/line-chart-glyph.tsx +17 -3
- package/src/charts/line-chart/private/nearest-pointer-events.tsx +155 -0
- package/src/charts/line-chart/test/line-chart.test.tsx +604 -9
- package/src/charts/line-chart/types.ts +4 -3
- package/src/charts/private/readings.ts +34 -0
- package/src/charts/private/test/readings.test.ts +29 -0
- package/src/charts/private/test/whole-number-ticks.test.tsx +57 -0
- package/src/charts/private/time-axis-options.ts +1 -1
- package/src/charts/private/whole-number-ticks.tsx +79 -0
- package/src/charts/private/with-responsive/with-responsive.tsx +2 -2
- package/src/charts/private/x-zoom/test/x-zoom.test.tsx +1 -3
- package/src/charts/private/x-zoom/x-zoom.tsx +1 -2
- package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +124 -0
- package/src/components/legend/hooks/use-chart-legend-items.ts +60 -2
- package/src/components/legend/private/base-legend.tsx +37 -22
- package/src/components/legend/test/legend.test.tsx +84 -0
- package/src/components/legend/types.ts +2 -0
- package/src/components/legend/utils/index.ts +0 -1
- package/src/components/tooltip/accessible-tooltip.tsx +128 -41
- package/src/components/tooltip/base-tooltip.module.scss +6 -1
- package/src/components/tooltip/private/bounded-tooltip.tsx +12 -6
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +128 -0
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +17 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +7 -0
- package/src/components/tooltip/xy-chart-tooltip.tsx +9 -10
- package/src/hooks/test/use-chart-margin.test.tsx +35 -0
- package/src/hooks/test/use-element-size.test.tsx +13 -13
- package/src/hooks/use-chart-margin.tsx +7 -2
- package/src/hooks/use-xychart-theme.ts +1 -1
- package/src/index.ts +7 -1
- package/src/providers/chart-context/global-charts-provider.tsx +1 -1
- package/src/providers/chart-context/test/chart-context.test.tsx +4 -4
- package/src/providers/chart-context/themes.ts +1 -0
- package/src/styles/test/chart-scope.test.ts +1 -1
- package/src/types.ts +14 -13
- package/src/utils/format-metric-value.ts +4 -4
- package/src/utils/get-edge-tick-widths.ts +1 -1
- package/src/utils/get-styles.ts +1 -1
- package/src/visx/types.ts +7 -10
- package/src/components/legend/utils/label-transform-factory.ts +0 -24
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getStringWidth as getStringWidth$1 } from "./visx/text/index.js";
|
|
2
2
|
import { formatNumber, formatNumberCompact } from "@automattic/number-formatters";
|
|
3
|
-
import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid, TooltipContext, XYChart, buildChartTheme } from "@visx/xychart";
|
|
3
|
+
import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid, TooltipContext, XYChart, buildChartTheme, useEventEmitter } from "@visx/xychart";
|
|
4
4
|
import { __, _x, sprintf } from "@wordpress/i18n";
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import * as React from "react";
|
|
@@ -12,7 +12,7 @@ import { Text, getStringWidth } from "@visx/text";
|
|
|
12
12
|
import deepmerge from "deepmerge";
|
|
13
13
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { Tooltip, defaultStyles, useTooltip } from "@visx/tooltip";
|
|
15
|
-
import { createScale, getTicks, scaleBand, scaleOrdinal, scaleTime } from "@visx/scale";
|
|
15
|
+
import { createScale, getTicks, scaleBand, scaleCanBeZeroed, scaleOrdinal, scaleTime } from "@visx/scale";
|
|
16
16
|
import { Group } from "@visx/group";
|
|
17
17
|
import { LegendItem, LegendLabel, LegendOrdinal, LegendShape } from "@visx/legend";
|
|
18
18
|
import { IconButton, Stack, Text as Text$1 } from "@wordpress/ui";
|
|
@@ -21,6 +21,7 @@ import { LinearGradient } from "@visx/gradient";
|
|
|
21
21
|
import { curveCatmullRom, curveLinear, curveMonotoneX } from "@visx/curve";
|
|
22
22
|
import { useParentSize } from "@visx/responsive";
|
|
23
23
|
import { Annotation, CircleSubject, Connector, HtmlLabel, Label, LineSubject } from "@visx/annotation";
|
|
24
|
+
import { bisector } from "@visx/vendor/d3-array";
|
|
24
25
|
import { PatternCircles, PatternHexagons, PatternLines, PatternWaves } from "@visx/pattern";
|
|
25
26
|
import { Chart } from "react-google-charts";
|
|
26
27
|
import DOMPurify from "dompurify";
|
|
@@ -981,7 +982,8 @@ const defaultTheme = {
|
|
|
981
982
|
},
|
|
982
983
|
heatmapChart: {
|
|
983
984
|
compactCellGap: 2,
|
|
984
|
-
compactCellSize: 11
|
|
985
|
+
compactCellSize: 11,
|
|
986
|
+
groupGap: 24
|
|
985
987
|
}
|
|
986
988
|
};
|
|
987
989
|
//#endregion
|
|
@@ -1073,7 +1075,7 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
|
1073
1075
|
return getChartColor(index, colorCache);
|
|
1074
1076
|
}, [colorCache, groupToColorMap]);
|
|
1075
1077
|
const getElementStyles = useCallback(({ data, index, overrideColor, legendShape }) => {
|
|
1076
|
-
const isSeriesData = data && typeof data === "object" && "data" in data
|
|
1078
|
+
const isSeriesData = data && typeof data === "object" && "data" in data;
|
|
1077
1079
|
const isPointPercentageData = data && typeof data === "object" && "value" in data && typeof data.value === "number" && !("data" in data);
|
|
1078
1080
|
return {
|
|
1079
1081
|
color: resolveColor({
|
|
@@ -1454,8 +1456,9 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1454
1456
|
const allDataPoints = data.flatMap((series) => series.data);
|
|
1455
1457
|
if (horizontal) return allDataPoints.map((d) => d.label || d.date?.getTime());
|
|
1456
1458
|
if (options.axis?.y?.tickValues?.length) return options.axis.y.tickValues;
|
|
1457
|
-
const
|
|
1458
|
-
const
|
|
1459
|
+
const values = allDataPoints.map((d) => d.value).filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
1460
|
+
const minY = values.length ? Math.min(...values) : 0;
|
|
1461
|
+
const maxY = values.length ? Math.max(...values) : 1;
|
|
1459
1462
|
const yScale = createScale({
|
|
1460
1463
|
...options.yScale,
|
|
1461
1464
|
domain: options.yScale?.domain ?? [minY, maxY],
|
|
@@ -1790,23 +1793,6 @@ function valueOrIdentityString(_) {
|
|
|
1790
1793
|
return String(valueOrIdentity(_));
|
|
1791
1794
|
}
|
|
1792
1795
|
//#endregion
|
|
1793
|
-
//#region src/components/legend/utils/label-transform-factory.ts
|
|
1794
|
-
/**
|
|
1795
|
-
* Returns a function which takes a Datum and index as input, and returns a formatted label object.
|
|
1796
|
-
* @param {object} root0 - The object to return the value of.
|
|
1797
|
-
* @param {AnyD3Scale} root0.scale - The scale to use.
|
|
1798
|
-
* @param {LabelFormatter<ScaleInput<Scale>>} root0.labelFormat - The label format to use.
|
|
1799
|
-
* @return {ItemTransformer<ScaleInput<Scale>, ReturnType<Scale>>} The label transform factory.
|
|
1800
|
-
*/
|
|
1801
|
-
function labelTransformFactory({ scale, labelFormat }) {
|
|
1802
|
-
return (d, i) => ({
|
|
1803
|
-
datum: d,
|
|
1804
|
-
index: i,
|
|
1805
|
-
text: `${labelFormat(d, i)}`,
|
|
1806
|
-
value: scale(d)
|
|
1807
|
-
});
|
|
1808
|
-
}
|
|
1809
|
-
//#endregion
|
|
1810
1796
|
//#region src/components/legend/private/base-legend.module.scss
|
|
1811
1797
|
var base_legend_module_default = {
|
|
1812
1798
|
"legend": "a8ccharts-04TogW-legend",
|
|
@@ -1848,7 +1834,7 @@ const getLegendItemAriaLabel = (text, value, visible, interactive) => {
|
|
|
1848
1834
|
if (visible) return;
|
|
1849
1835
|
return sprintf(_x("%s: hidden", "hidden non-interactive legend item", "jetpack-charts"), accessibleText);
|
|
1850
1836
|
};
|
|
1851
|
-
const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", alignment = "center", shape = "rect", fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform
|
|
1837
|
+
const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", alignment = "center", shape = "rect", fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform, itemStyles, itemClassName, labelStyles, labelClassName, shapeStyles, render, interactive = false, chartId }, ref) => {
|
|
1852
1838
|
const { margin: itemMargin = "0", flexDirection: itemDirection = "row" } = itemStyles ?? {};
|
|
1853
1839
|
const { justifyContent: labelJustifyContent = "flex-start", flex: labelFlex = "0 0 auto", margin: labelMargin = "0 4px", maxWidth, textOverflow = "wrap" } = labelStyles ?? {};
|
|
1854
1840
|
const { width: shapeWidth = 16, height: shapeHeight = 16, margin: shapeMargin = "2px 4px 2px 0" } = shapeStyles ?? {};
|
|
@@ -1856,11 +1842,17 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
|
|
|
1856
1842
|
const context = useContext(GlobalChartsContext);
|
|
1857
1843
|
const chartInstanceContext = useContext(ChartInstanceContext);
|
|
1858
1844
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
1845
|
+
const domain = items.map((item) => item.label);
|
|
1859
1846
|
const legendScale = scaleOrdinal({
|
|
1860
|
-
domain
|
|
1847
|
+
domain,
|
|
1861
1848
|
range: items.map((item) => item.color)
|
|
1862
1849
|
});
|
|
1863
|
-
const
|
|
1850
|
+
const defaultLabelTransform = useCallback(({ labelFormat: format }) => (datum, index) => ({
|
|
1851
|
+
datum,
|
|
1852
|
+
index,
|
|
1853
|
+
text: String(format(datum, index)),
|
|
1854
|
+
value: items[index].color
|
|
1855
|
+
}), [items]);
|
|
1864
1856
|
const getShapeStyle = useCallback(({ index }) => items[index]?.shapeStyle, [items]);
|
|
1865
1857
|
const handleLegendClick = useCallback((seriesLabels) => {
|
|
1866
1858
|
if (interactive && chartId && context) {
|
|
@@ -1881,24 +1873,26 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
|
|
|
1881
1873
|
chartInstanceContext,
|
|
1882
1874
|
context
|
|
1883
1875
|
]);
|
|
1884
|
-
const createClickHandler = useCallback((seriesLabels) => {
|
|
1885
|
-
if (!
|
|
1876
|
+
const createClickHandler = useCallback((seriesLabels, itemInteractive) => {
|
|
1877
|
+
if (!itemInteractive) return;
|
|
1886
1878
|
return () => handleLegendClick(seriesLabels);
|
|
1887
|
-
}, [
|
|
1888
|
-
const createKeyDownHandler = useCallback((seriesLabels) => {
|
|
1889
|
-
if (!
|
|
1879
|
+
}, [handleLegendClick]);
|
|
1880
|
+
const createKeyDownHandler = useCallback((seriesLabels, itemInteractive) => {
|
|
1881
|
+
if (!itemInteractive) return;
|
|
1890
1882
|
return (event) => {
|
|
1891
1883
|
if (event.key === "Enter" || event.key === " ") {
|
|
1892
1884
|
event.preventDefault();
|
|
1893
1885
|
handleLegendClick(seriesLabels);
|
|
1894
1886
|
}
|
|
1895
1887
|
};
|
|
1896
|
-
}, [
|
|
1888
|
+
}, [handleLegendClick]);
|
|
1897
1889
|
const flexAlignment = ALIGNMENT_TO_FLEX[alignment] ?? "center";
|
|
1890
|
+
const staticItemRole = interactive ? void 0 : "listitem";
|
|
1898
1891
|
return render ? render(items) : /* @__PURE__ */ jsx(LegendOrdinal, {
|
|
1899
1892
|
scale: legendScale,
|
|
1893
|
+
domain,
|
|
1900
1894
|
labelFormat,
|
|
1901
|
-
labelTransform,
|
|
1895
|
+
labelTransform: labelTransform ?? defaultLabelTransform,
|
|
1902
1896
|
children: (labels) => /* @__PURE__ */ jsx(Stack, {
|
|
1903
1897
|
ref,
|
|
1904
1898
|
direction: orientation === "vertical" ? "column" : "row",
|
|
@@ -1912,19 +1906,20 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
|
|
|
1912
1906
|
children: labels.map((label, i) => {
|
|
1913
1907
|
const matchedItem = items[i];
|
|
1914
1908
|
const seriesLabels = matchedItem?.seriesLabels?.length ? matchedItem.seriesLabels : [label.text];
|
|
1915
|
-
const visible = isSeriesVisible(seriesLabels[0]);
|
|
1916
|
-
const
|
|
1917
|
-
const
|
|
1909
|
+
const visible = matchedItem?.interactive === false || isSeriesVisible(seriesLabels[0]);
|
|
1910
|
+
const itemInteractive = interactive && matchedItem?.interactive !== false;
|
|
1911
|
+
const handleClick = createClickHandler(seriesLabels, itemInteractive);
|
|
1912
|
+
const handleKeyDown = createKeyDownHandler(seriesLabels, itemInteractive);
|
|
1918
1913
|
return /* @__PURE__ */ jsxs(LegendItem, {
|
|
1919
|
-
className: clsx("visx-legend-item", base_legend_module_default["legend-item"],
|
|
1914
|
+
className: clsx("visx-legend-item", base_legend_module_default["legend-item"], itemInteractive && base_legend_module_default["legend-item--interactive"], !visible && base_legend_module_default["legend-item--inactive"], itemClassName),
|
|
1920
1915
|
margin: itemMargin,
|
|
1921
1916
|
flexDirection: orientation === "vertical" && alignment === "end" ? "row-reverse" : itemDirection,
|
|
1922
1917
|
onClick: handleClick,
|
|
1923
1918
|
onKeyDown: handleKeyDown,
|
|
1924
|
-
role:
|
|
1925
|
-
tabIndex:
|
|
1926
|
-
"aria-pressed":
|
|
1927
|
-
"aria-label": getLegendItemAriaLabel(label.text, matchedItem?.value, visible,
|
|
1919
|
+
role: itemInteractive ? "button" : staticItemRole,
|
|
1920
|
+
tabIndex: itemInteractive ? 0 : void 0,
|
|
1921
|
+
"aria-pressed": itemInteractive ? visible : void 0,
|
|
1922
|
+
"aria-label": getLegendItemAriaLabel(label.text, matchedItem?.value, visible, itemInteractive),
|
|
1928
1923
|
children: [items[i]?.renderGlyph ? /* @__PURE__ */ jsx("svg", {
|
|
1929
1924
|
width: items[i]?.glyphSize * 2,
|
|
1930
1925
|
height: items[i]?.glyphSize * 2,
|
|
@@ -2126,6 +2121,32 @@ function processSeriesData(seriesData, getElementStyles, showValues, withGlyph,
|
|
|
2126
2121
|
});
|
|
2127
2122
|
}
|
|
2128
2123
|
/**
|
|
2124
|
+
* Builds the static item that names the comparison overlay, styled like its first series.
|
|
2125
|
+
* Skipped when a comparison series already has an item of its own, so nothing is listed twice.
|
|
2126
|
+
* @param seriesData - The series data to search for a comparison series
|
|
2127
|
+
* @param items - The legend items already built from the series
|
|
2128
|
+
* @param label - The item label
|
|
2129
|
+
* @param getElementStyles - Function to get element styles
|
|
2130
|
+
* @param legendShape - The shape type for legend items (string literal or React component)
|
|
2131
|
+
* @return The legend item, or null when it would add nothing
|
|
2132
|
+
*/
|
|
2133
|
+
function buildComparisonLegendItem(seriesData, items, label, getElementStyles, legendShape) {
|
|
2134
|
+
const itemLabels = new Set(items.map((item) => item.label));
|
|
2135
|
+
const index = seriesData.findIndex((series) => series.options?.type === "comparison" && !itemLabels.has(series.label));
|
|
2136
|
+
if (index === -1) return null;
|
|
2137
|
+
const { color, shapeStyles } = getElementStyles({
|
|
2138
|
+
data: seriesData[index],
|
|
2139
|
+
index,
|
|
2140
|
+
legendShape
|
|
2141
|
+
});
|
|
2142
|
+
return {
|
|
2143
|
+
label,
|
|
2144
|
+
color,
|
|
2145
|
+
shapeStyle: shapeStyles,
|
|
2146
|
+
interactive: false
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
/**
|
|
2129
2150
|
* Processes point data into legend items
|
|
2130
2151
|
* @param pointData - The point data to process
|
|
2131
2152
|
* @param getElementStyles - Function to get element styles
|
|
@@ -2161,11 +2182,16 @@ function processPointData(pointData, getElementStyles, showValues, legendValueDi
|
|
|
2161
2182
|
* @return Array of legend items ready for display
|
|
2162
2183
|
*/
|
|
2163
2184
|
function useChartLegendItems(data, options = {}, legendShape) {
|
|
2164
|
-
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, renderGlyph } = options;
|
|
2185
|
+
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, renderGlyph } = options;
|
|
2165
2186
|
const { getElementStyles } = useGlobalChartsContext();
|
|
2166
2187
|
return useMemo(() => {
|
|
2167
2188
|
if (!data || !Array.isArray(data) || data.length === 0) return [];
|
|
2168
|
-
if ("data" in data[0])
|
|
2189
|
+
if ("data" in data[0]) {
|
|
2190
|
+
const seriesData = data;
|
|
2191
|
+
const items = processSeriesData(seriesData, getElementStyles, showValues, withGlyph, glyphSize, collapseGroups, renderGlyph, legendShape);
|
|
2192
|
+
const comparison = comparisonItem ? buildComparisonLegendItem(seriesData, items, typeof comparisonItem === "string" ? comparisonItem : __("Comparison period", "jetpack-charts"), getElementStyles, legendShape) : null;
|
|
2193
|
+
return comparison ? [...items, comparison] : items;
|
|
2194
|
+
}
|
|
2169
2195
|
return processPointData(data, getElementStyles, showValues, legendValueDisplay, withGlyph, glyphSize, renderGlyph, legendShape);
|
|
2170
2196
|
}, [
|
|
2171
2197
|
data,
|
|
@@ -2175,13 +2201,17 @@ function useChartLegendItems(data, options = {}, legendShape) {
|
|
|
2175
2201
|
withGlyph,
|
|
2176
2202
|
glyphSize,
|
|
2177
2203
|
collapseGroups,
|
|
2204
|
+
comparisonItem,
|
|
2178
2205
|
renderGlyph,
|
|
2179
2206
|
legendShape
|
|
2180
2207
|
]);
|
|
2181
2208
|
}
|
|
2182
2209
|
//#endregion
|
|
2183
2210
|
//#region src/components/tooltip/base-tooltip.module.scss
|
|
2184
|
-
var base_tooltip_module_default = {
|
|
2211
|
+
var base_tooltip_module_default = {
|
|
2212
|
+
"surface": "a8ccharts--zY0xG-surface",
|
|
2213
|
+
"tooltip": "a8ccharts--zY0xG-tooltip"
|
|
2214
|
+
};
|
|
2185
2215
|
//#endregion
|
|
2186
2216
|
//#region src/components/tooltip/base-tooltip.tsx
|
|
2187
2217
|
const DefaultTooltipContent = ({ data }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
@@ -2231,7 +2261,8 @@ const findClippingAncestor = (wrapper) => {
|
|
|
2231
2261
|
/**
|
|
2232
2262
|
* Where the box goes, in wrapper coordinates. Automatic placement flips to
|
|
2233
2263
|
* the side that clips less, then clamps inside `bounds`; below-axis placement
|
|
2234
|
-
* is centered on the anchor and clamped horizontally
|
|
2264
|
+
* is centered on the anchor and clamped horizontally; beside placement preserves
|
|
2265
|
+
* the anchor's y and only flips horizontally before bounds clamping.
|
|
2235
2266
|
*
|
|
2236
2267
|
* The flip measures against the visible part of the wrapper, its intersection
|
|
2237
2268
|
* with `bounds`. Only the clamp is bound by the page: a box that fits inside the
|
|
@@ -2245,7 +2276,7 @@ const findClippingAncestor = (wrapper) => {
|
|
|
2245
2276
|
* @param params.offsetTop - Gap between the anchor and the box, vertically.
|
|
2246
2277
|
* @param params.box - Rendered size of the box.
|
|
2247
2278
|
* @param params.wrapper - The wrapper's own edges, in wrapper coordinates.
|
|
2248
|
-
* @param params.placement -
|
|
2279
|
+
* @param params.placement - Below-axis, beside without vertical flipping, or automatic flipping.
|
|
2249
2280
|
* @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
|
|
2250
2281
|
* @return The box's top-left corner; fixed placement preserves the axis's subpixel y.
|
|
2251
2282
|
*/
|
|
@@ -2269,7 +2300,8 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2269
2300
|
const upY = top - offsetTop - box.height;
|
|
2270
2301
|
const downOverflow = downY + box.height - fit.bottom;
|
|
2271
2302
|
const upOverflow = fit.top - upY;
|
|
2272
|
-
let y =
|
|
2303
|
+
let y = top;
|
|
2304
|
+
if (placement !== "beside") y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
|
|
2273
2305
|
x = clamp(x, bounds.left, bounds.right, box.width);
|
|
2274
2306
|
y = clamp(y, bounds.top, bounds.bottom, box.height);
|
|
2275
2307
|
return {
|
|
@@ -2285,8 +2317,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2285
2317
|
* alone would let the box spill into an `overflow: hidden` card and be cut off.
|
|
2286
2318
|
*
|
|
2287
2319
|
* Re-measures on every render, so a box whose content changes width between
|
|
2288
|
-
* two hovers is placed for its current size.
|
|
2289
|
-
* below-axis exception.
|
|
2320
|
+
* two hovers is placed for its current size.
|
|
2290
2321
|
*
|
|
2291
2322
|
* @param props - visx `Tooltip` props.
|
|
2292
2323
|
* @param props.left - Anchor x, in wrapper coordinates.
|
|
@@ -2296,7 +2327,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2296
2327
|
* @param props.style - Box styles; visx's defaults unless `unstyled`.
|
|
2297
2328
|
* @param props.unstyled - Skip `style` and leave the box bare.
|
|
2298
2329
|
* @param props.children - Box content.
|
|
2299
|
-
* @param props.placement -
|
|
2330
|
+
* @param props.placement - Below-axis, beside without vertical flipping, or automatic flipping.
|
|
2300
2331
|
* @return The tooltip box.
|
|
2301
2332
|
*/
|
|
2302
2333
|
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = defaultStyles, unstyled = false, children, placement = "auto", ...rest }) => {
|
|
@@ -2399,7 +2430,6 @@ const crosshairPaintProps = (props = {}) => {
|
|
|
2399
2430
|
};
|
|
2400
2431
|
const DEFAULT_GLYPH_RADIUS = 4;
|
|
2401
2432
|
const FALLBACK_COLOR = "#222";
|
|
2402
|
-
const DEFAULT_TOOLTIP_Z_INDEX = 3;
|
|
2403
2433
|
const PORTAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
2404
2434
|
"scroll",
|
|
2405
2435
|
"debounce",
|
|
@@ -2427,7 +2457,7 @@ const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ jsx(DefaultG
|
|
|
2427
2457
|
seriesKey: key,
|
|
2428
2458
|
...props
|
|
2429
2459
|
}, key);
|
|
2430
|
-
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", zIndex =
|
|
2460
|
+
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", tooltipAnchorTop, zIndex = 3, style, ...rest }) => {
|
|
2431
2461
|
const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
|
|
2432
2462
|
const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = useContext(DataContext) || {};
|
|
2433
2463
|
const tooltipContent = renderTooltip ? renderTooltip({
|
|
@@ -2482,7 +2512,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2482
2512
|
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2483
2513
|
const marginTop = margin?.top ?? 0;
|
|
2484
2514
|
const marginLeft = margin?.left ?? 0;
|
|
2485
|
-
const TooltipComponent = detectBounds || tooltipPlacement
|
|
2515
|
+
const TooltipComponent = detectBounds || tooltipPlacement !== "auto" ? BoundedTooltip : Tooltip;
|
|
2486
2516
|
const boxStyle = {
|
|
2487
2517
|
...defaultStyles,
|
|
2488
2518
|
zIndex,
|
|
@@ -2519,11 +2549,11 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2519
2549
|
]
|
|
2520
2550
|
}), container && createPortal(/* @__PURE__ */ jsx(TooltipComponent, {
|
|
2521
2551
|
left: tooltipLeft,
|
|
2522
|
-
top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipTop,
|
|
2552
|
+
top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipAnchorTop ?? tooltipTop,
|
|
2523
2553
|
style: boxStyle,
|
|
2524
2554
|
applyPositionStyle: true,
|
|
2525
2555
|
...tooltipProps,
|
|
2526
|
-
...tooltipPlacement
|
|
2556
|
+
...tooltipPlacement !== "auto" && { placement: tooltipPlacement },
|
|
2527
2557
|
children: tooltipContent
|
|
2528
2558
|
}), container)] });
|
|
2529
2559
|
};
|
|
@@ -2589,11 +2619,32 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2589
2619
|
return flattened;
|
|
2590
2620
|
}, [series, mode]);
|
|
2591
2621
|
const hasKeyboardSelection = useRef(false);
|
|
2622
|
+
const closeTooltipNow = useCallback(() => {
|
|
2623
|
+
tooltipContext?.updateTooltip({
|
|
2624
|
+
tooltipOpen: false,
|
|
2625
|
+
tooltipLeft: void 0,
|
|
2626
|
+
tooltipTop: void 0,
|
|
2627
|
+
tooltipData: void 0
|
|
2628
|
+
});
|
|
2629
|
+
}, []);
|
|
2630
|
+
const chartId = useContext(ChartInstanceContext)?.chartId;
|
|
2631
|
+
const { getHiddenSeries } = useGlobalChartsContext();
|
|
2632
|
+
const hiddenSeriesKey = chartId ? JSON.stringify([...getHiddenSeries(chartId)].sort()) : void 0;
|
|
2633
|
+
const lastHiddenSeriesKey = useRef(hiddenSeriesKey);
|
|
2634
|
+
useEffect(() => {
|
|
2635
|
+
const changed = lastHiddenSeriesKey.current !== hiddenSeriesKey;
|
|
2636
|
+
lastHiddenSeriesKey.current = hiddenSeriesKey;
|
|
2637
|
+
if (changed && selectedIndex === void 0) closeTooltipNow();
|
|
2638
|
+
}, [
|
|
2639
|
+
hiddenSeriesKey,
|
|
2640
|
+
selectedIndex,
|
|
2641
|
+
closeTooltipNow
|
|
2642
|
+
]);
|
|
2592
2643
|
useEffect(() => {
|
|
2593
2644
|
if (selectedIndex === void 0) {
|
|
2594
2645
|
if (hasKeyboardSelection.current) {
|
|
2595
2646
|
hasKeyboardSelection.current = false;
|
|
2596
|
-
|
|
2647
|
+
closeTooltipNow();
|
|
2597
2648
|
}
|
|
2598
2649
|
return;
|
|
2599
2650
|
}
|
|
@@ -2614,7 +2665,7 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2614
2665
|
tooltipContext?.showTooltip({
|
|
2615
2666
|
datum: tooltipItem.datum,
|
|
2616
2667
|
key: tooltipItem.seriesLabel,
|
|
2617
|
-
index: tooltipItem.
|
|
2668
|
+
index: tooltipItem.dataPointIndex
|
|
2618
2669
|
});
|
|
2619
2670
|
}
|
|
2620
2671
|
}
|
|
@@ -2662,14 +2713,43 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2662
2713
|
renderTooltip: focusableRenderTooltip
|
|
2663
2714
|
});
|
|
2664
2715
|
};
|
|
2665
|
-
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false }) => {
|
|
2716
|
+
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false, visibleSeriesKey }) => {
|
|
2717
|
+
const getChartRoot = useCallback(() => chartRef.current?.closest("[role=\"grid\"]") ?? chartRef.current, [chartRef]);
|
|
2718
|
+
const focusWithoutScrollIfNeeded = useCallback((element) => {
|
|
2719
|
+
if (preventTooltipScroll) element?.focus({ preventScroll: true });
|
|
2720
|
+
else element?.focus();
|
|
2721
|
+
}, [preventTooltipScroll]);
|
|
2722
|
+
const tooltipRef = useCallback((element) => {
|
|
2723
|
+
if (element && selectedIndex !== void 0) focusWithoutScrollIfNeeded(element);
|
|
2724
|
+
}, [focusWithoutScrollIfNeeded, selectedIndex]);
|
|
2725
|
+
const previousTotalPoints = useRef(totalPoints);
|
|
2726
|
+
const previousVisibleSeriesKey = useRef(visibleSeriesKey);
|
|
2727
|
+
useEffect(() => {
|
|
2728
|
+
const countChanged = previousTotalPoints.current !== totalPoints;
|
|
2729
|
+
const seriesChanged = previousVisibleSeriesKey.current !== visibleSeriesKey;
|
|
2730
|
+
previousTotalPoints.current = totalPoints;
|
|
2731
|
+
previousVisibleSeriesKey.current = visibleSeriesKey;
|
|
2732
|
+
if (!countChanged && !seriesChanged || selectedIndex === void 0) return;
|
|
2733
|
+
const { activeElement } = document;
|
|
2734
|
+
const focusIsInChart = activeElement !== null && !!getChartRoot()?.contains(activeElement);
|
|
2735
|
+
if (totalPoints === 0 || !focusIsInChart || !countChanged) {
|
|
2736
|
+
setSelectedIndex(void 0);
|
|
2737
|
+
setIsNavigating(false);
|
|
2738
|
+
if (focusIsInChart) focusWithoutScrollIfNeeded(getChartRoot());
|
|
2739
|
+
return;
|
|
2740
|
+
}
|
|
2741
|
+
setSelectedIndex(Math.min(selectedIndex, totalPoints - 1));
|
|
2742
|
+
}, [
|
|
2743
|
+
selectedIndex,
|
|
2744
|
+
totalPoints,
|
|
2745
|
+
visibleSeriesKey,
|
|
2746
|
+
setSelectedIndex,
|
|
2747
|
+
setIsNavigating,
|
|
2748
|
+
getChartRoot,
|
|
2749
|
+
focusWithoutScrollIfNeeded
|
|
2750
|
+
]);
|
|
2666
2751
|
return {
|
|
2667
|
-
tooltipRef
|
|
2668
|
-
if (element && selectedIndex !== void 0) {
|
|
2669
|
-
if (preventTooltipScroll) element.focus({ preventScroll: true });
|
|
2670
|
-
else element.focus();
|
|
2671
|
-
}
|
|
2672
|
-
}, [preventTooltipScroll, selectedIndex]),
|
|
2752
|
+
tooltipRef,
|
|
2673
2753
|
onChartFocus: useCallback((event) => {
|
|
2674
2754
|
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
2675
2755
|
if (!isNavigating && selectedIndex !== void 0) setSelectedIndex(0);
|
|
@@ -2682,44 +2762,35 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
|
|
|
2682
2762
|
setIsNavigating(false);
|
|
2683
2763
|
}, [setIsNavigating]),
|
|
2684
2764
|
onChartKeyDown: useCallback((event) => {
|
|
2685
|
-
if (
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
else chartRef.current?.focus();
|
|
2689
|
-
};
|
|
2690
|
-
if (event.key === "Tab") {
|
|
2691
|
-
focusChart();
|
|
2765
|
+
if (event.key === "Tab" || event.key === "Escape") {
|
|
2766
|
+
if (event.key === "Escape" && selectedIndex !== void 0) event.preventDefault();
|
|
2767
|
+
focusWithoutScrollIfNeeded(getChartRoot());
|
|
2692
2768
|
setSelectedIndex(void 0);
|
|
2693
2769
|
setIsNavigating(false);
|
|
2694
2770
|
return;
|
|
2695
2771
|
}
|
|
2772
|
+
if (totalPoints === 0) return;
|
|
2696
2773
|
const currentSelectedIndex = selectedIndex === void 0 ? -1 : selectedIndex;
|
|
2697
|
-
if (
|
|
2698
|
-
|
|
2699
|
-
setSelectedIndex(void 0);
|
|
2700
|
-
setIsNavigating(false);
|
|
2701
|
-
return;
|
|
2702
|
-
}
|
|
2703
|
-
event.preventDefault();
|
|
2704
|
-
if (["ArrowRight"].includes(event.key)) {
|
|
2774
|
+
if (event.key === "ArrowRight") {
|
|
2775
|
+
event.preventDefault();
|
|
2705
2776
|
setIsNavigating(true);
|
|
2706
|
-
setSelectedIndex((currentSelectedIndex + 1
|
|
2707
|
-
} else if (
|
|
2777
|
+
setSelectedIndex(Math.min(currentSelectedIndex + 1, totalPoints - 1));
|
|
2778
|
+
} else if (event.key === "ArrowLeft") {
|
|
2779
|
+
event.preventDefault();
|
|
2708
2780
|
setIsNavigating(true);
|
|
2709
|
-
setSelectedIndex((currentSelectedIndex - 1
|
|
2710
|
-
} else if (event.key === "
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
} else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) onActivate?.(selectedIndex);
|
|
2781
|
+
setSelectedIndex(Math.max(currentSelectedIndex - 1, 0));
|
|
2782
|
+
} else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) {
|
|
2783
|
+
event.preventDefault();
|
|
2784
|
+
onActivate?.(selectedIndex);
|
|
2785
|
+
}
|
|
2715
2786
|
}, [
|
|
2716
2787
|
totalPoints,
|
|
2717
2788
|
selectedIndex,
|
|
2718
2789
|
setSelectedIndex,
|
|
2719
2790
|
setIsNavigating,
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2791
|
+
getChartRoot,
|
|
2792
|
+
focusWithoutScrollIfNeeded,
|
|
2793
|
+
onActivate
|
|
2723
2794
|
])
|
|
2724
2795
|
};
|
|
2725
2796
|
};
|
|
@@ -2917,6 +2988,31 @@ const DefaultGlyph = (props) => {
|
|
|
2917
2988
|
});
|
|
2918
2989
|
};
|
|
2919
2990
|
//#endregion
|
|
2991
|
+
//#region src/charts/private/readings.ts
|
|
2992
|
+
/**
|
|
2993
|
+
* Whether a value is a reading a scale can place.
|
|
2994
|
+
*
|
|
2995
|
+
* @param value - The point's value.
|
|
2996
|
+
* @return True for a finite number.
|
|
2997
|
+
*/
|
|
2998
|
+
const isReading = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2999
|
+
/**
|
|
3000
|
+
* Whether a data point's value cannot be drawn.
|
|
3001
|
+
*
|
|
3002
|
+
* @param value - The point's value.
|
|
3003
|
+
* @param options - Validation options.
|
|
3004
|
+
* @param options.allowMissing - Whether `null` is a bucket with no reading rather than a fault.
|
|
3005
|
+
* @return True when the value is invalid.
|
|
3006
|
+
*/
|
|
3007
|
+
const isInvalidReading = (value, { allowMissing }) => value === null ? !allowMissing : value === void 0 || isNaN(value);
|
|
3008
|
+
/**
|
|
3009
|
+
* Formats a reading for a tooltip.
|
|
3010
|
+
*
|
|
3011
|
+
* @param value - The reading, or null when the bucket has none.
|
|
3012
|
+
* @return The formatted value.
|
|
3013
|
+
*/
|
|
3014
|
+
const formatReading = (value) => value == null ? __("No data", "jetpack-charts") : formatNumber(value);
|
|
3015
|
+
//#endregion
|
|
2920
3016
|
//#region src/charts/private/center/center.module.scss
|
|
2921
3017
|
var center_module_default = { "center": "a8ccharts-w3qxlG-center" };
|
|
2922
3018
|
//#endregion
|
|
@@ -3289,6 +3385,54 @@ const buildTimeAxisOptions = ({ dataSorted, width, axisOptions, scaleDomain, zoo
|
|
|
3289
3385
|
};
|
|
3290
3386
|
};
|
|
3291
3387
|
//#endregion
|
|
3388
|
+
//#region src/charts/private/whole-number-ticks.tsx
|
|
3389
|
+
/**
|
|
3390
|
+
* Whether every reading in the series is a whole number.
|
|
3391
|
+
*
|
|
3392
|
+
* @param series - The series visx renders.
|
|
3393
|
+
* @return True when at least one reading exists and none has a fraction.
|
|
3394
|
+
*/
|
|
3395
|
+
const hasOnlyWholeNumbers = (series) => {
|
|
3396
|
+
let sawReading = false;
|
|
3397
|
+
for (const { data } of series) for (const point of data) {
|
|
3398
|
+
const value = point?.value;
|
|
3399
|
+
if (!isReading(value)) continue;
|
|
3400
|
+
if (!Number.isInteger(value)) return false;
|
|
3401
|
+
sawReading = true;
|
|
3402
|
+
}
|
|
3403
|
+
return sawReading;
|
|
3404
|
+
};
|
|
3405
|
+
/**
|
|
3406
|
+
* The scale's ticks with the fractional ones dropped.
|
|
3407
|
+
*
|
|
3408
|
+
* d3 steps by 1, 2 or 5 times a power of ten, so every whole number inside the domain is one of its ticks.
|
|
3409
|
+
*
|
|
3410
|
+
* @param scale - The value scale visx built.
|
|
3411
|
+
* @param count - Ticks to ask the scale for; undefined uses the scale's own default, as visx does.
|
|
3412
|
+
* @return Whole-number ticks, or undefined when visx's own ticks need no change.
|
|
3413
|
+
*/
|
|
3414
|
+
const getWholeNumberTickValues = (scale, count) => {
|
|
3415
|
+
const ticks = scale?.ticks?.(count);
|
|
3416
|
+
if (!ticks?.every((tick) => typeof tick === "number")) return;
|
|
3417
|
+
const whole = ticks.filter((tick) => Number.isInteger(tick));
|
|
3418
|
+
return whole.length > 1 && whole.length < ticks.length ? whole : void 0;
|
|
3419
|
+
};
|
|
3420
|
+
/**
|
|
3421
|
+
* Hands its children the whole-number ticks of the chart's value scale.
|
|
3422
|
+
*
|
|
3423
|
+
* @param props - Component props.
|
|
3424
|
+
* @param props.axis - Which scale carries the values.
|
|
3425
|
+
* @param props.numTicks - Ticks to ask the scale for.
|
|
3426
|
+
* @param props.enabled - Whether the plotted values are all whole numbers and the caller pinned neither the ticks nor the value domain.
|
|
3427
|
+
* @param props.children - Renders the axis and grid with the tick values.
|
|
3428
|
+
* @return The rendered children.
|
|
3429
|
+
*/
|
|
3430
|
+
const WholeNumberTicks = ({ axis, numTicks, enabled, children }) => {
|
|
3431
|
+
const { xScale, yScale } = useContext(DataContext);
|
|
3432
|
+
const tickValues = enabled ? getWholeNumberTickValues(axis === "x" ? xScale : yScale, numTicks) : void 0;
|
|
3433
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: children(tickValues) });
|
|
3434
|
+
};
|
|
3435
|
+
//#endregion
|
|
3292
3436
|
//#region src/charts/private/with-responsive/with-responsive.module.scss
|
|
3293
3437
|
var with_responsive_module_default = {
|
|
3294
3438
|
"container": "a8ccharts-sP1gHa-container",
|
|
@@ -3955,11 +4099,15 @@ const toNumber$1 = (val) => {
|
|
|
3955
4099
|
const LineChartGlyph = ({ data, index, color, glyphStyle, renderGlyph, accessors, position }) => {
|
|
3956
4100
|
const { xScale, yScale } = useContext(DataContext) || {};
|
|
3957
4101
|
if (!xScale || !yScale) return null;
|
|
3958
|
-
|
|
3959
|
-
|
|
4102
|
+
const hasFiniteY = (datum) => {
|
|
4103
|
+
const scaledY = yScale(accessors.yAccessor(datum));
|
|
4104
|
+
return typeof scaledY === "number" && Number.isFinite(scaledY);
|
|
4105
|
+
};
|
|
4106
|
+
const point = position === "start" ? data.data.find(hasFiniteY) : data.data.findLast(hasFiniteY);
|
|
4107
|
+
if (!point) return null;
|
|
3960
4108
|
const x = xScale(accessors.xAccessor(point));
|
|
3961
4109
|
const y = yScale(accessors.yAccessor(point));
|
|
3962
|
-
if (typeof x !== "number" || typeof y !== "number") return null;
|
|
4110
|
+
if (typeof x !== "number" || typeof y !== "number" || !Number.isFinite(x) || !Number.isFinite(y)) return null;
|
|
3963
4111
|
const size = Math.max(0, toNumber$1(glyphStyle?.radius) ?? 4);
|
|
3964
4112
|
return renderGlyph({
|
|
3965
4113
|
key: `${position}-glyph-${data.label}`,
|
|
@@ -3974,6 +4122,106 @@ const LineChartGlyph = ({ data, index, color, glyphStyle, renderGlyph, accessors
|
|
|
3974
4122
|
});
|
|
3975
4123
|
};
|
|
3976
4124
|
//#endregion
|
|
4125
|
+
//#region src/charts/line-chart/private/nearest-pointer-events.tsx
|
|
4126
|
+
/**
|
|
4127
|
+
* Find the datum nearest a pointer along x, in one series sorted by x.
|
|
4128
|
+
*
|
|
4129
|
+
* @param data - The series' registered data, in ascending x order.
|
|
4130
|
+
* @param xAccessor - Reads a datum's x value.
|
|
4131
|
+
* @param xScale - The chart's x scale.
|
|
4132
|
+
* @param x - Pointer x in SVG coordinates.
|
|
4133
|
+
* @return Index of the nearest datum and its distance, or index -1 when none has a position.
|
|
4134
|
+
*/
|
|
4135
|
+
function nearestByX(data, xAccessor, xScale, x) {
|
|
4136
|
+
return (typeof xScale.invert === "function" ? [bisector(xAccessor).left(data, xScale.invert(x))].flatMap((index) => [index - 1, index]) : data.map((_datum, index) => index)).filter((index) => index >= 0 && index < data.length).reduce((best, index) => {
|
|
4137
|
+
const distance = Math.abs(Number(xScale(xAccessor(data[index]))) - x);
|
|
4138
|
+
return distance < best.distance ? {
|
|
4139
|
+
index,
|
|
4140
|
+
distance
|
|
4141
|
+
} : best;
|
|
4142
|
+
}, {
|
|
4143
|
+
index: -1,
|
|
4144
|
+
distance: Infinity
|
|
4145
|
+
});
|
|
4146
|
+
}
|
|
4147
|
+
/**
|
|
4148
|
+
* Pick the candidate to report: the closest placed reading, else the closest bucket with no reading along x.
|
|
4149
|
+
*
|
|
4150
|
+
* @param candidates - One candidate per series.
|
|
4151
|
+
* @return The chosen candidate's params, or undefined when there are none.
|
|
4152
|
+
*/
|
|
4153
|
+
function pickNearest(candidates) {
|
|
4154
|
+
const placed = candidates.map(({ params }) => params).filter((params) => Number.isFinite(params.distanceY));
|
|
4155
|
+
const missing = candidates.filter(({ isMissing }) => isMissing).map(({ params }) => params);
|
|
4156
|
+
const distance = (params) => placed.length ? Math.hypot(params.distanceX ?? 0, params.distanceY ?? 0) : params.distanceX ?? 0;
|
|
4157
|
+
return (placed.length ? placed : missing).reduce((best, params) => !best || distance(params) < distance(best) ? params : best, void 0);
|
|
4158
|
+
}
|
|
4159
|
+
/**
|
|
4160
|
+
* Report pointer events at the nearest datum, including a bucket with no reading.
|
|
4161
|
+
*
|
|
4162
|
+
* visx's own nearest search measures y distance too, which is NaN for a null value, so a pointer
|
|
4163
|
+
* over a bucket where no series has a reading fires no event at all.
|
|
4164
|
+
*
|
|
4165
|
+
* @param props - Handlers to call.
|
|
4166
|
+
* @param props.onPointerDown - Receives the nearest datum on pointer down.
|
|
4167
|
+
* @param props.onPointerMove - Receives the nearest datum on pointer move.
|
|
4168
|
+
* @param props.onPointerUp - Receives the nearest datum on pointer up.
|
|
4169
|
+
* @return No visual content.
|
|
4170
|
+
*/
|
|
4171
|
+
function NearestPointerEvents({ onPointerDown, onPointerMove, onPointerUp }) {
|
|
4172
|
+
const { xScale, yScale, dataRegistry } = useContext(DataContext);
|
|
4173
|
+
const findNearest = useCallback((params) => {
|
|
4174
|
+
const point = params?.svgPoint;
|
|
4175
|
+
if (!point || !xScale || !yScale || !dataRegistry) return;
|
|
4176
|
+
const candidates = [];
|
|
4177
|
+
for (const key of dataRegistry.keys()) {
|
|
4178
|
+
const entry = dataRegistry.get(key);
|
|
4179
|
+
if (!entry) continue;
|
|
4180
|
+
const { index, distance } = nearestByX(entry.data, entry.xAccessor, xScale, point.x);
|
|
4181
|
+
if (index < 0) continue;
|
|
4182
|
+
const datum = entry.data[index];
|
|
4183
|
+
const value = entry.yAccessor(datum);
|
|
4184
|
+
candidates.push({
|
|
4185
|
+
params: {
|
|
4186
|
+
event: params.event,
|
|
4187
|
+
svgPoint: point,
|
|
4188
|
+
key,
|
|
4189
|
+
datum,
|
|
4190
|
+
index,
|
|
4191
|
+
distanceX: distance,
|
|
4192
|
+
distanceY: Math.abs(Number(yScale(value)) - point.y)
|
|
4193
|
+
},
|
|
4194
|
+
isMissing: value == null
|
|
4195
|
+
});
|
|
4196
|
+
}
|
|
4197
|
+
return pickNearest(candidates);
|
|
4198
|
+
}, [
|
|
4199
|
+
xScale,
|
|
4200
|
+
yScale,
|
|
4201
|
+
dataRegistry
|
|
4202
|
+
]);
|
|
4203
|
+
const handlers = useMemo(() => {
|
|
4204
|
+
const report = (handler) => handler && ((params) => {
|
|
4205
|
+
const nearest = findNearest(params);
|
|
4206
|
+
if (nearest) handler(nearest);
|
|
4207
|
+
});
|
|
4208
|
+
return {
|
|
4209
|
+
pointerdown: report(onPointerDown),
|
|
4210
|
+
pointermove: report(onPointerMove),
|
|
4211
|
+
pointerup: report(onPointerUp)
|
|
4212
|
+
};
|
|
4213
|
+
}, [
|
|
4214
|
+
findNearest,
|
|
4215
|
+
onPointerDown,
|
|
4216
|
+
onPointerMove,
|
|
4217
|
+
onPointerUp
|
|
4218
|
+
]);
|
|
4219
|
+
useEventEmitter("pointerdown", handlers.pointerdown);
|
|
4220
|
+
useEventEmitter("pointermove", handlers.pointermove);
|
|
4221
|
+
useEventEmitter("pointerup", handlers.pointerup);
|
|
4222
|
+
return null;
|
|
4223
|
+
}
|
|
4224
|
+
//#endregion
|
|
3977
4225
|
//#region src/charts/line-chart/line-chart.tsx
|
|
3978
4226
|
const defaultRenderGlyph = (props) => {
|
|
3979
4227
|
return /* @__PURE__ */ createElement(DefaultGlyph, {
|
|
@@ -4017,8 +4265,13 @@ const renderDefaultTooltip = (params, contentStyle) => {
|
|
|
4017
4265
|
if (!nearestDatum) return null;
|
|
4018
4266
|
const tooltipPoints = Object.entries(tooltipData?.datumByKey || {}).map(([key, { datum }]) => ({
|
|
4019
4267
|
key,
|
|
4020
|
-
value: datum.value
|
|
4021
|
-
})).sort((a, b) =>
|
|
4268
|
+
value: datum.value ?? null
|
|
4269
|
+
})).sort((a, b) => {
|
|
4270
|
+
if (a.value === null && b.value === null) return 0;
|
|
4271
|
+
if (a.value === null) return 1;
|
|
4272
|
+
if (b.value === null) return -1;
|
|
4273
|
+
return b.value - a.value;
|
|
4274
|
+
});
|
|
4022
4275
|
return /* @__PURE__ */ jsxs("div", {
|
|
4023
4276
|
className: line_chart_module_default["line-chart__tooltip"],
|
|
4024
4277
|
style: contentStyle,
|
|
@@ -4038,16 +4291,23 @@ const renderDefaultTooltip = (params, contentStyle) => {
|
|
|
4038
4291
|
children: [point.key, ":"]
|
|
4039
4292
|
}), /* @__PURE__ */ jsx("span", {
|
|
4040
4293
|
className: line_chart_module_default["line-chart__tooltip-value"],
|
|
4041
|
-
children:
|
|
4294
|
+
children: formatReading(point.value)
|
|
4042
4295
|
})]
|
|
4043
4296
|
}, point.key))]
|
|
4044
4297
|
});
|
|
4045
4298
|
};
|
|
4046
4299
|
const validateData$4 = (data) => {
|
|
4047
|
-
if (!data?.length) return "No data available";
|
|
4048
|
-
if (data.some((series) => series.data.some((point) =>
|
|
4300
|
+
if (!data?.length) return __("No data available", "jetpack-charts");
|
|
4301
|
+
if (data.some((series) => series.data.some((point) => isInvalidReading(point.value, { allowMissing: true }) || "date" in point && point.date && isNaN(point.date.getTime())))) return __("Invalid data", "jetpack-charts");
|
|
4049
4302
|
return null;
|
|
4050
4303
|
};
|
|
4304
|
+
const getFallbackYDomain = (readingExtent, isLogScale) => {
|
|
4305
|
+
const emptyDomain = isLogScale ? [1, 10] : [0, 1];
|
|
4306
|
+
if (!readingExtent) return emptyDomain;
|
|
4307
|
+
const [min, max] = readingExtent;
|
|
4308
|
+
if (min !== max || isLogScale) return;
|
|
4309
|
+
return min === 0 ? emptyDomain : [Math.min(0, min), Math.max(0, max)];
|
|
4310
|
+
};
|
|
4051
4311
|
const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
4052
4312
|
const context = useContext(DataContext);
|
|
4053
4313
|
useImperativeHandle(chartRef, () => ({
|
|
@@ -4074,6 +4334,7 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
4074
4334
|
const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, tooltipPlacement, tooltipStyle, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, onDatumActivate = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
4075
4335
|
const legendInteractive = legend.interactive ?? false;
|
|
4076
4336
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
4337
|
+
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
4077
4338
|
const legendShape = legend.shape ?? "line";
|
|
4078
4339
|
const legendPosition = legend.position ?? "bottom";
|
|
4079
4340
|
const formatting = useChartFormatting();
|
|
@@ -4120,19 +4381,32 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4120
4381
|
const allSeriesHidden = useMemo(() => {
|
|
4121
4382
|
return seriesWithVisibility.every(({ isVisible }) => !isVisible);
|
|
4122
4383
|
}, [seriesWithVisibility]);
|
|
4123
|
-
const
|
|
4124
|
-
|
|
4384
|
+
const yDomain = useMemo(() => {
|
|
4385
|
+
const includeZero = options?.yScale?.zero === true && scaleCanBeZeroed({ type: options.yScale.type ?? "linear" });
|
|
4386
|
+
if (rescaleYOnVisibilityChange && !includeZero) return;
|
|
4125
4387
|
let min = Infinity;
|
|
4126
4388
|
let max = -Infinity;
|
|
4127
|
-
for (const series of dataSorted)
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4389
|
+
for (const series of dataSorted) {
|
|
4390
|
+
if (rescaleYOnVisibilityChange && !isSeriesVisible(series.label)) continue;
|
|
4391
|
+
for (const point of series.data ?? []) {
|
|
4392
|
+
const value = point?.value;
|
|
4393
|
+
if (isReading(value)) {
|
|
4394
|
+
min = Math.min(min, value);
|
|
4395
|
+
max = Math.max(max, value);
|
|
4396
|
+
}
|
|
4132
4397
|
}
|
|
4133
4398
|
}
|
|
4399
|
+
if (includeZero) {
|
|
4400
|
+
if (min === Infinity) return;
|
|
4401
|
+
return max === 0 && min === 0 ? [0, 1] : [Math.min(0, min), Math.max(0, max)];
|
|
4402
|
+
}
|
|
4134
4403
|
return min < max ? [min, max] : void 0;
|
|
4135
|
-
}, [
|
|
4404
|
+
}, [
|
|
4405
|
+
rescaleYOnVisibilityChange,
|
|
4406
|
+
dataSorted,
|
|
4407
|
+
isSeriesVisible,
|
|
4408
|
+
options?.yScale
|
|
4409
|
+
]);
|
|
4136
4410
|
const activateSelectedPoint = useCallback((index) => {
|
|
4137
4411
|
const series = dataSorted[0];
|
|
4138
4412
|
const datum = series?.data[index];
|
|
@@ -4152,7 +4426,24 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4152
4426
|
onActivate: activateSelectedPoint,
|
|
4153
4427
|
preventTooltipScroll: tooltipPlacement === "below-axis"
|
|
4154
4428
|
});
|
|
4429
|
+
const visibleReadingExtent = useMemo(() => {
|
|
4430
|
+
let min = Infinity;
|
|
4431
|
+
let max = -Infinity;
|
|
4432
|
+
for (const series of dataSorted) {
|
|
4433
|
+
if (!isSeriesVisible(series.label)) continue;
|
|
4434
|
+
for (const point of series.data) {
|
|
4435
|
+
const value = point?.value;
|
|
4436
|
+
if (isReading(value)) {
|
|
4437
|
+
min = Math.min(min, value);
|
|
4438
|
+
max = Math.max(max, value);
|
|
4439
|
+
}
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
return min <= max ? [min, max] : void 0;
|
|
4443
|
+
}, [dataSorted, isSeriesVisible]);
|
|
4444
|
+
const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(dataSorted.filter((series) => isSeriesVisible(series.label))), [dataSorted, isSeriesVisible]);
|
|
4155
4445
|
const chartOptions = useMemo(() => {
|
|
4446
|
+
const fallbackYDomain = getFallbackYDomain(visibleReadingExtent, options?.yScale?.type === "log");
|
|
4156
4447
|
return {
|
|
4157
4448
|
axis: {
|
|
4158
4449
|
x: buildTimeAxisOptions({
|
|
@@ -4181,7 +4472,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4181
4472
|
type: "linear",
|
|
4182
4473
|
nice: true,
|
|
4183
4474
|
zero: false,
|
|
4184
|
-
...
|
|
4475
|
+
...fallbackYDomain ? { domain: fallbackYDomain } : {},
|
|
4476
|
+
...yDomain ? { domain: yDomain } : {},
|
|
4185
4477
|
...options?.yScale
|
|
4186
4478
|
}
|
|
4187
4479
|
};
|
|
@@ -4190,7 +4482,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4190
4482
|
dataSorted,
|
|
4191
4483
|
width,
|
|
4192
4484
|
zoom.domain,
|
|
4193
|
-
|
|
4485
|
+
yDomain,
|
|
4486
|
+
visibleReadingExtent,
|
|
4194
4487
|
formatting,
|
|
4195
4488
|
isSeriesVisible
|
|
4196
4489
|
]);
|
|
@@ -4225,11 +4518,13 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4225
4518
|
withGlyph: withLegendGlyph,
|
|
4226
4519
|
glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
|
|
4227
4520
|
collapseGroups: legendCollapseGroups,
|
|
4521
|
+
comparisonItem: legendComparisonItem,
|
|
4228
4522
|
renderGlyph
|
|
4229
4523
|
}), [
|
|
4230
4524
|
withLegendGlyph,
|
|
4231
4525
|
glyphStyle?.radius,
|
|
4232
4526
|
legendCollapseGroups,
|
|
4527
|
+
legendComparisonItem,
|
|
4233
4528
|
renderGlyph
|
|
4234
4529
|
]), legendShape);
|
|
4235
4530
|
const chartMetadata = useMemo(() => ({
|
|
@@ -4341,18 +4636,26 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4341
4636
|
},
|
|
4342
4637
|
xScale: chartOptions.xScale,
|
|
4343
4638
|
yScale: chartOptions.yScale,
|
|
4344
|
-
onPointerDown: zoom.handlers.onPointerDown,
|
|
4345
|
-
onPointerUp: zoom.handlers.onPointerUp,
|
|
4346
|
-
onPointerMove: zoom.handlers.onPointerMove,
|
|
4347
4639
|
onPointerOut,
|
|
4348
|
-
pointerEventsDataKey: "nearest",
|
|
4349
4640
|
children: [
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4641
|
+
/* @__PURE__ */ jsx(NearestPointerEvents, { ...zoom.handlers }),
|
|
4642
|
+
/* @__PURE__ */ jsx(WholeNumberTicks, {
|
|
4643
|
+
axis: "y",
|
|
4644
|
+
numTicks: chartOptions.axis.y.numTicks,
|
|
4645
|
+
enabled: hasWholeNumberValues && !chartOptions.axis.y.tickValues && !options?.yScale?.domain,
|
|
4646
|
+
children: (tickValues) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
4647
|
+
!allSeriesHidden && gridVisibility !== "none" && /* @__PURE__ */ jsx(Grid, {
|
|
4648
|
+
columns: false,
|
|
4649
|
+
numTicks: chartOptions.axis.y.numTicks,
|
|
4650
|
+
tickValues: tickValues ?? chartOptions.axis.y.tickValues
|
|
4651
|
+
}),
|
|
4652
|
+
!allSeriesHidden && chartOptions.axis.x.display && /* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.x }),
|
|
4653
|
+
!allSeriesHidden && chartOptions.axis.y.display && /* @__PURE__ */ jsx(Axis, {
|
|
4654
|
+
...chartOptions.axis.y,
|
|
4655
|
+
...tickValues ? { tickValues } : {}
|
|
4656
|
+
})
|
|
4657
|
+
] })
|
|
4353
4658
|
}),
|
|
4354
|
-
!allSeriesHidden && chartOptions.axis.x.display && /* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.x }),
|
|
4355
|
-
!allSeriesHidden && chartOptions.axis.y.display && /* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.y }),
|
|
4356
4659
|
allSeriesHidden ? /* @__PURE__ */ jsx(SvgEmptyState, {
|
|
4357
4660
|
x: width / 2,
|
|
4358
4661
|
y: chartHeight / 2,
|
|
@@ -4493,7 +4796,7 @@ var area_chart_module_default = {
|
|
|
4493
4796
|
const validateData$3 = (data) => {
|
|
4494
4797
|
if (!data?.length) return __("No data available", "jetpack-charts");
|
|
4495
4798
|
if (data.some((series) => !series.data?.length)) return __("No data available", "jetpack-charts");
|
|
4496
|
-
if (data.some((series) => series.data.some((point) =>
|
|
4799
|
+
if (data.some((series) => series.data.some((point) => isInvalidReading(point.value, { allowMissing: false }) || "date" in point && point.date && isNaN(point.date.getTime())))) return __("Invalid data", "jetpack-charts");
|
|
4497
4800
|
return null;
|
|
4498
4801
|
};
|
|
4499
4802
|
//#endregion
|
|
@@ -4609,6 +4912,12 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4609
4912
|
}));
|
|
4610
4913
|
}, [dataSorted, hiddenSeries]);
|
|
4611
4914
|
const allSeriesHidden = useMemo(() => seriesWithVisibility.every(({ isVisible }) => !isVisible), [seriesWithVisibility]);
|
|
4915
|
+
const hasWholeNumberValues = useMemo(() => (!stacked || stackOffset === "none") && hasOnlyWholeNumbers(dataSorted.filter((series) => isSeriesVisible(series.label))), [
|
|
4916
|
+
dataSorted,
|
|
4917
|
+
isSeriesVisible,
|
|
4918
|
+
stacked,
|
|
4919
|
+
stackOffset
|
|
4920
|
+
]);
|
|
4612
4921
|
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
4613
4922
|
selectedIndex,
|
|
4614
4923
|
setSelectedIndex,
|
|
@@ -4701,8 +5010,9 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4701
5010
|
const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({
|
|
4702
5011
|
withGlyph: false,
|
|
4703
5012
|
glyphSize: 0,
|
|
4704
|
-
collapseGroups: legend.collapseGroups ?? false
|
|
4705
|
-
|
|
5013
|
+
collapseGroups: legend.collapseGroups ?? false,
|
|
5014
|
+
comparisonItem: legend.comparisonItem ?? false
|
|
5015
|
+
}), [legend.collapseGroups, legend.comparisonItem]), legendShape);
|
|
4706
5016
|
const chartMetadata = useMemo(() => ({
|
|
4707
5017
|
stacked,
|
|
4708
5018
|
stackOffset,
|
|
@@ -4852,12 +5162,23 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4852
5162
|
onPointerOut,
|
|
4853
5163
|
pointerEventsDataKey: "nearest",
|
|
4854
5164
|
children: [
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
numTicks:
|
|
5165
|
+
/* @__PURE__ */ jsx(WholeNumberTicks, {
|
|
5166
|
+
axis: "y",
|
|
5167
|
+
numTicks: chartOptions.axis.y.numTicks,
|
|
5168
|
+
enabled: hasWholeNumberValues && !chartOptions.axis.y.tickValues && !options?.yScale?.domain,
|
|
5169
|
+
children: (tickValues) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
5170
|
+
!allSeriesHidden && gridVisibility !== "none" && /* @__PURE__ */ jsx(Grid, {
|
|
5171
|
+
columns: false,
|
|
5172
|
+
numTicks: chartOptions.axis.y.numTicks,
|
|
5173
|
+
tickValues: tickValues ?? chartOptions.axis.y.tickValues
|
|
5174
|
+
}),
|
|
5175
|
+
!allSeriesHidden && chartOptions.axis.x.display && /* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.x }),
|
|
5176
|
+
!allSeriesHidden && chartOptions.axis.y.display && /* @__PURE__ */ jsx(Axis, {
|
|
5177
|
+
...chartOptions.axis.y,
|
|
5178
|
+
...tickValues ? { tickValues } : {}
|
|
5179
|
+
})
|
|
5180
|
+
] })
|
|
4858
5181
|
}),
|
|
4859
|
-
!allSeriesHidden && chartOptions.axis.x.display && /* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.x }),
|
|
4860
|
-
!allSeriesHidden && chartOptions.axis.y.display && /* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.y }),
|
|
4861
5182
|
allSeriesHidden ? /* @__PURE__ */ jsx(SvgEmptyState, {
|
|
4862
5183
|
x: width / 2,
|
|
4863
5184
|
y: chartHeight / 2,
|
|
@@ -5046,6 +5367,65 @@ const createTruncatedTickComponent = (axis) => (props) => {
|
|
|
5046
5367
|
const TruncatedXTickComponent = createTruncatedTickComponent("x");
|
|
5047
5368
|
const TruncatedYTickComponent = createTruncatedTickComponent("y");
|
|
5048
5369
|
//#endregion
|
|
5370
|
+
//#region src/charts/bar-chart/private/value-domain.ts
|
|
5371
|
+
/** Domain for a value axis that has nothing to scale, so its ticks still read 0 to 1. */
|
|
5372
|
+
const EMPTY_DOMAIN = [0, 1];
|
|
5373
|
+
/**
|
|
5374
|
+
* The value a bar is drawn at, preferring `visualValue` so a zero still shows a sliver.
|
|
5375
|
+
*
|
|
5376
|
+
* A missing reading is NaN, not null: `ComparisonBars` coerces the value with `Number()`,
|
|
5377
|
+
* which turns null into 0 and would draw a comparison shadow at the baseline.
|
|
5378
|
+
*
|
|
5379
|
+
* @param point - A data point handed to visx.
|
|
5380
|
+
* @return The bar value, or NaN when the bucket has no reading.
|
|
5381
|
+
*/
|
|
5382
|
+
const getBarValue = (point) => {
|
|
5383
|
+
const enhanced = point;
|
|
5384
|
+
return (enhanced?.visualValue !== void 0 ? enhanced.visualValue : point?.value) ?? NaN;
|
|
5385
|
+
};
|
|
5386
|
+
/**
|
|
5387
|
+
* Whether visx renders a bar for a point.
|
|
5388
|
+
*
|
|
5389
|
+
* @param point - A data point handed to visx.
|
|
5390
|
+
* @return True when the point has a finite bar value.
|
|
5391
|
+
*/
|
|
5392
|
+
const isBarRendered = (point) => Number.isFinite(getBarValue(point));
|
|
5393
|
+
/**
|
|
5394
|
+
* How many bars visx renders for a list of points.
|
|
5395
|
+
*
|
|
5396
|
+
* @param points - Data points handed to visx.
|
|
5397
|
+
* @return The number of points that get a bar.
|
|
5398
|
+
*/
|
|
5399
|
+
const countRenderedBars = (points) => points.filter(isBarRendered).length;
|
|
5400
|
+
/**
|
|
5401
|
+
* An explicit domain for the value scale, or null to let visx fit one to the data.
|
|
5402
|
+
*
|
|
5403
|
+
* Zero goes into the domain here rather than through the scale's `zero` flag: visx applies
|
|
5404
|
+
* `nice` before `zero`, which would leave the axis topping out at a raw maximum.
|
|
5405
|
+
*
|
|
5406
|
+
* @param data - Every series handed to the chart.
|
|
5407
|
+
* @param includeZero - Whether the domain must span zero.
|
|
5408
|
+
* @param isSeriesRendered - Whether visx mounts a series, i.e. the legend shows it.
|
|
5409
|
+
* @return Value domain, or null when visx should fit its own.
|
|
5410
|
+
*/
|
|
5411
|
+
const getValueScaleDomain = (data, includeZero, isSeriesRendered) => {
|
|
5412
|
+
let min = Infinity;
|
|
5413
|
+
let max = -Infinity;
|
|
5414
|
+
for (const series of data) {
|
|
5415
|
+
if (!isSeriesRendered(series)) continue;
|
|
5416
|
+
for (const point of series.data) {
|
|
5417
|
+
const value = getBarValue(point);
|
|
5418
|
+
if (!Number.isFinite(value)) continue;
|
|
5419
|
+
min = Math.min(min, value);
|
|
5420
|
+
max = Math.max(max, value);
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5423
|
+
if (min === Infinity) return [...EMPTY_DOMAIN];
|
|
5424
|
+
if (min === max) return min === 0 ? [...EMPTY_DOMAIN] : [Math.min(0, min), Math.max(0, max)];
|
|
5425
|
+
if (includeZero) return [Math.min(0, min), Math.max(0, max)];
|
|
5426
|
+
return null;
|
|
5427
|
+
};
|
|
5428
|
+
//#endregion
|
|
5049
5429
|
//#region src/charts/bar-chart/private/use-bar-chart-options.ts
|
|
5050
5430
|
/** Outer padding of the category band scale (space at the chart edges). */
|
|
5051
5431
|
const BASE_BAND_PADDING = .2;
|
|
@@ -5170,10 +5550,6 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
5170
5550
|
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution, formatting));
|
|
5171
5551
|
const valueFormatter = formatNumberCompact;
|
|
5172
5552
|
const bandDomain = timeTickFormatter ? getBandDomain(data, isSeriesRendered) : null;
|
|
5173
|
-
const valueAccessor = (d) => {
|
|
5174
|
-
const enhancedPoint = d;
|
|
5175
|
-
return enhancedPoint?.visualValue !== void 0 ? enhancedPoint.visualValue : d?.value;
|
|
5176
|
-
};
|
|
5177
5553
|
return {
|
|
5178
5554
|
timeAxis: bandDomain && timeTickFormatter && {
|
|
5179
5555
|
domain: bandDomain,
|
|
@@ -5184,7 +5560,7 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
5184
5560
|
yTickFormat: valueFormatter,
|
|
5185
5561
|
tooltipLabelFormatter: tooltipDatumFormatter,
|
|
5186
5562
|
xAccessor: bucketAccessor,
|
|
5187
|
-
yAccessor:
|
|
5563
|
+
yAccessor: getBarValue,
|
|
5188
5564
|
gridVisibility: "x",
|
|
5189
5565
|
xScale: bandScale,
|
|
5190
5566
|
yScale: linearScale
|
|
@@ -5193,7 +5569,7 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
5193
5569
|
xTickFormat: valueFormatter,
|
|
5194
5570
|
yTickFormat: labelFormatter,
|
|
5195
5571
|
tooltipLabelFormatter: tooltipDatumFormatter,
|
|
5196
|
-
xAccessor:
|
|
5572
|
+
xAccessor: getBarValue,
|
|
5197
5573
|
yAccessor: bucketAccessor,
|
|
5198
5574
|
gridVisibility: "y",
|
|
5199
5575
|
xScale: linearScale,
|
|
@@ -5208,20 +5584,10 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
5208
5584
|
]);
|
|
5209
5585
|
return useMemo(() => {
|
|
5210
5586
|
const { xTickFormat: defaultXTickFormat, yTickFormat: defaultYTickFormat, tooltipLabelFormatter: defaultTooltipLabelFormatter, xAccessor, yAccessor, gridVisibility, xScale: baseXScale, yScale: baseYScale } = defaultOptions[horizontal ? "horizontal" : "vertical"];
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
data.forEach((series) => {
|
|
5216
|
-
series.data.forEach((d) => {
|
|
5217
|
-
const enhanced = d;
|
|
5218
|
-
const v = enhanced.visualValue !== void 0 ? enhanced.visualValue : d.value;
|
|
5219
|
-
if (typeof v === "number" && Number.isFinite(v)) allValues.push(v);
|
|
5220
|
-
});
|
|
5221
|
-
});
|
|
5222
|
-
if (allValues.length > 0) valueScaleDomainOverride = { domain: [Math.min(0, ...allValues), Math.max(0, ...allValues)] };
|
|
5223
|
-
}
|
|
5224
|
-
}
|
|
5587
|
+
const valueScaleOptions = horizontal ? stableOptions.xScale : stableOptions.yScale;
|
|
5588
|
+
const includeZero = data.some((s) => s.options?.type === "comparison") || valueScaleOptions?.zero !== false;
|
|
5589
|
+
const domain = valueScaleOptions?.domain ? null : getValueScaleDomain(data, includeZero, isSeriesRendered);
|
|
5590
|
+
const valueScaleDomainOverride = domain ? { domain } : {};
|
|
5225
5591
|
const xScale = {
|
|
5226
5592
|
...baseXScale,
|
|
5227
5593
|
...stableOptions.xScale || {},
|
|
@@ -5272,10 +5638,25 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
5272
5638
|
axisConfig,
|
|
5273
5639
|
stableOptions,
|
|
5274
5640
|
horizontal,
|
|
5275
|
-
data
|
|
5641
|
+
data,
|
|
5642
|
+
isSeriesRendered
|
|
5276
5643
|
]);
|
|
5277
5644
|
}
|
|
5278
5645
|
//#endregion
|
|
5646
|
+
//#region src/charts/bar-chart/private/band-scale.ts
|
|
5647
|
+
/**
|
|
5648
|
+
* Match the inner slot scale used by visx BarGroup.
|
|
5649
|
+
* @param keys - Visible primary series keys.
|
|
5650
|
+
* @param bandwidth - Category band width.
|
|
5651
|
+
* @param padding - Padding between slots.
|
|
5652
|
+
* @return The grouped bar scale.
|
|
5653
|
+
*/
|
|
5654
|
+
const createGroupScale = (keys, bandwidth, padding) => scaleBand({
|
|
5655
|
+
domain: keys,
|
|
5656
|
+
range: [0, bandwidth],
|
|
5657
|
+
padding
|
|
5658
|
+
});
|
|
5659
|
+
//#endregion
|
|
5279
5660
|
//#region src/charts/bar-chart/private/comparison-bars-geometry.ts
|
|
5280
5661
|
/**
|
|
5281
5662
|
* Output position of a value scale's baseline: zero if in-domain, else the
|
|
@@ -5348,11 +5729,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
5348
5729
|
const valueScale = horizontal ? xScale : yScale;
|
|
5349
5730
|
const bandwidth = bandScale.bandwidth ? bandScale.bandwidth() : 0;
|
|
5350
5731
|
if (!bandwidth) return null;
|
|
5351
|
-
const groupScale =
|
|
5352
|
-
domain: primaryKeys,
|
|
5353
|
-
range: [0, bandwidth],
|
|
5354
|
-
padding: groupPadding
|
|
5355
|
-
});
|
|
5732
|
+
const groupScale = createGroupScale(primaryKeys, bandwidth, groupPadding);
|
|
5356
5733
|
const slotThickness = groupScale.bandwidth();
|
|
5357
5734
|
const baseline = getValueScaleBaseline(valueScale);
|
|
5358
5735
|
const bandAccessor = horizontal ? yAccessor : xAccessor;
|
|
@@ -5404,10 +5781,169 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
5404
5781
|
});
|
|
5405
5782
|
};
|
|
5406
5783
|
//#endregion
|
|
5784
|
+
//#region src/charts/bar-chart/private/band-highlight.tsx
|
|
5785
|
+
/**
|
|
5786
|
+
* Render and report the active band using the chart’s registered scales.
|
|
5787
|
+
* @param root0 - Highlight options.
|
|
5788
|
+
* @param root0.visible - Whether to paint the band.
|
|
5789
|
+
* @param root0.horizontal - Whether categories run vertically.
|
|
5790
|
+
* @param root0.onChange - Receives selected band geometry.
|
|
5791
|
+
* @return The optional band highlight.
|
|
5792
|
+
*/
|
|
5793
|
+
function BandHighlight({ visible, horizontal, onChange }) {
|
|
5794
|
+
const { xScale, yScale, dataRegistry, margin, innerWidth, innerHeight } = useContext(DataContext);
|
|
5795
|
+
const { tooltipOpen, tooltipData } = useContext(TooltipContext);
|
|
5796
|
+
const nearest = tooltipData?.nearestDatum;
|
|
5797
|
+
const selection = useMemo(() => {
|
|
5798
|
+
if (!tooltipOpen || !nearest) return null;
|
|
5799
|
+
const scale = horizontal ? yScale : xScale;
|
|
5800
|
+
const entry = dataRegistry?.get(nearest.key);
|
|
5801
|
+
const accessor = horizontal ? entry?.yAccessor : entry?.xAccessor;
|
|
5802
|
+
if (!scale?.bandwidth || !accessor) return null;
|
|
5803
|
+
const position = scale(accessor(nearest.datum));
|
|
5804
|
+
if (position === void 0 || !Number.isFinite(position)) return null;
|
|
5805
|
+
return {
|
|
5806
|
+
datum: nearest.datum,
|
|
5807
|
+
key: nearest.key,
|
|
5808
|
+
index: nearest.index,
|
|
5809
|
+
x: horizontal ? margin?.left ?? 0 : position,
|
|
5810
|
+
y: horizontal ? position : margin?.top ?? 0,
|
|
5811
|
+
width: horizontal ? innerWidth : scale.bandwidth(),
|
|
5812
|
+
height: horizontal ? scale.bandwidth() : innerHeight
|
|
5813
|
+
};
|
|
5814
|
+
}, [
|
|
5815
|
+
tooltipOpen,
|
|
5816
|
+
nearest,
|
|
5817
|
+
horizontal,
|
|
5818
|
+
xScale,
|
|
5819
|
+
yScale,
|
|
5820
|
+
dataRegistry,
|
|
5821
|
+
margin,
|
|
5822
|
+
innerWidth,
|
|
5823
|
+
innerHeight
|
|
5824
|
+
]);
|
|
5825
|
+
const stableSelection = useDeepMemo(selection);
|
|
5826
|
+
const onChangeRef = useRef(onChange);
|
|
5827
|
+
onChangeRef.current = onChange;
|
|
5828
|
+
useEffect(() => {
|
|
5829
|
+
onChangeRef.current?.(stableSelection);
|
|
5830
|
+
}, [stableSelection]);
|
|
5831
|
+
useEffect(() => () => onChangeRef.current?.(null), []);
|
|
5832
|
+
if (!visible || !selection) return null;
|
|
5833
|
+
const { x, y, width, height } = selection;
|
|
5834
|
+
return /* @__PURE__ */ jsx("rect", {
|
|
5835
|
+
x,
|
|
5836
|
+
y,
|
|
5837
|
+
width,
|
|
5838
|
+
height,
|
|
5839
|
+
pointerEvents: "none",
|
|
5840
|
+
fill: CATALOG_POINTERS.surfaceSecondary
|
|
5841
|
+
});
|
|
5842
|
+
}
|
|
5843
|
+
//#endregion
|
|
5844
|
+
//#region src/charts/bar-chart/private/band-tooltip.tsx
|
|
5845
|
+
/**
|
|
5846
|
+
* Find a category by its painted center, including outer padding and reversed ranges.
|
|
5847
|
+
* @param data - Registered series points.
|
|
5848
|
+
* @param accessor - Category accessor.
|
|
5849
|
+
* @param scale - Rendered category band scale.
|
|
5850
|
+
* @param position - Pointer coordinate on the category axis.
|
|
5851
|
+
* @return Index of the nearest category, or -1 when none is registered.
|
|
5852
|
+
*/
|
|
5853
|
+
function nearestBandIndex(data, accessor, scale, position) {
|
|
5854
|
+
let nearest = -1;
|
|
5855
|
+
let distance = Infinity;
|
|
5856
|
+
data.forEach((datum, index) => {
|
|
5857
|
+
const start = scale(accessor(datum));
|
|
5858
|
+
if (start === void 0) return;
|
|
5859
|
+
const candidate = Math.abs(start + scale.bandwidth() / 2 - position);
|
|
5860
|
+
if (candidate < distance) {
|
|
5861
|
+
distance = candidate;
|
|
5862
|
+
nearest = index;
|
|
5863
|
+
}
|
|
5864
|
+
});
|
|
5865
|
+
return nearest;
|
|
5866
|
+
}
|
|
5867
|
+
/**
|
|
5868
|
+
* Correct visx's range-based band inversion, which omits outer padding.
|
|
5869
|
+
* @param root0 - Registered series selection.
|
|
5870
|
+
* @param root0.keys - Visible series keys.
|
|
5871
|
+
* @param root0.groupPadding - Padding between grouped bars.
|
|
5872
|
+
* @param root0.withTooltips - Whether pointer events update the tooltip.
|
|
5873
|
+
* @param root0.onPointerDown - Receives the corrected pointer-down datum.
|
|
5874
|
+
* @param root0.onPointerUp - Receives the corrected pointer-up datum.
|
|
5875
|
+
* @return No visual content.
|
|
5876
|
+
*/
|
|
5877
|
+
function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointerUp }) {
|
|
5878
|
+
const { xScale, yScale, dataRegistry, horizontal } = useContext(DataContext);
|
|
5879
|
+
const { showTooltip } = useContext(TooltipContext);
|
|
5880
|
+
const scale = horizontal ? yScale : xScale;
|
|
5881
|
+
const bandwidth = scale?.bandwidth?.() ?? 0;
|
|
5882
|
+
const groupScale = useMemo(() => createGroupScale(keys, bandwidth, groupPadding), [
|
|
5883
|
+
keys,
|
|
5884
|
+
bandwidth,
|
|
5885
|
+
groupPadding
|
|
5886
|
+
]);
|
|
5887
|
+
const getSelections = useCallback((params) => {
|
|
5888
|
+
const point = params?.svgPoint;
|
|
5889
|
+
if (!point || !scale?.bandwidth) return [];
|
|
5890
|
+
const selections = [];
|
|
5891
|
+
for (const key of keys) {
|
|
5892
|
+
const entry = dataRegistry?.get(key);
|
|
5893
|
+
if (!entry) continue;
|
|
5894
|
+
const accessor = horizontal ? entry.yAccessor : entry.xAccessor;
|
|
5895
|
+
const index = nearestBandIndex(entry.data, accessor, scale, horizontal ? point.y : point.x);
|
|
5896
|
+
if (index < 0) continue;
|
|
5897
|
+
const datum = entry.data[index];
|
|
5898
|
+
const start = Number(scale(accessor(datum))) + Number(groupScale(key));
|
|
5899
|
+
const end = start + groupScale.step();
|
|
5900
|
+
const position = horizontal ? point.y : point.x;
|
|
5901
|
+
const distance = position >= start && position <= end ? 0 : Math.abs(position - (start + end) / 2);
|
|
5902
|
+
selections.push({
|
|
5903
|
+
event: params.event,
|
|
5904
|
+
key,
|
|
5905
|
+
datum,
|
|
5906
|
+
index,
|
|
5907
|
+
svgPoint: point,
|
|
5908
|
+
distanceX: horizontal ? 0 : distance,
|
|
5909
|
+
distanceY: horizontal ? distance : 0
|
|
5910
|
+
});
|
|
5911
|
+
}
|
|
5912
|
+
return selections;
|
|
5913
|
+
}, [
|
|
5914
|
+
scale,
|
|
5915
|
+
dataRegistry,
|
|
5916
|
+
horizontal,
|
|
5917
|
+
keys,
|
|
5918
|
+
groupScale
|
|
5919
|
+
]);
|
|
5920
|
+
const handlePointer = useCallback((params) => {
|
|
5921
|
+
const selections = getSelections(params);
|
|
5922
|
+
if (withTooltips && params?.event.type !== "pointerup") selections.forEach(showTooltip);
|
|
5923
|
+
const callback = params?.event.type === "pointerdown" ? onPointerDown : onPointerUp;
|
|
5924
|
+
if (params?.event.type === "pointermove" || !callback) return;
|
|
5925
|
+
const nearest = selections.reduce((best, selection) => {
|
|
5926
|
+
const distance = (value) => Math.hypot(value.distanceX, value.distanceY);
|
|
5927
|
+
return !best || distance(selection) <= distance(best) ? selection : best;
|
|
5928
|
+
}, void 0);
|
|
5929
|
+
if (nearest) callback(nearest);
|
|
5930
|
+
}, [
|
|
5931
|
+
getSelections,
|
|
5932
|
+
withTooltips,
|
|
5933
|
+
showTooltip,
|
|
5934
|
+
onPointerDown,
|
|
5935
|
+
onPointerUp
|
|
5936
|
+
]);
|
|
5937
|
+
useEventEmitter("pointermove", withTooltips ? handlePointer : void 0);
|
|
5938
|
+
useEventEmitter("pointerdown", handlePointer);
|
|
5939
|
+
useEventEmitter("pointerup", onPointerUp ? handlePointer : void 0);
|
|
5940
|
+
return null;
|
|
5941
|
+
}
|
|
5942
|
+
//#endregion
|
|
5407
5943
|
//#region src/charts/bar-chart/bar-chart.tsx
|
|
5408
5944
|
const validateData$2 = (data) => {
|
|
5409
|
-
if (!data?.length) return "No data available";
|
|
5410
|
-
if (data.some((series) => series.data.some((point) =>
|
|
5945
|
+
if (!data?.length) return __("No data available", "jetpack-charts");
|
|
5946
|
+
if (data.some((series) => series.data.some((point) => isInvalidReading(point.value, { allowMissing: true }) || !point.label && (!("date" in point && point.date) || isNaN(point.date.getTime()))))) return __("Invalid data", "jetpack-charts");
|
|
5411
5947
|
return null;
|
|
5412
5948
|
};
|
|
5413
5949
|
const getPatternId = (chartId, index) => `bar-pattern-${chartId}-${index}`;
|
|
@@ -5415,9 +5951,11 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ jsx("div", {
|
|
|
5415
5951
|
className: bar_chart_module_default["bar-chart__tooltip-row"],
|
|
5416
5952
|
children: sprintf(__("%1$s: %2$s", "jetpack-charts"), label, value)
|
|
5417
5953
|
});
|
|
5418
|
-
const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
5954
|
+
const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
5955
|
+
if (!withTooltips && (withBandHighlight || onBandHighlightChange)) warnOnce("bar-chart-band-highlight-without-tooltips", "BarChart: withBandHighlight and onBandHighlightChange require withTooltips.");
|
|
5419
5956
|
const legendInteractive = legend.interactive ?? false;
|
|
5420
5957
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
5958
|
+
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
5421
5959
|
const horizontal = orientation === "horizontal";
|
|
5422
5960
|
const chartId = useChartId(providedChartId);
|
|
5423
5961
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
@@ -5428,10 +5966,21 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5428
5966
|
enabled: showZeroValues,
|
|
5429
5967
|
valueAxisLength: horizontal ? width : height
|
|
5430
5968
|
});
|
|
5431
|
-
const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({
|
|
5969
|
+
const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({
|
|
5970
|
+
collapseGroups: legendCollapseGroups,
|
|
5971
|
+
comparisonItem: legendComparisonItem
|
|
5972
|
+
}), [legendCollapseGroups, legendComparisonItem]));
|
|
5432
5973
|
const { getElementStyles } = useGlobalChartsContext();
|
|
5433
5974
|
const isSeriesRendered = useCallback((series) => isSeriesVisible(series.label), [isSeriesVisible]);
|
|
5975
|
+
const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(dataSorted.filter(isSeriesRendered)), [dataSorted, isSeriesRendered]);
|
|
5434
5976
|
const chartOptions = useBarChartOptions(dataWithVisibleZeros, horizontal, options, isSeriesRendered);
|
|
5977
|
+
const valueAxis = horizontal ? chartOptions.axis.x : chartOptions.axis.y;
|
|
5978
|
+
const callerValueDomain = horizontal ? options.xScale?.domain : options.yScale?.domain;
|
|
5979
|
+
const wholeNumberTicksProps = {
|
|
5980
|
+
axis: horizontal ? "x" : "y",
|
|
5981
|
+
numTicks: valueAxis.numTicks,
|
|
5982
|
+
enabled: hasWholeNumberValues && !valueAxis.tickValues && !callerValueDomain
|
|
5983
|
+
};
|
|
5435
5984
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme, horizontal);
|
|
5436
5985
|
const chartRef = useRef(null);
|
|
5437
5986
|
const { legendChildren, nonLegendChildren } = useChartChildren(children, "BarChart");
|
|
@@ -5441,8 +5990,6 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5441
5990
|
}, [height]);
|
|
5442
5991
|
const [selectedIndex, setSelectedIndex] = useState(void 0);
|
|
5443
5992
|
const [isNavigating, setIsNavigating] = useState(false);
|
|
5444
|
-
const primarySeriesForNav = dataWithVisibleZeros.filter((s) => s.options?.type !== "comparison");
|
|
5445
|
-
const totalPoints = Math.max(0, ...primarySeriesForNav.map((s) => s.data?.length || 0)) * primarySeriesForNav.length;
|
|
5446
5993
|
const seriesWithVisibility = useMemo(() => dataWithVisibleZeros.map((series, index) => ({
|
|
5447
5994
|
series,
|
|
5448
5995
|
index,
|
|
@@ -5452,6 +5999,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5452
5999
|
return seriesWithVisibility.every(({ isVisible }) => !isVisible);
|
|
5453
6000
|
}, [seriesWithVisibility]);
|
|
5454
6001
|
const primaryEntries = useMemo(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
|
|
6002
|
+
const totalPoints = Math.max(0, ...primaryEntries.map((e) => e.series.data.length)) * primaryEntries.length;
|
|
5455
6003
|
const primaryKeys = useMemo(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
|
|
5456
6004
|
const primarySeries = useMemo(() => primaryEntries.map(({ series }) => series), [primaryEntries]);
|
|
5457
6005
|
const activateSelectedBar = useCallback((index) => {
|
|
@@ -5466,6 +6014,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5466
6014
|
key: series.label
|
|
5467
6015
|
});
|
|
5468
6016
|
}, [primaryEntries, onDatumActivate]);
|
|
6017
|
+
const visibleSeriesKey = useMemo(() => JSON.stringify(primaryKeys), [primaryKeys]);
|
|
5469
6018
|
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
5470
6019
|
selectedIndex,
|
|
5471
6020
|
setSelectedIndex,
|
|
@@ -5473,7 +6022,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5473
6022
|
setIsNavigating,
|
|
5474
6023
|
chartRef,
|
|
5475
6024
|
totalPoints,
|
|
5476
|
-
onActivate: activateSelectedBar
|
|
6025
|
+
onActivate: activateSelectedBar,
|
|
6026
|
+
visibleSeriesKey
|
|
5477
6027
|
});
|
|
5478
6028
|
const comparisonEntries = useMemo(() => {
|
|
5479
6029
|
const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
|
|
@@ -5536,7 +6086,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5536
6086
|
chartOptions.yScale,
|
|
5537
6087
|
horizontal
|
|
5538
6088
|
]);
|
|
5539
|
-
const getBarBackground = useCallback((index) => () => withPatterns ? `url(#${getPatternId(chartId, index)})` : getElementStyles({
|
|
6089
|
+
const getBarBackground = useCallback((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? getElementStyles({
|
|
5540
6090
|
data: dataSorted[index],
|
|
5541
6091
|
index
|
|
5542
6092
|
}).color, [
|
|
@@ -5563,15 +6113,15 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5563
6113
|
const p = point;
|
|
5564
6114
|
return nearestDatum.label != null ? p.label === nearestDatum.label : !!nearestDatum.date && !!p.date && p.date.getTime() === nearestDatum.date.getTime();
|
|
5565
6115
|
});
|
|
5566
|
-
if (comparisonEntry && comparisonDatum
|
|
6116
|
+
if (comparisonEntry && comparisonDatum) return /* @__PURE__ */ jsxs("div", {
|
|
5567
6117
|
className: bar_chart_module_default["bar-chart__tooltip"],
|
|
5568
6118
|
children: [
|
|
5569
6119
|
/* @__PURE__ */ jsx("div", {
|
|
5570
6120
|
className: bar_chart_module_default["bar-chart__tooltip-header"],
|
|
5571
6121
|
children: categoryLabel
|
|
5572
6122
|
}),
|
|
5573
|
-
renderTooltipRow(primaryKey,
|
|
5574
|
-
renderTooltipRow(comparisonEntry.series.label,
|
|
6123
|
+
renderTooltipRow(primaryKey, formatReading(nearestDatum.value)),
|
|
6124
|
+
renderTooltipRow(comparisonEntry.series.label, formatReading(comparisonDatum.value))
|
|
5575
6125
|
]
|
|
5576
6126
|
});
|
|
5577
6127
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -5579,7 +6129,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5579
6129
|
children: [/* @__PURE__ */ jsx("div", {
|
|
5580
6130
|
className: bar_chart_module_default["bar-chart__tooltip-header"],
|
|
5581
6131
|
children: primaryKey
|
|
5582
|
-
}), renderTooltipRow(categoryLabel,
|
|
6132
|
+
}), renderTooltipRow(categoryLabel, formatReading(nearestDatum.value))]
|
|
5583
6133
|
});
|
|
5584
6134
|
}, [chartOptions.tooltip, comparisonEntries]);
|
|
5585
6135
|
const renderPattern = useCallback((index, color) => {
|
|
@@ -5630,15 +6180,15 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5630
6180
|
const createKeyboardHighlightStyle = useCallback(() => {
|
|
5631
6181
|
if (selectedIndex === void 0) return "";
|
|
5632
6182
|
const primaryCount = primaryEntries.length;
|
|
5633
|
-
|
|
6183
|
+
if (!primaryCount) return "";
|
|
5634
6184
|
const dataPointIndex = Math.floor(selectedIndex / primaryCount);
|
|
5635
6185
|
const seriesIndex = selectedIndex % primaryCount;
|
|
5636
|
-
if (dataPointIndex >= maxDataPoints || seriesIndex >= primaryCount) return "";
|
|
5637
6186
|
const seriesData = primaryEntries[seriesIndex]?.series;
|
|
5638
|
-
|
|
5639
|
-
|
|
6187
|
+
const datum = seriesData?.data[dataPointIndex];
|
|
6188
|
+
if (!seriesData || !datum || !isBarRendered(datum)) return "";
|
|
6189
|
+
const domBarIndex = primaryEntries.slice(0, seriesIndex).reduce((count, { series }) => count + countRenderedBars(series.data), 0) + countRenderedBars(seriesData.data.slice(0, dataPointIndex));
|
|
5640
6190
|
return `
|
|
5641
|
-
.bar-chart[data-chart-id="bar-chart-${chartId}"] .visx-bar-group .visx-bar:nth-child(${
|
|
6191
|
+
.bar-chart[data-chart-id="bar-chart-${chartId}"] .visx-bar-group .visx-bar:nth-child(${domBarIndex + 1}) {
|
|
5642
6192
|
stroke: #005fcc;
|
|
5643
6193
|
stroke-width: 2px;
|
|
5644
6194
|
}
|
|
@@ -5706,13 +6256,13 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5706
6256
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
5707
6257
|
return /* @__PURE__ */ jsx("div", {
|
|
5708
6258
|
role: "grid",
|
|
6259
|
+
ref: chartRef,
|
|
5709
6260
|
"aria-label": __("Bar chart", "jetpack-charts"),
|
|
5710
6261
|
tabIndex: 0,
|
|
5711
6262
|
onKeyDown: onChartKeyDown,
|
|
5712
6263
|
onFocus: onChartFocus,
|
|
5713
6264
|
onBlur: onChartBlur,
|
|
5714
6265
|
children: chartHeight > 0 && /* @__PURE__ */ jsx("div", {
|
|
5715
|
-
ref: chartRef,
|
|
5716
6266
|
className: xy_plot_module_default["xy-plot"],
|
|
5717
6267
|
children: /* @__PURE__ */ jsxs(XYChart, {
|
|
5718
6268
|
theme,
|
|
@@ -5725,14 +6275,26 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5725
6275
|
xScale,
|
|
5726
6276
|
yScale,
|
|
5727
6277
|
horizontal,
|
|
5728
|
-
onPointerDown,
|
|
5729
|
-
onPointerUp,
|
|
5730
6278
|
pointerEventsDataKey: "nearest",
|
|
5731
6279
|
children: [
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
6280
|
+
withTooltips && (withBandHighlight || onBandHighlightChange) && /* @__PURE__ */ jsx(BandHighlight, {
|
|
6281
|
+
visible: withBandHighlight,
|
|
6282
|
+
horizontal,
|
|
6283
|
+
onChange: onBandHighlightChange
|
|
6284
|
+
}),
|
|
6285
|
+
!allSeriesHidden && /* @__PURE__ */ jsx(WholeNumberTicks, {
|
|
6286
|
+
...wholeNumberTicksProps,
|
|
6287
|
+
children: (valueTicks) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Grid, {
|
|
6288
|
+
columns: gridVisibility.includes("y"),
|
|
6289
|
+
rows: false,
|
|
6290
|
+
numTicks: chartOptions.axis.x.numTicks,
|
|
6291
|
+
tickValues: (horizontal ? valueTicks : void 0) ?? chartOptions.axis.x.tickValues
|
|
6292
|
+
}), /* @__PURE__ */ jsx(Grid, {
|
|
6293
|
+
columns: false,
|
|
6294
|
+
rows: gridVisibility.includes("x"),
|
|
6295
|
+
numTicks: chartOptions.axis.y.numTicks,
|
|
6296
|
+
tickValues: (horizontal ? void 0 : valueTicks) ?? chartOptions.axis.y.tickValues
|
|
6297
|
+
})] })
|
|
5736
6298
|
}),
|
|
5737
6299
|
withPatterns && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("defs", { children: dataSorted.map((seriesData, index) => renderPattern(index, getElementStyles({
|
|
5738
6300
|
data: seriesData,
|
|
@@ -5769,8 +6331,26 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5769
6331
|
colorAccessor: getBarBackground(index)
|
|
5770
6332
|
}, seriesData?.label))
|
|
5771
6333
|
}),
|
|
5772
|
-
|
|
6334
|
+
(withTooltips || onPointerDown || onPointerUp) && /* @__PURE__ */ jsx(BandTooltip, {
|
|
6335
|
+
keys: primaryKeys,
|
|
6336
|
+
groupPadding,
|
|
6337
|
+
withTooltips,
|
|
6338
|
+
onPointerDown,
|
|
6339
|
+
onPointerUp
|
|
6340
|
+
}),
|
|
6341
|
+
!allSeriesHidden && /* @__PURE__ */ jsx(WholeNumberTicks, {
|
|
6342
|
+
...wholeNumberTicksProps,
|
|
6343
|
+
children: (valueTicks) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Axis, {
|
|
6344
|
+
...chartOptions.axis.x,
|
|
6345
|
+
...horizontal && valueTicks ? { tickValues: valueTicks } : {}
|
|
6346
|
+
}), /* @__PURE__ */ jsx(Axis, {
|
|
6347
|
+
...chartOptions.axis.y,
|
|
6348
|
+
...!horizontal && valueTicks ? { tickValues: valueTicks } : {}
|
|
6349
|
+
})] })
|
|
6350
|
+
}),
|
|
5773
6351
|
withTooltips && /* @__PURE__ */ jsx(AccessibleTooltip, {
|
|
6352
|
+
tooltipPlacement,
|
|
6353
|
+
tooltipAnchorTop,
|
|
5774
6354
|
detectBounds: true,
|
|
5775
6355
|
snapTooltipToDatumX: true,
|
|
5776
6356
|
snapTooltipToDatumY: true,
|
|
@@ -6592,8 +7172,11 @@ var heatmap_chart_module_default = {
|
|
|
6592
7172
|
"heatmap-chart__gap-start": "a8ccharts-O3YMOW-heatmap-chart__gap-start",
|
|
6593
7173
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
6594
7174
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
7175
|
+
"heatmap-chart__grid--flex-gaps": "a8ccharts-O3YMOW-heatmap-chart__grid--flex-gaps",
|
|
6595
7176
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
7177
|
+
"heatmap-chart__group-label": "a8ccharts-O3YMOW-heatmap-chart__group-label",
|
|
6596
7178
|
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
7179
|
+
"heatmap-chart__legend-scale--bar": "a8ccharts-O3YMOW-heatmap-chart__legend-scale--bar",
|
|
6597
7180
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
6598
7181
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
6599
7182
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
@@ -6643,7 +7226,7 @@ const getNormalizedValue = (value, extent) => {
|
|
|
6643
7226
|
const HeatmapContext = createContext(null);
|
|
6644
7227
|
//#endregion
|
|
6645
7228
|
//#region src/charts/heatmap-chart/private/heatmap-legend.tsx
|
|
6646
|
-
const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
7229
|
+
const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }) => {
|
|
6647
7230
|
const context = useContext(HeatmapContext);
|
|
6648
7231
|
const { legend } = useGlobalChartsTheme();
|
|
6649
7232
|
if (!context) return null;
|
|
@@ -6662,11 +7245,12 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6662
7245
|
}),
|
|
6663
7246
|
/* @__PURE__ */ jsx(Stack, {
|
|
6664
7247
|
direction: "row",
|
|
6665
|
-
gap: "xs",
|
|
7248
|
+
gap: variant === "bar" ? void 0 : "xs",
|
|
7249
|
+
"aria-hidden": "true",
|
|
7250
|
+
className: variant === "bar" ? heatmap_chart_module_default["heatmap-chart__legend-scale--bar"] : void 0,
|
|
6666
7251
|
children: Array.from({ length: steps }, (_, index) => {
|
|
6667
7252
|
const intensity = steps <= 1 ? 1 : index / (steps - 1);
|
|
6668
7253
|
return /* @__PURE__ */ jsx("span", {
|
|
6669
|
-
"aria-hidden": "true",
|
|
6670
7254
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
6671
7255
|
style: {
|
|
6672
7256
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
@@ -6685,16 +7269,219 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6685
7269
|
});
|
|
6686
7270
|
};
|
|
6687
7271
|
//#endregion
|
|
7272
|
+
//#region src/charts/heatmap-chart/private/column-groups.ts
|
|
7273
|
+
const isSpan = (span) => Number.isInteger(span) && span > 0;
|
|
7274
|
+
/**
|
|
7275
|
+
* Validates column groups and lays them over the columns.
|
|
7276
|
+
*
|
|
7277
|
+
* @param groups - Groups as passed to the chart.
|
|
7278
|
+
* @param columnCount - Number of data columns.
|
|
7279
|
+
* @param firstLine - Grid column line of the first data column.
|
|
7280
|
+
* @return Grid column lines for every column and group; no groups when the input was unusable.
|
|
7281
|
+
*/
|
|
7282
|
+
const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
7283
|
+
const ungrouped = () => ({
|
|
7284
|
+
columns: Array.from({ length: columnCount }, (_, index) => ({
|
|
7285
|
+
line: firstLine + index,
|
|
7286
|
+
gapBefore: false
|
|
7287
|
+
})),
|
|
7288
|
+
groups: []
|
|
7289
|
+
});
|
|
7290
|
+
if (!groups || groups.length === 0 || columnCount === 0) return ungrouped();
|
|
7291
|
+
const spans = groups.map((group) => group.span);
|
|
7292
|
+
const total = spans.reduce((sum, span) => sum + span, 0);
|
|
7293
|
+
if (!spans.every(isSpan) || total > columnCount) {
|
|
7294
|
+
warnOnce(`heatmap:columnGroups:${JSON.stringify(spans)}:${columnCount}`, `columnGroups spans ${JSON.stringify(spans)} must be positive integers that fit the ${columnCount} columns, so no groups are drawn.`);
|
|
7295
|
+
return ungrouped();
|
|
7296
|
+
}
|
|
7297
|
+
const columns = [];
|
|
7298
|
+
const laidOut = [];
|
|
7299
|
+
let line = firstLine;
|
|
7300
|
+
groups.forEach((group, groupIndex) => {
|
|
7301
|
+
if (groupIndex > 0) line += 1;
|
|
7302
|
+
laidOut.push({
|
|
7303
|
+
...group,
|
|
7304
|
+
line
|
|
7305
|
+
});
|
|
7306
|
+
for (let offset = 0; offset < group.span; offset++) {
|
|
7307
|
+
columns.push({
|
|
7308
|
+
line,
|
|
7309
|
+
gapBefore: groupIndex > 0 && offset === 0,
|
|
7310
|
+
group: groupIndex
|
|
7311
|
+
});
|
|
7312
|
+
line += 1;
|
|
7313
|
+
}
|
|
7314
|
+
});
|
|
7315
|
+
while (columns.length < columnCount) {
|
|
7316
|
+
columns.push({
|
|
7317
|
+
line,
|
|
7318
|
+
gapBefore: false
|
|
7319
|
+
});
|
|
7320
|
+
line += 1;
|
|
7321
|
+
}
|
|
7322
|
+
return {
|
|
7323
|
+
columns,
|
|
7324
|
+
groups: laidOut
|
|
7325
|
+
};
|
|
7326
|
+
};
|
|
7327
|
+
//#endregion
|
|
7328
|
+
//#region src/charts/heatmap-chart/private/keyboard-navigation.ts
|
|
7329
|
+
const ARROW_KEYS = [
|
|
7330
|
+
"ArrowLeft",
|
|
7331
|
+
"ArrowRight",
|
|
7332
|
+
"ArrowUp",
|
|
7333
|
+
"ArrowDown"
|
|
7334
|
+
];
|
|
7335
|
+
const PAGE_KEYS = ["PageUp", "PageDown"];
|
|
7336
|
+
const isNavigationKey = (key, mode) => ARROW_KEYS.includes(key) || mode === "calendar" && PAGE_KEYS.includes(key);
|
|
7337
|
+
const inGrid = (grid, { column, row }) => column >= 0 && column < grid.columns && row >= 0 && row < grid.rows;
|
|
7338
|
+
const firstSelectable = (grid, cells) => cells.find((cell) => inGrid(grid, cell) && !grid.isInert(cell.column, cell.row));
|
|
7339
|
+
/**
|
|
7340
|
+
* Column-major scan for the first selectable cell.
|
|
7341
|
+
*
|
|
7342
|
+
* @param grid - The grid.
|
|
7343
|
+
* @return The cell, or undefined when every slot is inert.
|
|
7344
|
+
*/
|
|
7345
|
+
const firstGridCell = (grid) => {
|
|
7346
|
+
for (let column = 0; column < grid.columns; column++) for (let row = 0; row < grid.rows; row++) if (!grid.isInert(column, row)) return {
|
|
7347
|
+
column,
|
|
7348
|
+
row
|
|
7349
|
+
};
|
|
7350
|
+
};
|
|
7351
|
+
/**
|
|
7352
|
+
* Steps across the grid in the key's direction, past inert slots, staying put at the edge.
|
|
7353
|
+
*
|
|
7354
|
+
* @param grid - The grid.
|
|
7355
|
+
* @param from - The selected cell.
|
|
7356
|
+
* @param key - The arrow key.
|
|
7357
|
+
* @return The next cell, or undefined to keep the selection.
|
|
7358
|
+
*/
|
|
7359
|
+
const stepGridCell = (grid, from, key) => {
|
|
7360
|
+
const step = {
|
|
7361
|
+
ArrowRight: [1, 0],
|
|
7362
|
+
ArrowLeft: [-1, 0],
|
|
7363
|
+
ArrowDown: [0, 1],
|
|
7364
|
+
ArrowUp: [0, -1]
|
|
7365
|
+
}[key];
|
|
7366
|
+
if (!step) return;
|
|
7367
|
+
const [stepColumn, stepRow] = step;
|
|
7368
|
+
let cell = from;
|
|
7369
|
+
do
|
|
7370
|
+
cell = {
|
|
7371
|
+
column: cell.column + stepColumn,
|
|
7372
|
+
row: cell.row + stepRow
|
|
7373
|
+
};
|
|
7374
|
+
while (inGrid(grid, cell) && grid.isInert(cell.column, cell.row));
|
|
7375
|
+
return inGrid(grid, cell) ? cell : void 0;
|
|
7376
|
+
};
|
|
7377
|
+
/**
|
|
7378
|
+
* Every slot of the blocks in reading order: block by block, each a row at a time.
|
|
7379
|
+
*
|
|
7380
|
+
* @param grid - The grid.
|
|
7381
|
+
* @param blocks - The blocks, left to right.
|
|
7382
|
+
* @return The slots in order.
|
|
7383
|
+
*/
|
|
7384
|
+
const readingOrder = (grid, blocks) => blocks.flatMap((block) => Array.from({ length: grid.rows }, (_row, row) => Array.from({ length: block.end - block.start }, (_offset, offset) => ({
|
|
7385
|
+
column: block.start + offset,
|
|
7386
|
+
row
|
|
7387
|
+
}))).flat());
|
|
7388
|
+
const blockOf = (blocks, column) => blocks.findIndex((block) => column >= block.start && column < block.end);
|
|
7389
|
+
/**
|
|
7390
|
+
* The slots after a cell down its column (or before it, going up), continuing at the
|
|
7391
|
+
* same column offset of each following block.
|
|
7392
|
+
*
|
|
7393
|
+
* @param grid - The grid.
|
|
7394
|
+
* @param blocks - The blocks, left to right.
|
|
7395
|
+
* @param from - The selected cell.
|
|
7396
|
+
* @param direction - 1 downwards, -1 upwards.
|
|
7397
|
+
* @return The slots in order.
|
|
7398
|
+
*/
|
|
7399
|
+
const columnOrderFrom = (grid, blocks, from, direction) => {
|
|
7400
|
+
const blockIndex = blockOf(blocks, from.column);
|
|
7401
|
+
if (blockIndex < 0) return [];
|
|
7402
|
+
const offset = from.column - blocks[blockIndex].start;
|
|
7403
|
+
const cells = [];
|
|
7404
|
+
const pushRows = (column, startRow) => {
|
|
7405
|
+
for (let row = startRow; row >= 0 && row < grid.rows; row += direction) cells.push({
|
|
7406
|
+
column,
|
|
7407
|
+
row
|
|
7408
|
+
});
|
|
7409
|
+
};
|
|
7410
|
+
pushRows(from.column, from.row + direction);
|
|
7411
|
+
for (let index = blockIndex + direction; index >= 0 && index < blocks.length; index += direction) {
|
|
7412
|
+
const column = blocks[index].start + offset;
|
|
7413
|
+
if (column < blocks[index].end) pushRows(column, direction === 1 ? 0 : grid.rows - 1);
|
|
7414
|
+
}
|
|
7415
|
+
return cells;
|
|
7416
|
+
};
|
|
7417
|
+
/**
|
|
7418
|
+
* The first selectable cell in calendar reading order.
|
|
7419
|
+
*
|
|
7420
|
+
* @param grid - The grid.
|
|
7421
|
+
* @param blocks - The blocks, left to right.
|
|
7422
|
+
* @return The cell, or undefined when every slot is inert.
|
|
7423
|
+
*/
|
|
7424
|
+
const firstCalendarCell = (grid, blocks) => firstSelectable(grid, readingOrder(grid, blocks));
|
|
7425
|
+
/**
|
|
7426
|
+
* Steps through the blocks as pages of a calendar: Left/Right by one slot in reading
|
|
7427
|
+
* order, Up/Down by one row (into the neighboring block past the edge), Page Up/Down
|
|
7428
|
+
* to the same slot of the neighboring block or its nearest selectable cell.
|
|
7429
|
+
*
|
|
7430
|
+
* @param grid - The grid.
|
|
7431
|
+
* @param blocks - The blocks, left to right.
|
|
7432
|
+
* @param from - The selected cell.
|
|
7433
|
+
* @param key - The navigation key.
|
|
7434
|
+
* @return The next cell, or undefined to keep the selection.
|
|
7435
|
+
*/
|
|
7436
|
+
const stepCalendarCell = (grid, blocks, from, key) => {
|
|
7437
|
+
if (key === "ArrowRight" || key === "ArrowLeft") {
|
|
7438
|
+
const order = readingOrder(grid, blocks);
|
|
7439
|
+
const index = order.findIndex((cell) => cell.column === from.column && cell.row === from.row);
|
|
7440
|
+
if (index < 0) return;
|
|
7441
|
+
const ahead = key === "ArrowRight" ? order.slice(index + 1) : order.slice(0, index).reverse();
|
|
7442
|
+
return firstSelectable(grid, ahead);
|
|
7443
|
+
}
|
|
7444
|
+
if (key === "ArrowDown" || key === "ArrowUp") return firstSelectable(grid, columnOrderFrom(grid, blocks, from, key === "ArrowDown" ? 1 : -1));
|
|
7445
|
+
const blockIndex = blockOf(blocks, from.column);
|
|
7446
|
+
const target = blocks[blockIndex + (key === "PageDown" ? 1 : -1)];
|
|
7447
|
+
if (blockIndex < 0 || !target) return;
|
|
7448
|
+
const same = {
|
|
7449
|
+
column: target.start + (from.column - blocks[blockIndex].start),
|
|
7450
|
+
row: from.row
|
|
7451
|
+
};
|
|
7452
|
+
const page = readingOrder(grid, [target]);
|
|
7453
|
+
const at = page.findIndex((cell) => cell.row > same.row || cell.row === same.row && cell.column >= same.column);
|
|
7454
|
+
const after = at === -1 ? [] : page.slice(at);
|
|
7455
|
+
const before = page.slice(0, at === -1 ? page.length : at).reverse();
|
|
7456
|
+
return firstSelectable(grid, after) ?? firstSelectable(grid, before);
|
|
7457
|
+
};
|
|
7458
|
+
//#endregion
|
|
6688
7459
|
//#region src/charts/heatmap-chart/heatmap-chart.tsx
|
|
6689
7460
|
const CELL_MIX_FLOOR = .15;
|
|
6690
7461
|
const NO_ROW_LABELS = [];
|
|
6691
|
-
const
|
|
7462
|
+
const TOOLTIP_BOX_STYLES = {
|
|
7463
|
+
light: {
|
|
7464
|
+
...defaultStyles,
|
|
7465
|
+
zIndex: 3
|
|
7466
|
+
},
|
|
7467
|
+
dark: { zIndex: 3 }
|
|
7468
|
+
};
|
|
7469
|
+
const cellName = (info) => info.cellLabel || [
|
|
7470
|
+
info.groupLabel,
|
|
7471
|
+
info.columnLabel,
|
|
7472
|
+
info.rowLabel
|
|
7473
|
+
].filter(Boolean).join(" ");
|
|
7474
|
+
const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, columnGroups, keyboardNavigation = "grid", ariaLabel, primaryColor, gap = "md", withTooltips = false, renderTooltip, tooltipVariant = "light", tooltipStyle, children }) => {
|
|
6692
7475
|
const chartId = useChartId(providedChartId);
|
|
7476
|
+
const tooltipBoxStyle = tooltipStyle ? {
|
|
7477
|
+
...TOOLTIP_BOX_STYLES[tooltipVariant],
|
|
7478
|
+
...tooltipStyle
|
|
7479
|
+
} : TOOLTIP_BOX_STYLES[tooltipVariant];
|
|
6693
7480
|
const { getElementStyles, theme } = useGlobalChartsContext();
|
|
6694
7481
|
const scopeElement = useChartScopeElement();
|
|
6695
7482
|
const { heatmapChart: heatmapChartSettings } = theme;
|
|
6696
7483
|
const { nonLegendChildren } = useChartChildren(children, "HeatmapChart");
|
|
6697
|
-
const [
|
|
7484
|
+
const [selected, setSelected] = useState();
|
|
6698
7485
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = useTooltip();
|
|
6699
7486
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
6700
7487
|
const containerRef = useRef(null);
|
|
@@ -6713,69 +7500,75 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6713
7500
|
}), [extent, primaryColorHex]);
|
|
6714
7501
|
const columns = data.length;
|
|
6715
7502
|
const rows = Math.max(0, ...data.map((column) => column.data.length));
|
|
6716
|
-
const
|
|
7503
|
+
const groupLayout = useMemo(() => resolveColumnGroups(columnGroups, columns, 2), [columnGroups, columns]);
|
|
7504
|
+
const { compactCellGap, compactCellSize, groupGap } = heatmapChartSettings;
|
|
6717
7505
|
const drawValues = showValues ?? !compact;
|
|
6718
7506
|
const buildTooltipData = useCallback((columnIndex, rowIndex) => {
|
|
6719
7507
|
const cell = data[columnIndex]?.data[rowIndex];
|
|
7508
|
+
const group = groupLayout.columns[columnIndex]?.group;
|
|
6720
7509
|
return {
|
|
6721
7510
|
value: cell?.value ?? null,
|
|
6722
7511
|
rowLabel: rowLabels[rowIndex],
|
|
6723
7512
|
columnLabel: data[columnIndex]?.label,
|
|
7513
|
+
groupLabel: group === void 0 ? void 0 : groupLayout.groups[group]?.label,
|
|
6724
7514
|
cellLabel: cell?.label,
|
|
6725
7515
|
row: rowIndex,
|
|
6726
7516
|
column: columnIndex
|
|
6727
7517
|
};
|
|
6728
|
-
}, [
|
|
7518
|
+
}, [
|
|
7519
|
+
data,
|
|
7520
|
+
rowLabels,
|
|
7521
|
+
groupLayout
|
|
7522
|
+
]);
|
|
6729
7523
|
const onChartBlur = useCallback(() => {
|
|
6730
|
-
|
|
7524
|
+
setSelected(void 0);
|
|
6731
7525
|
hideTooltip();
|
|
6732
7526
|
}, [hideTooltip]);
|
|
6733
7527
|
const isCellInert = useCallback((col, row) => {
|
|
6734
7528
|
const cell = data[col]?.data[row];
|
|
6735
7529
|
return cell?.hidden === true || cell?.placeholder === true;
|
|
6736
7530
|
}, [data]);
|
|
7531
|
+
const blocks = useMemo(() => {
|
|
7532
|
+
const grouped = groupLayout.groups.map((group, index) => {
|
|
7533
|
+
const start = groupLayout.columns.findIndex((column) => column.group === index);
|
|
7534
|
+
return {
|
|
7535
|
+
start,
|
|
7536
|
+
end: start + group.span
|
|
7537
|
+
};
|
|
7538
|
+
});
|
|
7539
|
+
const groupedEnd = grouped.length ? grouped[grouped.length - 1].end : 0;
|
|
7540
|
+
return groupedEnd < columns ? [...grouped, {
|
|
7541
|
+
start: groupedEnd,
|
|
7542
|
+
end: columns
|
|
7543
|
+
}] : grouped;
|
|
7544
|
+
}, [groupLayout, columns]);
|
|
6737
7545
|
const onChartKeyDown = useCallback((event) => {
|
|
6738
|
-
if (![
|
|
6739
|
-
"ArrowLeft",
|
|
6740
|
-
"ArrowRight",
|
|
6741
|
-
"ArrowUp",
|
|
6742
|
-
"ArrowDown",
|
|
6743
|
-
"Escape",
|
|
6744
|
-
"Tab"
|
|
6745
|
-
].includes(event.key)) return;
|
|
6746
7546
|
if (event.key === "Tab" || event.key === "Escape") {
|
|
6747
|
-
|
|
7547
|
+
setSelected(void 0);
|
|
6748
7548
|
hideTooltip();
|
|
6749
7549
|
return;
|
|
6750
7550
|
}
|
|
7551
|
+
if (!isNavigationKey(event.key, keyboardNavigation)) return;
|
|
6751
7552
|
event.preventDefault();
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
7553
|
+
const grid = {
|
|
7554
|
+
columns,
|
|
7555
|
+
rows,
|
|
7556
|
+
isInert: isCellInert
|
|
7557
|
+
};
|
|
7558
|
+
if (selected === void 0) {
|
|
7559
|
+
setSelected(keyboardNavigation === "calendar" ? firstCalendarCell(grid, blocks) : firstGridCell(grid));
|
|
6757
7560
|
return;
|
|
6758
7561
|
}
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
if (event.key === "ArrowRight") stepCol = 1;
|
|
6762
|
-
else if (event.key === "ArrowLeft") stepCol = -1;
|
|
6763
|
-
else if (event.key === "ArrowDown") stepRow = 1;
|
|
6764
|
-
else if (event.key === "ArrowUp") stepRow = -1;
|
|
6765
|
-
let col = Math.floor(selectedIndex / rows);
|
|
6766
|
-
let row = selectedIndex % rows;
|
|
6767
|
-
do {
|
|
6768
|
-
col += stepCol;
|
|
6769
|
-
row += stepRow;
|
|
6770
|
-
} while (col >= 0 && col < columns && row >= 0 && row < rows && isCellInert(col, row));
|
|
6771
|
-
if (col < 0 || col >= columns || row < 0 || row >= rows) return;
|
|
6772
|
-
setSelectedIndex(col * rows + row);
|
|
7562
|
+
const next = keyboardNavigation === "calendar" ? stepCalendarCell(grid, blocks, selected, event.key) : stepGridCell(grid, selected, event.key);
|
|
7563
|
+
if (next) setSelected(next);
|
|
6773
7564
|
}, [
|
|
6774
7565
|
rows,
|
|
6775
7566
|
columns,
|
|
6776
|
-
|
|
7567
|
+
selected,
|
|
6777
7568
|
hideTooltip,
|
|
6778
|
-
isCellInert
|
|
7569
|
+
isCellInert,
|
|
7570
|
+
keyboardNavigation,
|
|
7571
|
+
blocks
|
|
6779
7572
|
]);
|
|
6780
7573
|
const handleCellMouseMove = useCallback((event) => {
|
|
6781
7574
|
if (!withTooltips) return;
|
|
@@ -6795,35 +7588,47 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6795
7588
|
buildTooltipData,
|
|
6796
7589
|
getTooltipOrigin
|
|
6797
7590
|
]);
|
|
7591
|
+
const getCellElement = useCallback((col, row) => typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null, [chartId]);
|
|
6798
7592
|
const handleCellMouseLeave = useCallback(() => {
|
|
6799
|
-
if (withTooltips &&
|
|
7593
|
+
if (withTooltips && selected === void 0) hideTooltip();
|
|
6800
7594
|
}, [
|
|
6801
7595
|
withTooltips,
|
|
6802
|
-
|
|
7596
|
+
selected,
|
|
6803
7597
|
hideTooltip
|
|
6804
7598
|
]);
|
|
6805
7599
|
useEffect(() => {
|
|
6806
|
-
if (
|
|
7600
|
+
if (selected && (selected.column >= columns || selected.row >= rows)) setSelected(void 0);
|
|
7601
|
+
}, [
|
|
7602
|
+
selected,
|
|
7603
|
+
columns,
|
|
7604
|
+
rows
|
|
7605
|
+
]);
|
|
7606
|
+
useEffect(() => {
|
|
7607
|
+
if (selected === void 0) return;
|
|
7608
|
+
getCellElement(selected.column, selected.row)?.scrollIntoView?.({
|
|
7609
|
+
block: "nearest",
|
|
7610
|
+
inline: "nearest"
|
|
7611
|
+
});
|
|
7612
|
+
}, [selected, getCellElement]);
|
|
7613
|
+
useEffect(() => {
|
|
7614
|
+
if (!withTooltips || selected === void 0) return;
|
|
6807
7615
|
const origin = getTooltipOrigin();
|
|
6808
7616
|
if (!origin) return;
|
|
6809
|
-
const
|
|
6810
|
-
const row = selectedIndex % rows;
|
|
6811
|
-
const rect = (typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null)?.getBoundingClientRect();
|
|
7617
|
+
const rect = getCellElement(selected.column, selected.row)?.getBoundingClientRect();
|
|
6812
7618
|
showTooltip({
|
|
6813
7619
|
tooltipLeft: rect ? rect.left + rect.width / 2 - origin.left : 0,
|
|
6814
7620
|
tooltipTop: rect ? rect.top + rect.height / 2 - origin.top : 0,
|
|
6815
|
-
tooltipData: buildTooltipData(
|
|
7621
|
+
tooltipData: buildTooltipData(selected.column, selected.row)
|
|
6816
7622
|
});
|
|
6817
7623
|
}, [
|
|
6818
|
-
|
|
7624
|
+
selected,
|
|
6819
7625
|
withTooltips,
|
|
6820
|
-
|
|
6821
|
-
chartId,
|
|
7626
|
+
getCellElement,
|
|
6822
7627
|
buildTooltipData,
|
|
6823
7628
|
showTooltip,
|
|
6824
7629
|
getTooltipOrigin
|
|
6825
7630
|
]);
|
|
6826
|
-
const defaultRenderTooltip = useCallback((info) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: info
|
|
7631
|
+
const defaultRenderTooltip = useCallback((info) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: cellName(info) }), /* @__PURE__ */ jsx("div", { children: info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value) })] }), []);
|
|
6827
7632
|
if (!columns || !rows) return /* @__PURE__ */ jsx(Center, {
|
|
6828
7633
|
className: clsx("heatmap-chart", heatmap_chart_module_default["heatmap-chart"], className),
|
|
6829
7634
|
style: {
|
|
@@ -6837,10 +7642,16 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6837
7642
|
});
|
|
6838
7643
|
const columnTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellWidth ?? 0}px, ${maxCellWidth ? `${maxCellWidth}px` : "1fr"})`;
|
|
6839
7644
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
7645
|
+
const hasColumnLabels = data.some((column) => Boolean(column.label));
|
|
7646
|
+
const hasGroups = groupLayout.groups.length > 0;
|
|
7647
|
+
const columnLine = (columnIndex) => groupLayout.columns[columnIndex].line;
|
|
7648
|
+
const firstDataRow = hasColumnLabels ? 2 : 1;
|
|
7649
|
+
const dataTrack = (column) => column.summary ? "minmax(auto, max-content)" : columnTrack;
|
|
7650
|
+
const gapTrack = compact ? `minmax(${groupGap}px, 1fr)` : `${groupGap}px`;
|
|
6840
7651
|
const gridStyle = {
|
|
6841
7652
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6842
|
-
gridTemplateColumns: `auto ${data.
|
|
6843
|
-
gridTemplateRows:
|
|
7653
|
+
gridTemplateColumns: `auto ${data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ")}`,
|
|
7654
|
+
gridTemplateRows: `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`
|
|
6844
7655
|
};
|
|
6845
7656
|
if (compact) {
|
|
6846
7657
|
gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
|
|
@@ -6853,7 +7664,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6853
7664
|
[heatmap_chart_module_default["heatmap-chart__gap-end"]]: columnIndex < columns - 1 && !data[columnIndex + 1]?.summary
|
|
6854
7665
|
};
|
|
6855
7666
|
};
|
|
6856
|
-
const activeDescendant =
|
|
7667
|
+
const activeDescendant = selected ? `${chartId}-cell-${selected.column}-${selected.row}` : void 0;
|
|
6857
7668
|
const heightCapped = !compact && Boolean(maxCellHeight);
|
|
6858
7669
|
return /* @__PURE__ */ jsx(HeatmapContext.Provider, {
|
|
6859
7670
|
value: heatmapContext,
|
|
@@ -6873,7 +7684,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6873
7684
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
6874
7685
|
ref: containerRef,
|
|
6875
7686
|
role: "grid",
|
|
6876
|
-
"aria-label": __("Heatmap chart", "jetpack-charts"),
|
|
7687
|
+
"aria-label": ariaLabel ?? __("Heatmap chart", "jetpack-charts"),
|
|
6877
7688
|
"aria-rowcount": rows,
|
|
6878
7689
|
"aria-colcount": columns,
|
|
6879
7690
|
"aria-activedescendant": activeDescendant,
|
|
@@ -6882,76 +7693,115 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6882
7693
|
onKeyDown: onChartKeyDown,
|
|
6883
7694
|
className: clsx(heatmap_chart_module_default["heatmap-chart__grid"], {
|
|
6884
7695
|
[heatmap_chart_module_default["heatmap-chart__grid--compact"]]: compact,
|
|
7696
|
+
[heatmap_chart_module_default["heatmap-chart__grid--flex-gaps"]]: compact && hasGroups,
|
|
6885
7697
|
[heatmap_chart_module_default["heatmap-chart__grid--height-capped"]]: heightCapped
|
|
6886
7698
|
}),
|
|
6887
7699
|
style: gridStyle,
|
|
6888
|
-
children: [
|
|
6889
|
-
|
|
6890
|
-
"aria-hidden": "true",
|
|
6891
|
-
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
6892
|
-
children: [/* @__PURE__ */ jsx("span", {}), data.map((column, columnIndex) => /* @__PURE__ */ jsx("span", {
|
|
6893
|
-
className: clsx(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
6894
|
-
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
6895
|
-
...summaryGaps(columnIndex)
|
|
6896
|
-
}),
|
|
6897
|
-
children: column.label
|
|
6898
|
-
}, `col-${columnIndex}`))]
|
|
6899
|
-
}), Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
6900
|
-
const labelVisible = !compact || rowIndex % 2 === 0;
|
|
6901
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
7700
|
+
children: [
|
|
7701
|
+
hasColumnLabels && /* @__PURE__ */ jsxs("div", {
|
|
6902
7702
|
role: "row",
|
|
6903
|
-
"aria-
|
|
7703
|
+
"aria-hidden": "true",
|
|
6904
7704
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
6905
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
7705
|
+
children: [/* @__PURE__ */ jsx("span", { style: {
|
|
7706
|
+
gridColumn: 1,
|
|
7707
|
+
gridRow: 1
|
|
7708
|
+
} }), data.map((column, columnIndex) => /* @__PURE__ */ jsx("span", {
|
|
7709
|
+
style: {
|
|
7710
|
+
gridColumn: columnLine(columnIndex),
|
|
7711
|
+
gridRow: 1
|
|
7712
|
+
},
|
|
7713
|
+
className: clsx(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
7714
|
+
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
7715
|
+
...summaryGaps(columnIndex)
|
|
7716
|
+
}),
|
|
7717
|
+
children: column.label
|
|
7718
|
+
}, `col-${columnIndex}`))]
|
|
7719
|
+
}),
|
|
7720
|
+
Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
7721
|
+
const labelVisible = !compact || rowIndex % 2 === 0;
|
|
7722
|
+
const gridRow = firstDataRow + rowIndex;
|
|
7723
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
7724
|
+
role: "row",
|
|
7725
|
+
"aria-rowindex": rowIndex + 1,
|
|
7726
|
+
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
7727
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
6916
7728
|
"aria-hidden": "true",
|
|
6917
|
-
className:
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
[heatmap_chart_module_default["heatmap-chart__cell--
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
7729
|
+
className: heatmap_chart_module_default["heatmap-chart__row-label"],
|
|
7730
|
+
style: {
|
|
7731
|
+
gridColumn: 1,
|
|
7732
|
+
gridRow
|
|
7733
|
+
},
|
|
7734
|
+
children: labelVisible ? rowLabels[rowIndex] ?? "" : ""
|
|
7735
|
+
}), data.map((column, columnIndex) => {
|
|
7736
|
+
const cell = column.data[rowIndex];
|
|
7737
|
+
const placement = {
|
|
7738
|
+
gridColumn: columnLine(columnIndex),
|
|
7739
|
+
gridRow
|
|
7740
|
+
};
|
|
7741
|
+
if (cell?.hidden) return /* @__PURE__ */ jsx("div", {
|
|
7742
|
+
"aria-hidden": "true",
|
|
7743
|
+
style: placement,
|
|
7744
|
+
className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--hidden"])
|
|
7745
|
+
}, `cell-${columnIndex}-${rowIndex}`);
|
|
7746
|
+
if (cell?.placeholder) return /* @__PURE__ */ jsx("div", {
|
|
7747
|
+
"aria-hidden": "true",
|
|
7748
|
+
style: placement,
|
|
7749
|
+
className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--placeholder"])
|
|
7750
|
+
}, `cell-${columnIndex}-${rowIndex}`);
|
|
7751
|
+
const value = cell?.value ?? null;
|
|
7752
|
+
const present = isPresent(value);
|
|
7753
|
+
const filled = present && !column.summary;
|
|
7754
|
+
const normalized = filled ? getNormalizedValue(value, extent) : 0;
|
|
7755
|
+
const info = buildTooltipData(columnIndex, rowIndex);
|
|
7756
|
+
const accessibleLabel = `${cellName(info)}: ${info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value)}`;
|
|
7757
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7758
|
+
id: `${chartId}-cell-${columnIndex}-${rowIndex}`,
|
|
7759
|
+
role: "gridcell",
|
|
7760
|
+
tabIndex: -1,
|
|
7761
|
+
"aria-colindex": columnIndex + 1,
|
|
7762
|
+
"aria-label": accessibleLabel,
|
|
7763
|
+
"data-column": columnIndex,
|
|
7764
|
+
"data-row": rowIndex,
|
|
7765
|
+
className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], {
|
|
7766
|
+
[heatmap_chart_module_default["heatmap-chart__cell--filled"]]: filled,
|
|
7767
|
+
[heatmap_chart_module_default["heatmap-chart__cell--strong"]]: filled && cellHasLightText(normalized),
|
|
7768
|
+
[heatmap_chart_module_default["heatmap-chart__cell--summary"]]: column.summary,
|
|
7769
|
+
...summaryGaps(columnIndex),
|
|
7770
|
+
[heatmap_chart_module_default["heatmap-chart__cell--selected"]]: selected?.column === columnIndex && selected?.row === rowIndex
|
|
7771
|
+
}),
|
|
7772
|
+
style: {
|
|
7773
|
+
...placement,
|
|
7774
|
+
...filled ? { "--a8c-charts-heatmap-cell-intensity": normalized } : {}
|
|
7775
|
+
},
|
|
7776
|
+
onMouseMove: handleCellMouseMove,
|
|
7777
|
+
onMouseLeave: handleCellMouseLeave,
|
|
7778
|
+
children: (drawValues || column.summary) && present && /* @__PURE__ */ jsx("span", {
|
|
7779
|
+
className: heatmap_chart_module_default["heatmap-chart__cell-value"],
|
|
7780
|
+
children: formatNumberCompact(value)
|
|
7781
|
+
})
|
|
7782
|
+
}, `cell-${columnIndex}-${rowIndex}`);
|
|
7783
|
+
})]
|
|
7784
|
+
}, `row-${rowIndex}`);
|
|
7785
|
+
}),
|
|
7786
|
+
hasGroups && /* @__PURE__ */ jsx("div", {
|
|
7787
|
+
role: "row",
|
|
7788
|
+
"aria-hidden": "true",
|
|
7789
|
+
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
7790
|
+
children: groupLayout.groups.map((group, groupIndex) => /* @__PURE__ */ jsx("span", {
|
|
7791
|
+
className: heatmap_chart_module_default["heatmap-chart__group-label"],
|
|
7792
|
+
style: {
|
|
7793
|
+
gridColumn: `${group.line} / span ${group.span}`,
|
|
7794
|
+
gridRow: firstDataRow + rows
|
|
7795
|
+
},
|
|
7796
|
+
children: group.label
|
|
7797
|
+
}, `group-${groupIndex}`))
|
|
7798
|
+
})
|
|
7799
|
+
]
|
|
6952
7800
|
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
6953
7801
|
top: tooltipTop,
|
|
6954
7802
|
left: tooltipLeft,
|
|
7803
|
+
className: tooltipVariant === "dark" ? base_tooltip_module_default.surface : void 0,
|
|
7804
|
+
style: tooltipBoxStyle,
|
|
6955
7805
|
children: /* @__PURE__ */ jsx("div", {
|
|
6956
7806
|
className: standaloneScopeClass,
|
|
6957
7807
|
role: "tooltip",
|
|
@@ -6987,6 +7837,43 @@ const KEY_OPTIONS = {
|
|
|
6987
7837
|
day: "2-digit"
|
|
6988
7838
|
};
|
|
6989
7839
|
const DATE_PREFIX = /^(\d{4})-(\d{2})-(\d{2})/;
|
|
7840
|
+
/**
|
|
7841
|
+
* Label formatters for UTC proxies, so both calendar layouts name a day alike.
|
|
7842
|
+
*
|
|
7843
|
+
* `gregory` keeps a locale whose default calendar is not Gregorian (fa-IR) from
|
|
7844
|
+
* splitting one grid month across two names.
|
|
7845
|
+
*
|
|
7846
|
+
* @param locale - BCP 47 locale.
|
|
7847
|
+
* @return Weekday, month and full-day formatters.
|
|
7848
|
+
*/
|
|
7849
|
+
const civilLabelFormatters = (locale) => {
|
|
7850
|
+
const formatting = {
|
|
7851
|
+
locale,
|
|
7852
|
+
timeZone: "UTC"
|
|
7853
|
+
};
|
|
7854
|
+
return {
|
|
7855
|
+
formatWeekday: createDateFormatter({
|
|
7856
|
+
weekday: "short",
|
|
7857
|
+
calendar: "gregory"
|
|
7858
|
+
}, formatting),
|
|
7859
|
+
formatMonth: createDateFormatter({
|
|
7860
|
+
month: "short",
|
|
7861
|
+
calendar: "gregory"
|
|
7862
|
+
}, formatting),
|
|
7863
|
+
formatMonthYear: createDateFormatter({
|
|
7864
|
+
month: "short",
|
|
7865
|
+
year: "numeric",
|
|
7866
|
+
calendar: "gregory"
|
|
7867
|
+
}, formatting),
|
|
7868
|
+
formatDay: createDateFormatter({
|
|
7869
|
+
weekday: "short",
|
|
7870
|
+
month: "short",
|
|
7871
|
+
day: "numeric",
|
|
7872
|
+
year: "numeric",
|
|
7873
|
+
calendar: "gregory"
|
|
7874
|
+
}, formatting)
|
|
7875
|
+
};
|
|
7876
|
+
};
|
|
6990
7877
|
const pad = (value, length) => String(value).padStart(length, "0");
|
|
6991
7878
|
/**
|
|
6992
7879
|
* The day a UTC proxy stands for.
|
|
@@ -7152,18 +8039,7 @@ const buildCalendarHeatmapData = (series, options = {}) => {
|
|
|
7152
8039
|
const gridMaxDayKey = widenTo(options.gridSpan?.end, maxDayKey, "later");
|
|
7153
8040
|
const requestedMinDate = civilDate(requestedMinDayKey);
|
|
7154
8041
|
const gridMaxDate = civilDate(gridMaxDayKey);
|
|
7155
|
-
const
|
|
7156
|
-
locale,
|
|
7157
|
-
timeZone: "UTC"
|
|
7158
|
-
};
|
|
7159
|
-
const formatWeekday = createDateFormatter({ weekday: "short" }, labelFormatting);
|
|
7160
|
-
const formatMonth = createDateFormatter({ month: "short" }, labelFormatting);
|
|
7161
|
-
const formatDay = createDateFormatter({
|
|
7162
|
-
weekday: "short",
|
|
7163
|
-
month: "short",
|
|
7164
|
-
day: "numeric",
|
|
7165
|
-
year: "numeric"
|
|
7166
|
-
}, labelFormatting);
|
|
8042
|
+
const { formatWeekday, formatMonth, formatDay } = civilLabelFormatters(locale);
|
|
7167
8043
|
const gridStart = startOfCivilWeek(requestedMinDate, weekStartsOn);
|
|
7168
8044
|
const gridMinDayKey = requestedMinDayKey < minDayKey ? civilKey(gridStart) : requestedMinDayKey;
|
|
7169
8045
|
const weekCount = civilWeekSpan(gridStart, gridMaxDate, weekStartsOn);
|
|
@@ -7204,6 +8080,89 @@ const buildCalendarHeatmapData = (series, options = {}) => {
|
|
|
7204
8080
|
};
|
|
7205
8081
|
};
|
|
7206
8082
|
//#endregion
|
|
8083
|
+
//#region src/charts/heatmap-chart/build-month-calendar-data.ts
|
|
8084
|
+
/** Week rows per month, fixed so every month block is the same height. */
|
|
8085
|
+
const MONTH_ROWS = 6;
|
|
8086
|
+
const DAYS_PER_WEEK = 7;
|
|
8087
|
+
const startOfCivilMonth = (date) => {
|
|
8088
|
+
const first = new Date(date.getTime());
|
|
8089
|
+
first.setUTCDate(1);
|
|
8090
|
+
return first;
|
|
8091
|
+
};
|
|
8092
|
+
const startOfNextCivilMonth = (date) => {
|
|
8093
|
+
const next = startOfCivilMonth(date);
|
|
8094
|
+
next.setUTCMonth(next.getUTCMonth() + 1);
|
|
8095
|
+
return next;
|
|
8096
|
+
};
|
|
8097
|
+
/**
|
|
8098
|
+
* Lay a day-keyed map out as one month calendar per month, weekdays across and
|
|
8099
|
+
* weeks down, for `HeatmapChart` with `columnGroups`.
|
|
8100
|
+
*
|
|
8101
|
+
* @param valueByDay - Value per `yyyy-MM-dd`. A missing day is `null`.
|
|
8102
|
+
* @param range - The measured days; every month from `start`'s through `end`'s is drawn.
|
|
8103
|
+
* @param options - Week start and label locale.
|
|
8104
|
+
* @return Columns and one group per month; empty for an invalid or reversed range.
|
|
8105
|
+
*/
|
|
8106
|
+
const buildMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
|
|
8107
|
+
const start = civilDate(range.start);
|
|
8108
|
+
const end = civilDate(range.end);
|
|
8109
|
+
if (!start || !end || start.getTime() > end.getTime()) {
|
|
8110
|
+
warnOnce(`heatmap:monthRange:${range.start}:${range.end}`, `range ${JSON.stringify(range)} must be two \`yyyy-MM-dd\` days with start on or before end, so the calendar is empty.`);
|
|
8111
|
+
return {
|
|
8112
|
+
data: [],
|
|
8113
|
+
columnGroups: []
|
|
8114
|
+
};
|
|
8115
|
+
}
|
|
8116
|
+
const startKey = civilKey(start);
|
|
8117
|
+
const endKey = civilKey(end);
|
|
8118
|
+
const weekStartsOn = options.weekStartsOn ?? 1;
|
|
8119
|
+
const { locale } = sanitizeFormatting({ locale: options.locale });
|
|
8120
|
+
for (const key of Object.keys(valueByDay)) if (!civilDate(key)) warnOnce(`heatmap:monthKey:${key}`, `${JSON.stringify(key)} is not a \`yyyy-MM-dd\` day, so its value is left out of the calendar.`);
|
|
8121
|
+
const readValue = (key) => {
|
|
8122
|
+
const value = valueByDay[key];
|
|
8123
|
+
return isPresent(value) ? value : null;
|
|
8124
|
+
};
|
|
8125
|
+
const { formatMonth, formatMonthYear, formatDay } = civilLabelFormatters(locale);
|
|
8126
|
+
const data = [];
|
|
8127
|
+
const columnGroups = [];
|
|
8128
|
+
const lastMonthStart = startOfCivilMonth(end);
|
|
8129
|
+
const formatGroup = (lastMonthStart.getUTCFullYear() - start.getUTCFullYear()) * 12 + lastMonthStart.getUTCMonth() - start.getUTCMonth() + 1 > 12 ? formatMonthYear : formatMonth;
|
|
8130
|
+
for (let monthStart = startOfCivilMonth(start); monthStart.getTime() <= lastMonthStart.getTime(); monthStart = startOfNextCivilMonth(monthStart)) {
|
|
8131
|
+
const monthStartKey = civilKey(monthStart);
|
|
8132
|
+
const monthEndKey = civilKey(addCivilDays(startOfNextCivilMonth(monthStart), -1));
|
|
8133
|
+
const gridStart = startOfCivilWeek(monthStart, weekStartsOn);
|
|
8134
|
+
for (let weekday = 0; weekday < DAYS_PER_WEEK; weekday++) {
|
|
8135
|
+
const cells = [];
|
|
8136
|
+
for (let week = 0; week < MONTH_ROWS; week++) {
|
|
8137
|
+
const day = addCivilDays(gridStart, week * DAYS_PER_WEEK + weekday);
|
|
8138
|
+
const key = civilKey(day);
|
|
8139
|
+
if (key < monthStartKey || key > monthEndKey) cells.push({
|
|
8140
|
+
value: null,
|
|
8141
|
+
hidden: true
|
|
8142
|
+
});
|
|
8143
|
+
else if (key < startKey || key > endKey) cells.push({
|
|
8144
|
+
label: formatDay(day),
|
|
8145
|
+
value: null,
|
|
8146
|
+
placeholder: true
|
|
8147
|
+
});
|
|
8148
|
+
else cells.push({
|
|
8149
|
+
label: formatDay(day),
|
|
8150
|
+
value: readValue(key)
|
|
8151
|
+
});
|
|
8152
|
+
}
|
|
8153
|
+
data.push({ data: cells });
|
|
8154
|
+
}
|
|
8155
|
+
columnGroups.push({
|
|
8156
|
+
label: formatGroup(monthStart),
|
|
8157
|
+
span: DAYS_PER_WEEK
|
|
8158
|
+
});
|
|
8159
|
+
}
|
|
8160
|
+
return {
|
|
8161
|
+
data,
|
|
8162
|
+
columnGroups
|
|
8163
|
+
};
|
|
8164
|
+
};
|
|
8165
|
+
//#endregion
|
|
7207
8166
|
//#region src/charts/heatmap-chart/use-calendar-heatmap-data.ts
|
|
7208
8167
|
/**
|
|
7209
8168
|
* `buildCalendarHeatmapData` with the locale and zone taken from
|
|
@@ -7240,6 +8199,36 @@ const useCalendarHeatmapData = (series, options = {}) => {
|
|
|
7240
8199
|
]);
|
|
7241
8200
|
};
|
|
7242
8201
|
//#endregion
|
|
8202
|
+
//#region src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts
|
|
8203
|
+
/**
|
|
8204
|
+
* `buildMonthCalendarHeatmapData` with the locale taken from `GlobalChartsProvider`
|
|
8205
|
+
* where the caller names none.
|
|
8206
|
+
*
|
|
8207
|
+
* @param valueByDay - Value per `yyyy-MM-dd`. Held by reference, so a caller that rebuilds it each render defeats the memo.
|
|
8208
|
+
* @param range - As for `buildMonthCalendarHeatmapData`.
|
|
8209
|
+
* @param options - As for `buildMonthCalendarHeatmapData`; `locale` wins over the provider.
|
|
8210
|
+
* @return Columns and groups for `HeatmapChart`.
|
|
8211
|
+
*/
|
|
8212
|
+
const useMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
|
|
8213
|
+
const formatting = useChartFormatting();
|
|
8214
|
+
const locale = options.locale ?? formatting.locale;
|
|
8215
|
+
const { weekStartsOn } = options;
|
|
8216
|
+
const { start, end } = range;
|
|
8217
|
+
return useMemo(() => buildMonthCalendarHeatmapData(valueByDay, {
|
|
8218
|
+
start,
|
|
8219
|
+
end
|
|
8220
|
+
}, {
|
|
8221
|
+
locale,
|
|
8222
|
+
weekStartsOn
|
|
8223
|
+
}), [
|
|
8224
|
+
valueByDay,
|
|
8225
|
+
start,
|
|
8226
|
+
end,
|
|
8227
|
+
locale,
|
|
8228
|
+
weekStartsOn
|
|
8229
|
+
]);
|
|
8230
|
+
};
|
|
8231
|
+
//#endregion
|
|
7243
8232
|
//#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
|
|
7244
8233
|
/*!
|
|
7245
8234
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
@@ -7307,7 +8296,24 @@ function paramCase(input, options) {
|
|
|
7307
8296
|
return dotCase(input, __assign({ delimiter: "-" }, options));
|
|
7308
8297
|
}
|
|
7309
8298
|
//#endregion
|
|
7310
|
-
//#region ../../../node_modules/.pnpm/@wordpress+
|
|
8299
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.55.0/node_modules/@wordpress/warning/build-module/utils.mjs
|
|
8300
|
+
var logged = /* @__PURE__ */ new Set();
|
|
8301
|
+
//#endregion
|
|
8302
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.55.0/node_modules/@wordpress/warning/build-module/index.mjs
|
|
8303
|
+
function isDev() {
|
|
8304
|
+
return globalThis.SCRIPT_DEBUG === true;
|
|
8305
|
+
}
|
|
8306
|
+
function warning(message) {
|
|
8307
|
+
if (!isDev()) return;
|
|
8308
|
+
if (logged.has(message)) return;
|
|
8309
|
+
console.warn(message);
|
|
8310
|
+
try {
|
|
8311
|
+
throw Error(message);
|
|
8312
|
+
} catch {}
|
|
8313
|
+
logged.add(message);
|
|
8314
|
+
}
|
|
8315
|
+
//#endregion
|
|
8316
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
|
|
7311
8317
|
function useUpdateEffect(effect, deps) {
|
|
7312
8318
|
const mountedRef = useRef$1(false);
|
|
7313
8319
|
useEffect$1(() => {
|
|
@@ -8877,7 +9883,7 @@ _createEmotion.css;
|
|
|
8877
9883
|
_createEmotion.sheet;
|
|
8878
9884
|
_createEmotion.cache;
|
|
8879
9885
|
//#endregion
|
|
8880
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
9886
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
|
|
8881
9887
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
8882
9888
|
var useCx = () => {
|
|
8883
9889
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -8984,7 +9990,7 @@ function memize(fn, options) {
|
|
|
8984
9990
|
return memoized;
|
|
8985
9991
|
}
|
|
8986
9992
|
//#endregion
|
|
8987
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
9993
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/colors-values.mjs
|
|
8988
9994
|
var white = "#fff";
|
|
8989
9995
|
var GRAY = {
|
|
8990
9996
|
900: "#1e1e1e",
|
|
@@ -9034,8 +10040,8 @@ var UI = {
|
|
|
9034
10040
|
border: THEME.gray[600],
|
|
9035
10041
|
borderHover: THEME.gray[700],
|
|
9036
10042
|
borderFocus: THEME.accent,
|
|
9037
|
-
borderDisabled:
|
|
9038
|
-
textDisabled:
|
|
10043
|
+
borderDisabled: `var(--wpds-color-stroke-interactive-neutral-disabled, #dbdbdb)`,
|
|
10044
|
+
textDisabled: `var(--wpds-color-foreground-interactive-neutral-disabled, #8d8d8d)`,
|
|
9039
10045
|
darkGrayPlaceholder: `color-mix(in srgb, ${THEME.foreground}, transparent 38%)`,
|
|
9040
10046
|
lightGrayPlaceholder: `color-mix(in srgb, ${THEME.background}, transparent 35%)`
|
|
9041
10047
|
};
|
|
@@ -9063,7 +10069,7 @@ var COLORS = Object.freeze({
|
|
|
9063
10069
|
ui: UI
|
|
9064
10070
|
});
|
|
9065
10071
|
//#endregion
|
|
9066
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10072
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/config-values.mjs
|
|
9067
10073
|
var CONTROL_HEIGHT = "36px";
|
|
9068
10074
|
var CONTROL_PROPS = {
|
|
9069
10075
|
controlPaddingX: 12,
|
|
@@ -9117,8 +10123,8 @@ var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
|
9117
10123
|
transitionTimingFunctionControl: "cubic-bezier(0.12, 0.8, 0.32, 1)"
|
|
9118
10124
|
});
|
|
9119
10125
|
//#endregion
|
|
9120
|
-
//#region ../../../node_modules/.pnpm
|
|
9121
|
-
var
|
|
10126
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
10127
|
+
var import_es6 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
9122
10128
|
module.exports = function equal(a, b) {
|
|
9123
10129
|
if (a === b) return true;
|
|
9124
10130
|
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
@@ -9162,31 +10168,8 @@ var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
9162
10168
|
}
|
|
9163
10169
|
return a !== a && b !== b;
|
|
9164
10170
|
};
|
|
9165
|
-
}));
|
|
9166
|
-
|
|
9167
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/utils.mjs
|
|
9168
|
-
var logged = /* @__PURE__ */ new Set();
|
|
9169
|
-
//#endregion
|
|
9170
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/index.mjs
|
|
9171
|
-
function isDev() {
|
|
9172
|
-
return globalThis.SCRIPT_DEBUG === true;
|
|
9173
|
-
}
|
|
9174
|
-
function warning(message) {
|
|
9175
|
-
if (!isDev()) return;
|
|
9176
|
-
if (logged.has(message)) return;
|
|
9177
|
-
console.warn(message);
|
|
9178
|
-
try {
|
|
9179
|
-
throw Error(message);
|
|
9180
|
-
} catch {}
|
|
9181
|
-
logged.add(message);
|
|
9182
|
-
}
|
|
9183
|
-
//#endregion
|
|
9184
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
9185
|
-
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
9186
|
-
var ComponentsContext = createContext$1(
|
|
9187
|
-
/** @type {Record<string, any>} */
|
|
9188
|
-
{}
|
|
9189
|
-
);
|
|
10171
|
+
})))(), 1);
|
|
10172
|
+
var ComponentsContext = createContext$1({});
|
|
9190
10173
|
ComponentsContext.displayName = "ComponentsContext";
|
|
9191
10174
|
var useComponentsContext = () => useContext$1(ComponentsContext);
|
|
9192
10175
|
function useContextSystemBridge({ value }) {
|
|
@@ -9208,18 +10191,18 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
9208
10191
|
};
|
|
9209
10192
|
memo(BaseContextSystemProvider);
|
|
9210
10193
|
//#endregion
|
|
9211
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10194
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/constants.mjs
|
|
9212
10195
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
9213
10196
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
9214
10197
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
9215
10198
|
//#endregion
|
|
9216
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10199
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
|
|
9217
10200
|
function getStyledClassName(namespace) {
|
|
9218
10201
|
return `components-${paramCase(namespace)}`;
|
|
9219
10202
|
}
|
|
9220
10203
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
9221
10204
|
//#endregion
|
|
9222
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10205
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/context-connect.mjs
|
|
9223
10206
|
function contextConnect(Component, namespace) {
|
|
9224
10207
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
9225
10208
|
}
|
|
@@ -9236,7 +10219,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
9236
10219
|
});
|
|
9237
10220
|
}
|
|
9238
10221
|
//#endregion
|
|
9239
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10222
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/utils.mjs
|
|
9240
10223
|
function getNamespace(componentName) {
|
|
9241
10224
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
9242
10225
|
}
|
|
@@ -9244,7 +10227,7 @@ function getConnectedNamespace() {
|
|
|
9244
10227
|
return { [CONNECTED_NAMESPACE]: true };
|
|
9245
10228
|
}
|
|
9246
10229
|
//#endregion
|
|
9247
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10230
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
|
|
9248
10231
|
function useContextSystem(props, namespace) {
|
|
9249
10232
|
const contextSystemProps = useComponentsContext();
|
|
9250
10233
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -9253,10 +10236,12 @@ function useContextSystem(props, namespace) {
|
|
|
9253
10236
|
...getConnectedNamespace(),
|
|
9254
10237
|
...getNamespace(namespace)
|
|
9255
10238
|
};
|
|
9256
|
-
const { _overrides
|
|
10239
|
+
const { _overrides, ...otherContextProps } = contextProps;
|
|
10240
|
+
const overrideProps = _overrides;
|
|
9257
10241
|
const initialMergedProps = Object.entries(otherContextProps).length ? Object.assign({}, otherContextProps, props) : props;
|
|
10242
|
+
const propsWithChildren = initialMergedProps;
|
|
9258
10243
|
const classes = useCx()(getStyledClassNameFromKey(namespace), props.className);
|
|
9259
|
-
const rendered = typeof
|
|
10244
|
+
const rendered = typeof propsWithChildren.renderChildren === "function" ? propsWithChildren.renderChildren(initialMergedProps) : propsWithChildren.children;
|
|
9260
10245
|
for (const key in initialMergedProps) finalComponentProps[key] = initialMergedProps[key];
|
|
9261
10246
|
for (const key in overrideProps) finalComponentProps[key] = overrideProps[key];
|
|
9262
10247
|
if (rendered !== void 0) finalComponentProps.children = rendered;
|
|
@@ -9264,7 +10249,7 @@ function useContextSystem(props, namespace) {
|
|
|
9264
10249
|
return finalComponentProps;
|
|
9265
10250
|
}
|
|
9266
10251
|
//#endregion
|
|
9267
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10252
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
|
|
9268
10253
|
var visuallyHidden = {
|
|
9269
10254
|
border: 0,
|
|
9270
10255
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -9280,7 +10265,7 @@ var visuallyHidden = {
|
|
|
9280
10265
|
wordBreak: "normal"
|
|
9281
10266
|
};
|
|
9282
10267
|
//#endregion
|
|
9283
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10268
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
|
|
9284
10269
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
9285
10270
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
9286
10271
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -9370,7 +10355,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
|
9370
10355
|
}
|
|
9371
10356
|
var PolymorphicElement = forwardRef$1(UnforwardedPolymorphicElement);
|
|
9372
10357
|
//#endregion
|
|
9373
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10358
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/view/component.mjs
|
|
9374
10359
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
9375
10360
|
return /* @__PURE__ */ jsx(PolymorphicElement, {
|
|
9376
10361
|
ref,
|
|
@@ -9379,7 +10364,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
9379
10364
|
}
|
|
9380
10365
|
var component_default$2 = Object.assign(forwardRef$1(UnforwardedView), { selector: ".components-view" });
|
|
9381
10366
|
//#endregion
|
|
9382
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10367
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
|
|
9383
10368
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
9384
10369
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
9385
10370
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -9394,7 +10379,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
9394
10379
|
}
|
|
9395
10380
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
9396
10381
|
//#endregion
|
|
9397
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10382
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
|
|
9398
10383
|
var breakpoints = [
|
|
9399
10384
|
"40em",
|
|
9400
10385
|
"52em",
|
|
@@ -9428,7 +10413,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
9428
10413
|
return array[index >= array.length ? array.length - 1 : index];
|
|
9429
10414
|
}
|
|
9430
10415
|
//#endregion
|
|
9431
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10416
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/utils.mjs
|
|
9432
10417
|
var ALIGNMENTS = {
|
|
9433
10418
|
bottom: {
|
|
9434
10419
|
alignItems: "flex-end",
|
|
@@ -9476,7 +10461,7 @@ function getAlignmentProps(alignment) {
|
|
|
9476
10461
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
9477
10462
|
}
|
|
9478
10463
|
//#endregion
|
|
9479
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10464
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/hook.mjs
|
|
9480
10465
|
function useGrid(props) {
|
|
9481
10466
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
9482
10467
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -9518,7 +10503,7 @@ function useGrid(props) {
|
|
|
9518
10503
|
};
|
|
9519
10504
|
}
|
|
9520
10505
|
//#endregion
|
|
9521
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10506
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/component.mjs
|
|
9522
10507
|
function UnconnectedGrid(props, forwardedRef) {
|
|
9523
10508
|
const gridProps = useGrid(props);
|
|
9524
10509
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -10774,6 +11759,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
|
|
|
10774
11759
|
});
|
|
10775
11760
|
}
|
|
10776
11761
|
//#endregion
|
|
10777
|
-
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
|
|
11762
|
+
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, buildMonthCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, useMonthCalendarHeatmapData, validateHexColor };
|
|
10778
11763
|
|
|
10779
11764
|
//# sourceMappingURL=index.js.map
|