@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.
Files changed (50) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.cjs +159 -66
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +14 -0
  5. package/dist/index.d.cts +27 -22
  6. package/dist/index.d.ts +27 -22
  7. package/dist/index.js +159 -66
  8. package/dist/index.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/charts/area-chart/area-chart.tsx +2 -1
  11. package/src/charts/area-chart/test/area-chart.test.tsx +0 -8
  12. package/src/charts/area-chart/types.ts +0 -2
  13. package/src/charts/bar-chart/bar-chart.tsx +7 -2
  14. package/src/charts/bar-chart/test/bar-chart.test.tsx +0 -8
  15. package/src/charts/bar-chart/types.ts +0 -2
  16. package/src/charts/bar-list-chart/bar-list-chart.tsx +3 -0
  17. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +23 -7
  18. package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +22 -0
  19. package/src/charts/conversion-funnel-chart/types.ts +1 -1
  20. package/src/charts/geo-chart/geo-chart.tsx +17 -2
  21. package/src/charts/geo-chart/test/geo-chart.test.tsx +9 -4
  22. package/src/charts/geo-chart/types.ts +1 -1
  23. package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +0 -6
  24. package/src/charts/heatmap-chart/types.ts +0 -2
  25. package/src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts +2 -2
  26. package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +6 -0
  27. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +34 -19
  28. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +27 -1
  29. package/src/charts/leaderboard-chart/types.ts +1 -0
  30. package/src/charts/line-chart/line-chart.tsx +3 -0
  31. package/src/charts/line-chart/test/line-chart.test.tsx +0 -8
  32. package/src/charts/line-chart/types.ts +0 -2
  33. package/src/charts/pie-chart/pie-chart.module.scss +3 -0
  34. package/src/charts/pie-chart/pie-chart.tsx +0 -5
  35. package/src/charts/pie-chart/test/pie-chart.test.tsx +4 -8
  36. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +3 -0
  37. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +0 -5
  38. package/src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx +8 -3
  39. package/src/charts/test/accessible-name.test.tsx +181 -0
  40. package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +63 -3
  41. package/src/components/legend/hooks/use-chart-legend-items.ts +63 -1
  42. package/src/components/legend/private/base-legend.tsx +27 -15
  43. package/src/components/legend/test/legend.test.tsx +42 -0
  44. package/src/components/legend/types.ts +2 -0
  45. package/src/hooks/test/use-xychart-theme.test.tsx +22 -0
  46. package/src/hooks/use-xychart-theme.ts +33 -2
  47. package/src/index.ts +1 -0
  48. package/src/types.ts +19 -1
  49. package/src/utils/resolve-font-size.ts +9 -10
  50. package/src/utils/test/resolve-font-size.test.ts +11 -2
package/dist/index.js CHANGED
@@ -669,16 +669,17 @@ function readCustomProperty(varName, styles) {
669
669
  }
670
670
  //#endregion
671
671
  //#region src/utils/resolve-font-size.ts
672
+ const toFontSize = (size) => Number.isFinite(size) && size >= 0 ? size : void 0;
672
673
  /**
673
674
  * Resolve a theme `fontSize` value into a plain number suitable for
674
675
  * canvas-based measurement (e.g. `getStringWidth`).
675
676
  *
676
677
  * Accepts:
677
- * - A number — returned as-is
678
+ * - A finite, non-negative number — returned as-is
678
679
  * - A pixel string like `"12px"` — parsed and returned as a number
679
680
  *
680
- * Returns `undefined` for any other input (missing value, NaN, or
681
- * relative units like `rem`/`em`/`%`/`vh`) so callers can fall back to
681
+ * Returns `undefined` for any other input (missing value, a non-finite or
682
+ * negative size, or relative units like `rem`/`em`/`%`/`vh`) so callers can fall back to
682
683
  * their own default. Relative units are intentionally rejected because
683
684
  * we cannot resolve them to absolute pixels here without a parent
684
685
  * computed style, and silently returning the unitless prefix
@@ -688,12 +689,10 @@ function readCustomProperty(varName, styles) {
688
689
  * @return Parsed numeric font size in pixels, or `undefined` when unresolvable
689
690
  */
690
691
  const resolveFontSize = (val) => {
691
- if (typeof val === "number") return isNaN(val) ? void 0 : val;
692
+ if (typeof val === "number") return toFontSize(val);
692
693
  if (typeof val === "string") {
693
- const match = val.trim().match(/^(-?\d+\.?\d*|-?\.\d+)(px)?$/);
694
- if (!match) return;
695
- const parsed = parseFloat(match[1]);
696
- return isNaN(parsed) ? void 0 : parsed;
694
+ const match = val.trim().match(/^\+?((?:\d*\.)?\d+)(px)?$/);
695
+ return match ? toFontSize(parseFloat(match[1])) : void 0;
697
696
  }
698
697
  };
699
698
  //#endregion
@@ -1572,6 +1571,20 @@ const useChartScopeElement = () => useContext(ChartScopeContext);
1572
1571
  const useStandaloneScopeClass = () => useContext(GlobalChartsContext) ? void 0 : CHART_SCOPE_CLASS;
1573
1572
  //#endregion
1574
1573
  //#region src/hooks/use-xychart-theme.ts
1574
+ const STARTS_LIKE_A_NUMBER = /^[+-]?[\d.]/;
1575
+ const NON_NEGATIVE_CSS_NUMBER = /^\+?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?:[a-z]+|%)?$/i;
1576
+ const isRenderableFontSize = (fontSize) => {
1577
+ if (typeof fontSize === "number") return resolveFontSize(fontSize) !== void 0;
1578
+ const value = fontSize.trim();
1579
+ if (!STARTS_LIKE_A_NUMBER.test(value)) return true;
1580
+ return NON_NEGATIVE_CSS_NUMBER.test(value) && Number.isFinite(parseFloat(value));
1581
+ };
1582
+ const withRenderableFontSize = (style) => {
1583
+ if (style?.fontSize === void 0 || isRenderableFontSize(style.fontSize)) return style;
1584
+ const rest = { ...style };
1585
+ delete rest.fontSize;
1586
+ return rest;
1587
+ };
1575
1588
  const useXYChartTheme = (data) => {
1576
1589
  const theme = useGlobalChartsTheme();
1577
1590
  const scopeElement = useChartScopeElement();
@@ -1602,9 +1615,10 @@ const useXYChartTheme = (data) => {
1602
1615
  yAxisLineStyles: { stroke: CATALOG_POINTERS.axisY },
1603
1616
  yTickLineStyles: { stroke: CATALOG_POINTERS.tickY },
1604
1617
  svgLabelSmall: {
1605
- ...theme.svgLabelSmall,
1618
+ ...withRenderableFontSize(theme.svgLabelSmall),
1606
1619
  fill: CATALOG_POINTERS.labelAxis
1607
- }
1620
+ },
1621
+ svgLabelBig: withRenderableFontSize(theme.svgLabelBig)
1608
1622
  });
1609
1623
  }, [
1610
1624
  theme,
@@ -2117,7 +2131,7 @@ const getLegendItemAriaLabel = (text, value, visible, interactive) => {
2117
2131
  if (visible) return;
2118
2132
  return sprintf(_x("%s: hidden", "hidden non-interactive legend item", "jetpack-charts"), accessibleText);
2119
2133
  };
2120
- 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) => {
2134
+ const BaseLegend = 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) => {
2121
2135
  const { margin: itemMargin = "0", flexDirection: itemDirection = "row" } = itemStyles ?? {};
2122
2136
  const { justifyContent: labelJustifyContent = "flex-start", flex: labelFlex = "0 0 auto", margin: labelMargin = "0 4px", maxWidth, textOverflow = "wrap" } = labelStyles ?? {};
2123
2137
  const { width: shapeWidth = 16, height: shapeHeight = 16, margin: shapeMargin = "2px 4px 2px 0" } = shapeStyles ?? {};
@@ -2125,6 +2139,16 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
2125
2139
  const context = useContext(GlobalChartsContext);
2126
2140
  const chartInstanceContext = useContext(ChartInstanceContext);
2127
2141
  const standaloneScopeClass = useStandaloneScopeClass();
2142
+ const isSeriesVisible = useCallback((seriesLabel) => {
2143
+ if (chartInstanceContext?.isSeriesVisible) return chartInstanceContext.isSeriesVisible(seriesLabel);
2144
+ if (!chartId || !context) return true;
2145
+ return context.isSeriesVisible(chartId, seriesLabel);
2146
+ }, [
2147
+ chartId,
2148
+ chartInstanceContext,
2149
+ context
2150
+ ]);
2151
+ const items = useMemo(() => allItems.filter((item) => item.interactive !== false || !item.describesSeries || isSeriesVisible(item.describesSeries)), [allItems, isSeriesVisible]);
2128
2152
  const domain = items.map((item) => item.label);
2129
2153
  const legendScale = scaleOrdinal({
2130
2154
  domain,
@@ -2147,15 +2171,6 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
2147
2171
  chartId,
2148
2172
  context
2149
2173
  ]);
2150
- const isSeriesVisible = useCallback((seriesLabel) => {
2151
- if (chartInstanceContext?.isSeriesVisible) return chartInstanceContext.isSeriesVisible(seriesLabel);
2152
- if (!chartId || !context) return true;
2153
- return context.isSeriesVisible(chartId, seriesLabel);
2154
- }, [
2155
- chartId,
2156
- chartInstanceContext,
2157
- context
2158
- ]);
2159
2174
  const createClickHandler = useCallback((seriesLabels, itemInteractive) => {
2160
2175
  if (!itemInteractive) return;
2161
2176
  return () => handleLegendClick(seriesLabels);
@@ -2430,6 +2445,34 @@ function buildComparisonLegendItem(seriesData, items, label, getElementStyles, l
2430
2445
  };
2431
2446
  }
2432
2447
  /**
2448
+ * Builds one static item per comparison series folded into another series' item, named after
2449
+ * that item and styled like the comparison series itself.
2450
+ * @param seriesData - The series data to search for comparison series
2451
+ * @param items - The legend items already built from the series
2452
+ * @param formatLabel - Names an item after the label of the item it was folded into
2453
+ * @param getElementStyles - Function to get element styles
2454
+ * @param legendShape - The shape type for legend items (string literal or React component)
2455
+ * @return The legend items, in series order
2456
+ */
2457
+ function buildPerSeriesComparisonItems(seriesData, items, formatLabel, getElementStyles, legendShape) {
2458
+ return seriesData.flatMap((series, index) => {
2459
+ const owner = items.find((item) => item.seriesLabels?.includes(series.label));
2460
+ if (series.options?.type !== "comparison" || !owner || owner.seriesLabels?.[0] === series.label) return [];
2461
+ const { color, shapeStyles } = getElementStyles({
2462
+ data: series,
2463
+ index,
2464
+ legendShape
2465
+ });
2466
+ return [{
2467
+ label: formatLabel(owner.label),
2468
+ color,
2469
+ shapeStyle: shapeStyles,
2470
+ interactive: false,
2471
+ describesSeries: series.label
2472
+ }];
2473
+ });
2474
+ }
2475
+ /**
2433
2476
  * Processes point data into legend items
2434
2477
  * @param pointData - The point data to process
2435
2478
  * @param getElementStyles - Function to get element styles
@@ -2465,13 +2508,14 @@ function processPointData(pointData, getElementStyles, showValues, legendValueDi
2465
2508
  * @return Array of legend items ready for display
2466
2509
  */
2467
2510
  function useChartLegendItems(data, options = {}, legendShape) {
2468
- const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, renderGlyph } = options;
2511
+ const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, renderGlyph } = options;
2469
2512
  const { getElementStyles } = useGlobalChartsContext();
2470
2513
  return useMemo(() => {
2471
2514
  if (!data || !Array.isArray(data) || data.length === 0) return [];
2472
2515
  if ("data" in data[0]) {
2473
2516
  const seriesData = data;
2474
2517
  const items = processSeriesData(seriesData, getElementStyles, showValues, withGlyph, glyphSize, collapseGroups, renderGlyph, legendShape);
2518
+ if (comparisonSeriesItems) return [...items, ...buildPerSeriesComparisonItems(seriesData, items, comparisonSeriesItems, getElementStyles, legendShape)];
2475
2519
  const comparison = comparisonItem ? buildComparisonLegendItem(seriesData, items, typeof comparisonItem === "string" ? comparisonItem : __("Comparison period", "jetpack-charts"), getElementStyles, legendShape) : null;
2476
2520
  return comparison ? [...items, comparison] : items;
2477
2521
  }
@@ -2485,6 +2529,7 @@ function useChartLegendItems(data, options = {}, legendShape) {
2485
2529
  glyphSize,
2486
2530
  collapseGroups,
2487
2531
  comparisonItem,
2532
+ comparisonSeriesItems,
2488
2533
  renderGlyph,
2489
2534
  legendShape
2490
2535
  ]);
@@ -4726,6 +4771,7 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
4726
4771
  const legendInteractive = legend.interactive ?? false;
4727
4772
  const legendCollapseGroups = legend.collapseGroups ?? false;
4728
4773
  const legendComparisonItem = legend.comparisonItem ?? false;
4774
+ const legendComparisonSeriesItems = legend.comparisonSeriesItems;
4729
4775
  const legendShape = legend.shape ?? "line";
4730
4776
  const legendPosition = legend.position ?? "bottom";
4731
4777
  const formatting = useChartFormatting();
@@ -4910,12 +4956,14 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
4910
4956
  glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
4911
4957
  collapseGroups: legendCollapseGroups,
4912
4958
  comparisonItem: legendComparisonItem,
4959
+ comparisonSeriesItems: legendComparisonSeriesItems,
4913
4960
  renderGlyph
4914
4961
  }), [
4915
4962
  withLegendGlyph,
4916
4963
  glyphStyle?.radius,
4917
4964
  legendCollapseGroups,
4918
4965
  legendComparisonItem,
4966
+ legendComparisonSeriesItems,
4919
4967
  renderGlyph
4920
4968
  ]), legendShape);
4921
4969
  const chartMetadata = useMemo(() => ({
@@ -5384,8 +5432,13 @@ const AreaChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
5384
5432
  withGlyph: false,
5385
5433
  glyphSize: 0,
5386
5434
  collapseGroups: legend.collapseGroups ?? false,
5387
- comparisonItem: legend.comparisonItem ?? false
5388
- }), [legend.collapseGroups, legend.comparisonItem]), legendShape);
5435
+ comparisonItem: legend.comparisonItem ?? false,
5436
+ comparisonSeriesItems: legend.comparisonSeriesItems
5437
+ }), [
5438
+ legend.collapseGroups,
5439
+ legend.comparisonItem,
5440
+ legend.comparisonSeriesItems
5441
+ ]), legendShape);
5389
5442
  const chartMetadata = useMemo(() => ({
5390
5443
  stacked,
5391
5444
  stackOffset,
@@ -6378,6 +6431,7 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6378
6431
  const legendInteractive = legend.interactive ?? false;
6379
6432
  const legendCollapseGroups = legend.collapseGroups ?? false;
6380
6433
  const legendComparisonItem = legend.comparisonItem ?? false;
6434
+ const legendComparisonSeriesItems = legend.comparisonSeriesItems;
6381
6435
  const horizontal = orientation === "horizontal";
6382
6436
  const chartId = useChartId(providedChartId);
6383
6437
  const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
@@ -6390,8 +6444,13 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6390
6444
  });
6391
6445
  const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({
6392
6446
  collapseGroups: legendCollapseGroups,
6393
- comparisonItem: legendComparisonItem
6394
- }), [legendCollapseGroups, legendComparisonItem]));
6447
+ comparisonItem: legendComparisonItem,
6448
+ comparisonSeriesItems: legendComparisonSeriesItems
6449
+ }), [
6450
+ legendCollapseGroups,
6451
+ legendComparisonItem,
6452
+ legendComparisonSeriesItems
6453
+ ]));
6395
6454
  const { getElementStyles } = useGlobalChartsContext();
6396
6455
  const isSeriesRendered = useCallback((series) => isSeriesVisible(series.label), [isSeriesVisible]);
6397
6456
  const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(dataSorted.filter(isSeriesRendered)), [dataSorted, isSeriesRendered]);
@@ -6902,7 +6961,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
6902
6961
  right: 20,
6903
6962
  bottom: 0,
6904
6963
  top: 0
6905
- }, className, ...rest }) => {
6964
+ }, className, ariaLabel, ...rest }) => {
6906
6965
  const { getElementStyles } = useGlobalChartsContext();
6907
6966
  const tintedData = useMemo(() => {
6908
6967
  if (data.length > 1) return data;
@@ -6977,6 +7036,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
6977
7036
  xScale: chartOptions.xScale,
6978
7037
  yScale: chartOptions.yScale
6979
7038
  },
7039
+ ariaLabel: ariaLabel ?? __("Bar list chart", "jetpack-charts"),
6980
7040
  ...rest
6981
7041
  });
6982
7042
  };
@@ -7052,6 +7112,8 @@ const useFunnelSelection = (hideTooltip) => {
7052
7112
  };
7053
7113
  //#endregion
7054
7114
  //#region src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx
7115
+ /** Chart height (px) below which the funnel tightens its gaps so the bars keep their room. */
7116
+ const SHORT_CHART_HEIGHT = 180;
7055
7117
  /**
7056
7118
  * Internal ConversionFunnelChart component with chart registration
7057
7119
  *
@@ -7063,6 +7125,7 @@ const useFunnelSelection = (hideTooltip) => {
7063
7125
  * @param props.loading - Whether the chart is in loading state
7064
7126
  * @param props.animation - Whether to show chart animation on initial render or not
7065
7127
  * @param props.className - Additional CSS class name
7128
+ * @param props.ariaLabel - Accessible name for the chart group
7066
7129
  * @param props.height - Height of the chart container. Falls back to style.height if set, otherwise defaults to "100%".
7067
7130
  * @param props.style - Custom styling
7068
7131
  * @param props.renderStepLabel - Custom render function for step labels
@@ -7072,7 +7135,7 @@ const useFunnelSelection = (hideTooltip) => {
7072
7135
  * @param props.tooltipStyle - Inline styles merged over the tooltip box defaults
7073
7136
  * @return JSX element representing the conversion funnel chart
7074
7137
  */
7075
- const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
7138
+ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, ariaLabel, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
7076
7139
  const chartId = useChartId(providedChartId);
7077
7140
  const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
7078
7141
  const chartRef = useRef(null);
@@ -7081,10 +7144,13 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7081
7144
  const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = useTooltip();
7082
7145
  const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
7083
7146
  const standaloneScopeClass = useStandaloneScopeClass();
7147
+ const [measureChartRef, , chartHeight] = useElementSize();
7148
+ const gap = chartHeight > 0 && chartHeight < SHORT_CHART_HEIGHT ? "sm" : "xl";
7084
7149
  const setChartRef = useCallback((node) => {
7085
7150
  chartRef.current = node;
7086
7151
  setScopeNode(node);
7087
- }, []);
7152
+ measureChartRef(node);
7153
+ }, [measureChartRef]);
7088
7154
  const clearSelectionAndRef = useCallback(() => {
7089
7155
  clearSelection();
7090
7156
  selectedBarRef.current = null;
@@ -7232,7 +7298,9 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7232
7298
  const maxRate = Math.max(...steps.map((step) => step.rate));
7233
7299
  return /* @__PURE__ */ jsxs(Stack, {
7234
7300
  direction: "column",
7235
- gap: "xl",
7301
+ gap,
7302
+ role: "group",
7303
+ "aria-label": ariaLabel ?? __("Conversion funnel chart", "jetpack-charts"),
7236
7304
  ref: setChartRef,
7237
7305
  className: clsx("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
7238
7306
  style: {
@@ -7263,7 +7331,7 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7263
7331
  return /* @__PURE__ */ jsxs(Stack, {
7264
7332
  direction: "column",
7265
7333
  className: clsx(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"]),
7266
- gap: "xl",
7334
+ gap,
7267
7335
  children: [/* @__PURE__ */ jsxs(Stack, {
7268
7336
  direction: "column",
7269
7337
  gap: "xs",
@@ -7457,6 +7525,7 @@ function normalizeGeoChartError(eventArgs) {
7457
7525
  *
7458
7526
  * @param props - The props for the GeoChart component
7459
7527
  * @param props.data - Data in Google Charts format (array of arrays with headers)
7528
+ * @param props.ariaLabel - Accessible name of the chart
7460
7529
  * @param props.width - Width of the chart in pixels
7461
7530
  * @param props.height - Height of the chart in pixels
7462
7531
  * @param props.region - Region to display ('world', 'US', or ISO 3166-1 alpha-2 code)
@@ -7468,7 +7537,7 @@ function normalizeGeoChartError(eventArgs) {
7468
7537
  * @param props.renderPlaceholder - Optional render function for the loading placeholder
7469
7538
  * @return A React component displaying an interactive map with data visualization
7470
7539
  */
7471
- const GeoChartInternal = ({ className, data, width, height, region = "world", resolution = "countries", displayMode = "regions", domain, onError, renderPlaceholder }) => {
7540
+ const GeoChartInternal = ({ className, data, ariaLabel, width, height, region = "world", resolution = "countries", displayMode = "regions", domain, onError, renderPlaceholder }) => {
7472
7541
  const { getElementStyles } = useGlobalChartsContext();
7473
7542
  const scopeElement = useChartScopeElement();
7474
7543
  const containerRef = useRef(null);
@@ -7556,8 +7625,14 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
7556
7625
  sanitizedData.hasHtmlTooltips
7557
7626
  ]);
7558
7627
  const chartEvents = useMemo(() => {
7559
- if (!onError) return;
7560
- return [{
7628
+ const readyEvent = {
7629
+ eventName: "ready",
7630
+ callback: () => {
7631
+ containerRef.current?.querySelectorAll("svg").forEach((svg) => svg.setAttribute("aria-hidden", "true"));
7632
+ }
7633
+ };
7634
+ if (!onError) return [readyEvent];
7635
+ return [readyEvent, {
7561
7636
  eventName: "error",
7562
7637
  callback: ({ eventArgs }) => {
7563
7638
  onError(normalizeGeoChartError(eventArgs));
@@ -7566,6 +7641,8 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
7566
7641
  }, [onError]);
7567
7642
  return /* @__PURE__ */ jsx(Center, {
7568
7643
  ref: containerRef,
7644
+ role: "group",
7645
+ "aria-label": ariaLabel ?? __("Geo chart", "jetpack-charts"),
7569
7646
  className: clsx("geo-chart", geo_chart_module_default.container, className),
7570
7647
  style: {
7571
7648
  width,
@@ -8120,7 +8197,7 @@ const CELL_VALUE_MODIFIER = {
8120
8197
  white: heatmap_chart_module_default["heatmap-chart__cell-value--white"]
8121
8198
  };
8122
8199
  const NO_ROW_LABELS = [];
8123
- const TOOLTIP_BOX_STYLE = { zIndex: 3 };
8200
+ const TOOLTIP_BOX_STYLE$1 = { zIndex: 3 };
8124
8201
  const largest = (root, selector, size) => Math.max(0, ...Array.from(root.querySelectorAll(selector), (el) => el[size]));
8125
8202
  const gridBox = (chart, grid) => {
8126
8203
  let height = chart.clientHeight;
@@ -8143,9 +8220,9 @@ const cellName = (info) => info.cellLabel || [
8143
8220
  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 }) => {
8144
8221
  const chartId = useChartId(providedChartId);
8145
8222
  const tooltipBoxStyle = tooltipStyle ? {
8146
- ...TOOLTIP_BOX_STYLE,
8223
+ ...TOOLTIP_BOX_STYLE$1,
8147
8224
  ...tooltipStyle
8148
- } : TOOLTIP_BOX_STYLE;
8225
+ } : TOOLTIP_BOX_STYLE$1;
8149
8226
  const { getElementStyles, theme } = useGlobalChartsContext();
8150
8227
  const scopeElement = useChartScopeElement();
8151
8228
  const { heatmapChart: heatmapChartSettings } = theme;
@@ -11270,8 +11347,8 @@ const SUBPIXEL_TOLERANCE = .5;
11270
11347
  * depends on `--a8c-charts-dimension-leaderboard-row-gap`, label wrapping, and
11271
11348
  * whatever a caller renders as a label, so any restated number would drift.
11272
11349
  *
11273
- * Every row is a direct grid child marked with `data-row-index`; interactive rows
11274
- * use a button wrapper and non-interactive rows use a div wrapper.
11350
+ * Every row is a `listitem` div, a direct grid child marked with `data-row-index`;
11351
+ * interactive rows hold a button inside it.
11275
11352
  *
11276
11353
  * @param enabled - Whether to measure at all. When false every row fits.
11277
11354
  * @param rowCount - Total number of rows rendered.
@@ -11413,6 +11490,7 @@ var leaderboard_chart_module_default = {
11413
11490
  "overlayLabel": "a8ccharts-GovfoW-overlayLabel",
11414
11491
  "row": "a8ccharts-GovfoW-row",
11415
11492
  "rowButton": "a8ccharts-GovfoW-rowButton",
11493
+ "rowItem": "a8ccharts-GovfoW-rowItem",
11416
11494
  "stretch": "a8ccharts-GovfoW-stretch",
11417
11495
  "valueContainer": "a8ccharts-GovfoW-valueContainer"
11418
11496
  };
@@ -11525,9 +11603,10 @@ const BarWithLabel = ({ entry, withComparison, withOverlayLabel, primaryColor, s
11525
11603
  * @param props.children - Child components for composition API
11526
11604
  * @param props.className - Additional CSS class name
11527
11605
  * @param props.style - Custom styling for the chart container
11606
+ * @param props.ariaLabel - Accessible name for the list, defaulting to "Leaderboard chart"
11528
11607
  * @return JSX element representing the leaderboard chart
11529
11608
  */
11530
- 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 }) => {
11609
+ 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 }) => {
11531
11610
  const legendInteractive = legend.interactive ?? false;
11532
11611
  const legendPosition = legend.position ?? "bottom";
11533
11612
  const chartId = useChartId(providedChartId);
@@ -11658,6 +11737,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
11658
11737
  className: leaderboard_chart_module_default.emptyState,
11659
11738
  children: getAllHiddenMessage(legendInteractive, "series")
11660
11739
  }) : /* @__PURE__ */ jsx(component_default, {
11740
+ role: "list",
11741
+ "aria-label": ariaLabel ?? __("Leaderboard chart", "jetpack-charts"),
11661
11742
  templateColumns: "minmax(0, 1fr) auto",
11662
11743
  rowGap: ROW_GAP,
11663
11744
  columnGap: COLUMN_GAP,
@@ -11705,40 +11786,49 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
11705
11786
  })
11706
11787
  ]
11707
11788
  })] });
11708
- if (entry.onClick && entry.hasInteractiveLabel) return /* @__PURE__ */ jsxs("div", {
11789
+ if (entry.onClick && entry.hasInteractiveLabel) return /* @__PURE__ */ jsx("div", {
11790
+ role: "listitem",
11709
11791
  "data-row-index": rowIndex,
11710
11792
  style: rowStyle,
11711
- className: clsx(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow, leaderboard_chart_module_default.layeredRow),
11712
- onClick: forwardCellClickToRowButton,
11713
- children: [
11714
- rowCells,
11715
- /* @__PURE__ */ jsx("button", {
11716
- type: "button",
11717
- className: leaderboard_chart_module_default.rowButton,
11718
- onClick: entry.onClick,
11719
- "aria-label": entry.ariaLabel
11720
- }),
11721
- /* @__PURE__ */ jsx(Icon, {
11722
- className: leaderboard_chart_module_default.chevron,
11723
- icon: chevronRight,
11724
- size: 24
11725
- })
11726
- ]
11793
+ className: leaderboard_chart_module_default.rowItem,
11794
+ children: /* @__PURE__ */ jsxs("div", {
11795
+ className: clsx(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow, leaderboard_chart_module_default.layeredRow),
11796
+ onClick: forwardCellClickToRowButton,
11797
+ children: [
11798
+ rowCells,
11799
+ /* @__PURE__ */ jsx("button", {
11800
+ type: "button",
11801
+ className: leaderboard_chart_module_default.rowButton,
11802
+ onClick: entry.onClick,
11803
+ "aria-label": entry.ariaLabel
11804
+ }),
11805
+ /* @__PURE__ */ jsx(Icon, {
11806
+ className: leaderboard_chart_module_default.chevron,
11807
+ icon: chevronRight,
11808
+ size: 24
11809
+ })
11810
+ ]
11811
+ })
11727
11812
  }, entry.id);
11728
- if (entry.onClick) return /* @__PURE__ */ jsxs("button", {
11729
- type: "button",
11813
+ if (entry.onClick) return /* @__PURE__ */ jsx("div", {
11814
+ role: "listitem",
11730
11815
  "data-row-index": rowIndex,
11731
11816
  style: rowStyle,
11732
- className: clsx(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow),
11733
- onClick: entry.onClick,
11734
- "aria-label": entry.ariaLabel,
11735
- children: [rowCells, /* @__PURE__ */ jsx(Icon, {
11736
- className: leaderboard_chart_module_default.chevron,
11737
- icon: chevronRight,
11738
- size: 24
11739
- })]
11817
+ className: leaderboard_chart_module_default.rowItem,
11818
+ children: /* @__PURE__ */ jsxs("button", {
11819
+ type: "button",
11820
+ className: clsx(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow),
11821
+ onClick: entry.onClick,
11822
+ "aria-label": entry.ariaLabel,
11823
+ children: [rowCells, /* @__PURE__ */ jsx(Icon, {
11824
+ className: leaderboard_chart_module_default.chevron,
11825
+ icon: chevronRight,
11826
+ size: 24
11827
+ })]
11828
+ })
11740
11829
  }, entry.id);
11741
11830
  return /* @__PURE__ */ jsx("div", {
11831
+ role: "listitem",
11742
11832
  "data-row-index": rowIndex,
11743
11833
  style: rowStyle,
11744
11834
  className: leaderboard_chart_module_default.row,
@@ -11775,11 +11865,13 @@ const PieSelectionAnnouncement = ({ data }) => /* @__PURE__ */ jsx(VisuallyHidde
11775
11865
  });
11776
11866
  //#endregion
11777
11867
  //#region src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx
11868
+ const TOOLTIP_BOX_STYLE = { zIndex: 3 };
11778
11869
  const PieTooltip = ({ top, left, selectedIndex, tooltipRef, children }) => {
11779
11870
  const standaloneScopeClass = useStandaloneScopeClass();
11780
11871
  return /* @__PURE__ */ jsx(BoundedTooltip, {
11781
11872
  top,
11782
11873
  left,
11874
+ style: TOOLTIP_BOX_STYLE,
11783
11875
  children: selectedIndex === void 0 ? /* @__PURE__ */ jsx("div", {
11784
11876
  className: standaloneScopeClass,
11785
11877
  role: "tooltip",
@@ -12002,6 +12094,7 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
12002
12094
  //#endregion
12003
12095
  //#region src/charts/pie-chart/pie-chart.module.scss
12004
12096
  var pie_chart_module_default = {
12097
+ "pie-chart": "a8ccharts-gnszbG-pie-chart",
12005
12098
  "pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
12006
12099
  "pie-chart__label-text": "a8ccharts-gnszbG-pie-chart__label-text",
12007
12100
  "pie-chart__label-text--black": "a8ccharts-gnszbG-pie-chart__label-text--black",