@automattic/charts 4.9.0 → 4.10.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 +14 -0
- package/dist/index.cjs +159 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +14 -0
- package/dist/index.d.cts +27 -22
- package/dist/index.d.ts +27 -22
- package/dist/index.js +159 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/charts/area-chart/area-chart.tsx +2 -1
- package/src/charts/area-chart/test/area-chart.test.tsx +0 -8
- package/src/charts/area-chart/types.ts +0 -2
- package/src/charts/bar-chart/bar-chart.tsx +7 -2
- package/src/charts/bar-chart/test/bar-chart.test.tsx +0 -8
- package/src/charts/bar-chart/types.ts +0 -2
- package/src/charts/bar-list-chart/bar-list-chart.tsx +3 -0
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +23 -7
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +22 -0
- package/src/charts/conversion-funnel-chart/types.ts +1 -1
- package/src/charts/geo-chart/geo-chart.tsx +17 -2
- package/src/charts/geo-chart/test/geo-chart.test.tsx +9 -4
- package/src/charts/geo-chart/types.ts +1 -1
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +0 -6
- package/src/charts/heatmap-chart/types.ts +0 -2
- package/src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts +2 -2
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +6 -0
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +34 -19
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +27 -1
- package/src/charts/leaderboard-chart/types.ts +1 -0
- package/src/charts/line-chart/line-chart.tsx +3 -0
- package/src/charts/line-chart/test/line-chart.test.tsx +0 -8
- package/src/charts/line-chart/types.ts +0 -2
- package/src/charts/pie-chart/pie-chart.module.scss +3 -0
- package/src/charts/pie-chart/pie-chart.tsx +0 -5
- package/src/charts/pie-chart/test/pie-chart.test.tsx +4 -8
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +3 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +0 -5
- package/src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx +8 -3
- package/src/charts/test/accessible-name.test.tsx +181 -0
- package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +63 -3
- package/src/components/legend/hooks/use-chart-legend-items.ts +63 -1
- package/src/components/legend/private/base-legend.tsx +27 -15
- package/src/components/legend/test/legend.test.tsx +42 -0
- package/src/components/legend/types.ts +2 -0
- package/src/hooks/test/use-xychart-theme.test.tsx +22 -0
- package/src/hooks/use-xychart-theme.ts +33 -2
- package/src/index.ts +1 -0
- package/src/types.ts +19 -1
- package/src/utils/resolve-font-size.ts +9 -10
- package/src/utils/test/resolve-font-size.test.ts +11 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.10.0] - 2026-10-14
|
|
9
|
+
### Added
|
|
10
|
+
- Give the geo, leaderboard, conversion funnel and bar list charts an accessible name, and accept `ariaLabel` on every chart except Sparkline. [#53516]
|
|
11
|
+
- Legend: Add a comparisonSeriesItems option that adds one static item per comparison series, named after its metric and hidden along with it. [#53457]
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- Reject invalid values like `12.px` when resolving theme font sizes. [#53475]
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Conversion funnel chart: Tighten the spacing on a short chart so its bars stay visible. [#53554]
|
|
18
|
+
- Ignore invalid theme label font sizes, such as negative values, so axis labels no longer clip. Accept a leading `+` sign, as CSS does. [#53498]
|
|
19
|
+
- Pie Chart, Pie Semi-Circle Chart: Paint the tooltip above content passed as children, such as a center total. [#53449]
|
|
20
|
+
|
|
8
21
|
## [4.9.0] - 2026-10-12
|
|
9
22
|
### Added
|
|
10
23
|
- Heatmap chart: Add a fitCells option that grows compact cells to fill the chart, wrapping column groups onto more rows when that makes the cells larger, and draw column group labels at 13px in the body text color. [#53341]
|
|
@@ -1174,6 +1187,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1174
1187
|
- Fixed lints following ESLint rule changes for TS [#40584]
|
|
1175
1188
|
- Fixing a bug in Chart storybook data. [#40640]
|
|
1176
1189
|
|
|
1190
|
+
[4.10.0]: https://github.com/Automattic/charts/compare/v4.9.0...v4.10.0
|
|
1177
1191
|
[4.9.0]: https://github.com/Automattic/charts/compare/v4.8.0...v4.9.0
|
|
1178
1192
|
[4.8.0]: https://github.com/Automattic/charts/compare/v4.7.0...v4.8.0
|
|
1179
1193
|
[4.7.0]: https://github.com/Automattic/charts/compare/v4.6.0...v4.7.0
|
package/dist/index.cjs
CHANGED
|
@@ -671,16 +671,17 @@ function readCustomProperty(varName, styles) {
|
|
|
671
671
|
}
|
|
672
672
|
//#endregion
|
|
673
673
|
//#region src/utils/resolve-font-size.ts
|
|
674
|
+
const toFontSize = (size) => Number.isFinite(size) && size >= 0 ? size : void 0;
|
|
674
675
|
/**
|
|
675
676
|
* Resolve a theme `fontSize` value into a plain number suitable for
|
|
676
677
|
* canvas-based measurement (e.g. `getStringWidth`).
|
|
677
678
|
*
|
|
678
679
|
* Accepts:
|
|
679
|
-
* - A number — returned as-is
|
|
680
|
+
* - A finite, non-negative number — returned as-is
|
|
680
681
|
* - A pixel string like `"12px"` — parsed and returned as a number
|
|
681
682
|
*
|
|
682
|
-
* Returns `undefined` for any other input (missing value,
|
|
683
|
-
* relative units like `rem`/`em`/`%`/`vh`) so callers can fall back to
|
|
683
|
+
* Returns `undefined` for any other input (missing value, a non-finite or
|
|
684
|
+
* negative size, or relative units like `rem`/`em`/`%`/`vh`) so callers can fall back to
|
|
684
685
|
* their own default. Relative units are intentionally rejected because
|
|
685
686
|
* we cannot resolve them to absolute pixels here without a parent
|
|
686
687
|
* computed style, and silently returning the unitless prefix
|
|
@@ -690,12 +691,10 @@ function readCustomProperty(varName, styles) {
|
|
|
690
691
|
* @return Parsed numeric font size in pixels, or `undefined` when unresolvable
|
|
691
692
|
*/
|
|
692
693
|
const resolveFontSize = (val) => {
|
|
693
|
-
if (typeof val === "number") return
|
|
694
|
+
if (typeof val === "number") return toFontSize(val);
|
|
694
695
|
if (typeof val === "string") {
|
|
695
|
-
const match = val.trim().match(
|
|
696
|
-
|
|
697
|
-
const parsed = parseFloat(match[1]);
|
|
698
|
-
return isNaN(parsed) ? void 0 : parsed;
|
|
696
|
+
const match = val.trim().match(/^\+?((?:\d*\.)?\d+)(px)?$/);
|
|
697
|
+
return match ? toFontSize(parseFloat(match[1])) : void 0;
|
|
699
698
|
}
|
|
700
699
|
};
|
|
701
700
|
//#endregion
|
|
@@ -1574,6 +1573,20 @@ const useChartScopeElement = () => (0, react.useContext)(ChartScopeContext);
|
|
|
1574
1573
|
const useStandaloneScopeClass = () => (0, react.useContext)(GlobalChartsContext) ? void 0 : CHART_SCOPE_CLASS;
|
|
1575
1574
|
//#endregion
|
|
1576
1575
|
//#region src/hooks/use-xychart-theme.ts
|
|
1576
|
+
const STARTS_LIKE_A_NUMBER = /^[+-]?[\d.]/;
|
|
1577
|
+
const NON_NEGATIVE_CSS_NUMBER = /^\+?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?:[a-z]+|%)?$/i;
|
|
1578
|
+
const isRenderableFontSize = (fontSize) => {
|
|
1579
|
+
if (typeof fontSize === "number") return resolveFontSize(fontSize) !== void 0;
|
|
1580
|
+
const value = fontSize.trim();
|
|
1581
|
+
if (!STARTS_LIKE_A_NUMBER.test(value)) return true;
|
|
1582
|
+
return NON_NEGATIVE_CSS_NUMBER.test(value) && Number.isFinite(parseFloat(value));
|
|
1583
|
+
};
|
|
1584
|
+
const withRenderableFontSize = (style) => {
|
|
1585
|
+
if (style?.fontSize === void 0 || isRenderableFontSize(style.fontSize)) return style;
|
|
1586
|
+
const rest = { ...style };
|
|
1587
|
+
delete rest.fontSize;
|
|
1588
|
+
return rest;
|
|
1589
|
+
};
|
|
1577
1590
|
const useXYChartTheme = (data) => {
|
|
1578
1591
|
const theme = useGlobalChartsTheme();
|
|
1579
1592
|
const scopeElement = useChartScopeElement();
|
|
@@ -1604,9 +1617,10 @@ const useXYChartTheme = (data) => {
|
|
|
1604
1617
|
yAxisLineStyles: { stroke: CATALOG_POINTERS.axisY },
|
|
1605
1618
|
yTickLineStyles: { stroke: CATALOG_POINTERS.tickY },
|
|
1606
1619
|
svgLabelSmall: {
|
|
1607
|
-
...theme.svgLabelSmall,
|
|
1620
|
+
...withRenderableFontSize(theme.svgLabelSmall),
|
|
1608
1621
|
fill: CATALOG_POINTERS.labelAxis
|
|
1609
|
-
}
|
|
1622
|
+
},
|
|
1623
|
+
svgLabelBig: withRenderableFontSize(theme.svgLabelBig)
|
|
1610
1624
|
});
|
|
1611
1625
|
}, [
|
|
1612
1626
|
theme,
|
|
@@ -2119,7 +2133,7 @@ const getLegendItemAriaLabel = (text, value, visible, interactive) => {
|
|
|
2119
2133
|
if (visible) return;
|
|
2120
2134
|
return (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n._x)("%s: hidden", "hidden non-interactive legend item", "jetpack-charts"), accessibleText);
|
|
2121
2135
|
};
|
|
2122
|
-
const BaseLegend = (0, react.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) => {
|
|
2136
|
+
const BaseLegend = (0, react.forwardRef)(({ items: allItems, className, orientation = "horizontal", alignment = "center", shape = "rect", fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform, itemStyles, itemClassName, labelStyles, labelClassName, shapeStyles, render, interactive = false, chartId }, ref) => {
|
|
2123
2137
|
const { margin: itemMargin = "0", flexDirection: itemDirection = "row" } = itemStyles ?? {};
|
|
2124
2138
|
const { justifyContent: labelJustifyContent = "flex-start", flex: labelFlex = "0 0 auto", margin: labelMargin = "0 4px", maxWidth, textOverflow = "wrap" } = labelStyles ?? {};
|
|
2125
2139
|
const { width: shapeWidth = 16, height: shapeHeight = 16, margin: shapeMargin = "2px 4px 2px 0" } = shapeStyles ?? {};
|
|
@@ -2127,6 +2141,16 @@ const BaseLegend = (0, react.forwardRef)(({ items, className, orientation = "hor
|
|
|
2127
2141
|
const context = (0, react.useContext)(GlobalChartsContext);
|
|
2128
2142
|
const chartInstanceContext = (0, react.useContext)(ChartInstanceContext);
|
|
2129
2143
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
2144
|
+
const isSeriesVisible = (0, react.useCallback)((seriesLabel) => {
|
|
2145
|
+
if (chartInstanceContext?.isSeriesVisible) return chartInstanceContext.isSeriesVisible(seriesLabel);
|
|
2146
|
+
if (!chartId || !context) return true;
|
|
2147
|
+
return context.isSeriesVisible(chartId, seriesLabel);
|
|
2148
|
+
}, [
|
|
2149
|
+
chartId,
|
|
2150
|
+
chartInstanceContext,
|
|
2151
|
+
context
|
|
2152
|
+
]);
|
|
2153
|
+
const items = (0, react.useMemo)(() => allItems.filter((item) => item.interactive !== false || !item.describesSeries || isSeriesVisible(item.describesSeries)), [allItems, isSeriesVisible]);
|
|
2130
2154
|
const domain = items.map((item) => item.label);
|
|
2131
2155
|
const legendScale = (0, _visx_scale.scaleOrdinal)({
|
|
2132
2156
|
domain,
|
|
@@ -2149,15 +2173,6 @@ const BaseLegend = (0, react.forwardRef)(({ items, className, orientation = "hor
|
|
|
2149
2173
|
chartId,
|
|
2150
2174
|
context
|
|
2151
2175
|
]);
|
|
2152
|
-
const isSeriesVisible = (0, react.useCallback)((seriesLabel) => {
|
|
2153
|
-
if (chartInstanceContext?.isSeriesVisible) return chartInstanceContext.isSeriesVisible(seriesLabel);
|
|
2154
|
-
if (!chartId || !context) return true;
|
|
2155
|
-
return context.isSeriesVisible(chartId, seriesLabel);
|
|
2156
|
-
}, [
|
|
2157
|
-
chartId,
|
|
2158
|
-
chartInstanceContext,
|
|
2159
|
-
context
|
|
2160
|
-
]);
|
|
2161
2176
|
const createClickHandler = (0, react.useCallback)((seriesLabels, itemInteractive) => {
|
|
2162
2177
|
if (!itemInteractive) return;
|
|
2163
2178
|
return () => handleLegendClick(seriesLabels);
|
|
@@ -2432,6 +2447,34 @@ function buildComparisonLegendItem(seriesData, items, label, getElementStyles, l
|
|
|
2432
2447
|
};
|
|
2433
2448
|
}
|
|
2434
2449
|
/**
|
|
2450
|
+
* Builds one static item per comparison series folded into another series' item, named after
|
|
2451
|
+
* that item and styled like the comparison series itself.
|
|
2452
|
+
* @param seriesData - The series data to search for comparison series
|
|
2453
|
+
* @param items - The legend items already built from the series
|
|
2454
|
+
* @param formatLabel - Names an item after the label of the item it was folded into
|
|
2455
|
+
* @param getElementStyles - Function to get element styles
|
|
2456
|
+
* @param legendShape - The shape type for legend items (string literal or React component)
|
|
2457
|
+
* @return The legend items, in series order
|
|
2458
|
+
*/
|
|
2459
|
+
function buildPerSeriesComparisonItems(seriesData, items, formatLabel, getElementStyles, legendShape) {
|
|
2460
|
+
return seriesData.flatMap((series, index) => {
|
|
2461
|
+
const owner = items.find((item) => item.seriesLabels?.includes(series.label));
|
|
2462
|
+
if (series.options?.type !== "comparison" || !owner || owner.seriesLabels?.[0] === series.label) return [];
|
|
2463
|
+
const { color, shapeStyles } = getElementStyles({
|
|
2464
|
+
data: series,
|
|
2465
|
+
index,
|
|
2466
|
+
legendShape
|
|
2467
|
+
});
|
|
2468
|
+
return [{
|
|
2469
|
+
label: formatLabel(owner.label),
|
|
2470
|
+
color,
|
|
2471
|
+
shapeStyle: shapeStyles,
|
|
2472
|
+
interactive: false,
|
|
2473
|
+
describesSeries: series.label
|
|
2474
|
+
}];
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
/**
|
|
2435
2478
|
* Processes point data into legend items
|
|
2436
2479
|
* @param pointData - The point data to process
|
|
2437
2480
|
* @param getElementStyles - Function to get element styles
|
|
@@ -2467,13 +2510,14 @@ function processPointData(pointData, getElementStyles, showValues, legendValueDi
|
|
|
2467
2510
|
* @return Array of legend items ready for display
|
|
2468
2511
|
*/
|
|
2469
2512
|
function useChartLegendItems(data, options = {}, legendShape) {
|
|
2470
|
-
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, renderGlyph } = options;
|
|
2513
|
+
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, renderGlyph } = options;
|
|
2471
2514
|
const { getElementStyles } = useGlobalChartsContext();
|
|
2472
2515
|
return (0, react.useMemo)(() => {
|
|
2473
2516
|
if (!data || !Array.isArray(data) || data.length === 0) return [];
|
|
2474
2517
|
if ("data" in data[0]) {
|
|
2475
2518
|
const seriesData = data;
|
|
2476
2519
|
const items = processSeriesData(seriesData, getElementStyles, showValues, withGlyph, glyphSize, collapseGroups, renderGlyph, legendShape);
|
|
2520
|
+
if (comparisonSeriesItems) return [...items, ...buildPerSeriesComparisonItems(seriesData, items, comparisonSeriesItems, getElementStyles, legendShape)];
|
|
2477
2521
|
const comparison = comparisonItem ? buildComparisonLegendItem(seriesData, items, typeof comparisonItem === "string" ? comparisonItem : (0, _wordpress_i18n.__)("Comparison period", "jetpack-charts"), getElementStyles, legendShape) : null;
|
|
2478
2522
|
return comparison ? [...items, comparison] : items;
|
|
2479
2523
|
}
|
|
@@ -2487,6 +2531,7 @@ function useChartLegendItems(data, options = {}, legendShape) {
|
|
|
2487
2531
|
glyphSize,
|
|
2488
2532
|
collapseGroups,
|
|
2489
2533
|
comparisonItem,
|
|
2534
|
+
comparisonSeriesItems,
|
|
2490
2535
|
renderGlyph,
|
|
2491
2536
|
legendShape
|
|
2492
2537
|
]);
|
|
@@ -4728,6 +4773,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
|
|
|
4728
4773
|
const legendInteractive = legend.interactive ?? false;
|
|
4729
4774
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
4730
4775
|
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
4776
|
+
const legendComparisonSeriesItems = legend.comparisonSeriesItems;
|
|
4731
4777
|
const legendShape = legend.shape ?? "line";
|
|
4732
4778
|
const legendPosition = legend.position ?? "bottom";
|
|
4733
4779
|
const formatting = useChartFormatting();
|
|
@@ -4912,12 +4958,14 @@ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
|
|
|
4912
4958
|
glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
|
|
4913
4959
|
collapseGroups: legendCollapseGroups,
|
|
4914
4960
|
comparisonItem: legendComparisonItem,
|
|
4961
|
+
comparisonSeriesItems: legendComparisonSeriesItems,
|
|
4915
4962
|
renderGlyph
|
|
4916
4963
|
}), [
|
|
4917
4964
|
withLegendGlyph,
|
|
4918
4965
|
glyphStyle?.radius,
|
|
4919
4966
|
legendCollapseGroups,
|
|
4920
4967
|
legendComparisonItem,
|
|
4968
|
+
legendComparisonSeriesItems,
|
|
4921
4969
|
renderGlyph
|
|
4922
4970
|
]), legendShape);
|
|
4923
4971
|
const chartMetadata = (0, react.useMemo)(() => ({
|
|
@@ -5386,8 +5434,13 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
|
|
|
5386
5434
|
withGlyph: false,
|
|
5387
5435
|
glyphSize: 0,
|
|
5388
5436
|
collapseGroups: legend.collapseGroups ?? false,
|
|
5389
|
-
comparisonItem: legend.comparisonItem ?? false
|
|
5390
|
-
|
|
5437
|
+
comparisonItem: legend.comparisonItem ?? false,
|
|
5438
|
+
comparisonSeriesItems: legend.comparisonSeriesItems
|
|
5439
|
+
}), [
|
|
5440
|
+
legend.collapseGroups,
|
|
5441
|
+
legend.comparisonItem,
|
|
5442
|
+
legend.comparisonSeriesItems
|
|
5443
|
+
]), legendShape);
|
|
5391
5444
|
const chartMetadata = (0, react.useMemo)(() => ({
|
|
5392
5445
|
stacked,
|
|
5393
5446
|
stackOffset,
|
|
@@ -6380,6 +6433,7 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6380
6433
|
const legendInteractive = legend.interactive ?? false;
|
|
6381
6434
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
6382
6435
|
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
6436
|
+
const legendComparisonSeriesItems = legend.comparisonSeriesItems;
|
|
6383
6437
|
const horizontal = orientation === "horizontal";
|
|
6384
6438
|
const chartId = useChartId(providedChartId);
|
|
6385
6439
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
@@ -6392,8 +6446,13 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6392
6446
|
});
|
|
6393
6447
|
const legendItems = useChartLegendItems(dataSorted, (0, react.useMemo)(() => ({
|
|
6394
6448
|
collapseGroups: legendCollapseGroups,
|
|
6395
|
-
comparisonItem: legendComparisonItem
|
|
6396
|
-
|
|
6449
|
+
comparisonItem: legendComparisonItem,
|
|
6450
|
+
comparisonSeriesItems: legendComparisonSeriesItems
|
|
6451
|
+
}), [
|
|
6452
|
+
legendCollapseGroups,
|
|
6453
|
+
legendComparisonItem,
|
|
6454
|
+
legendComparisonSeriesItems
|
|
6455
|
+
]));
|
|
6397
6456
|
const { getElementStyles } = useGlobalChartsContext();
|
|
6398
6457
|
const isSeriesRendered = (0, react.useCallback)((series) => isSeriesVisible(series.label), [isSeriesVisible]);
|
|
6399
6458
|
const hasWholeNumberValues = (0, react.useMemo)(() => hasOnlyWholeNumbers(dataSorted.filter(isSeriesRendered)), [dataSorted, isSeriesRendered]);
|
|
@@ -6904,7 +6963,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
6904
6963
|
right: 20,
|
|
6905
6964
|
bottom: 0,
|
|
6906
6965
|
top: 0
|
|
6907
|
-
}, className, ...rest }) => {
|
|
6966
|
+
}, className, ariaLabel, ...rest }) => {
|
|
6908
6967
|
const { getElementStyles } = useGlobalChartsContext();
|
|
6909
6968
|
const tintedData = (0, react.useMemo)(() => {
|
|
6910
6969
|
if (data.length > 1) return data;
|
|
@@ -6979,6 +7038,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
6979
7038
|
xScale: chartOptions.xScale,
|
|
6980
7039
|
yScale: chartOptions.yScale
|
|
6981
7040
|
},
|
|
7041
|
+
ariaLabel: ariaLabel ?? (0, _wordpress_i18n.__)("Bar list chart", "jetpack-charts"),
|
|
6982
7042
|
...rest
|
|
6983
7043
|
});
|
|
6984
7044
|
};
|
|
@@ -7054,6 +7114,8 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
7054
7114
|
};
|
|
7055
7115
|
//#endregion
|
|
7056
7116
|
//#region src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx
|
|
7117
|
+
/** Chart height (px) below which the funnel tightens its gaps so the bars keep their room. */
|
|
7118
|
+
const SHORT_CHART_HEIGHT = 180;
|
|
7057
7119
|
/**
|
|
7058
7120
|
* Internal ConversionFunnelChart component with chart registration
|
|
7059
7121
|
*
|
|
@@ -7065,6 +7127,7 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
7065
7127
|
* @param props.loading - Whether the chart is in loading state
|
|
7066
7128
|
* @param props.animation - Whether to show chart animation on initial render or not
|
|
7067
7129
|
* @param props.className - Additional CSS class name
|
|
7130
|
+
* @param props.ariaLabel - Accessible name for the chart group
|
|
7068
7131
|
* @param props.height - Height of the chart container. Falls back to style.height if set, otherwise defaults to "100%".
|
|
7069
7132
|
* @param props.style - Custom styling
|
|
7070
7133
|
* @param props.renderStepLabel - Custom render function for step labels
|
|
@@ -7074,7 +7137,7 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
7074
7137
|
* @param props.tooltipStyle - Inline styles merged over the tooltip box defaults
|
|
7075
7138
|
* @return JSX element representing the conversion funnel chart
|
|
7076
7139
|
*/
|
|
7077
|
-
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
|
|
7140
|
+
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, ariaLabel, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
|
|
7078
7141
|
const chartId = useChartId(providedChartId);
|
|
7079
7142
|
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
7080
7143
|
const chartRef = (0, react.useRef)(null);
|
|
@@ -7083,10 +7146,13 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7083
7146
|
const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
7084
7147
|
const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
|
|
7085
7148
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
7149
|
+
const [measureChartRef, , chartHeight] = useElementSize();
|
|
7150
|
+
const gap = chartHeight > 0 && chartHeight < SHORT_CHART_HEIGHT ? "sm" : "xl";
|
|
7086
7151
|
const setChartRef = (0, react.useCallback)((node) => {
|
|
7087
7152
|
chartRef.current = node;
|
|
7088
7153
|
setScopeNode(node);
|
|
7089
|
-
|
|
7154
|
+
measureChartRef(node);
|
|
7155
|
+
}, [measureChartRef]);
|
|
7090
7156
|
const clearSelectionAndRef = (0, react.useCallback)(() => {
|
|
7091
7157
|
clearSelection();
|
|
7092
7158
|
selectedBarRef.current = null;
|
|
@@ -7234,7 +7300,9 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7234
7300
|
const maxRate = Math.max(...steps.map((step) => step.rate));
|
|
7235
7301
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7236
7302
|
direction: "column",
|
|
7237
|
-
gap
|
|
7303
|
+
gap,
|
|
7304
|
+
role: "group",
|
|
7305
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Conversion funnel chart", "jetpack-charts"),
|
|
7238
7306
|
ref: setChartRef,
|
|
7239
7307
|
className: (0, clsx.default)("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
7240
7308
|
style: {
|
|
@@ -7265,7 +7333,7 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7265
7333
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7266
7334
|
direction: "column",
|
|
7267
7335
|
className: (0, clsx.default)(conversion_funnel_chart_module_default["funnel-step"], isColorPaletteResolved && conversion_funnel_chart_module_default["funnel-step--animated"], isBlurred && conversion_funnel_chart_module_default["funnel-step--blurred"]),
|
|
7268
|
-
gap
|
|
7336
|
+
gap,
|
|
7269
7337
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7270
7338
|
direction: "column",
|
|
7271
7339
|
gap: "xs",
|
|
@@ -7459,6 +7527,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
7459
7527
|
*
|
|
7460
7528
|
* @param props - The props for the GeoChart component
|
|
7461
7529
|
* @param props.data - Data in Google Charts format (array of arrays with headers)
|
|
7530
|
+
* @param props.ariaLabel - Accessible name of the chart
|
|
7462
7531
|
* @param props.width - Width of the chart in pixels
|
|
7463
7532
|
* @param props.height - Height of the chart in pixels
|
|
7464
7533
|
* @param props.region - Region to display ('world', 'US', or ISO 3166-1 alpha-2 code)
|
|
@@ -7470,7 +7539,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
7470
7539
|
* @param props.renderPlaceholder - Optional render function for the loading placeholder
|
|
7471
7540
|
* @return A React component displaying an interactive map with data visualization
|
|
7472
7541
|
*/
|
|
7473
|
-
const GeoChartInternal = ({ className, data, width, height, region = "world", resolution = "countries", displayMode = "regions", domain, onError, renderPlaceholder }) => {
|
|
7542
|
+
const GeoChartInternal = ({ className, data, ariaLabel, width, height, region = "world", resolution = "countries", displayMode = "regions", domain, onError, renderPlaceholder }) => {
|
|
7474
7543
|
const { getElementStyles } = useGlobalChartsContext();
|
|
7475
7544
|
const scopeElement = useChartScopeElement();
|
|
7476
7545
|
const containerRef = (0, react.useRef)(null);
|
|
@@ -7558,8 +7627,14 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
7558
7627
|
sanitizedData.hasHtmlTooltips
|
|
7559
7628
|
]);
|
|
7560
7629
|
const chartEvents = (0, react.useMemo)(() => {
|
|
7561
|
-
|
|
7562
|
-
|
|
7630
|
+
const readyEvent = {
|
|
7631
|
+
eventName: "ready",
|
|
7632
|
+
callback: () => {
|
|
7633
|
+
containerRef.current?.querySelectorAll("svg").forEach((svg) => svg.setAttribute("aria-hidden", "true"));
|
|
7634
|
+
}
|
|
7635
|
+
};
|
|
7636
|
+
if (!onError) return [readyEvent];
|
|
7637
|
+
return [readyEvent, {
|
|
7563
7638
|
eventName: "error",
|
|
7564
7639
|
callback: ({ eventArgs }) => {
|
|
7565
7640
|
onError(normalizeGeoChartError(eventArgs));
|
|
@@ -7568,6 +7643,8 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
7568
7643
|
}, [onError]);
|
|
7569
7644
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Center, {
|
|
7570
7645
|
ref: containerRef,
|
|
7646
|
+
role: "group",
|
|
7647
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Geo chart", "jetpack-charts"),
|
|
7571
7648
|
className: (0, clsx.default)("geo-chart", geo_chart_module_default.container, className),
|
|
7572
7649
|
style: {
|
|
7573
7650
|
width,
|
|
@@ -8122,7 +8199,7 @@ const CELL_VALUE_MODIFIER = {
|
|
|
8122
8199
|
white: heatmap_chart_module_default["heatmap-chart__cell-value--white"]
|
|
8123
8200
|
};
|
|
8124
8201
|
const NO_ROW_LABELS = [];
|
|
8125
|
-
const TOOLTIP_BOX_STYLE = { zIndex: 3 };
|
|
8202
|
+
const TOOLTIP_BOX_STYLE$1 = { zIndex: 3 };
|
|
8126
8203
|
const largest = (root, selector, size) => Math.max(0, ...Array.from(root.querySelectorAll(selector), (el) => el[size]));
|
|
8127
8204
|
const gridBox = (chart, grid) => {
|
|
8128
8205
|
let height = chart.clientHeight;
|
|
@@ -8145,9 +8222,9 @@ const cellName = (info) => info.cellLabel || [
|
|
|
8145
8222
|
const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, fitCells = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, columnGroups, keyboardNavigation = "grid", ariaLabel, primaryColor, gap = "md", withTooltips = false, renderTooltip, tooltipStyle, children }) => {
|
|
8146
8223
|
const chartId = useChartId(providedChartId);
|
|
8147
8224
|
const tooltipBoxStyle = tooltipStyle ? {
|
|
8148
|
-
...TOOLTIP_BOX_STYLE,
|
|
8225
|
+
...TOOLTIP_BOX_STYLE$1,
|
|
8149
8226
|
...tooltipStyle
|
|
8150
|
-
} : TOOLTIP_BOX_STYLE;
|
|
8227
|
+
} : TOOLTIP_BOX_STYLE$1;
|
|
8151
8228
|
const { getElementStyles, theme } = useGlobalChartsContext();
|
|
8152
8229
|
const scopeElement = useChartScopeElement();
|
|
8153
8230
|
const { heatmapChart: heatmapChartSettings } = theme;
|
|
@@ -11637,8 +11714,8 @@ const SUBPIXEL_TOLERANCE = .5;
|
|
|
11637
11714
|
* depends on `--a8c-charts-dimension-leaderboard-row-gap`, label wrapping, and
|
|
11638
11715
|
* whatever a caller renders as a label, so any restated number would drift.
|
|
11639
11716
|
*
|
|
11640
|
-
* Every row is a direct grid child marked with `data-row-index`;
|
|
11641
|
-
*
|
|
11717
|
+
* Every row is a `listitem` div, a direct grid child marked with `data-row-index`;
|
|
11718
|
+
* interactive rows hold a button inside it.
|
|
11642
11719
|
*
|
|
11643
11720
|
* @param enabled - Whether to measure at all. When false every row fits.
|
|
11644
11721
|
* @param rowCount - Total number of rows rendered.
|
|
@@ -11780,6 +11857,7 @@ var leaderboard_chart_module_default = {
|
|
|
11780
11857
|
"overlayLabel": "a8ccharts-GovfoW-overlayLabel",
|
|
11781
11858
|
"row": "a8ccharts-GovfoW-row",
|
|
11782
11859
|
"rowButton": "a8ccharts-GovfoW-rowButton",
|
|
11860
|
+
"rowItem": "a8ccharts-GovfoW-rowItem",
|
|
11783
11861
|
"stretch": "a8ccharts-GovfoW-stretch",
|
|
11784
11862
|
"valueContainer": "a8ccharts-GovfoW-valueContainer"
|
|
11785
11863
|
};
|
|
@@ -11892,9 +11970,10 @@ const BarWithLabel = ({ entry, withComparison, withOverlayLabel, primaryColor, s
|
|
|
11892
11970
|
* @param props.children - Child components for composition API
|
|
11893
11971
|
* @param props.className - Additional CSS class name
|
|
11894
11972
|
* @param props.style - Custom styling for the chart container
|
|
11973
|
+
* @param props.ariaLabel - Accessible name for the list, defaulting to "Leaderboard chart"
|
|
11895
11974
|
* @return JSX element representing the leaderboard chart
|
|
11896
11975
|
*/
|
|
11897
|
-
const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, withComparison = false, withOverlayLabel = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, animation, loading = false, fitRows = false, showLegend = false, legend = {}, legendLabels, gap = "md", className, style, children }) => {
|
|
11976
|
+
const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, withComparison = false, withOverlayLabel = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, animation, loading = false, fitRows = false, showLegend = false, legend = {}, legendLabels, gap = "md", ariaLabel, className, style, children }) => {
|
|
11898
11977
|
const legendInteractive = legend.interactive ?? false;
|
|
11899
11978
|
const legendPosition = legend.position ?? "bottom";
|
|
11900
11979
|
const chartId = useChartId(providedChartId);
|
|
@@ -12025,6 +12104,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
12025
12104
|
className: leaderboard_chart_module_default.emptyState,
|
|
12026
12105
|
children: getAllHiddenMessage(legendInteractive, "series")
|
|
12027
12106
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default, {
|
|
12107
|
+
role: "list",
|
|
12108
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Leaderboard chart", "jetpack-charts"),
|
|
12028
12109
|
templateColumns: "minmax(0, 1fr) auto",
|
|
12029
12110
|
rowGap: ROW_GAP,
|
|
12030
12111
|
columnGap: COLUMN_GAP,
|
|
@@ -12072,40 +12153,49 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
12072
12153
|
})
|
|
12073
12154
|
]
|
|
12074
12155
|
})] });
|
|
12075
|
-
if (entry.onClick && entry.hasInteractiveLabel) return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
12156
|
+
if (entry.onClick && entry.hasInteractiveLabel) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12157
|
+
role: "listitem",
|
|
12076
12158
|
"data-row-index": rowIndex,
|
|
12077
12159
|
style: rowStyle,
|
|
12078
|
-
className:
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12160
|
+
className: leaderboard_chart_module_default.rowItem,
|
|
12161
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12162
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow, leaderboard_chart_module_default.layeredRow),
|
|
12163
|
+
onClick: forwardCellClickToRowButton,
|
|
12164
|
+
children: [
|
|
12165
|
+
rowCells,
|
|
12166
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
12167
|
+
type: "button",
|
|
12168
|
+
className: leaderboard_chart_module_default.rowButton,
|
|
12169
|
+
onClick: entry.onClick,
|
|
12170
|
+
"aria-label": entry.ariaLabel
|
|
12171
|
+
}),
|
|
12172
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_icons.Icon, {
|
|
12173
|
+
className: leaderboard_chart_module_default.chevron,
|
|
12174
|
+
icon: _wordpress_icons.chevronRight,
|
|
12175
|
+
size: 24
|
|
12176
|
+
})
|
|
12177
|
+
]
|
|
12178
|
+
})
|
|
12094
12179
|
}, entry.id);
|
|
12095
|
-
if (entry.onClick) return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
12096
|
-
|
|
12180
|
+
if (entry.onClick) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12181
|
+
role: "listitem",
|
|
12097
12182
|
"data-row-index": rowIndex,
|
|
12098
12183
|
style: rowStyle,
|
|
12099
|
-
className:
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
|
|
12106
|
-
|
|
12184
|
+
className: leaderboard_chart_module_default.rowItem,
|
|
12185
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12186
|
+
type: "button",
|
|
12187
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow),
|
|
12188
|
+
onClick: entry.onClick,
|
|
12189
|
+
"aria-label": entry.ariaLabel,
|
|
12190
|
+
children: [rowCells, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_icons.Icon, {
|
|
12191
|
+
className: leaderboard_chart_module_default.chevron,
|
|
12192
|
+
icon: _wordpress_icons.chevronRight,
|
|
12193
|
+
size: 24
|
|
12194
|
+
})]
|
|
12195
|
+
})
|
|
12107
12196
|
}, entry.id);
|
|
12108
12197
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12198
|
+
role: "listitem",
|
|
12109
12199
|
"data-row-index": rowIndex,
|
|
12110
12200
|
style: rowStyle,
|
|
12111
12201
|
className: leaderboard_chart_module_default.row,
|
|
@@ -12142,11 +12232,13 @@ const PieSelectionAnnouncement = ({ data }) => /* @__PURE__ */ (0, react_jsx_run
|
|
|
12142
12232
|
});
|
|
12143
12233
|
//#endregion
|
|
12144
12234
|
//#region src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx
|
|
12235
|
+
const TOOLTIP_BOX_STYLE = { zIndex: 3 };
|
|
12145
12236
|
const PieTooltip = ({ top, left, selectedIndex, tooltipRef, children }) => {
|
|
12146
12237
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
12147
12238
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
12148
12239
|
top,
|
|
12149
12240
|
left,
|
|
12241
|
+
style: TOOLTIP_BOX_STYLE,
|
|
12150
12242
|
children: selectedIndex === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12151
12243
|
className: standaloneScopeClass,
|
|
12152
12244
|
role: "tooltip",
|
|
@@ -12369,6 +12461,7 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
|
|
|
12369
12461
|
//#endregion
|
|
12370
12462
|
//#region src/charts/pie-chart/pie-chart.module.scss
|
|
12371
12463
|
var pie_chart_module_default = {
|
|
12464
|
+
"pie-chart": "a8ccharts-gnszbG-pie-chart",
|
|
12372
12465
|
"pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
|
|
12373
12466
|
"pie-chart__label-text": "a8ccharts-gnszbG-pie-chart__label-text",
|
|
12374
12467
|
"pie-chart__label-text--black": "a8ccharts-gnszbG-pie-chart__label-text--black",
|