@automattic/charts 4.1.1 → 4.2.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 (73) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/TOKENS.md +1 -1
  3. package/dist/index.cjs +875 -237
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +30 -1
  6. package/dist/index.d.cts +106 -6
  7. package/dist/index.d.ts +106 -6
  8. package/dist/index.js +875 -239
  9. package/dist/index.js.map +1 -1
  10. package/package.json +8 -8
  11. package/src/charts/area-chart/private/overlays.tsx +1 -2
  12. package/src/charts/bar-chart/bar-chart.tsx +67 -17
  13. package/src/charts/bar-chart/index.ts +1 -1
  14. package/src/charts/bar-chart/private/band-highlight.tsx +85 -0
  15. package/src/charts/bar-chart/private/band-scale.ts +13 -0
  16. package/src/charts/bar-chart/private/band-tooltip.tsx +138 -0
  17. package/src/charts/bar-chart/private/comparison-bars.tsx +5 -10
  18. package/src/charts/bar-chart/private/index.ts +2 -0
  19. package/src/charts/bar-chart/private/test/band-highlight.test.tsx +109 -0
  20. package/src/charts/bar-chart/private/test/band-tooltip.test.ts +26 -0
  21. package/src/charts/bar-chart/private/truncated-tick-component.tsx +1 -1
  22. package/src/charts/bar-chart/private/use-bar-chart-options.ts +1 -1
  23. package/src/charts/bar-chart/test/bar-chart-pointer-events.test.tsx +11 -23
  24. package/src/charts/bar-chart/test/bar-chart.test.tsx +565 -1
  25. package/src/charts/bar-list-chart/bar-list-chart.tsx +5 -3
  26. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +1 -1
  27. package/src/charts/conversion-funnel-chart/types.ts +4 -2
  28. package/src/charts/geo-chart/types.ts +4 -2
  29. package/src/charts/heatmap-chart/build-calendar-data.ts +5 -11
  30. package/src/charts/heatmap-chart/build-month-calendar-data.ts +124 -0
  31. package/src/charts/heatmap-chart/heatmap-chart.module.scss +32 -0
  32. package/src/charts/heatmap-chart/heatmap-chart.tsx +191 -114
  33. package/src/charts/heatmap-chart/index.ts +6 -0
  34. package/src/charts/heatmap-chart/private/civil-day.ts +26 -0
  35. package/src/charts/heatmap-chart/private/column-groups.ts +71 -0
  36. package/src/charts/heatmap-chart/private/heatmap-legend.tsx +19 -3
  37. package/src/charts/heatmap-chart/private/index.ts +2 -0
  38. package/src/charts/heatmap-chart/private/keyboard-navigation.ts +201 -0
  39. package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +36 -0
  40. package/src/charts/heatmap-chart/test/build-month-calendar-data.test.ts +194 -0
  41. package/src/charts/heatmap-chart/test/column-groups.test.ts +83 -0
  42. package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +428 -2
  43. package/src/charts/heatmap-chart/test/keyboard-navigation.test.ts +25 -0
  44. package/src/charts/heatmap-chart/test/use-month-calendar-heatmap-data.test.tsx +90 -0
  45. package/src/charts/heatmap-chart/test/zoned-month-calendar-data.test.ts +23 -0
  46. package/src/charts/heatmap-chart/types.ts +59 -3
  47. package/src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts +34 -0
  48. package/src/charts/leaderboard-chart/types.ts +13 -14
  49. package/src/charts/line-chart/line-chart.tsx +1 -1
  50. package/src/charts/line-chart/private/line-chart-annotation.tsx +1 -1
  51. package/src/charts/line-chart/types.ts +2 -2
  52. package/src/charts/private/time-axis-options.ts +1 -1
  53. package/src/charts/private/with-responsive/with-responsive.tsx +2 -2
  54. package/src/charts/private/x-zoom/test/x-zoom.test.tsx +1 -3
  55. package/src/charts/private/x-zoom/x-zoom.tsx +1 -2
  56. package/src/components/legend/private/base-legend.tsx +1 -1
  57. package/src/components/tooltip/accessible-tooltip.tsx +127 -40
  58. package/src/components/tooltip/base-tooltip.module.scss +6 -1
  59. package/src/components/tooltip/private/bounded-tooltip.tsx +12 -6
  60. package/src/components/tooltip/test/accessible-tooltip.test.tsx +128 -0
  61. package/src/components/tooltip/test/bounded-tooltip.test.tsx +17 -0
  62. package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +7 -0
  63. package/src/components/tooltip/xy-chart-tooltip.tsx +9 -10
  64. package/src/hooks/test/use-element-size.test.tsx +13 -13
  65. package/src/hooks/use-xychart-theme.ts +1 -1
  66. package/src/index.ts +7 -1
  67. package/src/providers/chart-context/themes.ts +1 -0
  68. package/src/styles/test/chart-scope.test.ts +1 -1
  69. package/src/types.ts +6 -13
  70. package/src/utils/format-metric-value.ts +4 -4
  71. package/src/utils/get-edge-tick-widths.ts +1 -1
  72. package/src/utils/get-styles.ts +1 -1
  73. package/src/visx/types.ts +7 -10
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getStringWidth as getStringWidth$1 } from "./visx/text/index.js";
2
2
  import { formatNumber, formatNumberCompact } from "@automattic/number-formatters";
3
- import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid, TooltipContext, XYChart, buildChartTheme } from "@visx/xychart";
3
+ import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid, TooltipContext, XYChart, buildChartTheme, useEventEmitter } from "@visx/xychart";
4
4
  import { __, _x, sprintf } from "@wordpress/i18n";
5
5
  import clsx from "clsx";
6
6
  import * as React from "react";
@@ -981,7 +981,8 @@ const defaultTheme = {
981
981
  },
982
982
  heatmapChart: {
983
983
  compactCellGap: 2,
984
- compactCellSize: 11
984
+ compactCellSize: 11,
985
+ groupGap: 24
985
986
  }
986
987
  };
987
988
  //#endregion
@@ -2181,7 +2182,10 @@ function useChartLegendItems(data, options = {}, legendShape) {
2181
2182
  }
2182
2183
  //#endregion
2183
2184
  //#region src/components/tooltip/base-tooltip.module.scss
2184
- var base_tooltip_module_default = { "tooltip": "a8ccharts--zY0xG-tooltip" };
2185
+ var base_tooltip_module_default = {
2186
+ "surface": "a8ccharts--zY0xG-surface",
2187
+ "tooltip": "a8ccharts--zY0xG-tooltip"
2188
+ };
2185
2189
  //#endregion
2186
2190
  //#region src/components/tooltip/base-tooltip.tsx
2187
2191
  const DefaultTooltipContent = ({ data }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
@@ -2231,7 +2235,8 @@ const findClippingAncestor = (wrapper) => {
2231
2235
  /**
2232
2236
  * Where the box goes, in wrapper coordinates. Automatic placement flips to
2233
2237
  * the side that clips less, then clamps inside `bounds`; below-axis placement
2234
- * is centered on the anchor and clamped horizontally.
2238
+ * is centered on the anchor and clamped horizontally; beside placement preserves
2239
+ * the anchor's y and only flips horizontally before bounds clamping.
2235
2240
  *
2236
2241
  * The flip measures against the visible part of the wrapper, its intersection
2237
2242
  * with `bounds`. Only the clamp is bound by the page: a box that fits inside the
@@ -2245,7 +2250,7 @@ const findClippingAncestor = (wrapper) => {
2245
2250
  * @param params.offsetTop - Gap between the anchor and the box, vertically.
2246
2251
  * @param params.box - Rendered size of the box.
2247
2252
  * @param params.wrapper - The wrapper's own edges, in wrapper coordinates.
2248
- * @param params.placement - Fixed below-axis placement or automatic flipping.
2253
+ * @param params.placement - Below-axis, beside without vertical flipping, or automatic flipping.
2249
2254
  * @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
2250
2255
  * @return The box's top-left corner; fixed placement preserves the axis's subpixel y.
2251
2256
  */
@@ -2269,7 +2274,8 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
2269
2274
  const upY = top - offsetTop - box.height;
2270
2275
  const downOverflow = downY + box.height - fit.bottom;
2271
2276
  const upOverflow = fit.top - upY;
2272
- let y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
2277
+ let y = top;
2278
+ if (placement !== "beside") y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
2273
2279
  x = clamp(x, bounds.left, bounds.right, box.width);
2274
2280
  y = clamp(y, bounds.top, bounds.bottom, box.height);
2275
2281
  return {
@@ -2285,8 +2291,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
2285
2291
  * alone would let the box spill into an `overflow: hidden` card and be cut off.
2286
2292
  *
2287
2293
  * Re-measures on every render, so a box whose content changes width between
2288
- * two hovers is placed for its current size. See `getBoundedPosition` for the
2289
- * below-axis exception.
2294
+ * two hovers is placed for its current size.
2290
2295
  *
2291
2296
  * @param props - visx `Tooltip` props.
2292
2297
  * @param props.left - Anchor x, in wrapper coordinates.
@@ -2296,7 +2301,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
2296
2301
  * @param props.style - Box styles; visx's defaults unless `unstyled`.
2297
2302
  * @param props.unstyled - Skip `style` and leave the box bare.
2298
2303
  * @param props.children - Box content.
2299
- * @param props.placement - Fixed below-axis placement or automatic flipping.
2304
+ * @param props.placement - Below-axis, beside without vertical flipping, or automatic flipping.
2300
2305
  * @return The tooltip box.
2301
2306
  */
2302
2307
  const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = defaultStyles, unstyled = false, children, placement = "auto", ...rest }) => {
@@ -2399,7 +2404,6 @@ const crosshairPaintProps = (props = {}) => {
2399
2404
  };
2400
2405
  const DEFAULT_GLYPH_RADIUS = 4;
2401
2406
  const FALLBACK_COLOR = "#222";
2402
- const DEFAULT_TOOLTIP_Z_INDEX = 3;
2403
2407
  const PORTAL_OPTIONS = /* @__PURE__ */ new Set([
2404
2408
  "scroll",
2405
2409
  "debounce",
@@ -2427,7 +2431,7 @@ const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ jsx(DefaultG
2427
2431
  seriesKey: key,
2428
2432
  ...props
2429
2433
  }, key);
2430
- const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", zIndex = DEFAULT_TOOLTIP_Z_INDEX, style, ...rest }) => {
2434
+ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", tooltipAnchorTop, zIndex = 3, style, ...rest }) => {
2431
2435
  const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
2432
2436
  const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = useContext(DataContext) || {};
2433
2437
  const tooltipContent = renderTooltip ? renderTooltip({
@@ -2482,7 +2486,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
2482
2486
  const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
2483
2487
  const marginTop = margin?.top ?? 0;
2484
2488
  const marginLeft = margin?.left ?? 0;
2485
- const TooltipComponent = detectBounds || tooltipPlacement === "below-axis" ? BoundedTooltip : Tooltip;
2489
+ const TooltipComponent = detectBounds || tooltipPlacement !== "auto" ? BoundedTooltip : Tooltip;
2486
2490
  const boxStyle = {
2487
2491
  ...defaultStyles,
2488
2492
  zIndex,
@@ -2519,11 +2523,11 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
2519
2523
  ]
2520
2524
  }), container && createPortal(/* @__PURE__ */ jsx(TooltipComponent, {
2521
2525
  left: tooltipLeft,
2522
- top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipTop,
2526
+ top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipAnchorTop ?? tooltipTop,
2523
2527
  style: boxStyle,
2524
2528
  applyPositionStyle: true,
2525
2529
  ...tooltipProps,
2526
- ...tooltipPlacement === "below-axis" && { placement: tooltipPlacement },
2530
+ ...tooltipPlacement !== "auto" && { placement: tooltipPlacement },
2527
2531
  children: tooltipContent
2528
2532
  }), container)] });
2529
2533
  };
@@ -2589,11 +2593,32 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
2589
2593
  return flattened;
2590
2594
  }, [series, mode]);
2591
2595
  const hasKeyboardSelection = useRef(false);
2596
+ const closeTooltipNow = useCallback(() => {
2597
+ tooltipContext?.updateTooltip({
2598
+ tooltipOpen: false,
2599
+ tooltipLeft: void 0,
2600
+ tooltipTop: void 0,
2601
+ tooltipData: void 0
2602
+ });
2603
+ }, []);
2604
+ const chartId = useContext(ChartInstanceContext)?.chartId;
2605
+ const { getHiddenSeries } = useGlobalChartsContext();
2606
+ const hiddenSeriesKey = chartId ? JSON.stringify([...getHiddenSeries(chartId)].sort()) : void 0;
2607
+ const lastHiddenSeriesKey = useRef(hiddenSeriesKey);
2608
+ useEffect(() => {
2609
+ const changed = lastHiddenSeriesKey.current !== hiddenSeriesKey;
2610
+ lastHiddenSeriesKey.current = hiddenSeriesKey;
2611
+ if (changed && selectedIndex === void 0) closeTooltipNow();
2612
+ }, [
2613
+ hiddenSeriesKey,
2614
+ selectedIndex,
2615
+ closeTooltipNow
2616
+ ]);
2592
2617
  useEffect(() => {
2593
2618
  if (selectedIndex === void 0) {
2594
2619
  if (hasKeyboardSelection.current) {
2595
2620
  hasKeyboardSelection.current = false;
2596
- tooltipContext?.hideTooltip();
2621
+ closeTooltipNow();
2597
2622
  }
2598
2623
  return;
2599
2624
  }
@@ -2662,14 +2687,43 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
2662
2687
  renderTooltip: focusableRenderTooltip
2663
2688
  });
2664
2689
  };
2665
- const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false }) => {
2690
+ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false, visibleSeriesKey }) => {
2691
+ const getChartRoot = useCallback(() => chartRef.current?.closest("[role=\"grid\"]") ?? chartRef.current, [chartRef]);
2692
+ const focusWithoutScrollIfNeeded = useCallback((element) => {
2693
+ if (preventTooltipScroll) element?.focus({ preventScroll: true });
2694
+ else element?.focus();
2695
+ }, [preventTooltipScroll]);
2696
+ const tooltipRef = useCallback((element) => {
2697
+ if (element && selectedIndex !== void 0) focusWithoutScrollIfNeeded(element);
2698
+ }, [focusWithoutScrollIfNeeded, selectedIndex]);
2699
+ const previousTotalPoints = useRef(totalPoints);
2700
+ const previousVisibleSeriesKey = useRef(visibleSeriesKey);
2701
+ useEffect(() => {
2702
+ const countChanged = previousTotalPoints.current !== totalPoints;
2703
+ const seriesChanged = previousVisibleSeriesKey.current !== visibleSeriesKey;
2704
+ previousTotalPoints.current = totalPoints;
2705
+ previousVisibleSeriesKey.current = visibleSeriesKey;
2706
+ if (!countChanged && !seriesChanged || selectedIndex === void 0) return;
2707
+ const { activeElement } = document;
2708
+ const focusIsInChart = activeElement !== null && !!getChartRoot()?.contains(activeElement);
2709
+ if (totalPoints === 0 || !focusIsInChart || !countChanged) {
2710
+ setSelectedIndex(void 0);
2711
+ setIsNavigating(false);
2712
+ if (focusIsInChart) focusWithoutScrollIfNeeded(getChartRoot());
2713
+ return;
2714
+ }
2715
+ setSelectedIndex(Math.min(selectedIndex, totalPoints - 1));
2716
+ }, [
2717
+ selectedIndex,
2718
+ totalPoints,
2719
+ visibleSeriesKey,
2720
+ setSelectedIndex,
2721
+ setIsNavigating,
2722
+ getChartRoot,
2723
+ focusWithoutScrollIfNeeded
2724
+ ]);
2666
2725
  return {
2667
- tooltipRef: useCallback((element) => {
2668
- if (element && selectedIndex !== void 0) {
2669
- if (preventTooltipScroll) element.focus({ preventScroll: true });
2670
- else element.focus();
2671
- }
2672
- }, [preventTooltipScroll, selectedIndex]),
2726
+ tooltipRef,
2673
2727
  onChartFocus: useCallback((event) => {
2674
2728
  if (event.currentTarget.contains(event.relatedTarget)) return;
2675
2729
  if (!isNavigating && selectedIndex !== void 0) setSelectedIndex(0);
@@ -2682,44 +2736,35 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
2682
2736
  setIsNavigating(false);
2683
2737
  }, [setIsNavigating]),
2684
2738
  onChartKeyDown: useCallback((event) => {
2685
- if (totalPoints === 0) return;
2686
- const focusChart = () => {
2687
- if (preventTooltipScroll) chartRef.current?.focus({ preventScroll: true });
2688
- else chartRef.current?.focus();
2689
- };
2690
- if (event.key === "Tab") {
2691
- focusChart();
2739
+ if (event.key === "Tab" || event.key === "Escape") {
2740
+ if (event.key === "Escape" && selectedIndex !== void 0) event.preventDefault();
2741
+ focusWithoutScrollIfNeeded(getChartRoot());
2692
2742
  setSelectedIndex(void 0);
2693
2743
  setIsNavigating(false);
2694
2744
  return;
2695
2745
  }
2746
+ if (totalPoints === 0) return;
2696
2747
  const currentSelectedIndex = selectedIndex === void 0 ? -1 : selectedIndex;
2697
- if (currentSelectedIndex + 1 >= totalPoints && ["ArrowRight"].includes(event.key)) {
2698
- focusChart();
2699
- setSelectedIndex(void 0);
2700
- setIsNavigating(false);
2701
- return;
2702
- }
2703
- event.preventDefault();
2704
- if (["ArrowRight"].includes(event.key)) {
2748
+ if (event.key === "ArrowRight") {
2749
+ event.preventDefault();
2705
2750
  setIsNavigating(true);
2706
- setSelectedIndex((currentSelectedIndex + 1) % totalPoints);
2707
- } else if (["ArrowLeft"].includes(event.key)) {
2751
+ setSelectedIndex(Math.min(currentSelectedIndex + 1, totalPoints - 1));
2752
+ } else if (event.key === "ArrowLeft") {
2753
+ event.preventDefault();
2708
2754
  setIsNavigating(true);
2709
- setSelectedIndex((currentSelectedIndex - 1 + totalPoints) % totalPoints);
2710
- } else if (event.key === "Escape") {
2711
- setSelectedIndex(void 0);
2712
- setIsNavigating(false);
2713
- focusChart();
2714
- } else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) onActivate?.(selectedIndex);
2755
+ setSelectedIndex(Math.max(currentSelectedIndex - 1, 0));
2756
+ } else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) {
2757
+ event.preventDefault();
2758
+ onActivate?.(selectedIndex);
2759
+ }
2715
2760
  }, [
2716
2761
  totalPoints,
2717
2762
  selectedIndex,
2718
2763
  setSelectedIndex,
2719
2764
  setIsNavigating,
2720
- chartRef,
2721
- onActivate,
2722
- preventTooltipScroll
2765
+ getChartRoot,
2766
+ focusWithoutScrollIfNeeded,
2767
+ onActivate
2723
2768
  ])
2724
2769
  };
2725
2770
  };
@@ -5276,6 +5321,20 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
5276
5321
  ]);
5277
5322
  }
5278
5323
  //#endregion
5324
+ //#region src/charts/bar-chart/private/band-scale.ts
5325
+ /**
5326
+ * Match the inner slot scale used by visx BarGroup.
5327
+ * @param keys - Visible primary series keys.
5328
+ * @param bandwidth - Category band width.
5329
+ * @param padding - Padding between slots.
5330
+ * @return The grouped bar scale.
5331
+ */
5332
+ const createGroupScale = (keys, bandwidth, padding) => scaleBand({
5333
+ domain: keys,
5334
+ range: [0, bandwidth],
5335
+ padding
5336
+ });
5337
+ //#endregion
5279
5338
  //#region src/charts/bar-chart/private/comparison-bars-geometry.ts
5280
5339
  /**
5281
5340
  * Output position of a value scale's baseline: zero if in-domain, else the
@@ -5348,11 +5407,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
5348
5407
  const valueScale = horizontal ? xScale : yScale;
5349
5408
  const bandwidth = bandScale.bandwidth ? bandScale.bandwidth() : 0;
5350
5409
  if (!bandwidth) return null;
5351
- const groupScale = scaleBand({
5352
- domain: primaryKeys,
5353
- range: [0, bandwidth],
5354
- padding: groupPadding
5355
- });
5410
+ const groupScale = createGroupScale(primaryKeys, bandwidth, groupPadding);
5356
5411
  const slotThickness = groupScale.bandwidth();
5357
5412
  const baseline = getValueScaleBaseline(valueScale);
5358
5413
  const bandAccessor = horizontal ? yAccessor : xAccessor;
@@ -5404,6 +5459,163 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
5404
5459
  });
5405
5460
  };
5406
5461
  //#endregion
5462
+ //#region src/charts/bar-chart/private/band-highlight.tsx
5463
+ /**
5464
+ * Render and report the active band using the chart’s registered scales.
5465
+ * @param root0 - Highlight options.
5466
+ * @param root0.visible - Whether to paint the band.
5467
+ * @param root0.horizontal - Whether categories run vertically.
5468
+ * @param root0.onChange - Receives selected band geometry.
5469
+ * @return The optional band highlight.
5470
+ */
5471
+ function BandHighlight({ visible, horizontal, onChange }) {
5472
+ const { xScale, yScale, dataRegistry, margin, innerWidth, innerHeight } = useContext(DataContext);
5473
+ const { tooltipOpen, tooltipData } = useContext(TooltipContext);
5474
+ const nearest = tooltipData?.nearestDatum;
5475
+ const selection = useMemo(() => {
5476
+ if (!tooltipOpen || !nearest) return null;
5477
+ const scale = horizontal ? yScale : xScale;
5478
+ const entry = dataRegistry?.get(nearest.key);
5479
+ const accessor = horizontal ? entry?.yAccessor : entry?.xAccessor;
5480
+ if (!scale?.bandwidth || !accessor) return null;
5481
+ const position = scale(accessor(nearest.datum));
5482
+ if (position === void 0 || !Number.isFinite(position)) return null;
5483
+ return {
5484
+ datum: nearest.datum,
5485
+ x: horizontal ? margin?.left ?? 0 : position,
5486
+ y: horizontal ? position : margin?.top ?? 0,
5487
+ width: horizontal ? innerWidth : scale.bandwidth(),
5488
+ height: horizontal ? scale.bandwidth() : innerHeight
5489
+ };
5490
+ }, [
5491
+ tooltipOpen,
5492
+ nearest,
5493
+ horizontal,
5494
+ xScale,
5495
+ yScale,
5496
+ dataRegistry,
5497
+ margin,
5498
+ innerWidth,
5499
+ innerHeight
5500
+ ]);
5501
+ const stableSelection = useDeepMemo(selection);
5502
+ const onChangeRef = useRef(onChange);
5503
+ onChangeRef.current = onChange;
5504
+ useEffect(() => {
5505
+ onChangeRef.current?.(stableSelection);
5506
+ }, [stableSelection]);
5507
+ useEffect(() => () => onChangeRef.current?.(null), []);
5508
+ if (!visible || !selection) return null;
5509
+ const { x, y, width, height } = selection;
5510
+ return /* @__PURE__ */ jsx("rect", {
5511
+ x,
5512
+ y,
5513
+ width,
5514
+ height,
5515
+ pointerEvents: "none",
5516
+ fill: CATALOG_POINTERS.surfaceSecondary
5517
+ });
5518
+ }
5519
+ //#endregion
5520
+ //#region src/charts/bar-chart/private/band-tooltip.tsx
5521
+ /**
5522
+ * Find a category by its painted center, including outer padding and reversed ranges.
5523
+ * @param data - Registered series points.
5524
+ * @param accessor - Category accessor.
5525
+ * @param scale - Rendered category band scale.
5526
+ * @param position - Pointer coordinate on the category axis.
5527
+ * @return Index of the nearest category, or -1 when none is registered.
5528
+ */
5529
+ function nearestBandIndex(data, accessor, scale, position) {
5530
+ let nearest = -1;
5531
+ let distance = Infinity;
5532
+ data.forEach((datum, index) => {
5533
+ const start = scale(accessor(datum));
5534
+ if (start === void 0) return;
5535
+ const candidate = Math.abs(start + scale.bandwidth() / 2 - position);
5536
+ if (candidate < distance) {
5537
+ distance = candidate;
5538
+ nearest = index;
5539
+ }
5540
+ });
5541
+ return nearest;
5542
+ }
5543
+ /**
5544
+ * Correct visx's range-based band inversion, which omits outer padding.
5545
+ * @param root0 - Registered series selection.
5546
+ * @param root0.keys - Visible series keys.
5547
+ * @param root0.groupPadding - Padding between grouped bars.
5548
+ * @param root0.withTooltips - Whether pointer events update the tooltip.
5549
+ * @param root0.onPointerDown - Receives the corrected pointer-down datum.
5550
+ * @param root0.onPointerUp - Receives the corrected pointer-up datum.
5551
+ * @return No visual content.
5552
+ */
5553
+ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointerUp }) {
5554
+ const { xScale, yScale, dataRegistry, horizontal } = useContext(DataContext);
5555
+ const { showTooltip } = useContext(TooltipContext);
5556
+ const scale = horizontal ? yScale : xScale;
5557
+ const bandwidth = scale?.bandwidth?.() ?? 0;
5558
+ const groupScale = useMemo(() => createGroupScale(keys, bandwidth, groupPadding), [
5559
+ keys,
5560
+ bandwidth,
5561
+ groupPadding
5562
+ ]);
5563
+ const getSelections = useCallback((params) => {
5564
+ const point = params?.svgPoint;
5565
+ if (!point || !scale?.bandwidth) return [];
5566
+ const selections = [];
5567
+ for (const key of keys) {
5568
+ const entry = dataRegistry?.get(key);
5569
+ if (!entry) continue;
5570
+ const accessor = horizontal ? entry.yAccessor : entry.xAccessor;
5571
+ const index = nearestBandIndex(entry.data, accessor, scale, horizontal ? point.y : point.x);
5572
+ if (index < 0) continue;
5573
+ const datum = entry.data[index];
5574
+ const start = Number(scale(accessor(datum))) + Number(groupScale(key));
5575
+ const end = start + groupScale.step();
5576
+ const position = horizontal ? point.y : point.x;
5577
+ const distance = position >= start && position <= end ? 0 : Math.abs(position - (start + end) / 2);
5578
+ selections.push({
5579
+ event: params.event,
5580
+ key,
5581
+ datum,
5582
+ index,
5583
+ svgPoint: point,
5584
+ distanceX: horizontal ? 0 : distance,
5585
+ distanceY: horizontal ? distance : 0
5586
+ });
5587
+ }
5588
+ return selections;
5589
+ }, [
5590
+ scale,
5591
+ dataRegistry,
5592
+ horizontal,
5593
+ keys,
5594
+ groupScale
5595
+ ]);
5596
+ const handlePointer = useCallback((params) => {
5597
+ const selections = getSelections(params);
5598
+ if (withTooltips && params?.event.type !== "pointerup") selections.forEach(showTooltip);
5599
+ const callback = params?.event.type === "pointerdown" ? onPointerDown : onPointerUp;
5600
+ if (params?.event.type === "pointermove" || !callback) return;
5601
+ const nearest = selections.reduce((best, selection) => {
5602
+ const distance = (value) => Math.hypot(value.distanceX, value.distanceY);
5603
+ return !best || distance(selection) <= distance(best) ? selection : best;
5604
+ }, void 0);
5605
+ if (nearest) callback(nearest);
5606
+ }, [
5607
+ getSelections,
5608
+ withTooltips,
5609
+ showTooltip,
5610
+ onPointerDown,
5611
+ onPointerUp
5612
+ ]);
5613
+ useEventEmitter("pointermove", withTooltips ? handlePointer : void 0);
5614
+ useEventEmitter("pointerdown", handlePointer);
5615
+ useEventEmitter("pointerup", onPointerUp ? handlePointer : void 0);
5616
+ return null;
5617
+ }
5618
+ //#endregion
5407
5619
  //#region src/charts/bar-chart/bar-chart.tsx
5408
5620
  const validateData$2 = (data) => {
5409
5621
  if (!data?.length) return "No data available";
@@ -5415,7 +5627,7 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ jsx("div", {
5415
5627
  className: bar_chart_module_default["bar-chart__tooltip-row"],
5416
5628
  children: sprintf(__("%1$s: %2$s", "jetpack-charts"), label, value)
5417
5629
  });
5418
- const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
5630
+ const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
5419
5631
  const legendInteractive = legend.interactive ?? false;
5420
5632
  const legendCollapseGroups = legend.collapseGroups ?? false;
5421
5633
  const horizontal = orientation === "horizontal";
@@ -5441,8 +5653,6 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5441
5653
  }, [height]);
5442
5654
  const [selectedIndex, setSelectedIndex] = useState(void 0);
5443
5655
  const [isNavigating, setIsNavigating] = useState(false);
5444
- const primarySeriesForNav = dataWithVisibleZeros.filter((s) => s.options?.type !== "comparison");
5445
- const totalPoints = Math.max(0, ...primarySeriesForNav.map((s) => s.data?.length || 0)) * primarySeriesForNav.length;
5446
5656
  const seriesWithVisibility = useMemo(() => dataWithVisibleZeros.map((series, index) => ({
5447
5657
  series,
5448
5658
  index,
@@ -5452,6 +5662,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5452
5662
  return seriesWithVisibility.every(({ isVisible }) => !isVisible);
5453
5663
  }, [seriesWithVisibility]);
5454
5664
  const primaryEntries = useMemo(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
5665
+ const totalPoints = Math.max(0, ...primaryEntries.map((e) => e.series.data.length)) * primaryEntries.length;
5455
5666
  const primaryKeys = useMemo(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
5456
5667
  const primarySeries = useMemo(() => primaryEntries.map(({ series }) => series), [primaryEntries]);
5457
5668
  const activateSelectedBar = useCallback((index) => {
@@ -5466,6 +5677,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5466
5677
  key: series.label
5467
5678
  });
5468
5679
  }, [primaryEntries, onDatumActivate]);
5680
+ const visibleSeriesKey = useMemo(() => JSON.stringify(primaryKeys), [primaryKeys]);
5469
5681
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
5470
5682
  selectedIndex,
5471
5683
  setSelectedIndex,
@@ -5473,7 +5685,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5473
5685
  setIsNavigating,
5474
5686
  chartRef,
5475
5687
  totalPoints,
5476
- onActivate: activateSelectedBar
5688
+ onActivate: activateSelectedBar,
5689
+ visibleSeriesKey
5477
5690
  });
5478
5691
  const comparisonEntries = useMemo(() => {
5479
5692
  const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
@@ -5536,7 +5749,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5536
5749
  chartOptions.yScale,
5537
5750
  horizontal
5538
5751
  ]);
5539
- const getBarBackground = useCallback((index) => () => withPatterns ? `url(#${getPatternId(chartId, index)})` : getElementStyles({
5752
+ const getBarBackground = useCallback((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? getElementStyles({
5540
5753
  data: dataSorted[index],
5541
5754
  index
5542
5755
  }).color, [
@@ -5706,13 +5919,13 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5706
5919
  const chartHeight = contentHeight > 0 ? contentHeight : height;
5707
5920
  return /* @__PURE__ */ jsx("div", {
5708
5921
  role: "grid",
5922
+ ref: chartRef,
5709
5923
  "aria-label": __("Bar chart", "jetpack-charts"),
5710
5924
  tabIndex: 0,
5711
5925
  onKeyDown: onChartKeyDown,
5712
5926
  onFocus: onChartFocus,
5713
5927
  onBlur: onChartBlur,
5714
5928
  children: chartHeight > 0 && /* @__PURE__ */ jsx("div", {
5715
- ref: chartRef,
5716
5929
  className: xy_plot_module_default["xy-plot"],
5717
5930
  children: /* @__PURE__ */ jsxs(XYChart, {
5718
5931
  theme,
@@ -5725,15 +5938,24 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5725
5938
  xScale,
5726
5939
  yScale,
5727
5940
  horizontal,
5728
- onPointerDown,
5729
- onPointerUp,
5730
5941
  pointerEventsDataKey: "nearest",
5731
5942
  children: [
5732
- !allSeriesHidden && /* @__PURE__ */ jsx(Grid, {
5943
+ withTooltips && (withBandHighlight || onBandHighlightChange) && /* @__PURE__ */ jsx(BandHighlight, {
5944
+ visible: withBandHighlight,
5945
+ horizontal,
5946
+ onChange: onBandHighlightChange
5947
+ }),
5948
+ !allSeriesHidden && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Grid, {
5733
5949
  columns: gridVisibility.includes("y"),
5950
+ rows: false,
5951
+ numTicks: 4,
5952
+ tickValues: chartOptions.axis.x.tickValues
5953
+ }), /* @__PURE__ */ jsx(Grid, {
5954
+ columns: false,
5734
5955
  rows: gridVisibility.includes("x"),
5735
- numTicks: 4
5736
- }),
5956
+ numTicks: 4,
5957
+ tickValues: chartOptions.axis.y.tickValues
5958
+ })] }),
5737
5959
  withPatterns && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("defs", { children: dataSorted.map((seriesData, index) => renderPattern(index, getElementStyles({
5738
5960
  data: seriesData,
5739
5961
  index
@@ -5769,8 +5991,17 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
5769
5991
  colorAccessor: getBarBackground(index)
5770
5992
  }, seriesData?.label))
5771
5993
  }),
5994
+ (withTooltips || onPointerDown || onPointerUp) && /* @__PURE__ */ jsx(BandTooltip, {
5995
+ keys: primaryKeys,
5996
+ groupPadding,
5997
+ withTooltips,
5998
+ onPointerDown,
5999
+ onPointerUp
6000
+ }),
5772
6001
  !allSeriesHidden && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.x }), /* @__PURE__ */ jsx(Axis, { ...chartOptions.axis.y })] }),
5773
6002
  withTooltips && /* @__PURE__ */ jsx(AccessibleTooltip, {
6003
+ tooltipPlacement,
6004
+ tooltipAnchorTop,
5774
6005
  detectBounds: true,
5775
6006
  snapTooltipToDatumX: true,
5776
6007
  snapTooltipToDatumY: true,
@@ -6592,8 +6823,11 @@ var heatmap_chart_module_default = {
6592
6823
  "heatmap-chart__gap-start": "a8ccharts-O3YMOW-heatmap-chart__gap-start",
6593
6824
  "heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
6594
6825
  "heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
6826
+ "heatmap-chart__grid--flex-gaps": "a8ccharts-O3YMOW-heatmap-chart__grid--flex-gaps",
6595
6827
  "heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
6828
+ "heatmap-chart__group-label": "a8ccharts-O3YMOW-heatmap-chart__group-label",
6596
6829
  "heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
6830
+ "heatmap-chart__legend-scale--bar": "a8ccharts-O3YMOW-heatmap-chart__legend-scale--bar",
6597
6831
  "heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
6598
6832
  "heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
6599
6833
  "heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
@@ -6643,7 +6877,7 @@ const getNormalizedValue = (value, extent) => {
6643
6877
  const HeatmapContext = createContext(null);
6644
6878
  //#endregion
6645
6879
  //#region src/charts/heatmap-chart/private/heatmap-legend.tsx
6646
- const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
6880
+ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }) => {
6647
6881
  const context = useContext(HeatmapContext);
6648
6882
  const { legend } = useGlobalChartsTheme();
6649
6883
  if (!context) return null;
@@ -6662,11 +6896,12 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
6662
6896
  }),
6663
6897
  /* @__PURE__ */ jsx(Stack, {
6664
6898
  direction: "row",
6665
- gap: "xs",
6899
+ gap: variant === "bar" ? void 0 : "xs",
6900
+ "aria-hidden": "true",
6901
+ className: variant === "bar" ? heatmap_chart_module_default["heatmap-chart__legend-scale--bar"] : void 0,
6666
6902
  children: Array.from({ length: steps }, (_, index) => {
6667
6903
  const intensity = steps <= 1 ? 1 : index / (steps - 1);
6668
6904
  return /* @__PURE__ */ jsx("span", {
6669
- "aria-hidden": "true",
6670
6905
  className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
6671
6906
  style: {
6672
6907
  "--a8c-charts-color-heatmap-primary": primaryColorHex,
@@ -6685,16 +6920,219 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
6685
6920
  });
6686
6921
  };
6687
6922
  //#endregion
6923
+ //#region src/charts/heatmap-chart/private/column-groups.ts
6924
+ const isSpan = (span) => Number.isInteger(span) && span > 0;
6925
+ /**
6926
+ * Validates column groups and lays them over the columns.
6927
+ *
6928
+ * @param groups - Groups as passed to the chart.
6929
+ * @param columnCount - Number of data columns.
6930
+ * @param firstLine - Grid column line of the first data column.
6931
+ * @return Grid column lines for every column and group; no groups when the input was unusable.
6932
+ */
6933
+ const resolveColumnGroups = (groups, columnCount, firstLine) => {
6934
+ const ungrouped = () => ({
6935
+ columns: Array.from({ length: columnCount }, (_, index) => ({
6936
+ line: firstLine + index,
6937
+ gapBefore: false
6938
+ })),
6939
+ groups: []
6940
+ });
6941
+ if (!groups || groups.length === 0 || columnCount === 0) return ungrouped();
6942
+ const spans = groups.map((group) => group.span);
6943
+ const total = spans.reduce((sum, span) => sum + span, 0);
6944
+ if (!spans.every(isSpan) || total > columnCount) {
6945
+ warnOnce(`heatmap:columnGroups:${JSON.stringify(spans)}:${columnCount}`, `columnGroups spans ${JSON.stringify(spans)} must be positive integers that fit the ${columnCount} columns, so no groups are drawn.`);
6946
+ return ungrouped();
6947
+ }
6948
+ const columns = [];
6949
+ const laidOut = [];
6950
+ let line = firstLine;
6951
+ groups.forEach((group, groupIndex) => {
6952
+ if (groupIndex > 0) line += 1;
6953
+ laidOut.push({
6954
+ ...group,
6955
+ line
6956
+ });
6957
+ for (let offset = 0; offset < group.span; offset++) {
6958
+ columns.push({
6959
+ line,
6960
+ gapBefore: groupIndex > 0 && offset === 0,
6961
+ group: groupIndex
6962
+ });
6963
+ line += 1;
6964
+ }
6965
+ });
6966
+ while (columns.length < columnCount) {
6967
+ columns.push({
6968
+ line,
6969
+ gapBefore: false
6970
+ });
6971
+ line += 1;
6972
+ }
6973
+ return {
6974
+ columns,
6975
+ groups: laidOut
6976
+ };
6977
+ };
6978
+ //#endregion
6979
+ //#region src/charts/heatmap-chart/private/keyboard-navigation.ts
6980
+ const ARROW_KEYS = [
6981
+ "ArrowLeft",
6982
+ "ArrowRight",
6983
+ "ArrowUp",
6984
+ "ArrowDown"
6985
+ ];
6986
+ const PAGE_KEYS = ["PageUp", "PageDown"];
6987
+ const isNavigationKey = (key, mode) => ARROW_KEYS.includes(key) || mode === "calendar" && PAGE_KEYS.includes(key);
6988
+ const inGrid = (grid, { column, row }) => column >= 0 && column < grid.columns && row >= 0 && row < grid.rows;
6989
+ const firstSelectable = (grid, cells) => cells.find((cell) => inGrid(grid, cell) && !grid.isInert(cell.column, cell.row));
6990
+ /**
6991
+ * Column-major scan for the first selectable cell.
6992
+ *
6993
+ * @param grid - The grid.
6994
+ * @return The cell, or undefined when every slot is inert.
6995
+ */
6996
+ const firstGridCell = (grid) => {
6997
+ for (let column = 0; column < grid.columns; column++) for (let row = 0; row < grid.rows; row++) if (!grid.isInert(column, row)) return {
6998
+ column,
6999
+ row
7000
+ };
7001
+ };
7002
+ /**
7003
+ * Steps across the grid in the key's direction, past inert slots, staying put at the edge.
7004
+ *
7005
+ * @param grid - The grid.
7006
+ * @param from - The selected cell.
7007
+ * @param key - The arrow key.
7008
+ * @return The next cell, or undefined to keep the selection.
7009
+ */
7010
+ const stepGridCell = (grid, from, key) => {
7011
+ const step = {
7012
+ ArrowRight: [1, 0],
7013
+ ArrowLeft: [-1, 0],
7014
+ ArrowDown: [0, 1],
7015
+ ArrowUp: [0, -1]
7016
+ }[key];
7017
+ if (!step) return;
7018
+ const [stepColumn, stepRow] = step;
7019
+ let cell = from;
7020
+ do
7021
+ cell = {
7022
+ column: cell.column + stepColumn,
7023
+ row: cell.row + stepRow
7024
+ };
7025
+ while (inGrid(grid, cell) && grid.isInert(cell.column, cell.row));
7026
+ return inGrid(grid, cell) ? cell : void 0;
7027
+ };
7028
+ /**
7029
+ * Every slot of the blocks in reading order: block by block, each a row at a time.
7030
+ *
7031
+ * @param grid - The grid.
7032
+ * @param blocks - The blocks, left to right.
7033
+ * @return The slots in order.
7034
+ */
7035
+ const readingOrder = (grid, blocks) => blocks.flatMap((block) => Array.from({ length: grid.rows }, (_row, row) => Array.from({ length: block.end - block.start }, (_offset, offset) => ({
7036
+ column: block.start + offset,
7037
+ row
7038
+ }))).flat());
7039
+ const blockOf = (blocks, column) => blocks.findIndex((block) => column >= block.start && column < block.end);
7040
+ /**
7041
+ * The slots after a cell down its column (or before it, going up), continuing at the
7042
+ * same column offset of each following block.
7043
+ *
7044
+ * @param grid - The grid.
7045
+ * @param blocks - The blocks, left to right.
7046
+ * @param from - The selected cell.
7047
+ * @param direction - 1 downwards, -1 upwards.
7048
+ * @return The slots in order.
7049
+ */
7050
+ const columnOrderFrom = (grid, blocks, from, direction) => {
7051
+ const blockIndex = blockOf(blocks, from.column);
7052
+ if (blockIndex < 0) return [];
7053
+ const offset = from.column - blocks[blockIndex].start;
7054
+ const cells = [];
7055
+ const pushRows = (column, startRow) => {
7056
+ for (let row = startRow; row >= 0 && row < grid.rows; row += direction) cells.push({
7057
+ column,
7058
+ row
7059
+ });
7060
+ };
7061
+ pushRows(from.column, from.row + direction);
7062
+ for (let index = blockIndex + direction; index >= 0 && index < blocks.length; index += direction) {
7063
+ const column = blocks[index].start + offset;
7064
+ if (column < blocks[index].end) pushRows(column, direction === 1 ? 0 : grid.rows - 1);
7065
+ }
7066
+ return cells;
7067
+ };
7068
+ /**
7069
+ * The first selectable cell in calendar reading order.
7070
+ *
7071
+ * @param grid - The grid.
7072
+ * @param blocks - The blocks, left to right.
7073
+ * @return The cell, or undefined when every slot is inert.
7074
+ */
7075
+ const firstCalendarCell = (grid, blocks) => firstSelectable(grid, readingOrder(grid, blocks));
7076
+ /**
7077
+ * Steps through the blocks as pages of a calendar: Left/Right by one slot in reading
7078
+ * order, Up/Down by one row (into the neighboring block past the edge), Page Up/Down
7079
+ * to the same slot of the neighboring block or its nearest selectable cell.
7080
+ *
7081
+ * @param grid - The grid.
7082
+ * @param blocks - The blocks, left to right.
7083
+ * @param from - The selected cell.
7084
+ * @param key - The navigation key.
7085
+ * @return The next cell, or undefined to keep the selection.
7086
+ */
7087
+ const stepCalendarCell = (grid, blocks, from, key) => {
7088
+ if (key === "ArrowRight" || key === "ArrowLeft") {
7089
+ const order = readingOrder(grid, blocks);
7090
+ const index = order.findIndex((cell) => cell.column === from.column && cell.row === from.row);
7091
+ if (index < 0) return;
7092
+ const ahead = key === "ArrowRight" ? order.slice(index + 1) : order.slice(0, index).reverse();
7093
+ return firstSelectable(grid, ahead);
7094
+ }
7095
+ if (key === "ArrowDown" || key === "ArrowUp") return firstSelectable(grid, columnOrderFrom(grid, blocks, from, key === "ArrowDown" ? 1 : -1));
7096
+ const blockIndex = blockOf(blocks, from.column);
7097
+ const target = blocks[blockIndex + (key === "PageDown" ? 1 : -1)];
7098
+ if (blockIndex < 0 || !target) return;
7099
+ const same = {
7100
+ column: target.start + (from.column - blocks[blockIndex].start),
7101
+ row: from.row
7102
+ };
7103
+ const page = readingOrder(grid, [target]);
7104
+ const at = page.findIndex((cell) => cell.row > same.row || cell.row === same.row && cell.column >= same.column);
7105
+ const after = at === -1 ? [] : page.slice(at);
7106
+ const before = page.slice(0, at === -1 ? page.length : at).reverse();
7107
+ return firstSelectable(grid, after) ?? firstSelectable(grid, before);
7108
+ };
7109
+ //#endregion
6688
7110
  //#region src/charts/heatmap-chart/heatmap-chart.tsx
6689
7111
  const CELL_MIX_FLOOR = .15;
6690
7112
  const NO_ROW_LABELS = [];
6691
- const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, primaryColor, gap = "md", withTooltips = false, renderTooltip, children }) => {
7113
+ const TOOLTIP_BOX_STYLES = {
7114
+ light: {
7115
+ ...defaultStyles,
7116
+ zIndex: 3
7117
+ },
7118
+ dark: { zIndex: 3 }
7119
+ };
7120
+ const cellName = (info) => info.cellLabel || [
7121
+ info.groupLabel,
7122
+ info.columnLabel,
7123
+ info.rowLabel
7124
+ ].filter(Boolean).join(" ");
7125
+ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, columnGroups, keyboardNavigation = "grid", ariaLabel, primaryColor, gap = "md", withTooltips = false, renderTooltip, tooltipVariant = "light", tooltipStyle, children }) => {
6692
7126
  const chartId = useChartId(providedChartId);
7127
+ const tooltipBoxStyle = tooltipStyle ? {
7128
+ ...TOOLTIP_BOX_STYLES[tooltipVariant],
7129
+ ...tooltipStyle
7130
+ } : TOOLTIP_BOX_STYLES[tooltipVariant];
6693
7131
  const { getElementStyles, theme } = useGlobalChartsContext();
6694
7132
  const scopeElement = useChartScopeElement();
6695
7133
  const { heatmapChart: heatmapChartSettings } = theme;
6696
7134
  const { nonLegendChildren } = useChartChildren(children, "HeatmapChart");
6697
- const [selectedIndex, setSelectedIndex] = useState();
7135
+ const [selected, setSelected] = useState();
6698
7136
  const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = useTooltip();
6699
7137
  const standaloneScopeClass = useStandaloneScopeClass();
6700
7138
  const containerRef = useRef(null);
@@ -6713,69 +7151,75 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6713
7151
  }), [extent, primaryColorHex]);
6714
7152
  const columns = data.length;
6715
7153
  const rows = Math.max(0, ...data.map((column) => column.data.length));
6716
- const { compactCellGap, compactCellSize } = heatmapChartSettings;
7154
+ const groupLayout = useMemo(() => resolveColumnGroups(columnGroups, columns, 2), [columnGroups, columns]);
7155
+ const { compactCellGap, compactCellSize, groupGap } = heatmapChartSettings;
6717
7156
  const drawValues = showValues ?? !compact;
6718
7157
  const buildTooltipData = useCallback((columnIndex, rowIndex) => {
6719
7158
  const cell = data[columnIndex]?.data[rowIndex];
7159
+ const group = groupLayout.columns[columnIndex]?.group;
6720
7160
  return {
6721
7161
  value: cell?.value ?? null,
6722
7162
  rowLabel: rowLabels[rowIndex],
6723
7163
  columnLabel: data[columnIndex]?.label,
7164
+ groupLabel: group === void 0 ? void 0 : groupLayout.groups[group]?.label,
6724
7165
  cellLabel: cell?.label,
6725
7166
  row: rowIndex,
6726
7167
  column: columnIndex
6727
7168
  };
6728
- }, [data, rowLabels]);
7169
+ }, [
7170
+ data,
7171
+ rowLabels,
7172
+ groupLayout
7173
+ ]);
6729
7174
  const onChartBlur = useCallback(() => {
6730
- setSelectedIndex(void 0);
7175
+ setSelected(void 0);
6731
7176
  hideTooltip();
6732
7177
  }, [hideTooltip]);
6733
7178
  const isCellInert = useCallback((col, row) => {
6734
7179
  const cell = data[col]?.data[row];
6735
7180
  return cell?.hidden === true || cell?.placeholder === true;
6736
7181
  }, [data]);
7182
+ const blocks = useMemo(() => {
7183
+ const grouped = groupLayout.groups.map((group, index) => {
7184
+ const start = groupLayout.columns.findIndex((column) => column.group === index);
7185
+ return {
7186
+ start,
7187
+ end: start + group.span
7188
+ };
7189
+ });
7190
+ const groupedEnd = grouped.length ? grouped[grouped.length - 1].end : 0;
7191
+ return groupedEnd < columns ? [...grouped, {
7192
+ start: groupedEnd,
7193
+ end: columns
7194
+ }] : grouped;
7195
+ }, [groupLayout, columns]);
6737
7196
  const onChartKeyDown = useCallback((event) => {
6738
- if (![
6739
- "ArrowLeft",
6740
- "ArrowRight",
6741
- "ArrowUp",
6742
- "ArrowDown",
6743
- "Escape",
6744
- "Tab"
6745
- ].includes(event.key)) return;
6746
7197
  if (event.key === "Tab" || event.key === "Escape") {
6747
- setSelectedIndex(void 0);
7198
+ setSelected(void 0);
6748
7199
  hideTooltip();
6749
7200
  return;
6750
7201
  }
7202
+ if (!isNavigationKey(event.key, keyboardNavigation)) return;
6751
7203
  event.preventDefault();
6752
- if (selectedIndex === void 0) {
6753
- for (let index = 0; index < columns * rows; index++) if (!isCellInert(Math.floor(index / rows), index % rows)) {
6754
- setSelectedIndex(index);
6755
- return;
6756
- }
7204
+ const grid = {
7205
+ columns,
7206
+ rows,
7207
+ isInert: isCellInert
7208
+ };
7209
+ if (selected === void 0) {
7210
+ setSelected(keyboardNavigation === "calendar" ? firstCalendarCell(grid, blocks) : firstGridCell(grid));
6757
7211
  return;
6758
7212
  }
6759
- let stepCol = 0;
6760
- let stepRow = 0;
6761
- if (event.key === "ArrowRight") stepCol = 1;
6762
- else if (event.key === "ArrowLeft") stepCol = -1;
6763
- else if (event.key === "ArrowDown") stepRow = 1;
6764
- else if (event.key === "ArrowUp") stepRow = -1;
6765
- let col = Math.floor(selectedIndex / rows);
6766
- let row = selectedIndex % rows;
6767
- do {
6768
- col += stepCol;
6769
- row += stepRow;
6770
- } while (col >= 0 && col < columns && row >= 0 && row < rows && isCellInert(col, row));
6771
- if (col < 0 || col >= columns || row < 0 || row >= rows) return;
6772
- setSelectedIndex(col * rows + row);
7213
+ const next = keyboardNavigation === "calendar" ? stepCalendarCell(grid, blocks, selected, event.key) : stepGridCell(grid, selected, event.key);
7214
+ if (next) setSelected(next);
6773
7215
  }, [
6774
7216
  rows,
6775
7217
  columns,
6776
- selectedIndex,
7218
+ selected,
6777
7219
  hideTooltip,
6778
- isCellInert
7220
+ isCellInert,
7221
+ keyboardNavigation,
7222
+ blocks
6779
7223
  ]);
6780
7224
  const handleCellMouseMove = useCallback((event) => {
6781
7225
  if (!withTooltips) return;
@@ -6795,35 +7239,47 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6795
7239
  buildTooltipData,
6796
7240
  getTooltipOrigin
6797
7241
  ]);
7242
+ const getCellElement = useCallback((col, row) => typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null, [chartId]);
6798
7243
  const handleCellMouseLeave = useCallback(() => {
6799
- if (withTooltips && selectedIndex === void 0) hideTooltip();
7244
+ if (withTooltips && selected === void 0) hideTooltip();
6800
7245
  }, [
6801
7246
  withTooltips,
6802
- selectedIndex,
7247
+ selected,
6803
7248
  hideTooltip
6804
7249
  ]);
6805
7250
  useEffect(() => {
6806
- if (!withTooltips || selectedIndex === void 0) return;
7251
+ if (selected && (selected.column >= columns || selected.row >= rows)) setSelected(void 0);
7252
+ }, [
7253
+ selected,
7254
+ columns,
7255
+ rows
7256
+ ]);
7257
+ useEffect(() => {
7258
+ if (selected === void 0) return;
7259
+ getCellElement(selected.column, selected.row)?.scrollIntoView?.({
7260
+ block: "nearest",
7261
+ inline: "nearest"
7262
+ });
7263
+ }, [selected, getCellElement]);
7264
+ useEffect(() => {
7265
+ if (!withTooltips || selected === void 0) return;
6807
7266
  const origin = getTooltipOrigin();
6808
7267
  if (!origin) return;
6809
- const col = Math.floor(selectedIndex / rows);
6810
- const row = selectedIndex % rows;
6811
- const rect = (typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null)?.getBoundingClientRect();
7268
+ const rect = getCellElement(selected.column, selected.row)?.getBoundingClientRect();
6812
7269
  showTooltip({
6813
7270
  tooltipLeft: rect ? rect.left + rect.width / 2 - origin.left : 0,
6814
7271
  tooltipTop: rect ? rect.top + rect.height / 2 - origin.top : 0,
6815
- tooltipData: buildTooltipData(col, row)
7272
+ tooltipData: buildTooltipData(selected.column, selected.row)
6816
7273
  });
6817
7274
  }, [
6818
- selectedIndex,
7275
+ selected,
6819
7276
  withTooltips,
6820
- rows,
6821
- chartId,
7277
+ getCellElement,
6822
7278
  buildTooltipData,
6823
7279
  showTooltip,
6824
7280
  getTooltipOrigin
6825
7281
  ]);
6826
- const defaultRenderTooltip = useCallback((info) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: info.cellLabel || `${info.columnLabel ?? ""} ${info.rowLabel ?? ""}`.trim() }), /* @__PURE__ */ jsx("div", { children: info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value) })] }), []);
7282
+ const defaultRenderTooltip = useCallback((info) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: cellName(info) }), /* @__PURE__ */ jsx("div", { children: info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value) })] }), []);
6827
7283
  if (!columns || !rows) return /* @__PURE__ */ jsx(Center, {
6828
7284
  className: clsx("heatmap-chart", heatmap_chart_module_default["heatmap-chart"], className),
6829
7285
  style: {
@@ -6837,10 +7293,16 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6837
7293
  });
6838
7294
  const columnTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellWidth ?? 0}px, ${maxCellWidth ? `${maxCellWidth}px` : "1fr"})`;
6839
7295
  const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
7296
+ const hasColumnLabels = data.some((column) => Boolean(column.label));
7297
+ const hasGroups = groupLayout.groups.length > 0;
7298
+ const columnLine = (columnIndex) => groupLayout.columns[columnIndex].line;
7299
+ const firstDataRow = hasColumnLabels ? 2 : 1;
7300
+ const dataTrack = (column) => column.summary ? "minmax(auto, max-content)" : columnTrack;
7301
+ const gapTrack = compact ? `minmax(${groupGap}px, 1fr)` : `${groupGap}px`;
6840
7302
  const gridStyle = {
6841
7303
  "--a8c-charts-color-heatmap-primary": primaryColorHex,
6842
- gridTemplateColumns: `auto ${data.some((column) => column.summary) ? data.map((column) => column.summary ? "minmax(auto, max-content)" : columnTrack).join(" ") : `repeat(${columns}, ${columnTrack})`}`,
6843
- gridTemplateRows: `auto repeat(${rows}, ${rowTrack})`
7304
+ gridTemplateColumns: `auto ${data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ")}`,
7305
+ gridTemplateRows: `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`
6844
7306
  };
6845
7307
  if (compact) {
6846
7308
  gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
@@ -6853,7 +7315,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6853
7315
  [heatmap_chart_module_default["heatmap-chart__gap-end"]]: columnIndex < columns - 1 && !data[columnIndex + 1]?.summary
6854
7316
  };
6855
7317
  };
6856
- const activeDescendant = selectedIndex !== void 0 ? `${chartId}-cell-${Math.floor(selectedIndex / rows)}-${selectedIndex % rows}` : void 0;
7318
+ const activeDescendant = selected ? `${chartId}-cell-${selected.column}-${selected.row}` : void 0;
6857
7319
  const heightCapped = !compact && Boolean(maxCellHeight);
6858
7320
  return /* @__PURE__ */ jsx(HeatmapContext.Provider, {
6859
7321
  value: heatmapContext,
@@ -6873,7 +7335,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6873
7335
  children: [/* @__PURE__ */ jsxs("div", {
6874
7336
  ref: containerRef,
6875
7337
  role: "grid",
6876
- "aria-label": __("Heatmap chart", "jetpack-charts"),
7338
+ "aria-label": ariaLabel ?? __("Heatmap chart", "jetpack-charts"),
6877
7339
  "aria-rowcount": rows,
6878
7340
  "aria-colcount": columns,
6879
7341
  "aria-activedescendant": activeDescendant,
@@ -6882,76 +7344,115 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6882
7344
  onKeyDown: onChartKeyDown,
6883
7345
  className: clsx(heatmap_chart_module_default["heatmap-chart__grid"], {
6884
7346
  [heatmap_chart_module_default["heatmap-chart__grid--compact"]]: compact,
7347
+ [heatmap_chart_module_default["heatmap-chart__grid--flex-gaps"]]: compact && hasGroups,
6885
7348
  [heatmap_chart_module_default["heatmap-chart__grid--height-capped"]]: heightCapped
6886
7349
  }),
6887
7350
  style: gridStyle,
6888
- children: [/* @__PURE__ */ jsxs("div", {
6889
- role: "row",
6890
- "aria-hidden": "true",
6891
- className: heatmap_chart_module_default["heatmap-chart__row"],
6892
- children: [/* @__PURE__ */ jsx("span", {}), data.map((column, columnIndex) => /* @__PURE__ */ jsx("span", {
6893
- className: clsx(heatmap_chart_module_default["heatmap-chart__col-label"], {
6894
- [heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
6895
- ...summaryGaps(columnIndex)
6896
- }),
6897
- children: column.label
6898
- }, `col-${columnIndex}`))]
6899
- }), Array.from({ length: rows }).map((_row, rowIndex) => {
6900
- const labelVisible = !compact || rowIndex % 2 === 0;
6901
- return /* @__PURE__ */ jsxs("div", {
7351
+ children: [
7352
+ hasColumnLabels && /* @__PURE__ */ jsxs("div", {
6902
7353
  role: "row",
6903
- "aria-rowindex": rowIndex + 1,
7354
+ "aria-hidden": "true",
6904
7355
  className: heatmap_chart_module_default["heatmap-chart__row"],
6905
- children: [/* @__PURE__ */ jsx("span", {
6906
- "aria-hidden": "true",
6907
- className: heatmap_chart_module_default["heatmap-chart__row-label"],
6908
- children: labelVisible ? rowLabels[rowIndex] ?? "" : ""
6909
- }), data.map((column, columnIndex) => {
6910
- const cell = column.data[rowIndex];
6911
- if (cell?.hidden) return /* @__PURE__ */ jsx("div", {
6912
- "aria-hidden": "true",
6913
- className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--hidden"])
6914
- }, `cell-${columnIndex}-${rowIndex}`);
6915
- if (cell?.placeholder) return /* @__PURE__ */ jsx("div", {
7356
+ children: [/* @__PURE__ */ jsx("span", { style: {
7357
+ gridColumn: 1,
7358
+ gridRow: 1
7359
+ } }), data.map((column, columnIndex) => /* @__PURE__ */ jsx("span", {
7360
+ style: {
7361
+ gridColumn: columnLine(columnIndex),
7362
+ gridRow: 1
7363
+ },
7364
+ className: clsx(heatmap_chart_module_default["heatmap-chart__col-label"], {
7365
+ [heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
7366
+ ...summaryGaps(columnIndex)
7367
+ }),
7368
+ children: column.label
7369
+ }, `col-${columnIndex}`))]
7370
+ }),
7371
+ Array.from({ length: rows }).map((_row, rowIndex) => {
7372
+ const labelVisible = !compact || rowIndex % 2 === 0;
7373
+ const gridRow = firstDataRow + rowIndex;
7374
+ return /* @__PURE__ */ jsxs("div", {
7375
+ role: "row",
7376
+ "aria-rowindex": rowIndex + 1,
7377
+ className: heatmap_chart_module_default["heatmap-chart__row"],
7378
+ children: [/* @__PURE__ */ jsx("span", {
6916
7379
  "aria-hidden": "true",
6917
- className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--placeholder"])
6918
- }, `cell-${columnIndex}-${rowIndex}`);
6919
- const value = cell?.value ?? null;
6920
- const present = isPresent(value);
6921
- const filled = present && !column.summary;
6922
- const normalized = filled ? getNormalizedValue(value, extent) : 0;
6923
- const flatIndex = columnIndex * rows + rowIndex;
6924
- const info = buildTooltipData(columnIndex, rowIndex);
6925
- const accessibleLabel = `${info.cellLabel || `${info.columnLabel ?? ""} ${info.rowLabel ?? ""}`.trim()}: ${info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value)}`;
6926
- return /* @__PURE__ */ jsx("div", {
6927
- id: `${chartId}-cell-${columnIndex}-${rowIndex}`,
6928
- role: "gridcell",
6929
- tabIndex: -1,
6930
- "aria-colindex": columnIndex + 1,
6931
- "aria-label": accessibleLabel,
6932
- "data-column": columnIndex,
6933
- "data-row": rowIndex,
6934
- className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], {
6935
- [heatmap_chart_module_default["heatmap-chart__cell--filled"]]: filled,
6936
- [heatmap_chart_module_default["heatmap-chart__cell--strong"]]: filled && cellHasLightText(normalized),
6937
- [heatmap_chart_module_default["heatmap-chart__cell--summary"]]: column.summary,
6938
- ...summaryGaps(columnIndex),
6939
- [heatmap_chart_module_default["heatmap-chart__cell--selected"]]: selectedIndex === flatIndex
6940
- }),
6941
- style: filled ? { "--a8c-charts-heatmap-cell-intensity": normalized } : void 0,
6942
- onMouseMove: handleCellMouseMove,
6943
- onMouseLeave: handleCellMouseLeave,
6944
- children: (drawValues || column.summary) && present && /* @__PURE__ */ jsx("span", {
6945
- className: heatmap_chart_module_default["heatmap-chart__cell-value"],
6946
- children: formatNumberCompact(value)
6947
- })
6948
- }, `cell-${columnIndex}-${rowIndex}`);
6949
- })]
6950
- }, `row-${rowIndex}`);
6951
- })]
7380
+ className: heatmap_chart_module_default["heatmap-chart__row-label"],
7381
+ style: {
7382
+ gridColumn: 1,
7383
+ gridRow
7384
+ },
7385
+ children: labelVisible ? rowLabels[rowIndex] ?? "" : ""
7386
+ }), data.map((column, columnIndex) => {
7387
+ const cell = column.data[rowIndex];
7388
+ const placement = {
7389
+ gridColumn: columnLine(columnIndex),
7390
+ gridRow
7391
+ };
7392
+ if (cell?.hidden) return /* @__PURE__ */ jsx("div", {
7393
+ "aria-hidden": "true",
7394
+ style: placement,
7395
+ className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--hidden"])
7396
+ }, `cell-${columnIndex}-${rowIndex}`);
7397
+ if (cell?.placeholder) return /* @__PURE__ */ jsx("div", {
7398
+ "aria-hidden": "true",
7399
+ style: placement,
7400
+ className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--placeholder"])
7401
+ }, `cell-${columnIndex}-${rowIndex}`);
7402
+ const value = cell?.value ?? null;
7403
+ const present = isPresent(value);
7404
+ const filled = present && !column.summary;
7405
+ const normalized = filled ? getNormalizedValue(value, extent) : 0;
7406
+ const info = buildTooltipData(columnIndex, rowIndex);
7407
+ const accessibleLabel = `${cellName(info)}: ${info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value)}`;
7408
+ return /* @__PURE__ */ jsx("div", {
7409
+ id: `${chartId}-cell-${columnIndex}-${rowIndex}`,
7410
+ role: "gridcell",
7411
+ tabIndex: -1,
7412
+ "aria-colindex": columnIndex + 1,
7413
+ "aria-label": accessibleLabel,
7414
+ "data-column": columnIndex,
7415
+ "data-row": rowIndex,
7416
+ className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], {
7417
+ [heatmap_chart_module_default["heatmap-chart__cell--filled"]]: filled,
7418
+ [heatmap_chart_module_default["heatmap-chart__cell--strong"]]: filled && cellHasLightText(normalized),
7419
+ [heatmap_chart_module_default["heatmap-chart__cell--summary"]]: column.summary,
7420
+ ...summaryGaps(columnIndex),
7421
+ [heatmap_chart_module_default["heatmap-chart__cell--selected"]]: selected?.column === columnIndex && selected?.row === rowIndex
7422
+ }),
7423
+ style: {
7424
+ ...placement,
7425
+ ...filled ? { "--a8c-charts-heatmap-cell-intensity": normalized } : {}
7426
+ },
7427
+ onMouseMove: handleCellMouseMove,
7428
+ onMouseLeave: handleCellMouseLeave,
7429
+ children: (drawValues || column.summary) && present && /* @__PURE__ */ jsx("span", {
7430
+ className: heatmap_chart_module_default["heatmap-chart__cell-value"],
7431
+ children: formatNumberCompact(value)
7432
+ })
7433
+ }, `cell-${columnIndex}-${rowIndex}`);
7434
+ })]
7435
+ }, `row-${rowIndex}`);
7436
+ }),
7437
+ hasGroups && /* @__PURE__ */ jsx("div", {
7438
+ role: "row",
7439
+ "aria-hidden": "true",
7440
+ className: heatmap_chart_module_default["heatmap-chart__row"],
7441
+ children: groupLayout.groups.map((group, groupIndex) => /* @__PURE__ */ jsx("span", {
7442
+ className: heatmap_chart_module_default["heatmap-chart__group-label"],
7443
+ style: {
7444
+ gridColumn: `${group.line} / span ${group.span}`,
7445
+ gridRow: firstDataRow + rows
7446
+ },
7447
+ children: group.label
7448
+ }, `group-${groupIndex}`))
7449
+ })
7450
+ ]
6952
7451
  }), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
6953
7452
  top: tooltipTop,
6954
7453
  left: tooltipLeft,
7454
+ className: tooltipVariant === "dark" ? base_tooltip_module_default.surface : void 0,
7455
+ style: tooltipBoxStyle,
6955
7456
  children: /* @__PURE__ */ jsx("div", {
6956
7457
  className: standaloneScopeClass,
6957
7458
  role: "tooltip",
@@ -6987,6 +7488,43 @@ const KEY_OPTIONS = {
6987
7488
  day: "2-digit"
6988
7489
  };
6989
7490
  const DATE_PREFIX = /^(\d{4})-(\d{2})-(\d{2})/;
7491
+ /**
7492
+ * Label formatters for UTC proxies, so both calendar layouts name a day alike.
7493
+ *
7494
+ * `gregory` keeps a locale whose default calendar is not Gregorian (fa-IR) from
7495
+ * splitting one grid month across two names.
7496
+ *
7497
+ * @param locale - BCP 47 locale.
7498
+ * @return Weekday, month and full-day formatters.
7499
+ */
7500
+ const civilLabelFormatters = (locale) => {
7501
+ const formatting = {
7502
+ locale,
7503
+ timeZone: "UTC"
7504
+ };
7505
+ return {
7506
+ formatWeekday: createDateFormatter({
7507
+ weekday: "short",
7508
+ calendar: "gregory"
7509
+ }, formatting),
7510
+ formatMonth: createDateFormatter({
7511
+ month: "short",
7512
+ calendar: "gregory"
7513
+ }, formatting),
7514
+ formatMonthYear: createDateFormatter({
7515
+ month: "short",
7516
+ year: "numeric",
7517
+ calendar: "gregory"
7518
+ }, formatting),
7519
+ formatDay: createDateFormatter({
7520
+ weekday: "short",
7521
+ month: "short",
7522
+ day: "numeric",
7523
+ year: "numeric",
7524
+ calendar: "gregory"
7525
+ }, formatting)
7526
+ };
7527
+ };
6990
7528
  const pad = (value, length) => String(value).padStart(length, "0");
6991
7529
  /**
6992
7530
  * The day a UTC proxy stands for.
@@ -7152,18 +7690,7 @@ const buildCalendarHeatmapData = (series, options = {}) => {
7152
7690
  const gridMaxDayKey = widenTo(options.gridSpan?.end, maxDayKey, "later");
7153
7691
  const requestedMinDate = civilDate(requestedMinDayKey);
7154
7692
  const gridMaxDate = civilDate(gridMaxDayKey);
7155
- const labelFormatting = {
7156
- locale,
7157
- timeZone: "UTC"
7158
- };
7159
- const formatWeekday = createDateFormatter({ weekday: "short" }, labelFormatting);
7160
- const formatMonth = createDateFormatter({ month: "short" }, labelFormatting);
7161
- const formatDay = createDateFormatter({
7162
- weekday: "short",
7163
- month: "short",
7164
- day: "numeric",
7165
- year: "numeric"
7166
- }, labelFormatting);
7693
+ const { formatWeekday, formatMonth, formatDay } = civilLabelFormatters(locale);
7167
7694
  const gridStart = startOfCivilWeek(requestedMinDate, weekStartsOn);
7168
7695
  const gridMinDayKey = requestedMinDayKey < minDayKey ? civilKey(gridStart) : requestedMinDayKey;
7169
7696
  const weekCount = civilWeekSpan(gridStart, gridMaxDate, weekStartsOn);
@@ -7204,6 +7731,89 @@ const buildCalendarHeatmapData = (series, options = {}) => {
7204
7731
  };
7205
7732
  };
7206
7733
  //#endregion
7734
+ //#region src/charts/heatmap-chart/build-month-calendar-data.ts
7735
+ /** Week rows per month, fixed so every month block is the same height. */
7736
+ const MONTH_ROWS = 6;
7737
+ const DAYS_PER_WEEK = 7;
7738
+ const startOfCivilMonth = (date) => {
7739
+ const first = new Date(date.getTime());
7740
+ first.setUTCDate(1);
7741
+ return first;
7742
+ };
7743
+ const startOfNextCivilMonth = (date) => {
7744
+ const next = startOfCivilMonth(date);
7745
+ next.setUTCMonth(next.getUTCMonth() + 1);
7746
+ return next;
7747
+ };
7748
+ /**
7749
+ * Lay a day-keyed map out as one month calendar per month, weekdays across and
7750
+ * weeks down, for `HeatmapChart` with `columnGroups`.
7751
+ *
7752
+ * @param valueByDay - Value per `yyyy-MM-dd`. A missing day is `null`.
7753
+ * @param range - The measured days; every month from `start`'s through `end`'s is drawn.
7754
+ * @param options - Week start and label locale.
7755
+ * @return Columns and one group per month; empty for an invalid or reversed range.
7756
+ */
7757
+ const buildMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
7758
+ const start = civilDate(range.start);
7759
+ const end = civilDate(range.end);
7760
+ if (!start || !end || start.getTime() > end.getTime()) {
7761
+ warnOnce(`heatmap:monthRange:${range.start}:${range.end}`, `range ${JSON.stringify(range)} must be two \`yyyy-MM-dd\` days with start on or before end, so the calendar is empty.`);
7762
+ return {
7763
+ data: [],
7764
+ columnGroups: []
7765
+ };
7766
+ }
7767
+ const startKey = civilKey(start);
7768
+ const endKey = civilKey(end);
7769
+ const weekStartsOn = options.weekStartsOn ?? 1;
7770
+ const { locale } = sanitizeFormatting({ locale: options.locale });
7771
+ for (const key of Object.keys(valueByDay)) if (!civilDate(key)) warnOnce(`heatmap:monthKey:${key}`, `${JSON.stringify(key)} is not a \`yyyy-MM-dd\` day, so its value is left out of the calendar.`);
7772
+ const readValue = (key) => {
7773
+ const value = valueByDay[key];
7774
+ return isPresent(value) ? value : null;
7775
+ };
7776
+ const { formatMonth, formatMonthYear, formatDay } = civilLabelFormatters(locale);
7777
+ const data = [];
7778
+ const columnGroups = [];
7779
+ const lastMonthStart = startOfCivilMonth(end);
7780
+ const formatGroup = (lastMonthStart.getUTCFullYear() - start.getUTCFullYear()) * 12 + lastMonthStart.getUTCMonth() - start.getUTCMonth() + 1 > 12 ? formatMonthYear : formatMonth;
7781
+ for (let monthStart = startOfCivilMonth(start); monthStart.getTime() <= lastMonthStart.getTime(); monthStart = startOfNextCivilMonth(monthStart)) {
7782
+ const monthStartKey = civilKey(monthStart);
7783
+ const monthEndKey = civilKey(addCivilDays(startOfNextCivilMonth(monthStart), -1));
7784
+ const gridStart = startOfCivilWeek(monthStart, weekStartsOn);
7785
+ for (let weekday = 0; weekday < DAYS_PER_WEEK; weekday++) {
7786
+ const cells = [];
7787
+ for (let week = 0; week < MONTH_ROWS; week++) {
7788
+ const day = addCivilDays(gridStart, week * DAYS_PER_WEEK + weekday);
7789
+ const key = civilKey(day);
7790
+ if (key < monthStartKey || key > monthEndKey) cells.push({
7791
+ value: null,
7792
+ hidden: true
7793
+ });
7794
+ else if (key < startKey || key > endKey) cells.push({
7795
+ label: formatDay(day),
7796
+ value: null,
7797
+ placeholder: true
7798
+ });
7799
+ else cells.push({
7800
+ label: formatDay(day),
7801
+ value: readValue(key)
7802
+ });
7803
+ }
7804
+ data.push({ data: cells });
7805
+ }
7806
+ columnGroups.push({
7807
+ label: formatGroup(monthStart),
7808
+ span: DAYS_PER_WEEK
7809
+ });
7810
+ }
7811
+ return {
7812
+ data,
7813
+ columnGroups
7814
+ };
7815
+ };
7816
+ //#endregion
7207
7817
  //#region src/charts/heatmap-chart/use-calendar-heatmap-data.ts
7208
7818
  /**
7209
7819
  * `buildCalendarHeatmapData` with the locale and zone taken from
@@ -7240,6 +7850,36 @@ const useCalendarHeatmapData = (series, options = {}) => {
7240
7850
  ]);
7241
7851
  };
7242
7852
  //#endregion
7853
+ //#region src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts
7854
+ /**
7855
+ * `buildMonthCalendarHeatmapData` with the locale taken from `GlobalChartsProvider`
7856
+ * where the caller names none.
7857
+ *
7858
+ * @param valueByDay - Value per `yyyy-MM-dd`. Held by reference, so a caller that rebuilds it each render defeats the memo.
7859
+ * @param range - As for `buildMonthCalendarHeatmapData`.
7860
+ * @param options - As for `buildMonthCalendarHeatmapData`; `locale` wins over the provider.
7861
+ * @return Columns and groups for `HeatmapChart`.
7862
+ */
7863
+ const useMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
7864
+ const formatting = useChartFormatting();
7865
+ const locale = options.locale ?? formatting.locale;
7866
+ const { weekStartsOn } = options;
7867
+ const { start, end } = range;
7868
+ return useMemo(() => buildMonthCalendarHeatmapData(valueByDay, {
7869
+ start,
7870
+ end
7871
+ }, {
7872
+ locale,
7873
+ weekStartsOn
7874
+ }), [
7875
+ valueByDay,
7876
+ start,
7877
+ end,
7878
+ locale,
7879
+ weekStartsOn
7880
+ ]);
7881
+ };
7882
+ //#endregion
7243
7883
  //#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
7244
7884
  /*!
7245
7885
  * is-plain-object <https://github.com/jonschlinkert/is-plain-object>
@@ -7307,7 +7947,24 @@ function paramCase(input, options) {
7307
7947
  return dotCase(input, __assign({ delimiter: "-" }, options));
7308
7948
  }
7309
7949
  //#endregion
7310
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
7950
+ //#region ../../../node_modules/.pnpm/@wordpress+warning@3.55.0/node_modules/@wordpress/warning/build-module/utils.mjs
7951
+ var logged = /* @__PURE__ */ new Set();
7952
+ //#endregion
7953
+ //#region ../../../node_modules/.pnpm/@wordpress+warning@3.55.0/node_modules/@wordpress/warning/build-module/index.mjs
7954
+ function isDev() {
7955
+ return globalThis.SCRIPT_DEBUG === true;
7956
+ }
7957
+ function warning(message) {
7958
+ if (!isDev()) return;
7959
+ if (logged.has(message)) return;
7960
+ console.warn(message);
7961
+ try {
7962
+ throw Error(message);
7963
+ } catch {}
7964
+ logged.add(message);
7965
+ }
7966
+ //#endregion
7967
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
7311
7968
  function useUpdateEffect(effect, deps) {
7312
7969
  const mountedRef = useRef$1(false);
7313
7970
  useEffect$1(() => {
@@ -8877,7 +9534,7 @@ _createEmotion.css;
8877
9534
  _createEmotion.sheet;
8878
9535
  _createEmotion.cache;
8879
9536
  //#endregion
8880
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
9537
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
8881
9538
  var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
8882
9539
  var useCx = () => {
8883
9540
  const cache = __unsafe_useEmotionCache();
@@ -8984,7 +9641,7 @@ function memize(fn, options) {
8984
9641
  return memoized;
8985
9642
  }
8986
9643
  //#endregion
8987
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/colors-values.mjs
9644
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/colors-values.mjs
8988
9645
  var white = "#fff";
8989
9646
  var GRAY = {
8990
9647
  900: "#1e1e1e",
@@ -9034,8 +9691,8 @@ var UI = {
9034
9691
  border: THEME.gray[600],
9035
9692
  borderHover: THEME.gray[700],
9036
9693
  borderFocus: THEME.accent,
9037
- borderDisabled: THEME.gray[400],
9038
- textDisabled: THEME.gray[600],
9694
+ borderDisabled: `var(--wpds-color-stroke-interactive-neutral-disabled, #dbdbdb)`,
9695
+ textDisabled: `var(--wpds-color-foreground-interactive-neutral-disabled, #8d8d8d)`,
9039
9696
  darkGrayPlaceholder: `color-mix(in srgb, ${THEME.foreground}, transparent 38%)`,
9040
9697
  lightGrayPlaceholder: `color-mix(in srgb, ${THEME.background}, transparent 35%)`
9041
9698
  };
@@ -9063,7 +9720,7 @@ var COLORS = Object.freeze({
9063
9720
  ui: UI
9064
9721
  });
9065
9722
  //#endregion
9066
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/config-values.mjs
9723
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/config-values.mjs
9067
9724
  var CONTROL_HEIGHT = "36px";
9068
9725
  var CONTROL_PROPS = {
9069
9726
  controlPaddingX: 12,
@@ -9117,8 +9774,8 @@ var config_values_default = Object.assign({}, CONTROL_PROPS, {
9117
9774
  transitionTimingFunctionControl: "cubic-bezier(0.12, 0.8, 0.32, 1)"
9118
9775
  });
9119
9776
  //#endregion
9120
- //#region ../../../node_modules/.pnpm/fast-deep-equal@3.1.3/node_modules/fast-deep-equal/es6/index.js
9121
- var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
9777
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
9778
+ var import_es6 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
9122
9779
  module.exports = function equal(a, b) {
9123
9780
  if (a === b) return true;
9124
9781
  if (a && b && typeof a == "object" && typeof b == "object") {
@@ -9162,31 +9819,8 @@ var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
9162
9819
  }
9163
9820
  return a !== a && b !== b;
9164
9821
  };
9165
- }));
9166
- //#endregion
9167
- //#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/utils.mjs
9168
- var logged = /* @__PURE__ */ new Set();
9169
- //#endregion
9170
- //#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/index.mjs
9171
- function isDev() {
9172
- return globalThis.SCRIPT_DEBUG === true;
9173
- }
9174
- function warning(message) {
9175
- if (!isDev()) return;
9176
- if (logged.has(message)) return;
9177
- console.warn(message);
9178
- try {
9179
- throw Error(message);
9180
- } catch {}
9181
- logged.add(message);
9182
- }
9183
- //#endregion
9184
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
9185
- var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
9186
- var ComponentsContext = createContext$1(
9187
- /** @type {Record<string, any>} */
9188
- {}
9189
- );
9822
+ })))(), 1);
9823
+ var ComponentsContext = createContext$1({});
9190
9824
  ComponentsContext.displayName = "ComponentsContext";
9191
9825
  var useComponentsContext = () => useContext$1(ComponentsContext);
9192
9826
  function useContextSystemBridge({ value }) {
@@ -9208,18 +9842,18 @@ var BaseContextSystemProvider = ({ children, value }) => {
9208
9842
  };
9209
9843
  memo(BaseContextSystemProvider);
9210
9844
  //#endregion
9211
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/constants.mjs
9845
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/constants.mjs
9212
9846
  var COMPONENT_NAMESPACE = "data-wp-component";
9213
9847
  var CONNECTED_NAMESPACE = "data-wp-c16t";
9214
9848
  var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
9215
9849
  //#endregion
9216
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
9850
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
9217
9851
  function getStyledClassName(namespace) {
9218
9852
  return `components-${paramCase(namespace)}`;
9219
9853
  }
9220
9854
  var getStyledClassNameFromKey = memize(getStyledClassName);
9221
9855
  //#endregion
9222
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/context-connect.mjs
9856
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/context-connect.mjs
9223
9857
  function contextConnect(Component, namespace) {
9224
9858
  return _contextConnect(Component, namespace, { forwardsRef: true });
9225
9859
  }
@@ -9236,7 +9870,7 @@ function _contextConnect(Component, namespace, options) {
9236
9870
  });
9237
9871
  }
9238
9872
  //#endregion
9239
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/utils.mjs
9873
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/utils.mjs
9240
9874
  function getNamespace(componentName) {
9241
9875
  return { [COMPONENT_NAMESPACE]: componentName };
9242
9876
  }
@@ -9244,7 +9878,7 @@ function getConnectedNamespace() {
9244
9878
  return { [CONNECTED_NAMESPACE]: true };
9245
9879
  }
9246
9880
  //#endregion
9247
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
9881
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
9248
9882
  function useContextSystem(props, namespace) {
9249
9883
  const contextSystemProps = useComponentsContext();
9250
9884
  if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
@@ -9253,10 +9887,12 @@ function useContextSystem(props, namespace) {
9253
9887
  ...getConnectedNamespace(),
9254
9888
  ...getNamespace(namespace)
9255
9889
  };
9256
- const { _overrides: overrideProps, ...otherContextProps } = contextProps;
9890
+ const { _overrides, ...otherContextProps } = contextProps;
9891
+ const overrideProps = _overrides;
9257
9892
  const initialMergedProps = Object.entries(otherContextProps).length ? Object.assign({}, otherContextProps, props) : props;
9893
+ const propsWithChildren = initialMergedProps;
9258
9894
  const classes = useCx()(getStyledClassNameFromKey(namespace), props.className);
9259
- const rendered = typeof initialMergedProps.renderChildren === "function" ? initialMergedProps.renderChildren(initialMergedProps) : initialMergedProps.children;
9895
+ const rendered = typeof propsWithChildren.renderChildren === "function" ? propsWithChildren.renderChildren(initialMergedProps) : propsWithChildren.children;
9260
9896
  for (const key in initialMergedProps) finalComponentProps[key] = initialMergedProps[key];
9261
9897
  for (const key in overrideProps) finalComponentProps[key] = overrideProps[key];
9262
9898
  if (rendered !== void 0) finalComponentProps.children = rendered;
@@ -9264,7 +9900,7 @@ function useContextSystem(props, namespace) {
9264
9900
  return finalComponentProps;
9265
9901
  }
9266
9902
  //#endregion
9267
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
9903
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
9268
9904
  var visuallyHidden = {
9269
9905
  border: 0,
9270
9906
  clip: "rect(1px, 1px, 1px, 1px)",
@@ -9280,7 +9916,7 @@ var visuallyHidden = {
9280
9916
  wordBreak: "normal"
9281
9917
  };
9282
9918
  //#endregion
9283
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
9919
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
9284
9920
  var customAttributeRegExp = /^(data|aria|x)-/i;
9285
9921
  var eventHandlerRegExp = /^on[A-Z]/;
9286
9922
  var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
@@ -9370,7 +10006,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
9370
10006
  }
9371
10007
  var PolymorphicElement = forwardRef$1(UnforwardedPolymorphicElement);
9372
10008
  //#endregion
9373
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/view/component.mjs
10009
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/view/component.mjs
9374
10010
  function UnforwardedView({ css, ...restProps }, ref) {
9375
10011
  return /* @__PURE__ */ jsx(PolymorphicElement, {
9376
10012
  ref,
@@ -9379,7 +10015,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
9379
10015
  }
9380
10016
  var component_default$2 = Object.assign(forwardRef$1(UnforwardedView), { selector: ".components-view" });
9381
10017
  //#endregion
9382
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
10018
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
9383
10019
  function UnconnectedVisuallyHidden(props, forwardedRef) {
9384
10020
  const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
9385
10021
  return /* @__PURE__ */ jsx(component_default$2, {
@@ -9394,7 +10030,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
9394
10030
  }
9395
10031
  var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
9396
10032
  //#endregion
9397
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
10033
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
9398
10034
  var breakpoints = [
9399
10035
  "40em",
9400
10036
  "52em",
@@ -9428,7 +10064,7 @@ function useResponsiveValue(values, options = {}) {
9428
10064
  return array[index >= array.length ? array.length - 1 : index];
9429
10065
  }
9430
10066
  //#endregion
9431
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/grid/utils.mjs
10067
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/utils.mjs
9432
10068
  var ALIGNMENTS = {
9433
10069
  bottom: {
9434
10070
  alignItems: "flex-end",
@@ -9476,7 +10112,7 @@ function getAlignmentProps(alignment) {
9476
10112
  return alignment ? ALIGNMENTS[alignment] : {};
9477
10113
  }
9478
10114
  //#endregion
9479
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/grid/hook.mjs
10115
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/hook.mjs
9480
10116
  function useGrid(props) {
9481
10117
  const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
9482
10118
  const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
@@ -9518,7 +10154,7 @@ function useGrid(props) {
9518
10154
  };
9519
10155
  }
9520
10156
  //#endregion
9521
- //#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/grid/component.mjs
10157
+ //#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/component.mjs
9522
10158
  function UnconnectedGrid(props, forwardedRef) {
9523
10159
  const gridProps = useGrid(props);
9524
10160
  return /* @__PURE__ */ jsx(component_default$2, {
@@ -10774,6 +11410,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
10774
11410
  });
10775
11411
  }
10776
11412
  //#endregion
10777
- export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
11413
+ export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, buildMonthCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, useMonthCalendarHeatmapData, validateHexColor };
10778
11414
 
10779
11415
  //# sourceMappingURL=index.js.map