@automattic/charts 4.7.0 → 4.9.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 (92) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/TOKENS.md +6 -3
  3. package/dist/index.cjs +834 -321
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +68 -17
  6. package/dist/index.d.cts +102 -28
  7. package/dist/index.d.ts +102 -28
  8. package/dist/index.js +838 -327
  9. package/dist/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/charts/area-chart/area-chart.tsx +7 -4
  12. package/src/charts/area-chart/test/area-chart.test.tsx +24 -15
  13. package/src/charts/area-chart/test/tooltip-resolution-branches.test.tsx +1 -1
  14. package/src/charts/area-chart/test/tooltip-resolution.test.tsx +2 -2
  15. package/src/charts/area-chart/types.ts +2 -0
  16. package/src/charts/bar-chart/bar-chart.module.scss +7 -0
  17. package/src/charts/bar-chart/bar-chart.tsx +25 -16
  18. package/src/charts/bar-chart/private/comparison-bars.tsx +1 -0
  19. package/src/charts/bar-chart/test/bar-chart.test.tsx +106 -62
  20. package/src/charts/bar-chart/types.ts +2 -0
  21. package/src/charts/bar-list-chart/test/bar-list-chart.test.tsx +3 -1
  22. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +1 -1
  23. package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +9 -0
  24. package/src/charts/heatmap-chart/heatmap-chart.module.scss +16 -8
  25. package/src/charts/heatmap-chart/heatmap-chart.tsx +183 -66
  26. package/src/charts/heatmap-chart/private/column-groups.ts +79 -8
  27. package/src/charts/heatmap-chart/private/fit-compact-cells.ts +72 -0
  28. package/src/charts/heatmap-chart/private/heatmap-context.ts +2 -2
  29. package/src/charts/heatmap-chart/private/heatmap-legend.tsx +15 -3
  30. package/src/charts/heatmap-chart/private/heatmap-scale.ts +74 -0
  31. package/src/charts/heatmap-chart/private/index.ts +6 -3
  32. package/src/charts/heatmap-chart/private/use-heatmap-colors.ts +24 -6
  33. package/src/charts/heatmap-chart/test/column-groups.test.ts +41 -4
  34. package/src/charts/heatmap-chart/test/fit-compact-cells.test.ts +59 -0
  35. package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +231 -8
  36. package/src/charts/heatmap-chart/test/heatmap-scale.test.ts +78 -0
  37. package/src/charts/heatmap-chart/test/use-heatmap-colors.test.ts +18 -6
  38. package/src/charts/heatmap-chart/types.ts +6 -3
  39. package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +46 -4
  40. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +37 -1
  41. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +53 -0
  42. package/src/charts/leaderboard-chart/types.ts +6 -1
  43. package/src/charts/line-chart/line-chart.tsx +7 -4
  44. package/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx +19 -9
  45. package/src/charts/line-chart/test/default-tooltip-formatting.test.tsx +1 -1
  46. package/src/charts/line-chart/test/line-chart.test.tsx +45 -35
  47. package/src/charts/line-chart/test/tooltip-resolution.test.tsx +2 -2
  48. package/src/charts/line-chart/types.ts +5 -3
  49. package/src/charts/pie-chart/pie-chart.tsx +153 -143
  50. package/src/charts/pie-chart/test/pie-chart.test.tsx +171 -0
  51. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +126 -124
  52. package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +55 -1
  53. package/src/charts/private/chart-composition/use-chart-children.ts +11 -6
  54. package/src/charts/private/pie-keyboard-navigation/index.ts +4 -0
  55. package/src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts +10 -0
  56. package/src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss +16 -0
  57. package/src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx +14 -0
  58. package/src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx +82 -0
  59. package/src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx +44 -0
  60. package/src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx +47 -0
  61. package/src/charts/private/pie-keyboard-navigation/test/order-arcs-for-navigation.test.ts +34 -0
  62. package/src/charts/private/pie-keyboard-navigation/test/selected-segment-ring.test.ts +14 -0
  63. package/src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts +139 -0
  64. package/src/charts/private/test/label-text-color.test.ts +6 -8
  65. package/src/charts/private/x-zoom/test/x-zoom.test.tsx +3 -2
  66. package/src/components/tooltip/base-tooltip.tsx +31 -32
  67. package/src/components/tooltip/index.ts +3 -1
  68. package/src/components/tooltip/private/bounded-tooltip.tsx +15 -15
  69. package/src/components/tooltip/private/label-value-content.tsx +8 -0
  70. package/src/components/tooltip/private/xy-chart-tooltip-overlay.tsx +336 -0
  71. package/src/components/tooltip/test/tool-tip.test.tsx +8 -6
  72. package/src/components/tooltip/test/tooltip-box.test.tsx +53 -0
  73. package/src/components/tooltip/test/xy-chart-tooltip-overlay.test.tsx +445 -0
  74. package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +283 -365
  75. package/src/components/tooltip/{base-tooltip.module.scss → tooltip-box.module.scss} +5 -8
  76. package/src/components/tooltip/tooltip-box.tsx +43 -0
  77. package/src/components/tooltip/types.ts +7 -1
  78. package/src/components/tooltip/xy-chart-tooltip.tsx +410 -300
  79. package/src/hooks/test/use-chart-margin.test.tsx +8 -4
  80. package/src/hooks/use-chart-margin.tsx +21 -18
  81. package/src/index.ts +8 -3
  82. package/src/providers/chart-context/global-charts-provider.tsx +5 -14
  83. package/src/providers/chart-context/hooks/use-default-hidden-series.ts +1 -1
  84. package/src/providers/chart-context/private/catalog-pointers.ts +1 -0
  85. package/src/providers/chart-context/private/resolve-opaque-hex.ts +16 -0
  86. package/src/providers/chart-context/test/use-default-hidden-series.test.tsx +1 -1
  87. package/src/styles/chart-scope.scss +1 -0
  88. package/src/test-utils/zoned-parsing-suite.ts +0 -10
  89. package/src/types.ts +18 -2
  90. package/src/utils/test/date-formatting.test.ts +0 -10
  91. package/src/components/tooltip/accessible-tooltip.tsx +0 -433
  92. package/src/components/tooltip/test/accessible-tooltip.test.tsx +0 -331
package/dist/index.cjs CHANGED
@@ -29,12 +29,12 @@ let clsx = require("clsx");
29
29
  clsx = __toESM(clsx, 1);
30
30
  let react = require("react");
31
31
  react = __toESM(react);
32
- let _visx_vendor_d3_color = require("@visx/vendor/d3-color");
33
32
  let date_fns = require("date-fns");
34
33
  let _date_fns_tz = require("@date-fns/tz");
35
34
  let _visx_text = require("@visx/text");
36
35
  let deepmerge = require("deepmerge");
37
36
  deepmerge = __toESM(deepmerge, 1);
37
+ let _visx_vendor_d3_color = require("@visx/vendor/d3-color");
38
38
  let react_jsx_runtime = require("react/jsx-runtime");
39
39
  let _visx_tooltip = require("@visx/tooltip");
40
40
  let _visx_scale = require("@visx/scale");
@@ -836,6 +836,7 @@ const CATALOG_POINTERS = {
836
836
  annotation: "var(--a8c-charts-color-annotation, #1e1e1e)",
837
837
  surface: "var(--a8c-charts-color-surface, #fff)",
838
838
  surfaceSecondary: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
839
+ track: "var(--a8c-charts-color-track, #f0f0f0)",
839
840
  trendUp: "var(--a8c-charts-color-trend-up, #008030)",
840
841
  trendDown: "var(--a8c-charts-color-trend-down, #cc1818)",
841
842
  series: SERIES_PALETTE_POINTERS
@@ -1065,6 +1066,15 @@ const rgbLuminance = (rgb) => {
1065
1066
  * @return Ratio from 1 to 21.
1066
1067
  */
1067
1068
  const luminanceContrastRatio = (first, second) => (Math.max(first, second) + .05) / (Math.min(first, second) + .05);
1069
+ /**
1070
+ * WCAG contrast ratio between two hex colors.
1071
+ *
1072
+ * @param first - First hex color.
1073
+ * @param second - Second hex color.
1074
+ * @return Ratio from 1 to 21.
1075
+ * @throws {Error} if either hex string is malformed
1076
+ */
1077
+ const contrastRatio = (first, second) => luminanceContrastRatio(relativeLuminance(first), relativeLuminance(second));
1068
1078
  /** WCAG 1.4.3 text contrast, which a label drawn on a fill needs from at least one label color. */
1069
1079
  const MIN_LABEL_CONTRAST = 4.5;
1070
1080
  /** Degrees of hue one unit of OKLCH chroma is worth when ranking candidates by hue. */
@@ -1255,6 +1265,14 @@ const buildPaletteGenerator = (normalizedSeeds, background, labelColors) => {
1255
1265
  };
1256
1266
  };
1257
1267
  //#endregion
1268
+ //#region src/providers/chart-context/private/resolve-opaque-hex.ts
1269
+ const resolveOpaqueHex = (pointer, resolve) => {
1270
+ const raw = resolve(pointer);
1271
+ if (!raw || (0, _visx_vendor_d3_color.color)(raw)?.opacity !== 1) return null;
1272
+ const hex = normalizeColorToHex(raw);
1273
+ return isValidHexColor(hex) ? hex : null;
1274
+ };
1275
+ //#endregion
1258
1276
  //#region src/providers/chart-context/themes.ts
1259
1277
  /**
1260
1278
  * Default theme configuration: the shape and spacing a consumer can override.
@@ -1303,12 +1321,6 @@ const defaultTheme = {
1303
1321
  };
1304
1322
  //#endregion
1305
1323
  //#region src/providers/chart-context/global-charts-provider.tsx
1306
- const resolveOpaqueHex = (pointer, element) => {
1307
- const raw = resolveCssVariable(pointer, element);
1308
- if (!raw || (0, _visx_vendor_d3_color.color)(raw)?.opacity !== 1) return null;
1309
- const hex = normalizeColorToHex(pointer, element, resolveCssVariable);
1310
- return isValidHexColor(hex) ? hex : null;
1311
- };
1312
1324
  const PLACEHOLDER_LABEL_COLORS = [LABEL_FALLBACK, LABEL_INVERSE_FALLBACK];
1313
1325
  const GlobalChartsContext = (0, react.createContext)(null);
1314
1326
  const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
@@ -1336,8 +1348,9 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
1336
1348
  const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
1337
1349
  if (isValidHexColor(normalizedColor)) resolvedColors.push(normalizedColor);
1338
1350
  }
1339
- const backgroundHex = resolveOpaqueHex(CATALOG_POINTERS.background, wrapperRef.current) ?? "#ffffff";
1340
- const labelColors = [CATALOG_POINTERS.label, CATALOG_POINTERS.labelInverse].map((pointer) => resolveOpaqueHex(pointer, wrapperRef.current)).filter((hex) => hex !== null);
1351
+ const resolveAtWrapper = createCssVariableResolver(wrapperRef.current);
1352
+ const backgroundHex = resolveOpaqueHex(CATALOG_POINTERS.background, resolveAtWrapper) ?? "#ffffff";
1353
+ const labelColors = [CATALOG_POINTERS.label, CATALOG_POINTERS.labelInverse].map((pointer) => resolveOpaqueHex(pointer, resolveAtWrapper)).filter((hex) => hex !== null);
1341
1354
  setColorCache({
1342
1355
  colors: resolvedColors,
1343
1356
  background: backgroundHex,
@@ -1673,10 +1686,10 @@ const DEFAULT_MARGIN_BOTTOM = 20;
1673
1686
  */
1674
1687
  const DEFAULT_MARGIN_LEFT = 20;
1675
1688
  /**
1676
- * Bottom margin to use when the X-axis is rendered at the top.
1689
+ * Bottom margin when no X-axis sits below the chart, because it is on top or hidden.
1677
1690
  * We only need a small buffer below the chart in that case.
1678
1691
  */
1679
- const DEFAULT_BOTTOM_FOR_TOP_AXIS = 10;
1692
+ const DEFAULT_BOTTOM_WITHOUT_X_AXIS = 10;
1680
1693
  /**
1681
1694
  * Fallback font size used when we cannot derive a font size
1682
1695
  * from the theme or axis styles for X-axis tick labels.
@@ -1756,18 +1769,18 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
1756
1769
  if (yAxisOrientation === "right") defaultMargin.right = yMarginValue;
1757
1770
  else defaultMargin.left = yMarginValue;
1758
1771
  }
1759
- const xOrientation = options.axis?.x?.orientation === "top" ? "top" : "bottom";
1760
- const { fontSize, tickLength, tickLabelStyle } = getXAxisLabelMetrics(theme, xOrientation);
1761
- const computedXMargin = fontSize + tickLength;
1762
- if (xOrientation === "top") {
1763
- defaultMargin.top = Math.max(defaultMargin.top, computedXMargin);
1764
- defaultMargin.bottom = DEFAULT_BOTTOM_FOR_TOP_AXIS;
1765
- } else defaultMargin.bottom = Math.max(defaultMargin.bottom, computedXMargin);
1766
1772
  if (options.axis?.x?.display !== false) {
1773
+ const xOrientation = options.axis?.x?.orientation === "top" ? "top" : "bottom";
1774
+ const { fontSize, tickLength, tickLabelStyle } = getXAxisLabelMetrics(theme, xOrientation);
1775
+ const computedXMargin = fontSize + tickLength;
1776
+ if (xOrientation === "top") {
1777
+ defaultMargin.top = Math.max(defaultMargin.top, computedXMargin);
1778
+ defaultMargin.bottom = DEFAULT_BOTTOM_WITHOUT_X_AXIS;
1779
+ } else defaultMargin.bottom = Math.max(defaultMargin.bottom, computedXMargin);
1767
1780
  const { first, last } = getEdgeTickWidths(options.axis?.x?.tickValues ?? [], options.axis?.x?.tickFormat, tickLabelStyle);
1768
1781
  defaultMargin.left = Math.max(defaultMargin.left, Math.ceil(first / 2));
1769
1782
  defaultMargin.right = Math.max(defaultMargin.right, Math.ceil(last / 2));
1770
- }
1783
+ } else defaultMargin.bottom = DEFAULT_BOTTOM_WITHOUT_X_AXIS;
1771
1784
  return defaultMargin;
1772
1785
  }, [
1773
1786
  options,
@@ -2479,11 +2492,12 @@ function useChartLegendItems(data, options = {}, legendShape) {
2479
2492
  ]);
2480
2493
  }
2481
2494
  //#endregion
2482
- //#region src/components/tooltip/base-tooltip.module.scss
2483
- var base_tooltip_module_default = {
2484
- "surface": "a8ccharts--zY0xG-surface",
2485
- "tooltip": "a8ccharts--zY0xG-tooltip"
2486
- };
2495
+ //#region src/components/tooltip/private/label-value-content.tsx
2496
+ const LabelValueContent = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2497
+ data.label,
2498
+ ": ",
2499
+ data.valueDisplay || (0, _automattic_number_formatters.formatNumber)(data.value)
2500
+ ] });
2487
2501
  //#endregion
2488
2502
  //#region src/components/tooltip/private/tooltip-theme.tsx
2489
2503
  const DEFAULT_SURFACE = "#1e1e1e";
@@ -2509,28 +2523,63 @@ const TooltipTheme = ({ children }) => {
2509
2523
  });
2510
2524
  };
2511
2525
  //#endregion
2526
+ //#region src/components/tooltip/tooltip-box.module.scss
2527
+ var tooltip_box_module_default = { "surface": "a8ccharts-ddpU1W-surface" };
2528
+ //#endregion
2529
+ //#region src/components/tooltip/tooltip-box.tsx
2530
+ /**
2531
+ * The chart tooltip box: the dark surface every chart tooltip draws. It does not position itself; place it with `style` or a wrapper.
2532
+ *
2533
+ * @param props - Div attributes, plus `unstyled`.
2534
+ * @param props.unstyled - Drop the surface, scope class and theme.
2535
+ * @param ref - Forwarded to the box element.
2536
+ * @return The tooltip box.
2537
+ */
2538
+ const TooltipBox = (0, react.forwardRef)(({ unstyled = false, role = "tooltip", className, children, ...rest }, ref) => {
2539
+ const box = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2540
+ ref,
2541
+ role,
2542
+ className: (0, clsx.default)("visx-tooltip", !unstyled && ["a8c-charts-tooltip-scope", tooltip_box_module_default.surface], className),
2543
+ ...rest,
2544
+ children
2545
+ });
2546
+ return unstyled ? box : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTheme, { children: box });
2547
+ });
2548
+ TooltipBox.displayName = "TooltipBox";
2549
+ //#endregion
2512
2550
  //#region src/components/tooltip/base-tooltip.tsx
2513
- const DefaultTooltipContent = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2514
- data?.label,
2515
- ": ",
2516
- data?.valueDisplay || (0, _automattic_number_formatters.formatNumber)(data?.value)
2517
- ] });
2518
- const BaseTooltip = ({ data, top, left, component: Component = DefaultTooltipContent, children, className, style, renderContainer = true }) => {
2551
+ /**
2552
+ * A tooltip box with children or `label: value` content. Prefer `TooltipBox`.
2553
+ *
2554
+ * @param props - Tooltip props.
2555
+ * @param props.data - Data for the default content.
2556
+ * @param props.top - Deprecated vertical position.
2557
+ * @param props.left - Deprecated horizontal position.
2558
+ * @param props.component - Deprecated content component.
2559
+ * @param props.children - Tooltip content.
2560
+ * @param props.className - Class name passed to the content component.
2561
+ * @param props.style - Styles for the box.
2562
+ * @param props.renderContainer - Deprecated; render the content alone when false.
2563
+ * @return The tooltip.
2564
+ */
2565
+ const BaseTooltip = ({ data, top, left, component: Component = LabelValueContent, children, className, style, renderContainer = true }) => {
2519
2566
  const content = children || data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
2520
2567
  data,
2521
2568
  className
2522
2569
  });
2523
2570
  if (!renderContainer) return content;
2524
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTheme, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2525
- className: (0, clsx.default)(CHART_SCOPE_CLASS, base_tooltip_module_default.tooltip),
2571
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipBox, {
2526
2572
  style: {
2527
- top,
2528
- left,
2573
+ ...top === void 0 && left === void 0 ? void 0 : {
2574
+ position: "absolute",
2575
+ top,
2576
+ left,
2577
+ transform: "translate(-50%, -100%)"
2578
+ },
2529
2579
  ...style
2530
2580
  },
2531
- role: "tooltip",
2532
2581
  children: content
2533
- }) });
2582
+ });
2534
2583
  };
2535
2584
  //#endregion
2536
2585
  //#region src/components/tooltip/private/bounded-tooltip.tsx
@@ -2610,7 +2659,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
2610
2659
  };
2611
2660
  };
2612
2661
  /**
2613
- * visx's `Tooltip`, positioned like its `TooltipWithBounds` but kept inside the
2662
+ * A `TooltipBox`, positioned like visx's `TooltipWithBounds` but kept inside the
2614
2663
  * nearest clipping ancestor — or the viewport when there is none — rather than
2615
2664
  * inside its own parent. Rendered in-tree, a tooltip's parent is the chart
2616
2665
  * wrapper, which is often narrower than the box; measuring against the parent
@@ -2619,7 +2668,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
2619
2668
  * Re-measures on every render, so a box whose content changes width between
2620
2669
  * two hovers is placed for its current size.
2621
2670
  *
2622
- * @param props - visx `Tooltip` props.
2671
+ * @param props - `TooltipBox` props plus placement.
2623
2672
  * @param props.left - Anchor x, in wrapper coordinates.
2624
2673
  * @param props.top - Anchor y, in wrapper coordinates.
2625
2674
  * @param props.offsetLeft - Gap between the anchor and the box, horizontally.
@@ -2685,9 +2734,11 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
2685
2734
  ]);
2686
2735
  const x = position?.x ?? left + offsetLeft;
2687
2736
  const y = position?.y ?? top + (placement === "below-axis" ? POINTER_HEIGHT : offsetTop);
2688
- const box = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_tooltip.Tooltip, {
2737
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TooltipBox, {
2689
2738
  ref: nodeRef,
2690
- className: (0, clsx.default)(!unstyled && ["a8c-charts-tooltip-scope", base_tooltip_module_default.surface], className),
2739
+ role: "presentation",
2740
+ unstyled,
2741
+ className,
2691
2742
  style: {
2692
2743
  position: "absolute",
2693
2744
  left: 0,
@@ -2710,10 +2761,9 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
2710
2761
  }
2711
2762
  }), children]
2712
2763
  });
2713
- return unstyled ? box : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTheme, { children: box });
2714
2764
  };
2715
2765
  //#endregion
2716
- //#region src/components/tooltip/xy-chart-tooltip.tsx
2766
+ //#region src/components/tooltip/private/xy-chart-tooltip-overlay.tsx
2717
2767
  const CROSSHAIR_STROKE_WIDTH = 1.5;
2718
2768
  const CROSSHAIR_PAINT_PROPERTIES = /* @__PURE__ */ new Set([
2719
2769
  "stroke",
@@ -2815,21 +2865,35 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
2815
2865
  const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
2816
2866
  const marginTop = margin?.top ?? 0;
2817
2867
  const marginLeft = margin?.left ?? 0;
2818
- const TooltipComponent = detectBounds || tooltipPlacement !== "auto" ? BoundedTooltip : _visx_tooltip.Tooltip;
2819
2868
  const boxStyle = {
2820
2869
  zIndex,
2821
2870
  ...style
2822
2871
  };
2823
- const themesOwnBox = TooltipComponent === _visx_tooltip.Tooltip && !tooltipProps.unstyled;
2824
- const box = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipComponent, {
2872
+ const { offsetLeft = 10, offsetTop = 10, unstyled, className, ...boxProps } = tooltipProps;
2873
+ const anchorTop = tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipAnchorTop ?? tooltipTop;
2874
+ const box = detectBounds || tooltipPlacement !== "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
2825
2875
  left: tooltipLeft,
2826
- top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipAnchorTop ?? tooltipTop,
2876
+ top: anchorTop,
2877
+ offsetLeft,
2878
+ offsetTop,
2879
+ unstyled,
2880
+ className,
2827
2881
  style: boxStyle,
2828
- applyPositionStyle: true,
2829
- ...tooltipProps,
2830
- className: (0, clsx.default)(themesOwnBox && ["a8c-charts-scope", base_tooltip_module_default.surface], tooltipProps.className),
2882
+ ...boxProps,
2831
2883
  ...tooltipPlacement !== "auto" && { placement: tooltipPlacement },
2832
2884
  children: tooltipContent
2885
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipBox, {
2886
+ role: "presentation",
2887
+ unstyled,
2888
+ className,
2889
+ style: {
2890
+ position: "absolute",
2891
+ left: (tooltipLeft ?? 0) + offsetLeft,
2892
+ top: (anchorTop ?? 0) + offsetTop,
2893
+ ...!unstyled && boxStyle
2894
+ },
2895
+ ...boxProps,
2896
+ children: tooltipContent
2833
2897
  });
2834
2898
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
2835
2899
  className: "visx-tooltip-overlay",
@@ -2857,7 +2921,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
2857
2921
  }),
2858
2922
  glyphs
2859
2923
  ]
2860
- }), container && (0, react_dom.createPortal)(themesOwnBox ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTheme, { children: box }) : box, container)] });
2924
+ }), container && (0, react_dom.createPortal)(box, container)] });
2861
2925
  };
2862
2926
  /**
2863
2927
  * In-tree replacement for `@visx/xychart`'s `Tooltip`.
@@ -2882,7 +2946,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
2882
2946
  * @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
2883
2947
  * @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
2884
2948
  */
2885
- const XyChartTooltip = (props) => {
2949
+ const XyChartTooltipOverlay = (props) => {
2886
2950
  const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
2887
2951
  const [container, setContainer] = (0, react.useState)(null);
2888
2952
  const anchorRef = (0, react.useCallback)((node) => {
@@ -2895,8 +2959,8 @@ const XyChartTooltip = (props) => {
2895
2959
  })] });
2896
2960
  };
2897
2961
  //#endregion
2898
- //#region src/components/tooltip/accessible-tooltip.tsx
2899
- const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
2962
+ //#region src/components/tooltip/xy-chart-tooltip.tsx
2963
+ const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
2900
2964
  const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
2901
2965
  const scopeElement = useChartScopeElement();
2902
2966
  const crosshairStroke = (0, react.useMemo)(() => {
@@ -3002,7 +3066,7 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
3002
3066
  keyboardFocusedClassName,
3003
3067
  standaloneScopeClass
3004
3068
  ]);
3005
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltip, {
3069
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltipOverlay, {
3006
3070
  ...props,
3007
3071
  verticalCrosshairStyle: {
3008
3072
  ...crosshairStroke,
@@ -3015,8 +3079,10 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
3015
3079
  renderTooltip: focusableRenderTooltip
3016
3080
  });
3017
3081
  };
3082
+ /** @deprecated Use `XYChartTooltip`. */
3083
+ const AccessibleTooltip = XYChartTooltip;
3018
3084
  const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false, visibleSeriesKey }) => {
3019
- const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"grid\"]") ?? chartRef.current, [chartRef]);
3085
+ const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"application\"]") ?? chartRef.current, [chartRef]);
3020
3086
  const focusWithoutScrollIfNeeded = (0, react.useCallback)((element) => {
3021
3087
  if (preventTooltipScroll) element?.focus({ preventScroll: true });
3022
3088
  else element?.focus();
@@ -3231,11 +3297,13 @@ function useChartChildren(children, chartType) {
3231
3297
  }
3232
3298
  const displayName = child.type?.displayName;
3233
3299
  if (displayName === `${chartType}.SVG` || displayName === "Chart.SVG") {
3234
- if (child.props?.children) react.Children.forEach(child.props.children, (svgChild) => {
3300
+ const { children: svgChildren } = child.props ?? {};
3301
+ if (svgChildren) react.Children.forEach(svgChildren, (svgChild) => {
3235
3302
  svg.push(svgChild);
3236
3303
  });
3237
3304
  } else if (displayName === `${chartType}.HTML` || displayName === "Chart.HTML") {
3238
- if (child.props?.children) react.Children.forEach(child.props.children, (htmlChild) => {
3305
+ const { children: htmlChildren } = child.props ?? {};
3306
+ if (htmlChildren) react.Children.forEach(htmlChildren, (htmlChild) => {
3239
3307
  html.push(htmlChild);
3240
3308
  });
3241
3309
  } else if (child.type === _visx_group.Group) svg.push(child);
@@ -4057,6 +4125,7 @@ var line_chart_module_default = {
4057
4125
  "line-chart--animated": "a8ccharts-inuQka-line-chart--animated",
4058
4126
  "rise": "a8ccharts-inuQka-rise"
4059
4127
  };
4128
+ const isReact18 = react.version.startsWith("18.");
4060
4129
  const CloseIcon = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
4061
4130
  width: "16",
4062
4131
  height: "16",
@@ -4099,7 +4168,7 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
4099
4168
  className: line_chart_module_default["line-chart__annotation-label"],
4100
4169
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4101
4170
  ref: buttonRef,
4102
- popovertarget: popoverId,
4171
+ ...isReact18 ? { popovertarget: popoverId } : { popoverTarget: popoverId },
4103
4172
  className: line_chart_module_default["line-chart__annotation-label-trigger-button"],
4104
4173
  style: {
4105
4174
  width: `44px`,
@@ -4127,8 +4196,13 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
4127
4196
  subtitle
4128
4197
  })
4129
4198
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4130
- popovertarget: popoverId,
4131
- popovertargetaction: "hide",
4199
+ ...isReact18 ? {
4200
+ popovertarget: popoverId,
4201
+ popovertargetaction: "hide"
4202
+ } : {
4203
+ popoverTarget: popoverId,
4204
+ popoverTargetAction: "hide"
4205
+ },
4132
4206
  className: line_chart_module_default["line-chart__annotation-label-popover-close-button"],
4133
4207
  "aria-label": (0, _wordpress_i18n.__)("Close", "jetpack-charts"),
4134
4208
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseIcon, {})
@@ -4650,7 +4724,7 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
4650
4724
  ]);
4651
4725
  return null;
4652
4726
  };
4653
- const LineChartInternal = (0, react.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) => {
4727
+ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, 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) => {
4654
4728
  const legendInteractive = legend.interactive ?? false;
4655
4729
  const legendCollapseGroups = legend.collapseGroups ?? false;
4656
4730
  const legendComparisonItem = legend.comparisonItem ?? false;
@@ -4918,8 +4992,8 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
4918
4992
  const chartHeight = contentHeight > 0 ? contentHeight : height;
4919
4993
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4920
4994
  ref: chartRef,
4921
- role: "grid",
4922
- "aria-label": (0, _wordpress_i18n.__)("Line chart", "jetpack-charts"),
4995
+ role: "application",
4996
+ "aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Line chart", "jetpack-charts"),
4923
4997
  tabIndex: 0,
4924
4998
  onKeyDown: onChartKeyDown,
4925
4999
  onFocus: onChartFocus,
@@ -4927,6 +5001,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
4927
5001
  children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4928
5002
  className: xy_plot_module_default["xy-plot"],
4929
5003
  children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
5004
+ accessibilityLabel: "",
4930
5005
  theme,
4931
5006
  width,
4932
5007
  height: chartHeight,
@@ -5020,7 +5095,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
5020
5095
  ] }, seriesData?.label || index);
5021
5096
  })
5022
5097
  }),
5023
- withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccessibleTooltip, {
5098
+ withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
5024
5099
  detectBounds: true,
5025
5100
  snapTooltipToDatumX: true,
5026
5101
  tooltipPlacement,
@@ -5167,7 +5242,7 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
5167
5242
  };
5168
5243
  //#endregion
5169
5244
  //#region src/charts/area-chart/area-chart.tsx
5170
- const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
5245
+ const AreaChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
5171
5246
  const legendInteractive = legend.interactive ?? false;
5172
5247
  const legendShape = legend.shape ?? "rect";
5173
5248
  const legendPosition = legend.position ?? "bottom";
@@ -5438,8 +5513,8 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
5438
5513
  const chartHeight = contentHeight > 0 ? contentHeight : height;
5439
5514
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5440
5515
  ref: chartRef,
5441
- role: "grid",
5442
- "aria-label": (0, _wordpress_i18n.__)("Area chart", "jetpack-charts"),
5516
+ role: "application",
5517
+ "aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Area chart", "jetpack-charts"),
5443
5518
  tabIndex: 0,
5444
5519
  onKeyDown: onChartKeyDown,
5445
5520
  onFocus: onChartFocus,
@@ -5447,6 +5522,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
5447
5522
  children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5448
5523
  className: xy_plot_module_default["xy-plot"],
5449
5524
  children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
5525
+ accessibilityLabel: "",
5450
5526
  theme,
5451
5527
  width,
5452
5528
  height: chartHeight,
@@ -5496,7 +5572,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
5496
5572
  children: seriesWithVisibility.map(renderSeries)
5497
5573
  }), !allSeriesHidden && !stacked && seriesWithVisibility.map(renderSeries)]
5498
5574
  }),
5499
- withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccessibleTooltip, {
5575
+ withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
5500
5576
  detectBounds: true,
5501
5577
  snapTooltipToDatumX: true,
5502
5578
  snapTooltipToDatumY: !stacked,
@@ -6107,6 +6183,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6107
6183
  widthFactor
6108
6184
  });
6109
6185
  rects.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
6186
+ className: "bar-chart__comparison-bar",
6110
6187
  x: rect.x,
6111
6188
  y: rect.y,
6112
6189
  width: rect.width,
@@ -6298,7 +6375,7 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ (0, react_jsx_runtime
6298
6375
  className: bar_chart_module_default["bar-chart__tooltip-row"],
6299
6376
  children: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%1$s: %2$s", "jetpack-charts"), label, value)
6300
6377
  });
6301
- const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
6378
+ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
6302
6379
  if (!withTooltips && (withBandHighlight || onBandHighlightChange)) warnOnce("bar-chart-band-highlight-without-tooltips", "BarChart: withBandHighlight and onBandHighlightChange require withTooltips.");
6303
6380
  const legendInteractive = legend.interactive ?? false;
6304
6381
  const legendCollapseGroups = legend.collapseGroups ?? false;
@@ -6522,7 +6599,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
6522
6599
  const patternId = getPatternId(chartId, index);
6523
6600
  return `
6524
6601
  .visx-bar[fill="url(#${patternId})"],
6525
- .bar-chart__comparison-bars rect[fill="url(#${patternId})"] {
6602
+ .bar-chart__comparison-bar[fill="url(#${patternId})"] {
6526
6603
  stroke: ${color};
6527
6604
  stroke-width: 1;
6528
6605
  }
@@ -6606,9 +6683,9 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
6606
6683
  children: ({ contentHeight }) => {
6607
6684
  const chartHeight = contentHeight > 0 ? contentHeight : height;
6608
6685
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6609
- role: "grid",
6686
+ role: "application",
6610
6687
  ref: chartRef,
6611
- "aria-label": (0, _wordpress_i18n.__)("Bar chart", "jetpack-charts"),
6688
+ "aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Bar chart", "jetpack-charts"),
6612
6689
  tabIndex: 0,
6613
6690
  onKeyDown: onChartKeyDown,
6614
6691
  onFocus: onChartFocus,
@@ -6616,6 +6693,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
6616
6693
  children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6617
6694
  className: xy_plot_module_default["xy-plot"],
6618
6695
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
6696
+ accessibilityLabel: "",
6619
6697
  theme,
6620
6698
  width,
6621
6699
  height: chartHeight,
@@ -6704,15 +6782,15 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
6704
6782
  }),
6705
6783
  !allSeriesHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WholeNumberTicks, {
6706
6784
  ...wholeNumberTicksProps,
6707
- children: (valueTicks) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
6785
+ children: (valueTicks) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [chartOptions.axis.x.display !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
6708
6786
  ...chartOptions.axis.x,
6709
6787
  ...horizontal && valueTicks ? { tickValues: valueTicks } : {}
6710
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
6788
+ }), chartOptions.axis.y.display !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
6711
6789
  ...chartOptions.axis.y,
6712
6790
  ...!horizontal && valueTicks ? { tickValues: valueTicks } : {}
6713
6791
  })] })
6714
6792
  }),
6715
- withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccessibleTooltip, {
6793
+ withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
6716
6794
  tooltipPlacement,
6717
6795
  tooltipAnchorTop,
6718
6796
  style: tooltipStyle,
@@ -7239,7 +7317,10 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7239
7317
  left: tooltipLeft,
7240
7318
  className: standaloneScopeClass,
7241
7319
  style: tooltipStyle,
7242
- children: tooltipContent
7320
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7321
+ role: "tooltip",
7322
+ children: tooltipContent
7323
+ })
7243
7324
  });
7244
7325
  })()]
7245
7326
  });
@@ -7618,6 +7699,7 @@ var heatmap_chart_module_default = {
7618
7699
  "heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
7619
7700
  "heatmap-chart__legend-scale--bar": "a8ccharts-O3YMOW-heatmap-chart__legend-scale--bar",
7620
7701
  "heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
7702
+ "heatmap-chart__legend-swatch--empty": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch--empty",
7621
7703
  "heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
7622
7704
  "heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
7623
7705
  "heatmap-chart--height-capped": "a8ccharts-O3YMOW-heatmap-chart--height-capped"
@@ -7626,30 +7708,44 @@ var heatmap_chart_module_default = {
7626
7708
  //#region src/charts/heatmap-chart/private/use-heatmap-colors.ts
7627
7709
  const isPresent = (value) => value !== null && value !== void 0 && !isNaN(value);
7628
7710
  /**
7629
- * Get the min and max values from heatmap data, ignoring null/NaN. Summary
7630
- * columns stay out: a roll-up on the scale would flatten every real cell.
7711
+ * Get the min and max values from heatmap data, ignoring null/NaN and the zeros
7712
+ * `isEmptyValue` paints as empty. Summary columns stay out: a roll-up on the
7713
+ * scale would flatten every real cell.
7631
7714
  * @param data - The heatmap columns
7632
7715
  * @return Tuple of [min, max] values
7633
7716
  */
7634
7717
  const getValueExtent = (data) => {
7635
7718
  let min = Infinity;
7636
7719
  let max = -Infinity;
7720
+ let hasZero = false;
7637
7721
  for (const column of data) {
7638
7722
  if (column.summary) continue;
7639
7723
  for (const cell of column.data) {
7640
7724
  if (!isPresent(cell.value)) continue;
7725
+ if (cell.value === 0) {
7726
+ hasZero = true;
7727
+ continue;
7728
+ }
7641
7729
  if (cell.value < min) min = cell.value;
7642
7730
  if (cell.value > max) max = cell.value;
7643
7731
  }
7644
7732
  }
7733
+ if (hasZero && min < 0) max = Math.max(max, 0);
7645
7734
  if (min === Infinity) return [0, 0];
7646
7735
  return [min, max];
7647
7736
  };
7648
7737
  /**
7738
+ * Whether a value paints as an empty cell: a zero in data with no negatives
7739
+ * counts nothing, so it must not look like the lowest step of activity.
7740
+ *
7741
+ * @param value - The cell value
7742
+ * @param extent - The extent from `getValueExtent`
7743
+ * @return True when the cell takes the empty-cell color
7744
+ */
7745
+ const isEmptyValue = (value, extent) => value === 0 && extent[0] >= 0;
7746
+ /**
7649
7747
  * Normalize a value to 0–1 within the extent. A flat extent (min === max)
7650
- * maps to 1 — every cell is equally the "highest" — except an all-zero
7651
- * extent, which maps to 0 so a no-activity grid renders at the scale's
7652
- * bottom instead of full intensity.
7748
+ * maps to 1, since every cell is equally the "highest".
7653
7749
  *
7654
7750
  * @param value - The value to normalize
7655
7751
  * @param extent - Tuple of [min, max] values for the normalization range
@@ -7657,9 +7753,40 @@ const getValueExtent = (data) => {
7657
7753
  */
7658
7754
  const getNormalizedValue = (value, extent) => {
7659
7755
  const [min, max] = extent;
7660
- if (min === max) return max === 0 ? 0 : 1;
7756
+ if (min === max) return 1;
7661
7757
  return Math.min(1, Math.max(0, (value - min) / (max - min)));
7662
7758
  };
7759
+ const STEPS = 200;
7760
+ const firstMeeting = (from, to, meets) => {
7761
+ for (let step = 0; step <= STEPS; step++) {
7762
+ const color = mixHexColors(from, to, step / STEPS);
7763
+ if (meets(color)) return color;
7764
+ }
7765
+ return null;
7766
+ };
7767
+ /**
7768
+ * The two ends of the heatmap fill scale: 3:1 against the background and the empty cell at the
7769
+ * low end, toward 9:1 against the background at the high end.
7770
+ *
7771
+ * @param primary - The resolved primary color, as six-digit hex.
7772
+ * @param background - The resolved chart background, as six-digit hex.
7773
+ * @param emptyCell - The resolved empty-cell color, as six-digit hex, when it is opaque.
7774
+ * @return The scale ends, as six-digit hex.
7775
+ */
7776
+ const getHeatmapScale = (primary, background, emptyCell) => {
7777
+ const primaryStandsOut = contrastRatio(primary, background) >= 3;
7778
+ const extreme = (primaryStandsOut ? relativeLuminance(primary) > relativeLuminance(background) : contrastRatio("#ffffff", background) > contrastRatio("#000000", background)) ? "#ffffff" : "#000000";
7779
+ const lowAgainst = (references) => {
7780
+ const meets = (color) => references.every((reference) => contrastRatio(color, reference) >= 3);
7781
+ return (primaryStandsOut ? firstMeeting(background, primary, meets) : null) ?? firstMeeting(primary, extreme, meets);
7782
+ };
7783
+ const high = firstMeeting(primary, extreme, (color) => contrastRatio(color, background) >= 9) ?? extreme;
7784
+ const againstEmptyCell = emptyCell ? lowAgainst([background, emptyCell]) : null;
7785
+ return {
7786
+ low: (againstEmptyCell && contrastRatio(againstEmptyCell, background) <= contrastRatio(high, background) ? againstEmptyCell : lowAgainst([background])) ?? extreme,
7787
+ high
7788
+ };
7789
+ };
7663
7790
  //#endregion
7664
7791
  //#region src/charts/heatmap-chart/private/heatmap-context.ts
7665
7792
  /** Shared by the chart and legend without importing back from `heatmap-chart.tsx`. */
@@ -7670,8 +7797,9 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
7670
7797
  const context = (0, react.useContext)(HeatmapContext);
7671
7798
  const { legend } = useGlobalChartsTheme();
7672
7799
  if (!context) return null;
7673
- const { primaryColorHex } = context;
7800
+ const { extent, fillVars } = context;
7674
7801
  const labelStyle = legend.labelStyles;
7802
+ const showsEmptyCell = isEmptyValue(0, extent);
7675
7803
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7676
7804
  direction: "row",
7677
7805
  gap: "xs",
@@ -7683,21 +7811,21 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
7683
7811
  style: labelStyle,
7684
7812
  children: lessLabel ?? (0, _wordpress_i18n.__)("Less", "jetpack-charts")
7685
7813
  }),
7686
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Stack, {
7814
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7687
7815
  direction: "row",
7688
7816
  gap: variant === "bar" ? void 0 : "xs",
7689
7817
  "aria-hidden": "true",
7690
7818
  className: variant === "bar" ? heatmap_chart_module_default["heatmap-chart__legend-scale--bar"] : void 0,
7691
- children: Array.from({ length: steps }, (_, index) => {
7819
+ children: [showsEmptyCell && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__legend-swatch"], heatmap_chart_module_default["heatmap-chart__legend-swatch--empty"]) }), Array.from({ length: steps }, (_, index) => {
7692
7820
  const intensity = steps <= 1 ? 1 : index / (steps - 1);
7693
7821
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7694
7822
  className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
7695
7823
  style: {
7696
- "--a8c-charts-color-heatmap-primary": primaryColorHex,
7824
+ ...fillVars,
7697
7825
  "--a8c-charts-heatmap-cell-intensity": intensity
7698
7826
  }
7699
7827
  }, index);
7700
- })
7828
+ })]
7701
7829
  }),
7702
7830
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
7703
7831
  variant: "body-sm",
@@ -7723,9 +7851,11 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
7723
7851
  const ungrouped = () => ({
7724
7852
  columns: Array.from({ length: columnCount }, (_, index) => ({
7725
7853
  line: firstLine + index,
7854
+ band: 0,
7726
7855
  gapBefore: false
7727
7856
  })),
7728
- groups: []
7857
+ groups: [],
7858
+ bands: 1
7729
7859
  });
7730
7860
  if (!groups || groups.length === 0 || columnCount === 0) return ungrouped();
7731
7861
  const spans = groups.map((group) => group.span);
@@ -7741,11 +7871,13 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
7741
7871
  if (groupIndex > 0) line += 1;
7742
7872
  laidOut.push({
7743
7873
  ...group,
7744
- line
7874
+ line,
7875
+ band: 0
7745
7876
  });
7746
7877
  for (let offset = 0; offset < group.span; offset++) {
7747
7878
  columns.push({
7748
7879
  line,
7880
+ band: 0,
7749
7881
  gapBefore: groupIndex > 0 && offset === 0,
7750
7882
  group: groupIndex
7751
7883
  });
@@ -7755,13 +7887,99 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
7755
7887
  while (columns.length < columnCount) {
7756
7888
  columns.push({
7757
7889
  line,
7890
+ band: 0,
7758
7891
  gapBefore: false
7759
7892
  });
7760
7893
  line += 1;
7761
7894
  }
7762
7895
  return {
7763
7896
  columns,
7764
- groups: laidOut
7897
+ groups: laidOut,
7898
+ bands: 1
7899
+ };
7900
+ };
7901
+ /**
7902
+ * Wraps the groups onto bands of equal group count, each band starting back at
7903
+ * the first data line so the groups line up in slots down the bands.
7904
+ *
7905
+ * @param layout - The unwrapped layout from `resolveColumnGroups`.
7906
+ * @param bands - Bands to aim for; the groups split as evenly as whole bands allow.
7907
+ * @return The wrapped layout, or null when there is nothing to wrap: one band, one group, or a column outside every group.
7908
+ */
7909
+ const wrapColumnGroups = (layout, bands) => {
7910
+ const { columns, groups } = layout;
7911
+ if (bands < 2 || groups.length < 2 || columns.some((column) => column.group === void 0)) return null;
7912
+ const perBand = Math.ceil(groups.length / bands);
7913
+ const slotSpans = Array(perBand).fill(0);
7914
+ groups.forEach((group, index) => {
7915
+ const slot = index % perBand;
7916
+ slotSpans[slot] = Math.max(slotSpans[slot], group.span);
7917
+ });
7918
+ const slotLines = [];
7919
+ let line = columns[0].line;
7920
+ slotSpans.forEach((span, slot) => {
7921
+ if (slot > 0) line += 1;
7922
+ slotLines.push(line);
7923
+ line += span;
7924
+ });
7925
+ const wrappedGroups = groups.map((group, index) => ({
7926
+ ...group,
7927
+ line: slotLines[index % perBand],
7928
+ band: Math.floor(index / perBand)
7929
+ }));
7930
+ return {
7931
+ columns: columns.map((column) => {
7932
+ const group = column.group;
7933
+ const offset = column.line - groups[group].line;
7934
+ return {
7935
+ ...column,
7936
+ line: wrappedGroups[group].line + offset,
7937
+ band: wrappedGroups[group].band,
7938
+ gapBefore: offset === 0 && group % perBand > 0
7939
+ };
7940
+ }),
7941
+ groups: wrappedGroups,
7942
+ bands: Math.ceil(groups.length / perBand),
7943
+ slotSpans
7944
+ };
7945
+ };
7946
+ //#endregion
7947
+ //#region src/charts/heatmap-chart/private/fit-compact-cells.ts
7948
+ /**
7949
+ * Largest whole-pixel square cell, and the band count giving it, for a compact grid in a box.
7950
+ *
7951
+ * @param input - The box, the grid's layout, and its fixed gaps and label sizes.
7952
+ * @return The fit; one band at `minCellSize` when no band count reaches it.
7953
+ */
7954
+ const fitCompactCells = (input) => {
7955
+ const { width, height, layout, rows, cellGap, groupGap, minCellSize } = input;
7956
+ const columns = layout.columns.length;
7957
+ if (columns === 0 || rows === 0) return {
7958
+ bands: 1,
7959
+ cellSize: minCellSize
7960
+ };
7961
+ const maxBands = Math.max(1, layout.groups.length);
7962
+ const labelHeights = (input.columnLabelHeight ?? 0) + (input.groupLabelHeight ?? 0);
7963
+ const bandTracks = (input.columnLabelHeight === null ? 0 : 1) + rows + (input.groupLabelHeight === null ? 0 : 1);
7964
+ let best = null;
7965
+ for (let target = 1; target <= maxBands; target++) {
7966
+ const wrapped = target > 1 ? wrapColumnGroups(layout, target) : null;
7967
+ const { bands } = wrapped ?? layout;
7968
+ const cellColumns = wrapped ? wrapped.slotSpans.reduce((sum, span) => sum + span, 0) : columns;
7969
+ const gapTracks = wrapped ? wrapped.slotSpans.length - 1 : layout.columns.filter((column) => column.gapBefore).length;
7970
+ const columnTracks = 1 + cellColumns + gapTracks;
7971
+ const byWidth = (width - input.rowLabelWidth - gapTracks * groupGap - (columnTracks - 1) * cellGap) / cellColumns;
7972
+ const rowTracks = bands * bandTracks + (bands - 1);
7973
+ const byHeight = (height - (bands * labelHeights + (bands - 1) * groupGap + (rowTracks - 1) * cellGap)) / (bands * rows);
7974
+ const cellSize = Math.floor(Math.min(byWidth, byHeight));
7975
+ if (cellSize >= minCellSize && (!best || cellSize > best.cellSize)) best = {
7976
+ bands,
7977
+ cellSize
7978
+ };
7979
+ }
7980
+ return best ?? {
7981
+ bands: 1,
7982
+ cellSize: minCellSize
7765
7983
  };
7766
7984
  };
7767
7985
  //#endregion
@@ -7897,7 +8115,6 @@ const stepCalendarCell = (grid, blocks, from, key) => {
7897
8115
  };
7898
8116
  //#endregion
7899
8117
  //#region src/charts/heatmap-chart/heatmap-chart.tsx
7900
- const CELL_MIX_FLOOR = .15;
7901
8118
  const CELL_VALUE_MODIFIER = {
7902
8119
  label: void 0,
7903
8120
  "label-inverse": heatmap_chart_module_default["heatmap-chart__cell-value--inverse"],
@@ -7906,12 +8123,26 @@ const CELL_VALUE_MODIFIER = {
7906
8123
  };
7907
8124
  const NO_ROW_LABELS = [];
7908
8125
  const TOOLTIP_BOX_STYLE = { zIndex: 3 };
8126
+ const largest = (root, selector, size) => Math.max(0, ...Array.from(root.querySelectorAll(selector), (el) => el[size]));
8127
+ const gridBox = (chart, grid) => {
8128
+ let height = chart.clientHeight;
8129
+ const rowGap = parseFloat(getComputedStyle(chart).rowGap) || 0;
8130
+ Array.from(chart.children).forEach((child) => {
8131
+ const { display, position } = getComputedStyle(child);
8132
+ if (child === grid || display === "none" || position === "absolute" || position === "fixed") return;
8133
+ height -= child.offsetHeight + rowGap;
8134
+ });
8135
+ return {
8136
+ width: chart.clientWidth,
8137
+ height
8138
+ };
8139
+ };
7909
8140
  const cellName = (info) => info.cellLabel || [
7910
8141
  info.groupLabel,
7911
8142
  info.columnLabel,
7912
8143
  info.rowLabel
7913
8144
  ].filter(Boolean).join(" ");
7914
- 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, tooltipStyle, children }) => {
8145
+ 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 }) => {
7915
8146
  const chartId = useChartId(providedChartId);
7916
8147
  const tooltipBoxStyle = tooltipStyle ? {
7917
8148
  ...TOOLTIP_BOX_STYLE,
@@ -7925,19 +8156,30 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
7925
8156
  const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
7926
8157
  const standaloneScopeClass = useStandaloneScopeClass();
7927
8158
  const containerRef = (0, react.useRef)(null);
8159
+ const chartRef = (0, react.useRef)(null);
7928
8160
  const [labelRoles, setLabelRoles] = (0, react.useState)(null);
7929
- const getTooltipOrigin = (0, react.useCallback)(() => containerRef.current?.closest(`[data-chart-id="heatmap-chart-${chartId}"]`)?.getBoundingClientRect() ?? null, [chartId]);
8161
+ const getTooltipOrigin = (0, react.useCallback)(() => chartRef.current?.getBoundingClientRect() ?? null, []);
7930
8162
  const { color: primaryColorHex } = getElementStyles({
7931
8163
  index: 0,
7932
8164
  overrideColor: primaryColor
7933
8165
  });
7934
- const chartBackgroundHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable);
8166
+ const resolveAtScope = createCssVariableResolver(scopeElement);
8167
+ const chartBackgroundHex = resolveOpaqueHex(CATALOG_POINTERS.background, resolveAtScope) ?? "#ffffff";
8168
+ const emptyCellHex = resolveOpaqueHex(CATALOG_POINTERS.track, resolveAtScope);
7935
8169
  const primaryHex = normalizeColorToHex(primaryColorHex);
7936
- const cellMix = isValidHexColor(primaryHex) && isValidHexColor(chartBackgroundHex) ? {
7937
- primary: hexToRgb(primaryHex),
7938
- background: hexToRgb(chartBackgroundHex)
7939
- } : null;
7940
- const cellTextColor = (intensity) => cellMix ? pickLabelTextColorForFill(blendRgb(cellMix.primary, cellMix.background, CELL_MIX_FLOOR + .85 * intensity), labelRoles, "label") : "label";
8170
+ const scale = (0, react.useMemo)(() => isValidHexColor(primaryHex) ? getHeatmapScale(primaryHex, chartBackgroundHex, emptyCellHex) : null, [
8171
+ primaryHex,
8172
+ chartBackgroundHex,
8173
+ emptyCellHex
8174
+ ]);
8175
+ const fillVars = (0, react.useMemo)(() => ({
8176
+ "--a8c-charts-color-heatmap-primary": primaryColorHex,
8177
+ ...scale && {
8178
+ "--a8c-charts-color-heatmap-low": scale.low,
8179
+ "--a8c-charts-color-heatmap-high": scale.high
8180
+ }
8181
+ }), [primaryColorHex, scale]);
8182
+ const cellTextColor = (intensity) => scale ? pickLabelTextColorForFill(blendRgb(hexToRgb(scale.high), hexToRgb(scale.low), intensity), labelRoles, "label") : "label";
7941
8183
  useIsomorphicLayoutEffect(() => {
7942
8184
  if (!containerRef.current) return;
7943
8185
  const next = resolveLabelRoles(createCssVariableResolver(containerRef.current));
@@ -7951,13 +8193,56 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
7951
8193
  const extent = (0, react.useMemo)(() => getValueExtent(data), [data]);
7952
8194
  const heatmapContext = (0, react.useMemo)(() => ({
7953
8195
  extent,
7954
- primaryColorHex
7955
- }), [extent, primaryColorHex]);
8196
+ fillVars
8197
+ }), [extent, fillVars]);
7956
8198
  const columns = data.length;
7957
8199
  const rows = Math.max(0, ...data.map((column) => column.data.length));
7958
8200
  const groupLayout = (0, react.useMemo)(() => resolveColumnGroups(columnGroups, columns, 2), [columnGroups, columns]);
7959
8201
  const { compactCellGap, compactCellSize, groupGap } = heatmapChartSettings;
7960
8202
  const drawValues = showValues ?? !compact;
8203
+ const hasColumnLabels = data.some((column) => Boolean(column.label));
8204
+ const hasGroups = groupLayout.groups.length > 0;
8205
+ const [fit, setFit] = (0, react.useState)(null);
8206
+ const hasSummary = data.some((column) => column.summary);
8207
+ const fitting = compact && fitCells && !hasSummary;
8208
+ if (fitCells && !fitting) warnOnce("heatmap:fitCells", "fitCells applies only in compact mode without summary columns, so the cells keep their size.");
8209
+ useIsomorphicLayoutEffect(() => {
8210
+ const chart = chartRef.current;
8211
+ const grid = containerRef.current;
8212
+ if (!fitting || !chart || !grid) {
8213
+ setFit(null);
8214
+ return;
8215
+ }
8216
+ const measure = () => {
8217
+ const next = fitCompactCells({
8218
+ ...gridBox(chart, grid),
8219
+ layout: groupLayout,
8220
+ rows,
8221
+ cellGap: compactCellGap,
8222
+ groupGap,
8223
+ rowLabelWidth: largest(grid, `.${heatmap_chart_module_default["heatmap-chart__row-label"]}`, "offsetWidth"),
8224
+ columnLabelHeight: hasColumnLabels ? largest(grid, `.${heatmap_chart_module_default["heatmap-chart__col-label"]}`, "offsetHeight") : null,
8225
+ groupLabelHeight: hasGroups ? largest(grid, `.${heatmap_chart_module_default["heatmap-chart__group-label"]}`, "offsetHeight") : null,
8226
+ minCellSize: compactCellSize
8227
+ });
8228
+ setFit((previous) => (0, import_fast_deep_equal.default)(previous, next) ? previous : next);
8229
+ };
8230
+ measure();
8231
+ if (typeof ResizeObserver === "undefined") return;
8232
+ const observer = new ResizeObserver(() => (0, react_dom.flushSync)(measure));
8233
+ observer.observe(chart);
8234
+ return () => observer.disconnect();
8235
+ }, [
8236
+ fitting,
8237
+ groupLayout,
8238
+ rows,
8239
+ hasColumnLabels,
8240
+ hasGroups,
8241
+ compactCellGap,
8242
+ compactCellSize,
8243
+ groupGap
8244
+ ]);
8245
+ const wrapped = (0, react.useMemo)(() => fit ? wrapColumnGroups(groupLayout, fit.bands) : null, [fit, groupLayout]);
7961
8246
  const buildTooltipData = (0, react.useCallback)((columnIndex, rowIndex) => {
7962
8247
  const cell = data[columnIndex]?.data[rowIndex];
7963
8248
  const group = groupLayout.columns[columnIndex]?.group;
@@ -8097,20 +8382,25 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
8097
8382
  });
8098
8383
  const columnTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellWidth ?? 0}px, ${maxCellWidth ? `${maxCellWidth}px` : "1fr"})`;
8099
8384
  const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
8100
- const hasColumnLabels = data.some((column) => Boolean(column.label));
8101
- const hasGroups = groupLayout.groups.length > 0;
8102
- const columnLine = (columnIndex) => groupLayout.columns[columnIndex].line;
8103
- const firstDataRow = hasColumnLabels ? 2 : 1;
8385
+ const placed = wrapped ?? groupLayout;
8386
+ const columnLine = (columnIndex) => placed.columns[columnIndex].line;
8387
+ const bandOf = (columnIndex) => placed.columns[columnIndex].band;
8388
+ const { bands } = placed;
8389
+ const bandRowCount = (hasColumnLabels ? 1 : 0) + rows + (hasGroups ? 1 : 0) + 1;
8390
+ const labelRowOf = (band) => 1 + band * bandRowCount;
8391
+ const dataRowOf = (band, rowIndex) => labelRowOf(band) + (hasColumnLabels ? 1 : 0) + rowIndex;
8104
8392
  const dataTrack = (column) => column.summary ? "minmax(auto, max-content)" : columnTrack;
8105
8393
  const gapTrack = compact ? `minmax(${groupGap}px, 1fr)` : `${groupGap}px`;
8394
+ const columnTracks = wrapped ? wrapped.slotSpans.map((span, slot) => [...slot > 0 ? [gapTrack] : [], ...Array(span).fill(columnTrack)].join(" ")).join(" ") : data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ");
8395
+ const bandTracks = `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`;
8106
8396
  const gridStyle = {
8107
- "--a8c-charts-color-heatmap-primary": primaryColorHex,
8108
- gridTemplateColumns: `auto ${data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ")}`,
8109
- gridTemplateRows: `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`
8397
+ ...fillVars,
8398
+ gridTemplateColumns: `auto ${columnTracks}`,
8399
+ gridTemplateRows: Array(bands).fill(bandTracks).join(` ${groupGap}px `)
8110
8400
  };
8111
8401
  if (compact) {
8112
8402
  gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
8113
- gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${compactCellSize}px`;
8403
+ gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${fit?.cellSize ?? compactCellSize}px`;
8114
8404
  }
8115
8405
  const summaryGaps = (columnIndex) => {
8116
8406
  if (!data[columnIndex]?.summary) return {};
@@ -8130,6 +8420,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
8130
8420
  legendChildren: [],
8131
8421
  trailingContent: nonLegendChildren,
8132
8422
  gap,
8423
+ rootRef: chartRef,
8133
8424
  className: (0, clsx.default)("heatmap-chart", heatmap_chart_module_default["heatmap-chart"], className, { [heatmap_chart_module_default["heatmap-chart--height-capped"]]: heightCapped }),
8134
8425
  style: {
8135
8426
  width: width || void 0,
@@ -8159,11 +8450,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
8159
8450
  className: heatmap_chart_module_default["heatmap-chart__row"],
8160
8451
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
8161
8452
  gridColumn: 1,
8162
- gridRow: 1
8453
+ gridRow: labelRowOf(0)
8163
8454
  } }), data.map((column, columnIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8164
8455
  style: {
8165
8456
  gridColumn: columnLine(columnIndex),
8166
- gridRow: 1
8457
+ gridRow: labelRowOf(bandOf(columnIndex))
8167
8458
  },
8168
8459
  className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__col-label"], {
8169
8460
  [heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
@@ -8174,24 +8465,23 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
8174
8465
  }),
8175
8466
  Array.from({ length: rows }).map((_row, rowIndex) => {
8176
8467
  const labelVisible = !compact || rowIndex % 2 === 0;
8177
- const gridRow = firstDataRow + rowIndex;
8178
8468
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8179
8469
  role: "row",
8180
8470
  "aria-rowindex": rowIndex + 1,
8181
8471
  className: heatmap_chart_module_default["heatmap-chart__row"],
8182
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8472
+ children: [Array.from({ length: bands }).map((_band, band) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8183
8473
  "aria-hidden": "true",
8184
8474
  className: heatmap_chart_module_default["heatmap-chart__row-label"],
8185
8475
  style: {
8186
8476
  gridColumn: 1,
8187
- gridRow
8477
+ gridRow: dataRowOf(band, rowIndex)
8188
8478
  },
8189
8479
  children: labelVisible ? rowLabels[rowIndex] ?? "" : ""
8190
- }), data.map((column, columnIndex) => {
8480
+ }, `row-label-${band}`)), data.map((column, columnIndex) => {
8191
8481
  const cell = column.data[rowIndex];
8192
8482
  const placement = {
8193
8483
  gridColumn: columnLine(columnIndex),
8194
- gridRow
8484
+ gridRow: dataRowOf(bandOf(columnIndex), rowIndex)
8195
8485
  };
8196
8486
  if (cell?.hidden) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8197
8487
  "aria-hidden": "true",
@@ -8205,7 +8495,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
8205
8495
  }, `cell-${columnIndex}-${rowIndex}`);
8206
8496
  const value = cell?.value ?? null;
8207
8497
  const present = isPresent(value);
8208
- const filled = present && !column.summary;
8498
+ const filled = present && !column.summary && !isEmptyValue(value, extent);
8209
8499
  const normalized = filled ? getNormalizedValue(value, extent) : 0;
8210
8500
  const info = buildTooltipData(columnIndex, rowIndex);
8211
8501
  const accessibleLabel = `${cellName(info)}: ${info.value === null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(info.value)}`;
@@ -8241,11 +8531,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
8241
8531
  role: "row",
8242
8532
  "aria-hidden": "true",
8243
8533
  className: heatmap_chart_module_default["heatmap-chart__row"],
8244
- children: groupLayout.groups.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8534
+ children: placed.groups.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8245
8535
  className: heatmap_chart_module_default["heatmap-chart__group-label"],
8246
8536
  style: {
8247
8537
  gridColumn: `${group.line} / span ${group.span}`,
8248
- gridRow: firstDataRow + rows
8538
+ gridRow: dataRowOf(group.band, rows)
8249
8539
  },
8250
8540
  children: group.label
8251
8541
  }, `group-${groupIndex}`))
@@ -11480,6 +11770,7 @@ var leaderboard_chart_module_default = {
11480
11770
  "interactiveRow": "a8ccharts-GovfoW-interactiveRow",
11481
11771
  "is-overlay": "a8ccharts-GovfoW-is-overlay",
11482
11772
  "label": "a8ccharts-GovfoW-label",
11773
+ "layeredRow": "a8ccharts-GovfoW-layeredRow",
11483
11774
  "leaderboardChart": "a8ccharts-GovfoW-leaderboardChart",
11484
11775
  "leaderboardChart__content": "a8ccharts-GovfoW-leaderboardChart__content",
11485
11776
  "leaderboardChart__content--fit": "a8ccharts-GovfoW-leaderboardChart__content--fit",
@@ -11488,6 +11779,7 @@ var leaderboard_chart_module_default = {
11488
11779
  "overlap": "a8ccharts-GovfoW-overlap",
11489
11780
  "overlayLabel": "a8ccharts-GovfoW-overlayLabel",
11490
11781
  "row": "a8ccharts-GovfoW-row",
11782
+ "rowButton": "a8ccharts-GovfoW-rowButton",
11491
11783
  "stretch": "a8ccharts-GovfoW-stretch",
11492
11784
  "valueContainer": "a8ccharts-GovfoW-valueContainer"
11493
11785
  };
@@ -11538,6 +11830,16 @@ const defaultDeltaFormatter = (value) => {
11538
11830
  const getBarWidth = (share) => `calc(${share}% - var(--a8c-charts-dimension-leaderboard-bar-hover-inset, 0px) * ${share} / 100)`;
11539
11831
  const hasPreviousValue = (entry) => entry.previousValue != null && entry.previousShare != null;
11540
11832
  const hasDeltaValue = (entry) => hasPreviousValue(entry) && entry.delta != null;
11833
+ /**
11834
+ * A layered row's cell that takes pointer events of its own (a value tooltip)
11835
+ * sits above the row button; pass its clicks on so they still drill down.
11836
+ *
11837
+ * @param event - The click on the row.
11838
+ */
11839
+ function forwardCellClickToRowButton(event) {
11840
+ if (event.target.closest("a, button")) return;
11841
+ event.currentTarget.querySelector(":scope > button")?.click();
11842
+ }
11541
11843
  const BarLabel = ({ label }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: typeof label === "string" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
11542
11844
  className: leaderboard_chart_module_default.label,
11543
11845
  children: label
@@ -11770,6 +12072,26 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
11770
12072
  })
11771
12073
  ]
11772
12074
  })] });
12075
+ if (entry.onClick && entry.hasInteractiveLabel) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12076
+ "data-row-index": rowIndex,
12077
+ style: rowStyle,
12078
+ className: (0, clsx.default)(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow, leaderboard_chart_module_default.layeredRow),
12079
+ onClick: forwardCellClickToRowButton,
12080
+ children: [
12081
+ rowCells,
12082
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
12083
+ type: "button",
12084
+ className: leaderboard_chart_module_default.rowButton,
12085
+ onClick: entry.onClick,
12086
+ "aria-label": entry.ariaLabel
12087
+ }),
12088
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_icons.Icon, {
12089
+ className: leaderboard_chart_module_default.chevron,
12090
+ icon: _wordpress_icons.chevronRight,
12091
+ size: 24
12092
+ })
12093
+ ]
12094
+ }, entry.id);
11773
12095
  if (entry.onClick) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
11774
12096
  type: "button",
11775
12097
  "data-row-index": rowIndex,
@@ -11803,6 +12125,210 @@ LeaderboardChartWithProvider.displayName = "LeaderboardChart";
11803
12125
  const LeaderboardChart = attachSubComponents(LeaderboardChartWithProvider, { Legend });
11804
12126
  const LeaderboardChartResponsive = attachSubComponents(withResponsive(LeaderboardChartWithProvider), { Legend });
11805
12127
  //#endregion
12128
+ //#region src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts
12129
+ /**
12130
+ * Orders arcs the way they appear: clockwise from 12 o'clock, which for a semi-circle is left to right.
12131
+ *
12132
+ * @param arcs - Arcs from visx's `pie` factory, in data order.
12133
+ * @return A copy of `arcs` sorted by angular midpoint.
12134
+ */
12135
+ const orderArcsForNavigation = (arcs) => [...arcs].sort((a, b) => a.startAngle + a.endAngle - (b.startAngle + b.endAngle));
12136
+ //#endregion
12137
+ //#region src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx
12138
+ const PieSelectionAnnouncement = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.VisuallyHidden, {
12139
+ role: "status",
12140
+ "aria-atomic": "true",
12141
+ children: data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data })
12142
+ });
12143
+ //#endregion
12144
+ //#region src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx
12145
+ const PieTooltip = ({ top, left, selectedIndex, tooltipRef, children }) => {
12146
+ const standaloneScopeClass = useStandaloneScopeClass();
12147
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
12148
+ top,
12149
+ left,
12150
+ children: selectedIndex === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12151
+ className: standaloneScopeClass,
12152
+ role: "tooltip",
12153
+ children
12154
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12155
+ ref: tooltipRef,
12156
+ tabIndex: -1,
12157
+ role: "tooltip",
12158
+ "aria-atomic": "true",
12159
+ className: standaloneScopeClass,
12160
+ children
12161
+ }, `chart-tooltip-${selectedIndex}`)
12162
+ });
12163
+ };
12164
+ //#endregion
12165
+ //#region src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx
12166
+ /**
12167
+ * Reports the selected segment: a focused tooltip for a keyboard selection, a pointer tooltip on hover, or a screen reader announcement without tooltips.
12168
+ *
12169
+ * @param {PieSelectionOutputProps} props - Component props
12170
+ * @return {JSX.Element} The announcement region and the tooltip, if any
12171
+ */
12172
+ const PieSelectionOutput = ({ withTooltips, selectedIndex, selectedData, keyboardTooltipAnchor, pointerTooltip, chartRef, svgRef, tooltipRef, renderTooltip }) => {
12173
+ const [svgOffset, setSvgOffset] = (0, react.useState)({
12174
+ top: 0,
12175
+ left: 0
12176
+ });
12177
+ const showKeyboardTooltip = withTooltips && selectedData && keyboardTooltipAnchor;
12178
+ (0, react.useLayoutEffect)(() => {
12179
+ const chartBounds = chartRef.current?.getBoundingClientRect();
12180
+ const svgBounds = svgRef.current?.getBoundingClientRect();
12181
+ if (!showKeyboardTooltip || !chartBounds || !svgBounds) return;
12182
+ const top = svgBounds.top - chartBounds.top;
12183
+ const left = svgBounds.left - chartBounds.left;
12184
+ setSvgOffset((current) => current.top === top && current.left === left ? current : {
12185
+ top,
12186
+ left
12187
+ });
12188
+ });
12189
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
12190
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionAnnouncement, { data: withTooltips ? void 0 : selectedData }),
12191
+ showKeyboardTooltip && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieTooltip, {
12192
+ top: svgOffset.top + keyboardTooltipAnchor.top,
12193
+ left: svgOffset.left + keyboardTooltipAnchor.left,
12194
+ selectedIndex,
12195
+ tooltipRef,
12196
+ children: renderTooltip({ tooltipData: selectedData })
12197
+ }),
12198
+ withTooltips && !selectedData && pointerTooltip?.data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieTooltip, {
12199
+ top: pointerTooltip.top,
12200
+ left: pointerTooltip.left,
12201
+ children: renderTooltip({ tooltipData: pointerTooltip.data })
12202
+ })
12203
+ ] });
12204
+ };
12205
+ //#endregion
12206
+ //#region src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss
12207
+ var pie_keyboard_navigation_module_default = {
12208
+ "selected-ring__contrast": "a8ccharts-V2HDKq-selected-ring__contrast",
12209
+ "selected-ring__focus": "a8ccharts-V2HDKq-selected-ring__focus"
12210
+ };
12211
+ //#endregion
12212
+ //#region src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx
12213
+ /**
12214
+ * Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
12215
+ *
12216
+ * @param value - Any string.
12217
+ * @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
12218
+ */
12219
+ const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
12220
+ /**
12221
+ * Marks the selected segment with a two-tone ring drawn inside its edge, so the SVG edge cannot cut it off.
12222
+ *
12223
+ * @param {SelectedSegmentRingProps} props - Component props
12224
+ * @return {JSX.Element} The ring
12225
+ */
12226
+ const SelectedSegmentRing = ({ chartId, d }) => {
12227
+ const clipId = `pie-selected-ring-clip-${toSvgId(chartId)}`;
12228
+ const clipPath = `url(#${clipId})`;
12229
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
12230
+ pointerEvents: "none",
12231
+ "aria-hidden": "true",
12232
+ children: [
12233
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("clipPath", {
12234
+ id: clipId,
12235
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d })
12236
+ }),
12237
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
12238
+ d,
12239
+ clipPath,
12240
+ className: pie_keyboard_navigation_module_default["selected-ring__contrast"]
12241
+ }),
12242
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
12243
+ d,
12244
+ clipPath,
12245
+ className: pie_keyboard_navigation_module_default["selected-ring__focus"]
12246
+ })
12247
+ ]
12248
+ });
12249
+ };
12250
+ //#endregion
12251
+ //#region src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts
12252
+ const usePieKeyboardNavigation = ({ navigationArcs, withTooltips, tooltipOffsetX, tooltipOffsetY }) => {
12253
+ const chartRef = (0, react.useRef)(null);
12254
+ const svgRef = (0, react.useRef)(null);
12255
+ const [selectedIndex, setSelectedIndex] = (0, react.useState)(void 0);
12256
+ const [isNavigating, setIsNavigating] = (0, react.useState)(false);
12257
+ const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
12258
+ const { tooltipRef: focusTooltip, onChartFocus, onChartBlur, onChartKeyDown, onChartPointerMove } = useKeyboardNavigation({
12259
+ selectedIndex,
12260
+ setSelectedIndex,
12261
+ isNavigating,
12262
+ setIsNavigating,
12263
+ chartRef,
12264
+ totalPoints: navigationArcs.length,
12265
+ visibleSeriesKey: JSON.stringify(navigationArcs.map((arcDatum) => arcDatum.data.label))
12266
+ });
12267
+ const selectedArc = selectedIndex === void 0 ? void 0 : navigationArcs[selectedIndex];
12268
+ const keyboardTooltip = (0, react.useRef)(null);
12269
+ const tooltipLostFocus = (0, react.useRef)(false);
12270
+ const tooltipRef = (0, react.useCallback)((element) => {
12271
+ if (element) {
12272
+ keyboardTooltip.current = element;
12273
+ focusTooltip(element);
12274
+ } else if (keyboardTooltip.current?.ownerDocument.activeElement === keyboardTooltip.current) tooltipLostFocus.current = true;
12275
+ }, [focusTooltip]);
12276
+ (0, react.useLayoutEffect)(() => {
12277
+ if (!tooltipLostFocus.current) return;
12278
+ tooltipLostFocus.current = false;
12279
+ const { activeElement, body } = chartRef.current?.ownerDocument ?? document;
12280
+ if (activeElement === null || activeElement === body) chartRef.current?.focus();
12281
+ });
12282
+ const getSegmentHandlers = (data, navigationIndex) => ({
12283
+ onMouseMove: (event) => {
12284
+ onChartPointerMove(navigationIndex);
12285
+ if (!withTooltips) return;
12286
+ const bounds = chartRef.current?.getBoundingClientRect();
12287
+ if (!bounds) return;
12288
+ showTooltip({
12289
+ tooltipData: data,
12290
+ tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
12291
+ tooltipTop: event.clientY - bounds.top + tooltipOffsetY
12292
+ });
12293
+ },
12294
+ onMouseLeave: withTooltips ? hideTooltip : void 0
12295
+ });
12296
+ return {
12297
+ chartRef,
12298
+ svgRef,
12299
+ selectedArc,
12300
+ getSegmentHandlers,
12301
+ getKeyboardTooltipAnchor: (0, react.useCallback)((originX, originY, [x, y]) => withTooltips ? {
12302
+ left: originX + x + tooltipOffsetX,
12303
+ top: originY + y + tooltipOffsetY
12304
+ } : void 0, [
12305
+ withTooltips,
12306
+ tooltipOffsetX,
12307
+ tooltipOffsetY
12308
+ ]),
12309
+ selectionOutputProps: {
12310
+ withTooltips,
12311
+ selectedIndex,
12312
+ selectedData: selectedArc?.data,
12313
+ chartRef,
12314
+ svgRef,
12315
+ tooltipRef,
12316
+ pointerTooltip: tooltipOpen ? {
12317
+ data: tooltipData,
12318
+ left: tooltipLeft || 0,
12319
+ top: tooltipTop || 0
12320
+ } : void 0
12321
+ },
12322
+ chartProps: {
12323
+ role: "application",
12324
+ tabIndex: 0,
12325
+ onKeyDown: onChartKeyDown,
12326
+ onFocus: onChartFocus,
12327
+ onBlur: onChartBlur
12328
+ }
12329
+ };
12330
+ };
12331
+ //#endregion
11806
12332
  //#region src/charts/private/radial-wipe-animation/radial-wipe-animation.tsx
11807
12333
  /**
11808
12334
  * Renders a SVG mask that creates a radial wipe animation effect.
@@ -11855,18 +12381,13 @@ var pie_chart_module_default = {
11855
12381
  //#region src/charts/pie-chart/pie-chart.tsx
11856
12382
  /**
11857
12383
  * Default tooltip renderer for pie charts.
11858
- * Renders a BaseTooltip with the hovered segment's data.
12384
+ * Renders the default `label: value` tooltip content for the hovered segment.
11859
12385
  *
11860
12386
  * @param {PieChartRenderTooltipParams} params - The tooltip parameters containing the hovered data point
11861
12387
  * @return {ReactNode} The rendered tooltip content
11862
12388
  */
11863
12389
  const renderDefaultPieTooltip = ({ tooltipData }) => {
11864
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BaseTooltip, {
11865
- data: tooltipData,
11866
- top: 0,
11867
- left: 0,
11868
- renderContainer: false
11869
- });
12390
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data: tooltipData });
11870
12391
  };
11871
12392
  /**
11872
12393
  * Validates the pie chart data
@@ -11903,20 +12424,13 @@ const LABEL_TEXT_MODIFIER = {
11903
12424
  * @param {PieChartProps} props - Component props
11904
12425
  * @return {JSX.Element} The rendered chart component
11905
12426
  */
11906
- const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legend = {}, width: propWidth, height: propHeight, size, animation, thickness = 1, padding = 0, gapScale = 0, cornerScale = 0, showLabels = true, legendValueDisplay = "percentage", children = null, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieTooltip, gap = "md" }) => {
12427
+ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legend = {}, width: propWidth, height: propHeight, size, animation, thickness = 1, padding = 0, gapScale = 0, cornerScale = 0, showLabels = true, legendValueDisplay = "percentage", children = null, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieTooltip, ariaLabel, gap = "md" }) => {
11907
12428
  const legendInteractive = legend.interactive ?? false;
11908
12429
  const legendPosition = legend.position ?? "bottom";
11909
12430
  const providerTheme = useGlobalChartsTheme();
11910
12431
  const chartId = useChartId(providedChartId);
11911
- const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
11912
- const standaloneScopeClass = useStandaloneScopeClass();
11913
- const containerRef = (0, react.useRef)(null);
11914
12432
  const rootRef = (0, react.useRef)(null);
11915
12433
  const [labelRoles, setLabelRoles] = (0, react.useState)(null);
11916
- const onMouseLeave = (0, react.useCallback)(() => {
11917
- if (!withTooltips) return;
11918
- hideTooltip();
11919
- }, [withTooltips, hideTooltip]);
11920
12434
  const { getElementStyles, isSeriesVisible, isColorPaletteResolved } = useGlobalChartsContext();
11921
12435
  const { isValid, message } = validateData$1(data);
11922
12436
  (0, react.useLayoutEffect)(() => {
@@ -11960,13 +12474,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
11960
12474
  metadata: chartMetadata
11961
12475
  });
11962
12476
  const prefersReducedMotion = usePrefersReducedMotion();
11963
- if (!isValid) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11964
- className: (0, clsx.default)("pie-chart", pie_chart_module_default["pie-chart"], className),
11965
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11966
- className: pie_chart_module_default["error-message"],
11967
- children: message
11968
- })
11969
- });
12477
+ const wipeMask = animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null;
11970
12478
  const padAngle = gapScale * (2 * Math.PI / data.length);
11971
12479
  const dataWithIndex = visibleData.map((d) => {
11972
12480
  const originalIndex = data.findIndex((item) => item.label === d.label);
@@ -11984,6 +12492,24 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
11984
12492
  }).color;
11985
12493
  }
11986
12494
  };
12495
+ const arcs = (0, _visx_shape.pie)({
12496
+ value: accessors.value,
12497
+ padAngle
12498
+ })(dataWithIndex);
12499
+ const navigationArcs = orderArcsForNavigation(arcs);
12500
+ const { chartRef, svgRef, selectedArc, getSegmentHandlers, getKeyboardTooltipAnchor, selectionOutputProps, chartProps } = usePieKeyboardNavigation({
12501
+ navigationArcs,
12502
+ withTooltips,
12503
+ tooltipOffsetX,
12504
+ tooltipOffsetY
12505
+ });
12506
+ if (!isValid) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12507
+ className: (0, clsx.default)("pie-chart", pie_chart_module_default["pie-chart"], className),
12508
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12509
+ className: pie_chart_module_default["error-message"],
12510
+ children: message
12511
+ })
12512
+ });
11987
12513
  const legendElement = showLegend && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
11988
12514
  orientation: legend.orientation ?? "horizontal",
11989
12515
  position: legendPosition,
@@ -12022,102 +12548,96 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
12022
12548
  const innerRadius = thickness === 0 ? 0 : outerRadius * (1 - thickness);
12023
12549
  const maxCornerRadius = (outerRadius - innerRadius) / 2;
12024
12550
  const cornerRadius = cornerScale ? Math.min(cornerScale * outerRadius, maxCornerRadius) : 0;
12551
+ const path = (0, _visx_shape.arc)({
12552
+ innerRadius,
12553
+ outerRadius,
12554
+ cornerRadius
12555
+ });
12556
+ const svgLabelSmall = providerTheme.svgLabelSmall;
12557
+ const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
12558
+ const renderLabel = (arcDatum, index) => {
12559
+ if (arcDatum.endAngle - arcDatum.startAngle < .25) return null;
12560
+ const [centroidX, centroidY] = path.centroid(arcDatum);
12561
+ const backgroundWidth = (0, _visx_text.getStringWidth)(arcDatum.data.label, {
12562
+ fontSize,
12563
+ fontFamily: svgLabelSmall?.fontFamily,
12564
+ fontWeight: svgLabelSmall?.fontWeight
12565
+ }) + 12;
12566
+ const backgroundHeight = fontSize + 12;
12567
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
12568
+ className: pie_chart_module_default["pie-chart__label-plate"],
12569
+ x: centroidX - backgroundWidth / 2,
12570
+ y: centroidY - backgroundHeight / 2,
12571
+ width: backgroundWidth,
12572
+ height: backgroundHeight,
12573
+ rx: 4,
12574
+ ry: 4,
12575
+ pointerEvents: "none"
12576
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
12577
+ className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"], LABEL_TEXT_MODIFIER[pickLabelTextColor(accessors.fill(arcDatum.data), labelRoles, "label-inverse")]),
12578
+ x: centroidX,
12579
+ y: centroidY,
12580
+ dy: ".33em",
12581
+ fontSize,
12582
+ textAnchor: "middle",
12583
+ pointerEvents: "none",
12584
+ children: arcDatum.data.label
12585
+ })] }, `label-${index}`);
12586
+ };
12025
12587
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
12026
- ref: containerRef,
12588
+ ref: chartRef,
12027
12589
  className: pie_chart_module_default["pie-chart__plot"],
12590
+ ...chartProps,
12591
+ "aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Pie chart", "jetpack-charts"),
12028
12592
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
12593
+ ref: svgRef,
12029
12594
  viewBox: `0 0 ${width} ${height}`,
12030
12595
  preserveAspectRatio: "xMidYMid meet",
12031
12596
  width,
12032
12597
  height,
12033
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
12034
- id: `radial-wipe-${chartId}`,
12035
- radius: outerRadius,
12036
- innerRadius
12037
- }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
12038
- top: centerY,
12039
- left: centerX,
12040
- mask: animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null,
12041
- children: [allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
12042
- x: 0,
12043
- y: 0,
12044
- width,
12045
- height,
12046
- children: getAllHiddenMessage(legendInteractive, "segments")
12047
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_shape.Pie, {
12048
- data: dataWithIndex,
12049
- pieValue: accessors.value,
12050
- outerRadius,
12051
- innerRadius,
12052
- padAngle,
12053
- cornerRadius,
12054
- children: (pie) => {
12055
- return pie.arcs.map((arc, index) => {
12056
- const [centroidX, centroidY] = pie.path.centroid(arc);
12057
- const hasSpaceForLabel = arc.endAngle - arc.startAngle >= .25;
12058
- const handleMouseMove = (event) => {
12059
- if (!withTooltips) return;
12060
- const bounds = containerRef.current?.getBoundingClientRect();
12061
- if (!bounds) return;
12062
- showTooltip({
12063
- tooltipData: arc.data,
12064
- tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
12065
- tooltipTop: event.clientY - bounds.top + tooltipOffsetY
12066
- });
12067
- };
12068
- const fill = accessors.fill(arc.data);
12069
- const pathProps = {
12070
- d: pie.path(arc) || "",
12071
- fill,
12072
- "data-testid": "pie-segment"
12073
- };
12074
- const groupProps = {};
12075
- if (withTooltips) {
12076
- groupProps.onMouseMove = handleMouseMove;
12077
- groupProps.onMouseLeave = onMouseLeave;
12078
- }
12079
- const svgLabelSmall = providerTheme.svgLabelSmall;
12080
- const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
12081
- const backgroundWidth = (0, _visx_text.getStringWidth)(arc.data.label, {
12082
- fontSize,
12083
- fontFamily: svgLabelSmall?.fontFamily,
12084
- fontWeight: svgLabelSmall?.fontWeight
12085
- }) + 12;
12086
- const backgroundHeight = fontSize + 12;
12087
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
12088
- ...groupProps,
12089
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
12090
- className: pie_chart_module_default["pie-chart__label-plate"],
12091
- x: centroidX - backgroundWidth / 2,
12092
- y: centroidY - backgroundHeight / 2,
12093
- width: backgroundWidth,
12094
- height: backgroundHeight,
12095
- rx: 4,
12096
- ry: 4,
12097
- pointerEvents: "none"
12098
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
12099
- className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"], LABEL_TEXT_MODIFIER[pickLabelTextColor(fill, labelRoles, "label-inverse")]),
12100
- x: centroidX,
12101
- y: centroidY,
12102
- dy: ".33em",
12103
- fontSize,
12104
- textAnchor: "middle",
12105
- pointerEvents: "none",
12106
- children: arc.data.label
12107
- })] })]
12108
- }, `arc-${index}`);
12109
- });
12110
- }
12111
- }), !allSegmentsHidden && svgChildren]
12112
- })]
12113
- }), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
12114
- top: tooltipTop || 0,
12115
- left: tooltipLeft || 0,
12116
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12117
- className: standaloneScopeClass,
12118
- role: "tooltip",
12119
- children: renderTooltip({ tooltipData })
12120
- })
12598
+ children: [
12599
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
12600
+ id: `radial-wipe-${chartId}`,
12601
+ radius: outerRadius,
12602
+ innerRadius
12603
+ }) }),
12604
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
12605
+ top: centerY,
12606
+ left: centerX,
12607
+ mask: wipeMask,
12608
+ children: allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
12609
+ x: 0,
12610
+ y: 0,
12611
+ width,
12612
+ height,
12613
+ children: getAllHiddenMessage(legendInteractive, "segments")
12614
+ }) : arcs.map((arcDatum, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
12615
+ ...getSegmentHandlers(arcDatum.data, navigationArcs.indexOf(arcDatum)),
12616
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
12617
+ d: path(arcDatum) || "",
12618
+ fill: accessors.fill(arcDatum.data)
12619
+ })
12620
+ }, `arc-${index}`))
12621
+ }),
12622
+ selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
12623
+ top: centerY,
12624
+ left: centerX,
12625
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
12626
+ chartId,
12627
+ d: path(selectedArc) || ""
12628
+ })
12629
+ }),
12630
+ !allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
12631
+ top: centerY,
12632
+ left: centerX,
12633
+ mask: wipeMask,
12634
+ children: [showLabels && arcs.map(renderLabel), svgChildren]
12635
+ })
12636
+ ]
12637
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionOutput, {
12638
+ ...selectionOutputProps,
12639
+ keyboardTooltipAnchor: selectedArc && getKeyboardTooltipAnchor(centerX, centerY, path.centroid(selectedArc)),
12640
+ renderTooltip
12121
12641
  })]
12122
12642
  });
12123
12643
  }
@@ -12152,18 +12672,13 @@ var pie_semi_circle_chart_module_default = {
12152
12672
  //#region src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx
12153
12673
  /**
12154
12674
  * Default tooltip renderer for semi-circle pie charts.
12155
- * Renders a BaseTooltip with the hovered segment's data.
12675
+ * Renders the default `label: value` tooltip content for the hovered segment.
12156
12676
  *
12157
12677
  * @param {PieSemiCircleChartRenderTooltipParams} params - The tooltip parameters containing the hovered data point
12158
12678
  * @return {ReactNode} The rendered tooltip content
12159
12679
  */
12160
12680
  const renderDefaultPieSemiCircleTooltip = ({ tooltipData }) => {
12161
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BaseTooltip, {
12162
- data: tooltipData,
12163
- top: 0,
12164
- left: 0,
12165
- renderContainer: false
12166
- });
12681
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data: tooltipData });
12167
12682
  };
12168
12683
  const PAD_ANGLE = .03;
12169
12684
  const DEFAULT_WIDTH$1 = 400;
@@ -12190,32 +12705,10 @@ const validateData = (data) => {
12190
12705
  message: ""
12191
12706
  };
12192
12707
  };
12193
- const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, thickness = .4, clockwise = true, withTooltips = false, showLegend = false, legend = {}, legendValueDisplay = "percentage", label, animation, note, className, children, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieSemiCircleTooltip, gap = "md" }) => {
12708
+ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, thickness = .4, clockwise = true, withTooltips = false, showLegend = false, legend = {}, legendValueDisplay = "percentage", label, animation, note, className, children, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieSemiCircleTooltip, ariaLabel, gap = "md" }) => {
12194
12709
  const legendInteractive = legend.interactive ?? false;
12195
12710
  const legendPosition = legend.position ?? "bottom";
12196
12711
  const chartId = useChartId(providedChartId);
12197
- const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
12198
- const standaloneScopeClass = useStandaloneScopeClass();
12199
- const containerRef = (0, react.useRef)(null);
12200
- const handleMouseMove = (0, react.useCallback)((event, arc) => {
12201
- const bounds = containerRef.current?.getBoundingClientRect();
12202
- if (!bounds) return;
12203
- showTooltip({
12204
- tooltipData: arc.data,
12205
- tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
12206
- tooltipTop: event.clientY - bounds.top + tooltipOffsetY
12207
- });
12208
- }, [
12209
- showTooltip,
12210
- tooltipOffsetX,
12211
- tooltipOffsetY
12212
- ]);
12213
- const handleMouseLeave = (0, react.useCallback)(() => {
12214
- hideTooltip();
12215
- }, [hideTooltip]);
12216
- const handleArcMouseMove = (0, react.useCallback)((arc) => (event) => {
12217
- handleMouseMove(event, arc);
12218
- }, [handleMouseMove]);
12219
12712
  const { isValid, message } = validateData(data);
12220
12713
  const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
12221
12714
  const dataWithPercentages = useDataWithPercentages(data);
@@ -12249,7 +12742,31 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
12249
12742
  metadata: chartMetadata
12250
12743
  });
12251
12744
  const prefersReducedMotion = usePrefersReducedMotion();
12745
+ const wipeMask = animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null;
12252
12746
  const effectiveWidth = propWidth || DEFAULT_WIDTH$1;
12747
+ const dataWithIndex = visibleData.map((d) => {
12748
+ const originalIndex = data.findIndex((item) => item.label === d.label);
12749
+ return {
12750
+ ...d,
12751
+ index: originalIndex >= 0 ? originalIndex : 0
12752
+ };
12753
+ });
12754
+ const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2;
12755
+ const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2;
12756
+ const arcs = (0, _visx_shape.pie)({
12757
+ value: accessors.value,
12758
+ sort: accessors.sort,
12759
+ padAngle: PAD_ANGLE,
12760
+ startAngle,
12761
+ endAngle
12762
+ })(dataWithIndex);
12763
+ const navigationArcs = orderArcsForNavigation(arcs);
12764
+ const { chartRef, svgRef, selectedArc, getSegmentHandlers, getKeyboardTooltipAnchor, selectionOutputProps, chartProps } = usePieKeyboardNavigation({
12765
+ navigationArcs,
12766
+ withTooltips,
12767
+ tooltipOffsetX,
12768
+ tooltipOffsetY
12769
+ });
12253
12770
  if (!isValid) {
12254
12771
  const errorWidth = propHeight ? Math.min(propWidth || propHeight * 2, propHeight * 2) : effectiveWidth;
12255
12772
  const errorHeight = errorWidth / 2;
@@ -12268,15 +12785,6 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
12268
12785
  })
12269
12786
  });
12270
12787
  }
12271
- const dataWithIndex = visibleData.map((d) => {
12272
- const originalIndex = data.findIndex((item) => item.label === d.label);
12273
- return {
12274
- ...d,
12275
- index: originalIndex >= 0 ? originalIndex : 0
12276
- };
12277
- });
12278
- const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2;
12279
- const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2;
12280
12788
  const legendElement = showLegend && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
12281
12789
  orientation: legend.orientation ?? "horizontal",
12282
12790
  position: legendPosition,
@@ -12309,52 +12817,60 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
12309
12817
  const height = width / 2;
12310
12818
  const radius = height;
12311
12819
  const innerRadius = radius * (1 - thickness);
12820
+ const path = (0, _visx_shape.arc)({
12821
+ innerRadius,
12822
+ outerRadius: radius,
12823
+ cornerRadius: 3
12824
+ });
12312
12825
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
12313
- ref: containerRef,
12826
+ ref: chartRef,
12314
12827
  className: pie_semi_circle_chart_module_default["pie-semi-circle-chart__plot"],
12828
+ ...chartProps,
12829
+ "aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Semi-circle chart", "jetpack-charts"),
12315
12830
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
12831
+ ref: svgRef,
12316
12832
  width,
12317
12833
  height,
12318
12834
  viewBox: `0 0 ${width} ${height}`,
12319
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
12320
- id: `radial-wipe-${chartId}`,
12321
- radius,
12322
- innerRadius,
12323
- startAngle: "-180deg",
12324
- wipePercentage: 50
12325
- }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
12326
- top: height,
12327
- left: width / 2,
12328
- mask: animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null,
12329
- children: allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
12330
- x: 0,
12331
- y: -radius / 2,
12332
- width,
12333
- height,
12334
- children: getAllHiddenMessage(legendInteractive, "segments")
12335
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
12336
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_shape.Pie, {
12337
- data: dataWithIndex,
12338
- pieValue: accessors.value,
12339
- outerRadius: radius,
12340
- innerRadius,
12341
- cornerRadius: 3,
12342
- padAngle: PAD_ANGLE,
12343
- startAngle,
12344
- endAngle,
12345
- pieSort: accessors.sort,
12346
- children: (pie) => {
12347
- return pie.arcs.map((arc) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
12348
- onMouseMove: withTooltips ? handleArcMouseMove(arc) : void 0,
12349
- onMouseLeave: withTooltips ? handleMouseLeave : void 0,
12350
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
12351
- d: pie.path(arc) || "",
12352
- fill: accessors.fill(arc.data)
12353
- })
12354
- }, arc.data.label));
12355
- }
12356
- }),
12357
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_text.Text, {
12835
+ children: [
12836
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
12837
+ id: `radial-wipe-${chartId}`,
12838
+ radius,
12839
+ innerRadius,
12840
+ startAngle: "-180deg",
12841
+ wipePercentage: 50
12842
+ }) }),
12843
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
12844
+ top: height,
12845
+ left: width / 2,
12846
+ mask: wipeMask,
12847
+ children: allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
12848
+ x: 0,
12849
+ y: -radius / 2,
12850
+ width,
12851
+ height,
12852
+ children: getAllHiddenMessage(legendInteractive, "segments")
12853
+ }) : arcs.map((arcDatum) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
12854
+ ...getSegmentHandlers(arcDatum.data, navigationArcs.indexOf(arcDatum)),
12855
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
12856
+ d: path(arcDatum) || "",
12857
+ fill: accessors.fill(arcDatum.data)
12858
+ })
12859
+ }, arcDatum.data.label))
12860
+ }),
12861
+ selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
12862
+ top: height,
12863
+ left: width / 2,
12864
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
12865
+ chartId,
12866
+ d: path(selectedArc) || ""
12867
+ })
12868
+ }),
12869
+ !allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
12870
+ top: height,
12871
+ left: width / 2,
12872
+ mask: wipeMask,
12873
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_text.Text, {
12358
12874
  textAnchor: "middle",
12359
12875
  verticalAnchor: "start",
12360
12876
  y: -40,
@@ -12366,18 +12882,13 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
12366
12882
  y: -20,
12367
12883
  className: pie_semi_circle_chart_module_default.note,
12368
12884
  children: note
12369
- })] }),
12370
- !allSegmentsHidden && svgChildren
12371
- ] })
12372
- })]
12373
- }), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
12374
- top: tooltipTop || 0,
12375
- left: tooltipLeft || 0,
12376
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12377
- className: standaloneScopeClass,
12378
- role: "tooltip",
12379
- children: renderTooltip({ tooltipData })
12380
- })
12885
+ })] }), svgChildren]
12886
+ })
12887
+ ]
12888
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionOutput, {
12889
+ ...selectionOutputProps,
12890
+ keyboardTooltipAnchor: selectedArc && getKeyboardTooltipAnchor(width / 2, height, path.centroid(selectedArc)),
12891
+ renderTooltip
12381
12892
  })]
12382
12893
  });
12383
12894
  }
@@ -12631,7 +13142,9 @@ exports.PieSemiCircleChartUnresponsive = PieSemiCircleChart;
12631
13142
  exports.Sparkline = Sparkline;
12632
13143
  exports.SparklineUnresponsive = SparklineUnresponsive;
12633
13144
  exports.ThemeProvider = GlobalChartsProvider;
13145
+ exports.TooltipBox = TooltipBox;
12634
13146
  exports.TrendIndicator = TrendIndicator;
13147
+ exports.XYChartTooltip = XYChartTooltip;
12635
13148
  exports.buildCalendarHeatmapData = buildCalendarHeatmapData;
12636
13149
  exports.buildMonthCalendarHeatmapData = buildMonthCalendarHeatmapData;
12637
13150
  exports.defaultTheme = defaultTheme;