@automattic/charts 4.11.1 → 4.13.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 +24 -0
  2. package/dist/index.cjs +1412 -787
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +59 -25
  5. package/dist/index.d.cts +64 -120
  6. package/dist/index.d.ts +64 -120
  7. package/dist/index.js +1400 -765
  8. package/dist/index.js.map +1 -1
  9. package/package.json +9 -9
  10. package/src/charts/area-chart/area-chart.tsx +16 -6
  11. package/src/charts/area-chart/test/area-chart.test.tsx +42 -9
  12. package/src/charts/bar-chart/bar-chart.tsx +143 -142
  13. package/src/charts/bar-chart/index.ts +3 -0
  14. package/src/charts/bar-chart/private/band-tooltip.tsx +41 -15
  15. package/src/charts/bar-chart/private/bar-layer.tsx +132 -0
  16. package/src/charts/bar-chart/private/comparison-bars-geometry.ts +22 -34
  17. package/src/charts/bar-chart/private/comparison-bars.tsx +9 -18
  18. package/src/charts/bar-chart/private/comparison-constants.ts +4 -10
  19. package/src/charts/bar-chart/private/grouped-bars.ts +68 -0
  20. package/src/charts/bar-chart/private/index.ts +7 -1
  21. package/src/charts/bar-chart/private/overlap-bars.ts +183 -0
  22. package/src/charts/bar-chart/private/selected-bar-ring.tsx +84 -0
  23. package/src/charts/bar-chart/private/slot-tooltip-members.tsx +28 -0
  24. package/src/charts/bar-chart/private/slotted-bar-series.tsx +84 -0
  25. package/src/charts/bar-chart/private/test/comparison-bars-geometry.test.ts +4 -11
  26. package/src/charts/bar-chart/private/test/comparison-bars.test.tsx +2 -3
  27. package/src/charts/bar-chart/private/test/grouped-bars.test.ts +87 -0
  28. package/src/charts/bar-chart/private/test/overlap-bars.test.ts +159 -0
  29. package/src/charts/bar-chart/private/use-bar-stops.ts +87 -0
  30. package/src/charts/bar-chart/private/use-overlap-slots.ts +213 -0
  31. package/src/charts/bar-chart/private/value-domain.ts +0 -10
  32. package/src/charts/bar-chart/test/bar-chart-overlap.test.tsx +347 -0
  33. package/src/charts/bar-chart/test/bar-chart.test.tsx +181 -19
  34. package/src/charts/bar-chart/test/use-bar-legend-items.test.tsx +81 -0
  35. package/src/charts/bar-chart/types.ts +3 -0
  36. package/src/charts/bar-chart/use-bar-colors.ts +46 -0
  37. package/src/charts/bar-chart/use-bar-legend-items.ts +87 -0
  38. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +24 -11
  39. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +235 -182
  40. package/src/charts/conversion-funnel-chart/index.ts +2 -0
  41. package/src/charts/conversion-funnel-chart/private/index.ts +1 -0
  42. package/src/charts/conversion-funnel-chart/private/use-funnel-selection.ts +9 -47
  43. package/src/charts/conversion-funnel-chart/private/use-roving-step-focus.ts +83 -0
  44. package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +312 -92
  45. package/src/charts/conversion-funnel-chart/test/use-funnel-selection.test.ts +23 -188
  46. package/src/charts/conversion-funnel-chart/types.ts +22 -0
  47. package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +41 -1
  48. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +101 -30
  49. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +47 -0
  50. package/src/charts/line-chart/line-chart.tsx +25 -18
  51. package/src/charts/line-chart/test/line-chart.test.tsx +240 -1
  52. package/src/charts/pie-chart/pie-chart.tsx +7 -2
  53. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +7 -2
  54. package/src/charts/private/pie-keyboard-navigation/index.ts +0 -1
  55. package/src/charts/private/{pie-keyboard-navigation/pie-keyboard-navigation.module.scss → selected-ring/selected-ring.module.scss} +11 -6
  56. package/src/charts/private/selected-ring/selected-ring.tsx +73 -0
  57. package/src/charts/private/{pie-keyboard-navigation/test/selected-segment-ring.test.ts → selected-ring/test/selected-ring.test.ts} +1 -1
  58. package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +20 -0
  59. package/src/components/legend/hooks/use-chart-legend-items.ts +27 -3
  60. package/src/components/tooltip/private/at-nearest-date.ts +49 -0
  61. package/src/components/tooltip/private/keyboard-stops.ts +67 -0
  62. package/src/components/tooltip/private/xy-chart-tooltip-overlay.tsx +10 -2
  63. package/src/components/tooltip/test/keyboard-stops.test.ts +36 -0
  64. package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +135 -1
  65. package/src/components/tooltip/xy-chart-tooltip.tsx +11 -14
  66. package/src/index.ts +10 -2
  67. package/src/providers/chart-context/global-charts-provider.tsx +2 -0
  68. package/src/providers/chart-context/test/chart-context.test.tsx +0 -13
  69. package/src/providers/chart-context/themes.ts +0 -1
  70. package/src/providers/chart-context/types.ts +2 -0
  71. package/src/test-utils/selected-bar-ring.ts +14 -0
  72. package/src/types.ts +14 -5
  73. package/src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx +0 -47
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region \0rolldown/runtime.js
2
+ // \0rolldown/runtime.js
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -21,7 +21,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  value: mod,
22
22
  enumerable: true
23
23
  }) : target, mod));
24
- //#endregion
25
24
  let _automattic_number_formatters = require("@automattic/number-formatters");
26
25
  let _visx_xychart = require("@visx/xychart");
27
26
  let _wordpress_i18n = require("@wordpress/i18n");
@@ -55,25 +54,22 @@ dompurify = __toESM(dompurify, 1);
55
54
  require("@babel/runtime/helpers/esm/extends");
56
55
  let _wordpress_icons = require("@wordpress/icons");
57
56
  let _visx_shape = require("@visx/shape");
58
- //#region src/charts/private/chart-instance-context/chart-instance-context.ts
57
+ // src/charts/private/chart-instance-context/chart-instance-context.ts
59
58
  const ChartInstanceContext = (0, react.createContext)(null);
60
- //#endregion
61
- //#region src/charts/private/chart-instance-context/use-chart-instance-context.ts
59
+ // src/charts/private/chart-instance-context/use-chart-instance-context.ts
62
60
  const useChartInstanceContext = () => {
63
61
  const context = (0, react.useContext)(ChartInstanceContext);
64
62
  if (!context) throw new Error("useChartInstanceContext must be used within a Chart component");
65
63
  return context;
66
64
  };
67
- //#endregion
68
- //#region src/styles/chart-scope-class.ts
65
+ // src/styles/chart-scope-class.ts
69
66
  /**
70
67
  * Stable class that carries the `--a8c-charts-*` catalog. Applied to the `GlobalChartsProvider` wrapper, to portal-rendered surfaces (which sit outside the provider tree), and to standalone components when no provider is above them.
71
68
  *
72
69
  * Deliberately unhashed: consumers are documented as being able to target it to override a token on the provider element.
73
70
  */
74
71
  const CHART_SCOPE_CLASS = "a8c-charts-scope";
75
- //#endregion
76
- //#region src/utils/create-composition.ts
72
+ // src/utils/create-composition.ts
77
73
  /**
78
74
  * Utility function to create chart components with composition API.
79
75
  *
@@ -87,8 +83,7 @@ const CHART_SCOPE_CLASS = "a8c-charts-scope";
87
83
  function attachSubComponents(Chart, subComponents) {
88
84
  return Object.assign(Chart, subComponents);
89
85
  }
90
- //#endregion
91
- //#region src/utils/warn-once.ts
86
+ // src/utils/warn-once.ts
92
87
  const warned = /* @__PURE__ */ new Set();
93
88
  /**
94
89
  * Warns about a host-supplied value once per process, and never in production.
@@ -101,8 +96,7 @@ const warnOnce = (key, message) => {
101
96
  warned.add(key);
102
97
  console.warn(`[Charts] ${message}`);
103
98
  };
104
- //#endregion
105
- //#region src/utils/date-parsing.ts
99
+ // src/utils/date-parsing.ts
106
100
  /**
107
101
  * @file Date parsing: a naive string is dated in a supplied IANA zone, or the runtime's own
108
102
  *
@@ -197,8 +191,7 @@ const parseAsLocalDate = (dateString, timeZone) => {
197
191
  }
198
192
  return /* @__PURE__ */ new Date(NaN);
199
193
  };
200
- //#endregion
201
- //#region src/utils/bucket-info.ts
194
+ // src/utils/bucket-info.ts
202
195
  const getInstant = (point) => {
203
196
  if (!point) return;
204
197
  if ("date" in point && point.date) return point.date.getTime();
@@ -230,8 +223,7 @@ const getBucketInfo = (data, tickResolution) => ({
230
223
  bucket: tickResolution ?? getBucketResolution(data),
231
224
  displayResolution: getBucketResolution(data, tickResolution)
232
225
  });
233
- //#endregion
234
- //#region src/utils/format-metric-value.ts
226
+ // src/utils/format-metric-value.ts
235
227
  /**
236
228
  * Format a numeric metric value based on type, precision and scale.
237
229
  * Supports currency, number and percentage, using `@automattic/number-formatters`.
@@ -280,8 +272,7 @@ const formatMetricValue = (value, type = "number", { decimals, useMultipliers =
280
272
  });
281
273
  }
282
274
  };
283
- //#endregion
284
- //#region src/utils/format-percentage.ts
275
+ // src/utils/format-percentage.ts
285
276
  /**
286
277
  * Format a percentage value with smart decimal handling.
287
278
  * Uses `@automattic/number-formatters` for consistent formatting.
@@ -297,8 +288,7 @@ const formatPercentage = (value) => {
297
288
  maximumFractionDigits: 2
298
289
  } });
299
290
  };
300
- //#endregion
301
- //#region src/utils/get-edge-tick-widths.ts
291
+ // src/utils/get-edge-tick-widths.ts
302
292
  /**
303
293
  * Rendered widths of the first and last tick labels on an axis.
304
294
  *
@@ -322,8 +312,7 @@ const getEdgeTickWidths = (ticks, formatTick, labelStyle) => {
322
312
  last: (0, _visx_text.getStringWidth)(label(ticks[lastIndex], lastIndex), labelStyle) ?? 0
323
313
  };
324
314
  };
325
- //#endregion
326
- //#region src/utils/get-longest-tick-width.ts
315
+ // src/utils/get-longest-tick-width.ts
327
316
  /**
328
317
  * Returns the width of the longest tick.
329
318
  *
@@ -337,8 +326,7 @@ const getLongestTickWidth = (ticks, formatTick, labelStyle) => {
337
326
  const longestTick = formattedTicks.reduce((longest, current) => longest.length >= current.length ? longest : current, formattedTicks[0]);
338
327
  return (0, _visx_text.getStringWidth)(longestTick, labelStyle);
339
328
  };
340
- //#endregion
341
- //#region src/utils/get-styles.ts
329
+ // src/utils/get-styles.ts
342
330
  /**
343
331
  * Utility function to get consolidated line styles for a series
344
332
  * This consolidates the logic used by both LineChart and Legend components
@@ -391,19 +379,16 @@ function getItemShapeStyles(series, index, theme, legendShape) {
391
379
  ...barShapeStyles
392
380
  };
393
381
  }
394
- //#endregion
395
- //#region src/utils/is-safari.ts
382
+ // src/utils/is-safari.ts
396
383
  const isSafari = () => {
397
384
  if (typeof navigator !== "undefined" && navigator.userAgent) return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
398
385
  return false;
399
386
  };
400
- //#endregion
401
- //#region src/utils/merge-themes.ts
387
+ // src/utils/merge-themes.ts
402
388
  function mergeThemes(baseTheme, overrideTheme) {
403
389
  return (0, deepmerge.default)(baseTheme, overrideTheme, { arrayMerge: (_destinationArray, sourceArray) => sourceArray });
404
390
  }
405
- //#endregion
406
- //#region src/utils/color-utils.ts
391
+ // src/utils/color-utils.ts
407
392
  /**
408
393
  * Check if a value is a valid 6-digit hex color
409
394
  * @param hex - The value to check
@@ -570,8 +555,7 @@ const prefersLightText = (backgroundHex) => {
570
555
  if (!isValidHexColor(backgroundHex)) return false;
571
556
  return relativeLuminance(backgroundHex) <= .179;
572
557
  };
573
- //#endregion
574
- //#region src/utils/resolve-css-var.ts
558
+ // src/utils/resolve-css-var.ts
575
559
  /**
576
560
  * Pattern for valid CSS custom property names (e.g., '--my-color', '--jp-gray-10')
577
561
  */
@@ -668,8 +652,7 @@ function readCustomProperty(varName, styles) {
668
652
  return null;
669
653
  }
670
654
  }
671
- //#endregion
672
- //#region src/utils/resolve-font-size.ts
655
+ // src/utils/resolve-font-size.ts
673
656
  const toFontSize = (size) => Number.isFinite(size) && size >= 0 ? size : void 0;
674
657
  /**
675
658
  * Resolve a theme `fontSize` value into a plain number suitable for
@@ -696,8 +679,7 @@ const resolveFontSize = (val) => {
696
679
  return match ? toFontSize(parseFloat(match[1])) : void 0;
697
680
  }
698
681
  };
699
- //#endregion
700
- //#region src/utils/date-formatting.ts
682
+ // src/utils/date-formatting.ts
701
683
  const formatters = /* @__PURE__ */ new Map();
702
684
  const getFormatter$1 = (options, { locale, timeZone }) => {
703
685
  const key = `${locale ?? ""}|${timeZone ?? ""}|${JSON.stringify(options)}`;
@@ -796,8 +778,7 @@ const createZonedClock = (timeZone) => {
796
778
  };
797
779
  };
798
780
  };
799
- //#endregion
800
- //#region src/providers/chart-scope/chart-scope-context.ts
781
+ // src/providers/chart-scope/chart-scope-context.ts
801
782
  /**
802
783
  * The nearest chart element, published so JS token resolution reads the same CSS cascade that paints the chart's own colours.
803
784
  *
@@ -814,8 +795,7 @@ const seriesRole = (slot) => `--a8c-charts-color-series-${slot}`;
814
795
  const SERIES_SLOT_1_FALLBACK = "#3858e9";
815
796
  /** The catalog pointer for every slot, in slot order. */
816
797
  const SERIES_PALETTE_POINTERS = Array.from({ length: 5 }, (_, index) => index === 0 ? `var(${seriesRole(1)}, ${SERIES_SLOT_1_FALLBACK})` : `var(${seriesRole(index + 1)})`);
817
- //#endregion
818
- //#region src/providers/chart-context/private/catalog-pointers.ts
798
+ // src/providers/chart-context/private/catalog-pointers.ts
819
799
  /** Terminal literals the provider also generates from before its first read, so SSR and the first client render agree. */
820
800
  const BACKGROUND_FALLBACK = "#ffffff";
821
801
  const LABEL_FALLBACK = "#1e1e1e";
@@ -855,8 +835,7 @@ const ANNOTATION_POINTERS = {
855
835
  radius: 5
856
836
  }
857
837
  };
858
- //#endregion
859
- //#region src/providers/chart-context/private/perceptual-color.ts
838
+ // src/providers/chart-context/private/perceptual-color.ts
860
839
  const DEUTERANOPIA = [
861
840
  .367322,
862
841
  .860646,
@@ -1262,16 +1241,14 @@ const buildPaletteGenerator = (normalizedSeeds, background, labelColors) => {
1262
1241
  return palette[index].hex;
1263
1242
  };
1264
1243
  };
1265
- //#endregion
1266
- //#region src/providers/chart-context/private/resolve-opaque-hex.ts
1244
+ // src/providers/chart-context/private/resolve-opaque-hex.ts
1267
1245
  const resolveOpaqueHex = (pointer, resolve) => {
1268
1246
  const raw = resolve(pointer);
1269
1247
  if (!raw || (0, _visx_vendor_d3_color.color)(raw)?.opacity !== 1) return null;
1270
1248
  const hex = normalizeColorToHex(raw);
1271
1249
  return isValidHexColor(hex) ? hex : null;
1272
1250
  };
1273
- //#endregion
1274
- //#region src/providers/chart-context/themes.ts
1251
+ // src/providers/chart-context/themes.ts
1275
1252
  /**
1276
1253
  * Default theme configuration: the shape and spacing a consumer can override.
1277
1254
  *
@@ -1298,10 +1275,7 @@ const defaultTheme = {
1298
1275
  strokeDasharray: "4 4",
1299
1276
  strokeLinecap: "square"
1300
1277
  } } },
1301
- barChart: { barStyles: { comparison: {
1302
- widthFactor: 1.5,
1303
- opacity: .5
1304
- } } },
1278
+ barChart: { barStyles: { comparison: { widthFactor: 1.5 } } },
1305
1279
  sparkline: {
1306
1280
  margin: {
1307
1281
  top: 2,
@@ -1317,8 +1291,7 @@ const defaultTheme = {
1317
1291
  groupGap: 24
1318
1292
  }
1319
1293
  };
1320
- //#endregion
1321
- //#region src/providers/chart-context/global-charts-provider.tsx
1294
+ // src/providers/chart-context/global-charts-provider.tsx
1322
1295
  const PLACEHOLDER_LABEL_COLORS = [LABEL_FALLBACK, LABEL_INVERSE_FALLBACK];
1323
1296
  const GlobalChartsContext = (0, react.createContext)(null);
1324
1297
  const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
@@ -1459,6 +1432,7 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
1459
1432
  theme: providerTheme,
1460
1433
  formatting,
1461
1434
  getElementStyles,
1435
+ backgroundColor: colorCache.background,
1462
1436
  toggleSeriesVisibility,
1463
1437
  setSeriesVisibility,
1464
1438
  setChartHiddenSeries,
@@ -1475,6 +1449,7 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
1475
1449
  providerTheme,
1476
1450
  formatting,
1477
1451
  getElementStyles,
1452
+ colorCache.background,
1478
1453
  toggleSeriesVisibility,
1479
1454
  setSeriesVisibility,
1480
1455
  setChartHiddenSeries,
@@ -1497,21 +1472,18 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
1497
1472
  })
1498
1473
  });
1499
1474
  };
1500
- //#endregion
1501
- //#region src/providers/chart-context/hooks/use-global-charts-context.ts
1475
+ // src/providers/chart-context/hooks/use-global-charts-context.ts
1502
1476
  const useGlobalChartsContext = () => {
1503
1477
  const context = (0, react.useContext)(GlobalChartsContext);
1504
1478
  if (!context) throw new Error("useGlobalChartsContext must be used within a GlobalChartsProvider");
1505
1479
  return context;
1506
1480
  };
1507
- //#endregion
1508
- //#region src/providers/chart-context/hooks/use-chart-id.ts
1481
+ // src/providers/chart-context/hooks/use-chart-id.ts
1509
1482
  const useChartId = (providedId) => {
1510
1483
  const generatedId = (0, react.useId)();
1511
1484
  return providedId || generatedId;
1512
1485
  };
1513
- //#endregion
1514
- //#region src/hooks/use-deep-memo.ts
1486
+ // src/hooks/use-deep-memo.ts
1515
1487
  var import_fast_deep_equal = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
1516
1488
  module.exports = function equal(a, b) {
1517
1489
  if (a === b) return true;
@@ -1552,16 +1524,14 @@ const useDeepMemo = (value) => {
1552
1524
  if (!(0, import_fast_deep_equal.default)(ref.current, value)) ref.current = value;
1553
1525
  return ref.current;
1554
1526
  };
1555
- //#endregion
1556
- //#region src/providers/chart-scope/use-chart-scope-element.ts
1527
+ // src/providers/chart-scope/use-chart-scope-element.ts
1557
1528
  /**
1558
1529
  * Returns the nearest chart scope element, or `null` when rendered outside any scope (and during SSR, before the ref is attached).
1559
1530
  *
1560
1531
  * @return {HTMLElement | null} The nearest chart scope element, or `null`.
1561
1532
  */
1562
1533
  const useChartScopeElement = () => (0, react.useContext)(ChartScopeContext);
1563
- //#endregion
1564
- //#region src/providers/chart-scope/use-standalone-scope-class.ts
1534
+ // src/providers/chart-scope/use-standalone-scope-class.ts
1565
1535
  /**
1566
1536
  * Returns the catalog class when there is no `GlobalChartsProvider` above this component, and `undefined` when there is.
1567
1537
  *
@@ -1570,8 +1540,7 @@ const useChartScopeElement = () => (0, react.useContext)(ChartScopeContext);
1570
1540
  * @return The scope class name, or undefined when a provider is present.
1571
1541
  */
1572
1542
  const useStandaloneScopeClass = () => (0, react.useContext)(GlobalChartsContext) ? void 0 : CHART_SCOPE_CLASS;
1573
- //#endregion
1574
- //#region src/hooks/use-xychart-theme.ts
1543
+ // src/hooks/use-xychart-theme.ts
1575
1544
  const STARTS_LIKE_A_NUMBER = /^[+-]?[\d.]/;
1576
1545
  const NON_NEGATIVE_CSS_NUMBER = /^\+?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?:[a-z]+|%)?$/i;
1577
1546
  const isRenderableFontSize = (fontSize) => {
@@ -1627,8 +1596,7 @@ const useXYChartTheme = (data) => {
1627
1596
  scopeElement
1628
1597
  ]);
1629
1598
  };
1630
- //#endregion
1631
- //#region src/providers/chart-context/hooks/use-chart-formatting.ts
1599
+ // src/providers/chart-context/hooks/use-chart-formatting.ts
1632
1600
  const RUNTIME_FORMATTING = {};
1633
1601
  /**
1634
1602
  * The locale and time zone dates are rendered in, as set on `GlobalChartsProvider`.
@@ -1642,8 +1610,7 @@ const RUNTIME_FORMATTING = {};
1642
1610
  const useChartFormatting = () => {
1643
1611
  return (0, react.useContext)(GlobalChartsContext)?.formatting ?? RUNTIME_FORMATTING;
1644
1612
  };
1645
- //#endregion
1646
- //#region src/hooks/use-chart-data-transform.ts
1613
+ // src/hooks/use-chart-data-transform.ts
1647
1614
  /**
1648
1615
  * Hook that transforms and sorts chart data, handling date parsing and sorting
1649
1616
  *
@@ -1678,8 +1645,7 @@ const useChartDataTransform = (data) => {
1678
1645
  }));
1679
1646
  }, [data, timeZone]);
1680
1647
  };
1681
- //#endregion
1682
- //#region src/hooks/use-chart-margin.tsx
1648
+ // src/hooks/use-chart-margin.tsx
1683
1649
  /**
1684
1650
  * Base top margin used when no dynamic adjustments are necessary.
1685
1651
  */
@@ -1801,8 +1767,7 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
1801
1767
  yTicks
1802
1768
  ]);
1803
1769
  };
1804
- //#endregion
1805
- //#region src/hooks/use-element-size.ts
1770
+ // src/hooks/use-element-size.ts
1806
1771
  /**
1807
1772
  * Hook to measure the width and height of a DOM element.
1808
1773
  * Returns a ref callback to attach to the element and the current dimensions in pixels.
@@ -1839,8 +1804,7 @@ function useElementSize({ initialWidth = 0, initialHeight = 0 } = {}) {
1839
1804
  height
1840
1805
  ];
1841
1806
  }
1842
- //#endregion
1843
- //#region src/hooks/use-text-truncation.ts
1807
+ // src/hooks/use-text-truncation.ts
1844
1808
  /**
1845
1809
  * Hook to detect if text content is truncated within its container.
1846
1810
  * Uses ResizeObserver to dynamically track changes in element size.
@@ -1881,8 +1845,7 @@ function useTextTruncation(enabled = true) {
1881
1845
  } else setIsTruncated(false);
1882
1846
  }, [enabled]), isTruncated];
1883
1847
  }
1884
- //#endregion
1885
- //#region src/hooks/use-zero-value-display.ts
1848
+ // src/hooks/use-zero-value-display.ts
1886
1849
  /**
1887
1850
  * Minimum pixel size for near-zero bars (non-zero values that would render too small).
1888
1851
  * Using 3px to be visible but not misleading - larger values might look like actual data.
@@ -1922,8 +1885,7 @@ const useZeroValueDisplay = (data, options = { enabled: false }) => {
1922
1885
  valueAxisLength
1923
1886
  ]);
1924
1887
  };
1925
- //#endregion
1926
- //#region src/hooks/use-data-with-percentages.ts
1888
+ // src/hooks/use-data-with-percentages.ts
1927
1889
  /**
1928
1890
  * Hook to calculate percentages from values for chart data.
1929
1891
  * Ensures percentages are always derived from values (single source of truth).
@@ -1940,8 +1902,7 @@ const useDataWithPercentages = (data) => {
1940
1902
  }));
1941
1903
  }, [data]);
1942
1904
  };
1943
- //#endregion
1944
- //#region src/hooks/use-legend-visibility-data.ts
1905
+ // src/hooks/use-legend-visibility-data.ts
1945
1906
  /**
1946
1907
  * Custom hook to filter and recalculate chart data based on series visibility.
1947
1908
  *
@@ -2013,8 +1974,7 @@ const useLegendVisibilityData = ({ data, chartId, isSeriesVisible }) => {
2013
1974
  ])
2014
1975
  };
2015
1976
  };
2016
- //#endregion
2017
- //#region src/hooks/use-prefers-reduced-motion.ts
1977
+ // src/hooks/use-prefers-reduced-motion.ts
2018
1978
  const QUERY = "(prefers-reduced-motion: no-preference)";
2019
1979
  const getInitialState = () => !window.matchMedia(QUERY).matches;
2020
1980
  /**
@@ -2035,11 +1995,9 @@ function usePrefersReducedMotion() {
2035
1995
  }, []);
2036
1996
  return prefersReducedMotion;
2037
1997
  }
2038
- //#endregion
2039
- //#region src/hooks/use-isomorphic-layout-effect.ts
1998
+ // src/hooks/use-isomorphic-layout-effect.ts
2040
1999
  const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
2041
- //#endregion
2042
- //#region src/providers/chart-context/hooks/use-chart-registration.ts
2000
+ // src/providers/chart-context/hooks/use-chart-registration.ts
2043
2001
  const useChartRegistration = ({ chartId, legendItems, chartType, isDataValid, metadata }) => {
2044
2002
  const { registerChart, unregisterChart } = useGlobalChartsContext();
2045
2003
  const stableLegendItems = useDeepMemo(legendItems);
@@ -2061,8 +2019,7 @@ const useChartRegistration = ({ chartId, legendItems, chartType, isDataValid, me
2061
2019
  isDataValid
2062
2020
  ]);
2063
2021
  };
2064
- //#endregion
2065
- //#region src/providers/chart-context/hooks/use-global-charts-theme.ts
2022
+ // src/providers/chart-context/hooks/use-global-charts-theme.ts
2066
2023
  /**
2067
2024
  * Hook to get the global chart theme from GlobalChartsProvider
2068
2025
  *
@@ -2071,8 +2028,7 @@ const useChartRegistration = ({ chartId, legendItems, chartType, isDataValid, me
2071
2028
  const useGlobalChartsTheme = () => {
2072
2029
  return (0, react.useContext)(GlobalChartsContext)?.theme ?? defaultTheme;
2073
2030
  };
2074
- //#endregion
2075
- //#region src/components/legend/utils/value-or-identity.ts
2031
+ // src/components/legend/utils/value-or-identity.ts
2076
2032
  /**
2077
2033
  * Returns an object's value if defined, or the object.
2078
2034
  * @param _ - The object to return the value of.
@@ -2090,8 +2046,7 @@ function valueOrIdentity(_) {
2090
2046
  function valueOrIdentityString(_) {
2091
2047
  return String(valueOrIdentity(_));
2092
2048
  }
2093
- //#endregion
2094
- //#region src/components/legend/private/base-legend.module.scss
2049
+ // src/components/legend/private/base-legend.module.scss
2095
2050
  var base_legend_module_default = {
2096
2051
  "legend": "a8ccharts-04TogW-legend",
2097
2052
  "legend--horizontal": "a8ccharts-04TogW-legend--horizontal",
@@ -2103,8 +2058,7 @@ var base_legend_module_default = {
2103
2058
  "legend-item-text--wrap": "a8ccharts-04TogW-legend-item-text--wrap",
2104
2059
  "legend-item-value": "a8ccharts-04TogW-legend-item-value"
2105
2060
  };
2106
- //#endregion
2107
- //#region src/components/legend/private/base-legend.tsx
2061
+ // src/components/legend/private/base-legend.tsx
2108
2062
  const ALIGNMENT_TO_FLEX = {
2109
2063
  start: "flex-start",
2110
2064
  center: "center",
@@ -2269,8 +2223,7 @@ const BaseLegend = (0, react.forwardRef)(({ items: allItems, className, orientat
2269
2223
  })
2270
2224
  });
2271
2225
  });
2272
- //#endregion
2273
- //#region src/components/legend/legend.tsx
2226
+ // src/components/legend/legend.tsx
2274
2227
  const defaultShapeByChartType = {
2275
2228
  area: "rect",
2276
2229
  line: "line",
@@ -2296,8 +2249,22 @@ const Legend = (0, react.forwardRef)(({ chartId, items, shape, ...props }, ref)
2296
2249
  chartId: contextChartId
2297
2250
  });
2298
2251
  });
2299
- //#endregion
2300
- //#region src/components/legend/hooks/use-chart-legend-items.ts
2252
+ // src/components/legend/hooks/use-chart-legend-items.ts
2253
+ /**
2254
+ * Wraps `getElementStyles` so a swatch takes the color given for its series.
2255
+ * @param getElementStyles - Function to get element styles
2256
+ * @param seriesColors - Each series' swatch color, by index
2257
+ * @return Element styles with the given color
2258
+ */
2259
+ function withSeriesColors(getElementStyles, seriesColors) {
2260
+ return (params) => {
2261
+ const styles = getElementStyles(params);
2262
+ return {
2263
+ ...styles,
2264
+ color: seriesColors[params.index] ?? styles.color
2265
+ };
2266
+ };
2267
+ }
2301
2268
  /**
2302
2269
  * Formats the value for a data point based on its type and display preference
2303
2270
  * @param point - The data point to format
@@ -2510,21 +2477,22 @@ function processPointData(pointData, getElementStyles, showValues, legendValueDi
2510
2477
  * @return Array of legend items ready for display
2511
2478
  */
2512
2479
  function useChartLegendItems(data, options = {}, legendShape) {
2513
- const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, renderGlyph } = options;
2514
- const { getElementStyles } = useGlobalChartsContext();
2480
+ const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, seriesColors, renderGlyph } = options;
2481
+ const { getElementStyles: getSeriesStyles } = useGlobalChartsContext();
2515
2482
  return (0, react.useMemo)(() => {
2516
2483
  if (!data || !Array.isArray(data) || data.length === 0) return [];
2517
2484
  if ("data" in data[0]) {
2518
2485
  const seriesData = data;
2486
+ const getElementStyles = seriesColors ? withSeriesColors(getSeriesStyles, seriesColors) : getSeriesStyles;
2519
2487
  const items = processSeriesData(seriesData, getElementStyles, showValues, withGlyph, glyphSize, collapseGroups, renderGlyph, legendShape);
2520
2488
  if (comparisonSeriesItems) return [...items, ...buildPerSeriesComparisonItems(seriesData, items, comparisonSeriesItems, getElementStyles, legendShape)];
2521
2489
  const comparison = comparisonItem ? buildComparisonLegendItem(seriesData, items, typeof comparisonItem === "string" ? comparisonItem : (0, _wordpress_i18n.__)("Comparison period", "jetpack-charts"), getElementStyles, legendShape) : null;
2522
2490
  return comparison ? [...items, comparison] : items;
2523
2491
  }
2524
- return processPointData(data, getElementStyles, showValues, legendValueDisplay, withGlyph, glyphSize, renderGlyph, legendShape);
2492
+ return processPointData(data, getSeriesStyles, showValues, legendValueDisplay, withGlyph, glyphSize, renderGlyph, legendShape);
2525
2493
  }, [
2526
2494
  data,
2527
- getElementStyles,
2495
+ getSeriesStyles,
2528
2496
  showValues,
2529
2497
  legendValueDisplay,
2530
2498
  withGlyph,
@@ -2532,19 +2500,18 @@ function useChartLegendItems(data, options = {}, legendShape) {
2532
2500
  collapseGroups,
2533
2501
  comparisonItem,
2534
2502
  comparisonSeriesItems,
2503
+ seriesColors,
2535
2504
  renderGlyph,
2536
2505
  legendShape
2537
2506
  ]);
2538
2507
  }
2539
- //#endregion
2540
- //#region src/components/tooltip/private/label-value-content.tsx
2508
+ // src/components/tooltip/private/label-value-content.tsx
2541
2509
  const LabelValueContent = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2542
2510
  data.label,
2543
2511
  ": ",
2544
2512
  data.valueDisplay || (0, _automattic_number_formatters.formatNumber)(data.value)
2545
2513
  ] });
2546
- //#endregion
2547
- //#region src/components/tooltip/private/tooltip-theme.tsx
2514
+ // src/components/tooltip/private/tooltip-theme.tsx
2548
2515
  const DEFAULT_SURFACE = "#1e1e1e";
2549
2516
  const TOOLTIP_SURFACE = `var(--a8c-charts-color-tooltip-surface, ${DEFAULT_SURFACE})`;
2550
2517
  const toSeed = (value) => {
@@ -2567,11 +2534,9 @@ const TooltipTheme = ({ children }) => {
2567
2534
  children
2568
2535
  });
2569
2536
  };
2570
- //#endregion
2571
- //#region src/components/tooltip/tooltip-box.module.scss
2537
+ // src/components/tooltip/tooltip-box.module.scss
2572
2538
  var tooltip_box_module_default = { "surface": "a8ccharts-ddpU1W-surface" };
2573
- //#endregion
2574
- //#region src/components/tooltip/tooltip-box.tsx
2539
+ // src/components/tooltip/tooltip-box.tsx
2575
2540
  /**
2576
2541
  * The chart tooltip box: the dark surface every chart tooltip draws. It does not position itself; place it with `style` or a wrapper.
2577
2542
  *
@@ -2591,8 +2556,7 @@ const TooltipBox = (0, react.forwardRef)(({ unstyled = false, role = "tooltip",
2591
2556
  return unstyled ? box : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTheme, { children: box });
2592
2557
  });
2593
2558
  TooltipBox.displayName = "TooltipBox";
2594
- //#endregion
2595
- //#region src/components/tooltip/base-tooltip.tsx
2559
+ // src/components/tooltip/base-tooltip.tsx
2596
2560
  /**
2597
2561
  * A tooltip box with children or `label: value` content. Prefer `TooltipBox`.
2598
2562
  *
@@ -2626,6 +2590,80 @@ const BaseTooltip = ({ data, top, left, component: Component = LabelValueContent
2626
2590
  children: content
2627
2591
  });
2628
2592
  };
2593
+ // src/components/tooltip/private/keyboard-stops.ts
2594
+ const timeOf$1 = (point) => point?.date?.getTime();
2595
+ const getXPositions = (series) => {
2596
+ const positions = /* @__PURE__ */ new Set();
2597
+ for (const { data } of series) for (const point of data) {
2598
+ const time = timeOf$1(point);
2599
+ if (time !== void 0) positions.add(time);
2600
+ }
2601
+ return [...positions].sort((a, b) => a - b);
2602
+ };
2603
+ /**
2604
+ * Keyboard stops over the series: the sorted union of their dates, or array indexes when no point has a date.
2605
+ *
2606
+ * Once any point has a date, a series of undated points has no stop.
2607
+ *
2608
+ * @param series - The series to step through.
2609
+ * @return The stop count, and each series' point at a stop.
2610
+ */
2611
+ const getKeyboardStops = (series) => {
2612
+ const positions = getXPositions(series);
2613
+ if (positions.length === 0) return {
2614
+ count: Math.max(0, ...series.map(({ data }) => data.length)),
2615
+ membersAt: (stop) => series.flatMap((s) => stop < s.data.length ? [{
2616
+ series: s,
2617
+ datum: s.data[stop],
2618
+ index: stop
2619
+ }] : [])
2620
+ };
2621
+ return {
2622
+ count: positions.length,
2623
+ membersAt: (stop) => {
2624
+ const time = positions[stop];
2625
+ if (time === void 0) return [];
2626
+ return series.flatMap((s) => {
2627
+ const index = s.data.findIndex((point) => timeOf$1(point) === time);
2628
+ return index === -1 ? [] : [{
2629
+ series: s,
2630
+ datum: s.data[index],
2631
+ index
2632
+ }];
2633
+ });
2634
+ }
2635
+ };
2636
+ };
2637
+ // src/components/tooltip/private/at-nearest-date.ts
2638
+ const timeOf = (datum) => datum.date?.getTime();
2639
+ /**
2640
+ * Lists every registered series at the nearest datum's date, each with its own point there.
2641
+ *
2642
+ * The pointer hands each series its own nearest point, which for a series that skips that date, or that the pointer sits nearer another date of, is a neighbor's.
2643
+ *
2644
+ * @param tooltipData - The tooltip data visx collected.
2645
+ * @param registry - The chart's data registry.
2646
+ * @return The tooltip data, unchanged when the nearest datum has no date.
2647
+ */
2648
+ const atNearestDate = (tooltipData, registry) => {
2649
+ const nearest = tooltipData?.nearestDatum?.datum;
2650
+ const time = nearest ? timeOf(nearest) : void 0;
2651
+ if (!tooltipData || time === void 0) return tooltipData;
2652
+ const datumByKey = {};
2653
+ for (const { key, data } of registry?.entries() ?? []) {
2654
+ const index = data.findIndex((datum) => timeOf(datum) === time);
2655
+ if (index !== -1) datumByKey[key] = {
2656
+ key,
2657
+ index,
2658
+ datum: data[index]
2659
+ };
2660
+ }
2661
+ for (const [key, entry] of Object.entries(tooltipData.datumByKey)) if (!datumByKey[key] && timeOf(entry.datum) === time) datumByKey[key] = entry;
2662
+ return {
2663
+ ...tooltipData,
2664
+ datumByKey
2665
+ };
2666
+ };
2629
2667
  const POINTER_HEIGHT = 6;
2630
2668
  const clamp = (position, min, max, size) => Math.min(Math.max(position, min), Math.max(min, max - size));
2631
2669
  const isClipping = (element) => {
@@ -2804,8 +2842,7 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = 10, offsetTop = 10, st
2804
2842
  }), children]
2805
2843
  });
2806
2844
  };
2807
- //#endregion
2808
- //#region src/components/tooltip/private/xy-chart-tooltip-overlay.tsx
2845
+ // src/components/tooltip/private/xy-chart-tooltip-overlay.tsx
2809
2846
  const CROSSHAIR_STROKE_WIDTH = 1.5;
2810
2847
  const CROSSHAIR_PAINT_PROPERTIES = /* @__PURE__ */ new Set([
2811
2848
  "stroke",
@@ -2990,18 +3027,21 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
2990
3027
  */
2991
3028
  const XyChartTooltipOverlay = (props) => {
2992
3029
  const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
3030
+ const dataRegistry = (0, react.useContext)(_visx_xychart.DataContext)?.dataRegistry;
2993
3031
  const [container, setContainer] = (0, react.useState)(null);
2994
3032
  const anchorRef = (0, react.useCallback)((node) => {
2995
3033
  setContainer(node?.ownerSVGElement?.parentElement ?? null);
2996
3034
  }, []);
2997
3035
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", { ref: anchorRef }), tooltipContext?.tooltipOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltipContent, {
2998
3036
  ...props,
2999
- tooltipContext,
3037
+ tooltipContext: {
3038
+ ...tooltipContext,
3039
+ tooltipData: atNearestDate(tooltipContext.tooltipData, dataRegistry)
3040
+ },
3000
3041
  container
3001
3042
  })] });
3002
3043
  };
3003
- //#endregion
3004
- //#region src/components/tooltip/xy-chart-tooltip.tsx
3044
+ // src/components/tooltip/xy-chart-tooltip.tsx
3005
3045
  const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
3006
3046
  const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
3007
3047
  const scopeElement = useChartScopeElement();
@@ -3026,6 +3066,7 @@ const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocu
3026
3066
  }
3027
3067
  return flattened;
3028
3068
  }, [series, mode]);
3069
+ const stops = (0, react.useMemo)(() => getKeyboardStops(series), [series]);
3029
3070
  const hasKeyboardSelection = (0, react.useRef)(false);
3030
3071
  const closeTooltipNow = (0, react.useCallback)(() => {
3031
3072
  tooltipContext?.updateTooltip({
@@ -3057,19 +3098,22 @@ const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocu
3057
3098
  return;
3058
3099
  }
3059
3100
  hasKeyboardSelection.current = true;
3060
- if (mode === "group") series.forEach((s, index) => {
3061
- if (selectedIndex < s.data.length) {
3062
- const datum = s.data[selectedIndex];
3101
+ if (mode === "group") {
3102
+ closeTooltipNow();
3103
+ stops.membersAt(selectedIndex).forEach(({ series: member, datum, index }) => {
3063
3104
  tooltipContext?.showTooltip({
3064
3105
  datum,
3065
- key: s.label,
3106
+ key: member.label,
3066
3107
  index
3067
3108
  });
3068
- }
3069
- });
3070
- else if (mode === "individual") {
3109
+ });
3110
+ } else if (mode === "individual") {
3071
3111
  if (selectedIndex < tooltipData.length) {
3072
3112
  const tooltipItem = tooltipData[selectedIndex];
3113
+ tooltipContext?.updateTooltip((state) => ({
3114
+ ...state,
3115
+ tooltipData: void 0
3116
+ }));
3073
3117
  tooltipContext?.showTooltip({
3074
3118
  datum: tooltipItem.datum,
3075
3119
  key: tooltipItem.seriesLabel,
@@ -3080,7 +3124,7 @@ const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocu
3080
3124
  }, [
3081
3125
  selectedIndex,
3082
3126
  tooltipData,
3083
- series
3127
+ stops
3084
3128
  ]);
3085
3129
  const focusableRenderTooltip = (0, react.useMemo)(() => {
3086
3130
  if (!renderTooltip) return void 0;
@@ -3230,8 +3274,7 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
3230
3274
  onChartPointerMove
3231
3275
  };
3232
3276
  };
3233
- //#endregion
3234
- //#region src/providers/chart-context/hooks/use-default-hidden-series.ts
3277
+ // src/providers/chart-context/hooks/use-default-hidden-series.ts
3235
3278
  /**
3236
3279
  * Seeds a chart's hidden series once per chart ID, the first time the provider
3237
3280
  * sees that ID.
@@ -3266,8 +3309,7 @@ const useDefaultHiddenSeries = (chartId, seriesLabels) => {
3266
3309
  chartId
3267
3310
  ]);
3268
3311
  };
3269
- //#endregion
3270
- //#region src/charts/private/chart-composition/chart-svg.tsx
3312
+ // src/charts/private/chart-composition/chart-svg.tsx
3271
3313
  /**
3272
3314
  * Compound component for SVG children in charts.
3273
3315
  * This component serves as a marker for SVG content that should be rendered
@@ -3281,8 +3323,7 @@ const ChartSVG = ({ children }) => {
3281
3323
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
3282
3324
  };
3283
3325
  ChartSVG.displayName = "Chart.SVG";
3284
- //#endregion
3285
- //#region src/charts/private/chart-composition/chart-html.tsx
3326
+ // src/charts/private/chart-composition/chart-html.tsx
3286
3327
  /**
3287
3328
  * Compound component for HTML children in charts.
3288
3329
  * This component serves as a marker for HTML content that should be rendered
@@ -3296,8 +3337,7 @@ const ChartHTML = ({ children }) => {
3296
3337
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
3297
3338
  };
3298
3339
  ChartHTML.displayName = "Chart.HTML";
3299
- //#endregion
3300
- //#region src/charts/private/chart-composition/render-legend-slot.ts
3340
+ // src/charts/private/chart-composition/render-legend-slot.ts
3301
3341
  /**
3302
3342
  * Renders legend children filtered by position slot.
3303
3343
  *
@@ -3308,8 +3348,7 @@ ChartHTML.displayName = "Chart.HTML";
3308
3348
  function renderLegendSlot(legendChildren, position) {
3309
3349
  return legendChildren.filter((l) => l.position === position).map((l, i) => (0, react.createElement)(react.Fragment, { key: `legend-${position}-${i}` }, l.element));
3310
3350
  }
3311
- //#endregion
3312
- //#region src/charts/private/chart-composition/use-chart-children.ts
3351
+ // src/charts/private/chart-composition/use-chart-children.ts
3313
3352
  /**
3314
3353
  * Custom hook to process and categorize chart children for composition API.
3315
3354
  * Extracts children from compound components (Chart.SVG, Chart.HTML) and
@@ -3362,11 +3401,9 @@ function useChartChildren(children, chartType) {
3362
3401
  };
3363
3402
  }, [children, chartType]);
3364
3403
  }
3365
- //#endregion
3366
- //#region src/charts/private/chart-layout/chart-layout.module.scss
3404
+ // src/charts/private/chart-layout/chart-layout.module.scss
3367
3405
  var chart_layout_module_default = { "chart-layout__content": "a8ccharts-fpNVAq-chart-layout__content" };
3368
- //#endregion
3369
- //#region src/charts/private/chart-layout/chart-layout.tsx
3406
+ // src/charts/private/chart-layout/chart-layout.tsx
3370
3407
  const ChartLayout = ({ legendPosition, legendElement, legendChildren, children, trailingContent, onContentHeightChange, gap, className, rootRef, style, "data-testid": dataTestId, "data-chart-id": dataChartId }) => {
3371
3408
  const [contentRef, contentWidth, contentHeight] = useElementSize();
3372
3409
  const isRenderProp = typeof children === "function";
@@ -3409,8 +3446,7 @@ const ChartLayout = ({ legendPosition, legendElement, legendChildren, children,
3409
3446
  ]
3410
3447
  });
3411
3448
  };
3412
- //#endregion
3413
- //#region src/charts/private/default-glyph/default-glyph.tsx
3449
+ // src/charts/private/default-glyph/default-glyph.tsx
3414
3450
  const DefaultGlyph = (props) => {
3415
3451
  const { theme } = (0, react.useContext)(_visx_xychart.DataContext) || {};
3416
3452
  props.position;
@@ -3425,8 +3461,7 @@ const DefaultGlyph = (props) => {
3425
3461
  ...props.glyphStyle
3426
3462
  });
3427
3463
  };
3428
- //#endregion
3429
- //#region src/charts/private/readings.ts
3464
+ // src/charts/private/readings.ts
3430
3465
  /**
3431
3466
  * Whether a value is a reading a scale can place.
3432
3467
  *
@@ -3450,11 +3485,9 @@ const isInvalidReading = (value, { allowMissing }) => value === null ? !allowMis
3450
3485
  * @return The formatted value.
3451
3486
  */
3452
3487
  const formatReading = (value) => value == null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(value);
3453
- //#endregion
3454
- //#region src/charts/private/center/center.module.scss
3488
+ // src/charts/private/center/center.module.scss
3455
3489
  var center_module_default = { "center": "a8ccharts-w3qxlG-center" };
3456
- //#endregion
3457
- //#region src/charts/private/center/center.tsx
3490
+ // src/charts/private/center/center.tsx
3458
3491
  /**
3459
3492
  * Centers its children on both axes and fills its parent.
3460
3493
  *
@@ -3476,11 +3509,9 @@ const Center = (0, react.forwardRef)(({ align = "center", justify = "center", cl
3476
3509
  ...props
3477
3510
  }));
3478
3511
  Center.displayName = "Center";
3479
- //#endregion
3480
- //#region src/charts/private/svg-empty-state/svg-empty-state.module.scss
3512
+ // src/charts/private/svg-empty-state/svg-empty-state.module.scss
3481
3513
  var svg_empty_state_module_default = { "svg-empty-state": "a8ccharts-udGPVq-svg-empty-state" };
3482
- //#endregion
3483
- //#region src/charts/private/svg-empty-state/svg-empty-state.tsx
3514
+ // src/charts/private/svg-empty-state/svg-empty-state.tsx
3484
3515
  /**
3485
3516
  * Renders empty-state text inside an SVG using foreignObject so that the
3486
3517
  * message wraps onto multiple lines instead of being clipped.
@@ -3507,8 +3538,7 @@ const SvgEmptyState = ({ x, y, width, height, children }) => {
3507
3538
  })
3508
3539
  });
3509
3540
  };
3510
- //#endregion
3511
- //#region src/charts/private/svg-empty-state/get-all-hidden-message.ts
3541
+ // src/charts/private/svg-empty-state/get-all-hidden-message.ts
3512
3542
  /**
3513
3543
  * Return the empty-state message for a chart whose items are all hidden.
3514
3544
  *
@@ -3528,8 +3558,7 @@ const getAllHiddenMessage = (interactive, itemType) => {
3528
3558
  if (interactive) return (0, _wordpress_i18n._x)("All series are hidden. Click legend items to show data.", "chart empty state: interactive series", "jetpack-charts");
3529
3559
  return (0, _wordpress_i18n._x)("All series are hidden.", "chart empty state: series", "jetpack-charts");
3530
3560
  };
3531
- //#endregion
3532
- //#region src/charts/private/time-axis.ts
3561
+ // src/charts/private/time-axis.ts
3533
3562
  const X_TICK_WIDTH = 60;
3534
3563
  const getCurveType = (type, smoothing) => {
3535
3564
  if (!type) return smoothing ? _visx_curve.curveCatmullRom : _visx_curve.curveLinear;
@@ -3786,8 +3815,7 @@ const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
3786
3815
  }
3787
3816
  return Math.max(1, secondBestGuess);
3788
3817
  };
3789
- //#endregion
3790
- //#region src/charts/private/time-axis-options.ts
3818
+ // src/charts/private/time-axis-options.ts
3791
3819
  const toDateDomain = (domain) => domain ? [new Date(domain[0]), new Date(domain[1])] : void 0;
3792
3820
  /**
3793
3821
  * The x-axis options for a continuous time chart, shared by LineChart and AreaChart.
@@ -3822,8 +3850,7 @@ const buildTimeAxisOptions = ({ dataSorted, width, axisOptions, scaleDomain, zoo
3822
3850
  ...numTicks === void 0 ? {} : { numTicks }
3823
3851
  };
3824
3852
  };
3825
- //#endregion
3826
- //#region src/charts/private/whole-number-ticks.tsx
3853
+ // src/charts/private/whole-number-ticks.tsx
3827
3854
  /**
3828
3855
  * Whether every reading in the series is a whole number.
3829
3856
  *
@@ -3870,15 +3897,13 @@ const WholeNumberTicks = ({ axis, numTicks, enabled, children }) => {
3870
3897
  const tickValues = enabled ? getWholeNumberTickValues(axis === "x" ? xScale : yScale, numTicks) : void 0;
3871
3898
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: children(tickValues) });
3872
3899
  };
3873
- //#endregion
3874
- //#region src/charts/private/with-responsive/with-responsive.module.scss
3900
+ // src/charts/private/with-responsive/with-responsive.module.scss
3875
3901
  var with_responsive_module_default = {
3876
3902
  "container": "a8ccharts-sP1gHa-container",
3877
3903
  "content": "a8ccharts-sP1gHa-content",
3878
3904
  "isContained": "a8ccharts-sP1gHa-isContained"
3879
3905
  };
3880
- //#endregion
3881
- //#region src/charts/private/with-responsive/with-responsive.tsx
3906
+ // src/charts/private/with-responsive/with-responsive.tsx
3882
3907
  /**
3883
3908
  * A higher-order component that provides responsive dimensions
3884
3909
  * to the wrapped chart component using useParentSize from `@visx/responsive`.
@@ -3957,14 +3982,12 @@ function withResponsive(WrappedComponent) {
3957
3982
  });
3958
3983
  };
3959
3984
  }
3960
- //#endregion
3961
- //#region src/charts/private/x-zoom/x-zoom.module.scss
3985
+ // src/charts/private/x-zoom/x-zoom.module.scss
3962
3986
  var x_zoom_module_default = {
3963
3987
  "x-zoom__reset": "a8ccharts-ur9dWW-x-zoom__reset",
3964
3988
  "x-zoom__selection": "a8ccharts-ur9dWW-x-zoom__selection"
3965
3989
  };
3966
- //#endregion
3967
- //#region src/charts/private/x-zoom/x-zoom.tsx
3990
+ // src/charts/private/x-zoom/x-zoom.tsx
3968
3991
  const MIN_DRAG_PIXELS = 6;
3969
3992
  /**
3970
3993
  * Drag-to-zoom state + pointer handlers for an XY chart. Designed to be
@@ -4147,11 +4170,9 @@ function ZoomResetButton({ onClick }) {
4147
4170
  })
4148
4171
  });
4149
4172
  }
4150
- //#endregion
4151
- //#region src/charts/private/xy-plot/xy-plot.module.scss
4173
+ // src/charts/private/xy-plot/xy-plot.module.scss
4152
4174
  var xy_plot_module_default = { "xy-plot": "a8ccharts-bIyhgG-xy-plot" };
4153
- //#endregion
4154
- //#region src/charts/line-chart/line-chart.module.scss
4175
+ // src/charts/line-chart/line-chart.module.scss
4155
4176
  var line_chart_module_default = {
4156
4177
  "line-chart": "a8ccharts-inuQka-line-chart",
4157
4178
  "line-chart__annotation-label": "a8ccharts-inuQka-line-chart__annotation-label",
@@ -4253,8 +4274,7 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
4253
4274
  })]
4254
4275
  });
4255
4276
  };
4256
- //#endregion
4257
- //#region src/charts/line-chart/private/line-chart-annotations-overlay.tsx
4277
+ // src/charts/line-chart/private/line-chart-annotations-overlay.tsx
4258
4278
  const LineChartAnnotationsOverlay = ({ children }) => {
4259
4279
  const { chartRef, chartWidth, chartHeight } = useChartInstanceContext();
4260
4280
  const [scales, setScales] = (0, react.useState)(null);
@@ -4337,8 +4357,7 @@ const LineChartAnnotationsOverlay = ({ children }) => {
4337
4357
  })
4338
4358
  });
4339
4359
  };
4340
- //#endregion
4341
- //#region src/charts/line-chart/private/line-chart-annotation.tsx
4360
+ // src/charts/line-chart/private/line-chart-annotation.tsx
4342
4361
  const ANNOTATION_MAX_WIDTH = 125;
4343
4362
  const ANNOTATION_INIT_HEIGHT = 100;
4344
4363
  const getLabelPosition = ({ subjectType, x, xMax, y, yMin, yMax, maxWidth, height }) => {
@@ -4531,8 +4550,7 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
4531
4550
  ]
4532
4551
  }) });
4533
4552
  };
4534
- //#endregion
4535
- //#region src/charts/line-chart/private/line-chart-glyph.tsx
4553
+ // src/charts/line-chart/private/line-chart-glyph.tsx
4536
4554
  const toNumber$1 = (val) => {
4537
4555
  const num = typeof val === "number" ? val : parseFloat(val);
4538
4556
  return isNaN(num) ? void 0 : num;
@@ -4562,8 +4580,7 @@ const LineChartGlyph = ({ data, index, color, glyphStyle, renderGlyph, accessors
4562
4580
  position
4563
4581
  });
4564
4582
  };
4565
- //#endregion
4566
- //#region src/charts/line-chart/private/nearest-pointer-events.tsx
4583
+ // src/charts/line-chart/private/nearest-pointer-events.tsx
4567
4584
  /**
4568
4585
  * Find the datum nearest a pointer along x, in one series sorted by x.
4569
4586
  *
@@ -4662,8 +4679,7 @@ function NearestPointerEvents({ onPointerDown, onPointerMove, onPointerUp }) {
4662
4679
  (0, _visx_xychart.useEventEmitter)("pointerup", handlers.pointerup);
4663
4680
  return null;
4664
4681
  }
4665
- //#endregion
4666
- //#region src/charts/line-chart/line-chart.tsx
4682
+ // src/charts/line-chart/line-chart.tsx
4667
4683
  const defaultRenderGlyph = (props) => {
4668
4684
  return /* @__PURE__ */ (0, react.createElement)(DefaultGlyph, {
4669
4685
  ...props,
@@ -4814,6 +4830,8 @@ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
4814
4830
  isVisible: !hiddenSeries.has(series.label)
4815
4831
  }));
4816
4832
  }, [dataSorted, hiddenSeries]);
4833
+ const visibleSeries = (0, react.useMemo)(() => dataSorted.filter((series) => isSeriesVisible(series.label)), [dataSorted, isSeriesVisible]);
4834
+ const visibleSeriesKey = (0, react.useMemo)(() => JSON.stringify(visibleSeries.map((series) => series.label)), [visibleSeries]);
4817
4835
  const allSeriesHidden = (0, react.useMemo)(() => {
4818
4836
  return seriesWithVisibility.every(({ isVisible }) => !isVisible);
4819
4837
  }, [seriesWithVisibility]);
@@ -4843,22 +4861,23 @@ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
4843
4861
  isSeriesVisible,
4844
4862
  options?.yScale
4845
4863
  ]);
4846
- const activateSelectedPoint = (0, react.useCallback)((index) => {
4847
- const series = dataSorted[0];
4848
- const datum = series?.data[index];
4849
- if (series && datum) onDatumActivate?.({
4850
- datum,
4851
- index,
4852
- key: series.label
4864
+ const stops = (0, react.useMemo)(() => getKeyboardStops(visibleSeries), [visibleSeries]);
4865
+ const activateSelectedPoint = (0, react.useCallback)((stop) => {
4866
+ const match = stops.membersAt(stop)[0];
4867
+ if (match) onDatumActivate?.({
4868
+ datum: match.datum,
4869
+ index: match.index,
4870
+ key: match.series.label
4853
4871
  });
4854
- }, [dataSorted, onDatumActivate]);
4872
+ }, [stops, onDatumActivate]);
4855
4873
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
4856
4874
  selectedIndex,
4857
4875
  setSelectedIndex,
4858
4876
  isNavigating,
4859
4877
  setIsNavigating,
4860
4878
  chartRef,
4861
- totalPoints: dataSorted[0]?.data.length || 0,
4879
+ totalPoints: stops.count,
4880
+ visibleSeriesKey,
4862
4881
  onActivate: activateSelectedPoint,
4863
4882
  preventTooltipScroll: tooltipPlacement === "below-axis"
4864
4883
  });
@@ -4877,7 +4896,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
4877
4896
  }
4878
4897
  return min <= max ? [min, max] : void 0;
4879
4898
  }, [dataSorted, isSeriesVisible]);
4880
- const hasWholeNumberValues = (0, react.useMemo)(() => hasOnlyWholeNumbers(dataSorted.filter((series) => isSeriesVisible(series.label))), [dataSorted, isSeriesVisible]);
4899
+ const hasWholeNumberValues = (0, react.useMemo)(() => hasOnlyWholeNumbers(visibleSeries), [visibleSeries]);
4881
4900
  const chartOptions = (0, react.useMemo)(() => {
4882
4901
  const fallbackYDomain = getFallbackYDomain(visibleReadingExtent, options?.yScale?.type === "log");
4883
4902
  return {
@@ -4923,11 +4942,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
4923
4942
  formatting,
4924
4943
  isSeriesVisible
4925
4944
  ]);
4926
- const bucketInfo = (0, react.useMemo)(() => getBucketInfo(dataSorted.filter((series) => isSeriesVisible(series.label)), options?.axis?.x?.tickResolution), [
4927
- dataSorted,
4928
- isSeriesVisible,
4929
- options?.axis?.x?.tickResolution
4930
- ]);
4945
+ const bucketInfo = (0, react.useMemo)(() => getBucketInfo(visibleSeries, options?.axis?.x?.tickResolution), [visibleSeries, options?.axis?.x?.tickResolution]);
4931
4946
  const tooltipRenderGlyph = (0, react.useMemo)(() => {
4932
4947
  return (props) => {
4933
4948
  const seriesIndex = dataSorted.findIndex((series) => series.label === props.key || series.data.includes(props.datum));
@@ -5157,7 +5172,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
5157
5172
  selectedIndex,
5158
5173
  tooltipRef,
5159
5174
  keyboardFocusedClassName: line_chart_module_default["line-chart__tooltip--keyboard-focused"],
5160
- series: dataSorted
5175
+ series: visibleSeries
5161
5176
  }),
5162
5177
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LineChartScalesRef, {
5163
5178
  chartRef: internalChartRef,
@@ -5195,15 +5210,13 @@ const LineChartResponsive = attachSubComponents(withResponsive(LineChartWithProv
5195
5210
  AnnotationsOverlay: LineChartAnnotationsOverlay,
5196
5211
  Annotation: LineChartAnnotation
5197
5212
  });
5198
- //#endregion
5199
- //#region src/charts/area-chart/area-chart.module.scss
5213
+ // src/charts/area-chart/area-chart.module.scss
5200
5214
  var area_chart_module_default = {
5201
5215
  "area-chart": "a8ccharts-jlynaq-area-chart",
5202
5216
  "area-chart--animated": "a8ccharts-jlynaq-area-chart--animated",
5203
5217
  "rise": "a8ccharts-jlynaq-rise"
5204
5218
  };
5205
- //#endregion
5206
- //#region src/charts/area-chart/private/validate-data.ts
5219
+ // src/charts/area-chart/private/validate-data.ts
5207
5220
  /**
5208
5221
  * Up-front data validation. Returns a localised error message when the chart
5209
5222
  * cannot safely render, otherwise `null`. Catches the cases that would
@@ -5219,8 +5232,7 @@ const validateData$3 = (data) => {
5219
5232
  if (data.some((series) => series.data.some((point) => isInvalidReading(point.value, { allowMissing: false }) || "date" in point && point.date && isNaN(point.date.getTime())))) return (0, _wordpress_i18n.__)("Invalid data", "jetpack-charts");
5220
5233
  return null;
5221
5234
  };
5222
- //#endregion
5223
- //#region src/charts/area-chart/private/overlays.tsx
5235
+ // src/charts/area-chart/private/overlays.tsx
5224
5236
  const AreaChartScalesRef = ({ chartRef, width, height, margin }) => {
5225
5237
  const context = (0, react.useContext)(_visx_xychart.DataContext);
5226
5238
  (0, react.useImperativeHandle)(chartRef, () => ({
@@ -5285,8 +5297,7 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
5285
5297
  children: circles
5286
5298
  });
5287
5299
  };
5288
- //#endregion
5289
- //#region src/charts/area-chart/area-chart.tsx
5300
+ // src/charts/area-chart/area-chart.tsx
5290
5301
  const AreaChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
5291
5302
  const legendInteractive = legend.interactive ?? false;
5292
5303
  const legendShape = legend.shape ?? "rect";
@@ -5332,19 +5343,22 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
5332
5343
  }));
5333
5344
  }, [dataSorted, hiddenSeries]);
5334
5345
  const allSeriesHidden = (0, react.useMemo)(() => seriesWithVisibility.every(({ isVisible }) => !isVisible), [seriesWithVisibility]);
5335
- const hasWholeNumberValues = (0, react.useMemo)(() => (!stacked || stackOffset === "none") && hasOnlyWholeNumbers(dataSorted.filter((series) => isSeriesVisible(series.label))), [
5336
- dataSorted,
5337
- isSeriesVisible,
5346
+ const visibleDataSeries = (0, react.useMemo)(() => dataSorted.filter((series) => isSeriesVisible(series.label)), [dataSorted, isSeriesVisible]);
5347
+ const hasWholeNumberValues = (0, react.useMemo)(() => (!stacked || stackOffset === "none") && hasOnlyWholeNumbers(visibleDataSeries), [
5348
+ visibleDataSeries,
5338
5349
  stacked,
5339
5350
  stackOffset
5340
5351
  ]);
5352
+ const visibleSeriesKey = (0, react.useMemo)(() => JSON.stringify(visibleDataSeries.map((series) => series.label)), [visibleDataSeries]);
5353
+ const stops = (0, react.useMemo)(() => getKeyboardStops(visibleDataSeries), [visibleDataSeries]);
5341
5354
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
5342
5355
  selectedIndex,
5343
5356
  setSelectedIndex,
5344
5357
  isNavigating,
5345
5358
  setIsNavigating,
5346
5359
  chartRef,
5347
- totalPoints: dataSorted[0]?.data.length || 0
5360
+ totalPoints: stops.count,
5361
+ visibleSeriesKey
5348
5362
  });
5349
5363
  const fixedYDomain = (0, react.useMemo)(() => {
5350
5364
  if (rescaleYOnVisibilityChange || !dataSorted.length || !dataSorted[0].data.length || stacked && stackOffset !== "none") return;
@@ -5632,7 +5646,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: pro
5632
5646
  selectedIndex,
5633
5647
  tooltipRef,
5634
5648
  keyboardFocusedClassName: area_chart_module_default["area-chart__tooltip--keyboard-focused"],
5635
- series: dataSorted
5649
+ series: visibleDataSeries
5636
5650
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HoverGlyphs, {
5637
5651
  visibleSeries,
5638
5652
  stacked,
@@ -5668,8 +5682,7 @@ const AreaChartWithProvider = (0, react.forwardRef)((props, ref) => {
5668
5682
  AreaChartWithProvider.displayName = "AreaChart";
5669
5683
  const AreaChart = attachSubComponents(AreaChartWithProvider, { Legend });
5670
5684
  const AreaChartResponsive = attachSubComponents(withResponsive(AreaChartWithProvider), { Legend });
5671
- //#endregion
5672
- //#region src/charts/bar-chart/bar-chart.module.scss
5685
+ // src/charts/bar-chart/bar-chart.module.scss
5673
5686
  var bar_chart_module_default = {
5674
5687
  "bar-chart": "a8ccharts-97yN9W-bar-chart",
5675
5688
  "bar-chart--animated": "a8ccharts-97yN9W-bar-chart--animated",
@@ -5677,8 +5690,7 @@ var bar_chart_module_default = {
5677
5690
  "rise": "a8ccharts-97yN9W-rise",
5678
5691
  "stretch": "a8ccharts-97yN9W-stretch"
5679
5692
  };
5680
- //#endregion
5681
- //#region src/charts/bar-chart/private/truncated-tick-component.tsx
5693
+ // src/charts/bar-chart/private/truncated-tick-component.tsx
5682
5694
  /**
5683
5695
  * Get the bandwidth of a scale
5684
5696
  *
@@ -5792,8 +5804,7 @@ const createTruncatedTickComponent = (axis) => (props) => {
5792
5804
  */
5793
5805
  const TruncatedXTickComponent = createTruncatedTickComponent("x");
5794
5806
  const TruncatedYTickComponent = createTruncatedTickComponent("y");
5795
- //#endregion
5796
- //#region src/charts/bar-chart/private/value-domain.ts
5807
+ // src/charts/bar-chart/private/value-domain.ts
5797
5808
  /** Domain for a value axis that has nothing to scale, so its ticks still read 0 to 1. */
5798
5809
  const EMPTY_DOMAIN = [0, 1];
5799
5810
  /**
@@ -5817,13 +5828,6 @@ const getBarValue = (point) => {
5817
5828
  */
5818
5829
  const isBarRendered = (point) => Number.isFinite(getBarValue(point));
5819
5830
  /**
5820
- * How many bars visx renders for a list of points.
5821
- *
5822
- * @param points - Data points handed to visx.
5823
- * @return The number of points that get a bar.
5824
- */
5825
- const countRenderedBars = (points) => points.filter(isBarRendered).length;
5826
- /**
5827
5831
  * An explicit domain for the value scale, or null to let visx fit one to the data.
5828
5832
  *
5829
5833
  * Zero goes into the domain here rather than through the scale's `zero` flag: visx applies
@@ -5851,8 +5855,7 @@ const getValueScaleDomain = (data, includeZero, isSeriesRendered) => {
5851
5855
  if (includeZero) return [Math.min(0, min), Math.max(0, max)];
5852
5856
  return null;
5853
5857
  };
5854
- //#endregion
5855
- //#region src/charts/bar-chart/private/use-bar-chart-options.ts
5858
+ // src/charts/bar-chart/private/use-bar-chart-options.ts
5856
5859
  /** Outer padding of the category band scale (space at the chart edges). */
5857
5860
  const BASE_BAND_PADDING = .2;
5858
5861
  /** Inner padding of the category band scale (the base gap between ticks). */
@@ -6068,8 +6071,7 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
6068
6071
  isSeriesRendered
6069
6072
  ]);
6070
6073
  }
6071
- //#endregion
6072
- //#region src/charts/bar-chart/private/band-scale.ts
6074
+ // src/charts/bar-chart/private/band-scale.ts
6073
6075
  /**
6074
6076
  * Match the inner slot scale used by visx BarGroup.
6075
6077
  * @param keys - Visible primary series keys.
@@ -6082,11 +6084,9 @@ const createGroupScale = (keys, bandwidth, padding) => (0, _visx_scale.scaleBand
6082
6084
  range: [0, bandwidth],
6083
6085
  padding
6084
6086
  });
6085
- //#endregion
6086
- //#region src/charts/bar-chart/private/comparison-bars-geometry.ts
6087
+ // src/charts/bar-chart/private/comparison-bars-geometry.ts
6087
6088
  /**
6088
- * Mirrors visx's getScaleBaseline so comparison shadows and primary bars
6089
- * share the same baseline, including out-of-domain zero values.
6089
+ * Mirrors visx's getScaleBaseline so bars drawn outside visx share the baseline of its bars, including out-of-domain zero values.
6090
6090
  *
6091
6091
  * @param {ValueScale} scale - The continuous value scale.
6092
6092
  * @return {number} The baseline output position in pixels.
@@ -6100,41 +6100,37 @@ function getValueScaleBaseline(scale) {
6100
6100
  return Number.isFinite(maybeZero) ? Math.max(maybeZero, minOutput) : minOutput;
6101
6101
  }
6102
6102
  /**
6103
- * Compute the rect for a comparison "shadow" bar, centered on the paired
6104
- * primary bar slot and scaled by `widthFactor`.
6105
- *
6106
- * @param {object} params - Geometry inputs.
6107
- * @param {boolean} params.horizontal - True for a horizontal bar chart, false for vertical.
6108
- * @param {number} params.bandPosition - bandScale(category): start px of the category band.
6109
- * @param {number} params.slotOffset - groupScale(primaryKey): offset of the primary slot within the band.
6110
- * @param {number} params.slotThickness - groupScale.bandwidth(): primary bar thickness in px.
6111
- * @param {number} params.valuePosition - valueScale(value): output px for the bar's data value.
6112
- * @param {number} params.baseline - getValueScaleBaseline(valueScale): zero-line output px.
6113
- * @param {number} params.widthFactor - Shadow thickness multiplier, e.g. 1.5 for 150% width.
6114
- * @return {ComparisonRect} The {x, y, width, height} of the shadow rect.
6115
- */
6116
- function computeComparisonRect(params) {
6117
- const { horizontal, bandPosition, slotOffset, slotThickness, valuePosition, baseline, widthFactor } = params;
6118
- const slotStart = bandPosition + slotOffset;
6119
- const shadowThickness = slotThickness * widthFactor;
6120
- const shadowStart = slotStart + slotThickness / 2 - shadowThickness / 2;
6121
- const valueStart = Math.min(valuePosition, baseline);
6122
- const valueLength = Math.abs(baseline - valuePosition);
6103
+ * Compute the rect that spans `valuePositions` along the value axis, centered on a slot and scaled by `widthFactor` across it.
6104
+ *
6105
+ * @param {object} params - Geometry inputs.
6106
+ * @param {boolean} params.horizontal - True for a horizontal bar chart, false for vertical.
6107
+ * @param {number} params.bandPosition - bandScale(category): start px of the category band.
6108
+ * @param {number} params.slotOffset - groupScale(slotKey): offset of the slot within the band.
6109
+ * @param {number} params.slotThickness - groupScale.bandwidth(): slot thickness in px.
6110
+ * @param {number[]} params.valuePositions - Output px the rect must reach, such as the baseline and each bar's value.
6111
+ * @param {number} params.widthFactor - Thickness multiplier, e.g. 0.5 for half the slot.
6112
+ * @return {SlotRect} The {x, y, width, height} of the rect.
6113
+ */
6114
+ function computeSlotRect(params) {
6115
+ const { horizontal, bandPosition, slotOffset, slotThickness, valuePositions, widthFactor } = params;
6116
+ const thickness = slotThickness * widthFactor;
6117
+ const start = bandPosition + slotOffset + slotThickness / 2 - thickness / 2;
6118
+ const valueStart = Math.min(...valuePositions);
6119
+ const valueLength = Math.max(...valuePositions) - valueStart;
6123
6120
  if (horizontal) return {
6124
6121
  x: valueStart,
6125
- y: shadowStart,
6122
+ y: start,
6126
6123
  width: valueLength,
6127
- height: shadowThickness
6124
+ height: thickness
6128
6125
  };
6129
6126
  return {
6130
- x: shadowStart,
6127
+ x: start,
6131
6128
  y: valueStart,
6132
- width: shadowThickness,
6129
+ width: thickness,
6133
6130
  height: valueLength
6134
6131
  };
6135
6132
  }
6136
- //#endregion
6137
- //#region src/charts/bar-chart/private/classified-bar-series.tsx
6133
+ // src/charts/bar-chart/private/classified-bar-series.tsx
6138
6134
  const ClassifiedBarSeries = ({ barClassName, primaryKeys, groupPadding, ...props }) => {
6139
6135
  const { xScale, yScale, horizontal } = (0, react.useContext)(_visx_xychart.DataContext);
6140
6136
  const bandScale = horizontal ? yScale : xScale;
@@ -6178,6 +6174,515 @@ const ClassifiedBarSeries = ({ barClassName, primaryKeys, groupPadding, ...props
6178
6174
  renderGlyph
6179
6175
  });
6180
6176
  };
6177
+ // src/charts/bar-chart/private/slotted-bar-series.tsx
6178
+ const SlottedBarSeries = ({ barClassName, slotKeys, slotKey, thickness, groupPadding, ...props }) => {
6179
+ const { xScale, yScale, horizontal } = (0, react.useContext)(_visx_xychart.DataContext);
6180
+ const bandScale = horizontal ? yScale : xScale;
6181
+ const valueScale = horizontal ? xScale : yScale;
6182
+ const groupScale = (0, react.useMemo)(() => createGroupScale(slotKeys, bandScale?.bandwidth?.() ?? 0, groupPadding), [
6183
+ slotKeys,
6184
+ bandScale,
6185
+ groupPadding
6186
+ ]);
6187
+ const renderGlyph = (0, react.useCallback)(({ datum, x, y, color }) => {
6188
+ if (!bandScale?.bandwidth || !valueScale) return null;
6189
+ const baseline = getValueScaleBaseline(valueScale);
6190
+ const rect = computeSlotRect({
6191
+ horizontal: !!horizontal,
6192
+ bandPosition: Number(bandScale((horizontal ? props.yAccessor : props.xAccessor)(datum))),
6193
+ slotOffset: groupScale(slotKey) ?? 0,
6194
+ slotThickness: groupScale.bandwidth(),
6195
+ valuePositions: [baseline, horizontal ? x : y],
6196
+ widthFactor: thickness
6197
+ });
6198
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
6199
+ ...rect,
6200
+ className: (0, clsx.default)("visx-bar", barClassName?.(datum)),
6201
+ fill: color
6202
+ });
6203
+ }, [
6204
+ bandScale,
6205
+ valueScale,
6206
+ horizontal,
6207
+ groupScale,
6208
+ slotKey,
6209
+ thickness,
6210
+ props.xAccessor,
6211
+ props.yAccessor,
6212
+ barClassName
6213
+ ]);
6214
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.GlyphSeries, {
6215
+ ...props,
6216
+ enableEvents: false,
6217
+ renderGlyph
6218
+ });
6219
+ };
6220
+ // src/charts/private/selected-ring/selected-ring.module.scss
6221
+ var selected_ring_module_default = {
6222
+ "selected-ring__contrast": "a8ccharts-gx1_AW-selected-ring__contrast",
6223
+ "selected-ring__edge": "a8ccharts-gx1_AW-selected-ring__edge",
6224
+ "selected-ring__far": "a8ccharts-gx1_AW-selected-ring__far",
6225
+ "selected-ring__focus": "a8ccharts-gx1_AW-selected-ring__focus"
6226
+ };
6227
+ // src/charts/private/selected-ring/selected-ring.tsx
6228
+ const TONES = {
6229
+ inside: ["contrast", "focus"],
6230
+ outside: ["focus", "contrast"]
6231
+ };
6232
+ const EVERYWHERE = "M-1e6 -1e6H1e6V1e6H-1e6Z";
6233
+ /**
6234
+ * Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
6235
+ *
6236
+ * @param value - Any string.
6237
+ * @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
6238
+ */
6239
+ const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
6240
+ /**
6241
+ * Marks a selected shape with a focus-colored ring and a contrast ring, so it reads against any fill.
6242
+ *
6243
+ * @param {SelectedRingProps} props - Component props
6244
+ * @return {JSX.Element} The ring
6245
+ */
6246
+ const SelectedRing = ({ chartId, d, side, testId }) => {
6247
+ const clipId = `selected-ring-clip-${toSvgId(chartId)}`;
6248
+ const clipPath = `url(#${clipId})`;
6249
+ const [far, edge] = TONES[side];
6250
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
6251
+ pointerEvents: "none",
6252
+ "aria-hidden": "true",
6253
+ children: [
6254
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("clipPath", {
6255
+ id: clipId,
6256
+ children: side === "inside" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
6257
+ d: `${EVERYWHERE} ${d}`,
6258
+ clipRule: "evenodd"
6259
+ })
6260
+ }),
6261
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
6262
+ d,
6263
+ clipPath,
6264
+ className: (0, clsx.default)(selected_ring_module_default["selected-ring__far"], selected_ring_module_default[`selected-ring__${far}`])
6265
+ }),
6266
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
6267
+ d,
6268
+ clipPath,
6269
+ className: (0, clsx.default)(selected_ring_module_default["selected-ring__edge"], selected_ring_module_default[`selected-ring__${edge}`])
6270
+ })
6271
+ ]
6272
+ });
6273
+ };
6274
+ // src/charts/bar-chart/private/selected-bar-ring.tsx
6275
+ /**
6276
+ * Marks the keyboard-selected slot with a two-tone ring outside its edge, so the ring reads against any bar color.
6277
+ *
6278
+ * @param props - Component props.
6279
+ * @param props.chartId - The chart's id, which keeps the clip path unique on a page with several charts.
6280
+ * @param props.selected - The selected slot.
6281
+ * @param props.slotKeys - The slots, in the order the band lays them out.
6282
+ * @param props.groupPadding - The padding between slots.
6283
+ * @param props.horizontal - Whether the bars run horizontally.
6284
+ * @param props.xAccessor - Reads a datum's x value.
6285
+ * @param props.yAccessor - Reads a datum's y value.
6286
+ * @return The ring, or nothing when the slot has no position.
6287
+ */
6288
+ const SelectedBarRing = ({ chartId, selected, slotKeys, groupPadding, horizontal, xAccessor, yAccessor }) => {
6289
+ const context = (0, react.useContext)(_visx_xychart.DataContext);
6290
+ const bandScale = horizontal ? context?.yScale : context?.xScale;
6291
+ const valueScale = horizontal ? context?.xScale : context?.yScale;
6292
+ const bandwidth = bandScale?.bandwidth?.() ?? 0;
6293
+ const [category] = selected.data;
6294
+ if (!bandScale || !valueScale || !bandwidth || !category) return null;
6295
+ const groupScale = createGroupScale(slotKeys, bandwidth, groupPadding);
6296
+ const slotOffset = groupScale(selected.slotKey);
6297
+ const bandPosition = Number(bandScale((horizontal ? yAccessor : xAccessor)(category)));
6298
+ if (slotOffset == null || !Number.isFinite(bandPosition)) return null;
6299
+ const valuePositions = selected.data.map((datum) => Number(valueScale(Number((horizontal ? xAccessor : yAccessor)(datum)))));
6300
+ const rect = computeSlotRect({
6301
+ horizontal,
6302
+ bandPosition,
6303
+ slotOffset,
6304
+ slotThickness: groupScale.bandwidth(),
6305
+ valuePositions: [getValueScaleBaseline(valueScale), ...valuePositions],
6306
+ widthFactor: selected.thickness
6307
+ });
6308
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedRing, {
6309
+ chartId,
6310
+ d: `M${rect.x} ${rect.y}h${rect.width}v${rect.height}h${-rect.width}Z`,
6311
+ side: "outside",
6312
+ testId: "bar-chart-selected-ring"
6313
+ });
6314
+ };
6315
+ // src/charts/bar-chart/private/bar-layer.tsx
6316
+ /**
6317
+ * Draws the bars in front of any comparison shadows, slotted for an overlap layout and grouped by visx otherwise, then the selected bar's ring.
6318
+ *
6319
+ * @param props - Component props.
6320
+ * @param props.chartId - The chart's id, which keeps the ring's clip path unique on a page with several charts.
6321
+ * @param props.overlapSlots - The overlap layout, or undefined for a grouped one.
6322
+ * @param props.selectedBar - The bar or slot the keyboard has selected.
6323
+ * @param props.primaryEntries - The visible primary series, for a grouped layout.
6324
+ * @param props.primaryKeys - Their labels, in group order.
6325
+ * @param props.getBarBackground - Reads a series' bar fill.
6326
+ * @param props.barClassName - Adds classes to a bar.
6327
+ * @param props.groupPadding - The padding between the bars of a category.
6328
+ * @param props.horizontal - Whether the bars run horizontally.
6329
+ * @param props.xAccessor - Reads a datum's x value.
6330
+ * @param props.yAccessor - Reads a datum's y value.
6331
+ * @return The bars.
6332
+ */
6333
+ const BarLayer = ({ chartId, overlapSlots, selectedBar, primaryEntries, primaryKeys, getBarBackground, barClassName, groupPadding, horizontal, xAccessor, yAccessor }) => {
6334
+ let bars;
6335
+ if (overlapSlots) bars = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
6336
+ className: "visx-bar-group",
6337
+ children: overlapSlots.entries.map(({ series, index }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SlottedBarSeries, {
6338
+ dataKey: series.label,
6339
+ data: series.data,
6340
+ xAccessor,
6341
+ yAccessor,
6342
+ colorAccessor: getBarBackground(index),
6343
+ barClassName,
6344
+ slotKeys: overlapSlots.slotKeys,
6345
+ slotKey: overlapSlots.slotOf(series.label),
6346
+ thickness: overlapSlots.thicknessOf(series.label),
6347
+ groupPadding
6348
+ }, series.label))
6349
+ });
6350
+ else if (barClassName) bars = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
6351
+ className: "visx-bar-group",
6352
+ children: primaryEntries.map(({ series, index }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClassifiedBarSeries, {
6353
+ dataKey: series.label,
6354
+ data: series.data,
6355
+ xAccessor,
6356
+ yAccessor,
6357
+ colorAccessor: getBarBackground(index),
6358
+ barClassName,
6359
+ primaryKeys,
6360
+ groupPadding
6361
+ }, series.label))
6362
+ });
6363
+ else bars = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.BarGroup, {
6364
+ padding: groupPadding,
6365
+ children: primaryEntries.map(({ series, index }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.BarSeries, {
6366
+ dataKey: series.label,
6367
+ data: series.data,
6368
+ xAccessor,
6369
+ yAccessor,
6370
+ colorAccessor: getBarBackground(index)
6371
+ }, series.label))
6372
+ });
6373
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [bars, selectedBar && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedBarRing, {
6374
+ chartId,
6375
+ selected: selectedBar,
6376
+ slotKeys: overlapSlots?.slotKeys ?? primaryKeys,
6377
+ groupPadding,
6378
+ horizontal,
6379
+ xAccessor,
6380
+ yAccessor
6381
+ })] });
6382
+ };
6383
+ // src/charts/bar-chart/private/slot-tooltip-members.tsx
6384
+ /**
6385
+ * Fills the tooltip with every bar of the keyboard-selected category, and only those.
6386
+ *
6387
+ * The last member shown becomes the tooltip's nearest datum, so the caller lists the keyboard stop last.
6388
+ *
6389
+ * @param props - Component props.
6390
+ * @param props.members - The category's bars, the keyboard stop last.
6391
+ * @return No visual content.
6392
+ */
6393
+ function SlotTooltipMembers({ members }) {
6394
+ const { showTooltip, updateTooltip } = (0, react.useContext)(_visx_xychart.TooltipContext) ?? {};
6395
+ (0, react.useEffect)(() => {
6396
+ updateTooltip?.((state) => ({
6397
+ ...state,
6398
+ tooltipData: void 0
6399
+ }));
6400
+ members.forEach((member) => showTooltip?.(member));
6401
+ }, [members]);
6402
+ return null;
6403
+ }
6404
+ // src/charts/bar-chart/private/overlap-bars.ts
6405
+ const PRIMARY_SLOT = "primary";
6406
+ const COMPARISON_SLOT = "comparison";
6407
+ const OVERLAP_SLOTS = [PRIMARY_SLOT, COMPARISON_SLOT];
6408
+ const SEARCH_STEPS = 16;
6409
+ /**
6410
+ * Places each series of an overlap layout: primaries in one slot and comparisons in the other, with each `group` a layer, back to front in order of first appearance.
6411
+ *
6412
+ * @param series - The series to place.
6413
+ * @return Each series' placement, by index.
6414
+ */
6415
+ function getOverlapPlacements(series) {
6416
+ const layerByGroup = /* @__PURE__ */ new Map();
6417
+ series.forEach(({ group }) => {
6418
+ if (!layerByGroup.has(group)) layerByGroup.set(group, layerByGroup.size);
6419
+ });
6420
+ const layerCount = layerByGroup.size;
6421
+ return series.map((item) => {
6422
+ const layer = layerByGroup.get(item.group) ?? 0;
6423
+ return {
6424
+ slot: item.options?.type === "comparison" ? COMPARISON_SLOT : PRIMARY_SLOT,
6425
+ layer,
6426
+ thickness: layerCount > 1 ? 1 - layer * .5 / (layerCount - 1) : 1
6427
+ };
6428
+ });
6429
+ }
6430
+ /**
6431
+ * Blends `from` toward `to` and returns the blend nearest the point where `passes` changes, on its passing side.
6432
+ *
6433
+ * @param from - Where the blend starts.
6434
+ * @param to - Where the blend ends.
6435
+ * @param passes - A test that changes at most once along the blend.
6436
+ * @return A hex color.
6437
+ */
6438
+ function blendToEdge(from, to, passes) {
6439
+ const passesAtStart = passes(from);
6440
+ let low = 0;
6441
+ let high = 1;
6442
+ for (let step = 0; step < SEARCH_STEPS; step++) {
6443
+ const middle = (low + high) / 2;
6444
+ if (passes(mixHexColors(from, to, middle)) === passesAtStart) low = middle;
6445
+ else high = middle;
6446
+ }
6447
+ return mixHexColors(from, to, passesAtStart ? low : high);
6448
+ }
6449
+ const awayFrom = (background) => contrastRatio(background, "#000000") >= contrastRatio(background, "#ffffff") ? "#000000" : "#ffffff";
6450
+ const opposite = (end) => end === "#000000" ? "#ffffff" : "#000000";
6451
+ /**
6452
+ * The tone of a color nearest the background that keeps 3:1 against it.
6453
+ *
6454
+ * @param color - A hex color.
6455
+ * @param background - The hex chart background.
6456
+ * @return A hex color.
6457
+ */
6458
+ function tintWithContrast(color, background) {
6459
+ const passes = (tone) => contrastRatio(tone, background) >= 3;
6460
+ return blendToEdge(color, passes(color) ? background : awayFrom(background), passes);
6461
+ }
6462
+ /**
6463
+ * The tone of a color nearest the original that keeps 3:1 against the bar it is drawn over, on the far side of that bar from the background when that side can reach 3:1.
6464
+ *
6465
+ * @param color - A hex color.
6466
+ * @param under - The hex color of the bar behind it.
6467
+ * @param background - The hex chart background.
6468
+ * @return A hex color.
6469
+ */
6470
+ function shadeWithContrast(color, under, background) {
6471
+ const passes = (tone) => contrastRatio(tone, under) >= 3;
6472
+ const start = contrastRatio(color, background) > contrastRatio(under, background) ? color : under;
6473
+ if (passes(start)) return start;
6474
+ const away = awayFrom(background);
6475
+ return blendToEdge(start, passes(away) ? away : opposite(away), passes);
6476
+ }
6477
+ /**
6478
+ * The colors an overlap layout fills its series with: per slot, the back layer tinted to 3:1 against the background and each layer in front shaded to 3:1 against the one behind. A slot whose front-most series has its own `stroke` keeps its colors as given.
6479
+ *
6480
+ * @param series - Every series of the chart.
6481
+ * @param colors - Each series' resolved color.
6482
+ * @param slotColors - The palette color of each slot, primaries first.
6483
+ * @param background - The hex chart background.
6484
+ * @return Each series' fill, by index.
6485
+ */
6486
+ function getOverlapBarColors(series, colors, slotColors, background) {
6487
+ const placements = getOverlapPlacements(series);
6488
+ const barColors = [...colors];
6489
+ OVERLAP_SLOTS.forEach((slot, slotIndex) => {
6490
+ const members = placements.flatMap((placement, index) => placement.slot === slot ? [{
6491
+ index,
6492
+ layer: placement.layer
6493
+ }] : []);
6494
+ if (!members.length) return;
6495
+ const layers = [...new Set(members.map(({ layer }) => layer))].sort((a, b) => a - b);
6496
+ const back = members.find(({ layer }) => layer === layers[0]);
6497
+ const base = back && series[back.index].options?.stroke ? colors[back.index] : slotColors[slotIndex];
6498
+ if (members.some(({ index, layer }) => layer === layers[layers.length - 1] && !!series[index].options?.stroke) || !isValidHexColor(base) || !isValidHexColor(background)) return;
6499
+ const toneByLayer = /* @__PURE__ */ new Map();
6500
+ let under;
6501
+ layers.forEach((layer) => {
6502
+ const tone = under === void 0 ? tintWithContrast(base, background) : shadeWithContrast(base, under, background);
6503
+ toneByLayer.set(layer, tone);
6504
+ under = tone;
6505
+ });
6506
+ members.forEach(({ index, layer }) => {
6507
+ barColors[index] = toneByLayer.get(layer) ?? colors[index];
6508
+ });
6509
+ });
6510
+ return barColors;
6511
+ }
6512
+ // src/charts/bar-chart/private/use-overlap-slots.ts
6513
+ /**
6514
+ * Whether two data points sit at the same category: the same label, or the same date.
6515
+ *
6516
+ * @param point - A data point.
6517
+ * @param category - The data point naming the category.
6518
+ * @return Whether `point` is at `category`.
6519
+ */
6520
+ function isSameCategory(point, category) {
6521
+ return category.label ? point.label === category.label : !!category.date && !!point.date && point.date.getTime() === category.date.getTime();
6522
+ }
6523
+ /**
6524
+ * Lays out the visible series of an overlap layout in slots and layers.
6525
+ *
6526
+ * @param enabled - Whether the chart draws an overlap layout.
6527
+ * @param seriesWithVisibility - Every series, with its index and whether it is visible.
6528
+ * @return The layout, or undefined when the chart is not an overlap layout.
6529
+ */
6530
+ function useOverlapSlots(enabled, seriesWithVisibility) {
6531
+ return (0, react.useMemo)(() => {
6532
+ if (!enabled) return;
6533
+ const visible = seriesWithVisibility.filter(({ isVisible }) => isVisible);
6534
+ const placements = getOverlapPlacements(visible.map(({ series }) => series));
6535
+ const placed = visible.map(({ series, index }, position) => ({
6536
+ entry: {
6537
+ series,
6538
+ index
6539
+ },
6540
+ placement: placements[position]
6541
+ })).sort((a, b) => a.placement.layer - b.placement.layer);
6542
+ const entries = placed.map(({ entry }) => entry);
6543
+ const placementByKey = new Map(placed.map(({ entry, placement }) => [entry.series.label, placement]));
6544
+ const slotOf = (key) => placementByKey.get(key)?.slot ?? "primary";
6545
+ const thicknessOf = (key) => placementByKey.get(key)?.thickness ?? 1;
6546
+ const hasPrimaries = seriesWithVisibility.some(({ series }) => series.options?.type !== "comparison");
6547
+ const showsComparisons = entries.some(({ series }) => slotOf(series.label) === COMPARISON_SLOT);
6548
+ const slotKeys = [...hasPrimaries ? [PRIMARY_SLOT] : [], ...showsComparisons ? [COMPARISON_SLOT] : []];
6549
+ return {
6550
+ entries,
6551
+ keys: entries.map(({ series }) => series.label),
6552
+ slotKeys,
6553
+ slotOf,
6554
+ thicknessOf,
6555
+ positions: getStopPositions(entries, slotKeys, slotOf)
6556
+ };
6557
+ }, [enabled, seriesWithVisibility]);
6558
+ }
6559
+ /**
6560
+ * The category a data point sits at, as a key two points share when `isSameCategory` holds.
6561
+ *
6562
+ * @param point - A data point.
6563
+ * @return The category key.
6564
+ */
6565
+ function categoryKey(point) {
6566
+ return point.label ? `label:${point.label}` : `date:${point.date?.getTime()}`;
6567
+ }
6568
+ /**
6569
+ * Lists a stop for every slot at every category that slot draws a bar at, category by category.
6570
+ *
6571
+ * @param entries - The visible series, back to front.
6572
+ * @param slotKeys - The slots, in band order.
6573
+ * @param slotOf - The slot a series sits in.
6574
+ * @return The positions, in keyboard order.
6575
+ */
6576
+ function getStopPositions(entries, slotKeys, slotOf) {
6577
+ const categories = /* @__PURE__ */ new Map();
6578
+ entries.forEach(({ series }) => {
6579
+ series.data.forEach((datum, dataPointIndex) => {
6580
+ const key = categoryKey(datum);
6581
+ const slots = categories.get(key) ?? /* @__PURE__ */ new Map();
6582
+ categories.set(key, slots);
6583
+ if (!isBarRendered(datum)) return;
6584
+ const slotKey = slotOf(series.label);
6585
+ slots.set(slotKey, {
6586
+ slotKey,
6587
+ key: series.label,
6588
+ datum,
6589
+ dataPointIndex
6590
+ });
6591
+ });
6592
+ });
6593
+ const ordered = [...categories.values()].filter((slots) => slots.size > 0);
6594
+ if (ordered.every((slots) => [...slots.values()].every(({ datum }) => datum.label == null && datum.date))) {
6595
+ const time = (slots) => [...slots.values()][0].datum.date?.getTime() ?? 0;
6596
+ ordered.sort((a, b) => time(a) - time(b));
6597
+ }
6598
+ return ordered.flatMap((slots) => slotKeys.flatMap((slotKey) => {
6599
+ const position = slots.get(slotKey);
6600
+ return position ? [position] : [];
6601
+ }));
6602
+ }
6603
+ /**
6604
+ * Every bar at a category, each with its own data point index, the keyboard stop last.
6605
+ *
6606
+ * @param entries - The visible series.
6607
+ * @param category - The data point naming the category.
6608
+ * @param stopKey - The series the keyboard stop is on.
6609
+ * @return The category's bars; the last one shown becomes the tooltip's nearest datum.
6610
+ */
6611
+ function membersAt(entries, category, stopKey) {
6612
+ const members = entries.flatMap(({ series }) => {
6613
+ const index = series.data.findIndex((point) => isSameCategory(point, category));
6614
+ return index === -1 ? [] : [{
6615
+ key: series.label,
6616
+ datum: series.data[index],
6617
+ index
6618
+ }];
6619
+ });
6620
+ return [...members.filter(({ key }) => key !== stopKey), ...members.filter(({ key }) => key === stopKey)];
6621
+ }
6622
+ /**
6623
+ * The slot a keyboard index selects, and every bar at its category.
6624
+ *
6625
+ * @param slots - The overlap layout.
6626
+ * @param selectedIndex - The keyboard index into `slots.positions`.
6627
+ * @return The selected slot, or undefined when nothing is selected or drawn there.
6628
+ */
6629
+ function getSelectedSlot(slots, selectedIndex) {
6630
+ const position = selectedIndex === void 0 ? void 0 : slots?.positions[selectedIndex];
6631
+ if (!slots || !position) return;
6632
+ const { slotKey, key: stopKey, datum: category } = position;
6633
+ const members = membersAt(slots.entries, category, stopKey);
6634
+ const slotBars = members.filter(({ key, datum }) => isBarRendered(datum) && slots.slotOf(key) === slotKey);
6635
+ return {
6636
+ data: slotBars.map(({ datum }) => datum),
6637
+ slotKey,
6638
+ thickness: Math.max(...slotBars.map(({ key }) => slots.thicknessOf(key))),
6639
+ members
6640
+ };
6641
+ }
6642
+ // src/charts/bar-chart/private/use-bar-stops.ts
6643
+ /**
6644
+ * Lays out the keyboard stops: one per slot and category in an overlap layout, else one per primary bar, series-major within each category.
6645
+ *
6646
+ * @param overlapSlots - The overlap layout, or undefined for a grouped one.
6647
+ * @param primaryEntries - The visible primary series.
6648
+ * @return The stops.
6649
+ */
6650
+ function useBarStops(overlapSlots, primaryEntries) {
6651
+ const series = (0, react.useMemo)(() => overlapSlots ? [] : primaryEntries.map((entry) => entry.series), [overlapSlots, primaryEntries]);
6652
+ return {
6653
+ count: overlapSlots?.positions.length ?? Math.max(0, ...series.map((item) => item.data.length)) * series.length,
6654
+ key: (0, react.useMemo)(() => JSON.stringify(overlapSlots?.keys ?? series.map((item) => item.label)), [overlapSlots, series]),
6655
+ barAt: (0, react.useCallback)((stop) => {
6656
+ if (overlapSlots) {
6657
+ const position = overlapSlots.positions[stop];
6658
+ return position && {
6659
+ datum: position.datum,
6660
+ index: position.dataPointIndex,
6661
+ key: position.key
6662
+ };
6663
+ }
6664
+ if (!series.length) return;
6665
+ const index = Math.floor(stop / series.length);
6666
+ const item = series[stop % series.length];
6667
+ const datum = item?.data[index];
6668
+ return item && datum ? {
6669
+ datum,
6670
+ index,
6671
+ key: item.label
6672
+ } : void 0;
6673
+ }, [overlapSlots, series]),
6674
+ stopOf: (0, react.useCallback)((seriesKey, dataPointIndex) => {
6675
+ if (overlapSlots) {
6676
+ const hovered = overlapSlots.entries.find((entry) => entry.series.label === seriesKey)?.series.data[dataPointIndex];
6677
+ const slotKey = overlapSlots.slotOf(seriesKey);
6678
+ const stop = hovered ? overlapSlots.positions.findIndex((position) => position.slotKey === slotKey && isSameCategory(position.datum, hovered)) : -1;
6679
+ return stop >= 0 ? stop : void 0;
6680
+ }
6681
+ const seriesIndex = series.findIndex((item) => item.label === seriesKey);
6682
+ return seriesIndex >= 0 ? dataPointIndex * series.length + seriesIndex : void 0;
6683
+ }, [overlapSlots, series])
6684
+ };
6685
+ }
6181
6686
  /**
6182
6687
  * Upper clamp on the computed group padding, so bars can never collapse to zero width
6183
6688
  * even at very large `widthFactor` values.
@@ -6188,8 +6693,7 @@ const MAX_GROUP_PADDING = .9;
6188
6693
  * gap between ticks. `0.75` = a 25% reduction of the tick-gap padding.
6189
6694
  */
6190
6695
  const COMPARISON_TICK_GAP_FACTOR = .75;
6191
- //#endregion
6192
- //#region src/charts/bar-chart/private/comparison-bars.tsx
6696
+ // src/charts/bar-chart/private/comparison-bars.tsx
6193
6697
  const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizontal, xAccessor, yAccessor, getElementStyles, resolveFill }) => {
6194
6698
  const context = (0, react.useContext)(_visx_xychart.DataContext);
6195
6699
  const xScale = context?.xScale;
@@ -6213,9 +6717,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6213
6717
  data: series,
6214
6718
  index
6215
6719
  });
6216
- const opacity = barStyles?.opacity ?? .5;
6217
6720
  const widthFactor = barStyles?.widthFactor ?? 1.5;
6218
- const fill = resolveFill(entry);
6219
6721
  series.data.forEach((datum, i) => {
6220
6722
  const bandPosition = Number(bandScale(bandAccessor(datum)));
6221
6723
  const valuePosition = Number(valueScale(Number(valueAccessor(datum))));
@@ -6223,13 +6725,12 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6223
6725
  if (process.env.NODE_ENV !== "production" && !Number.isFinite(bandPosition)) console.warn(`[Charts] ComparisonBars: datum key "${String(bandAccessor(datum))}" did not match any primary category. Shadow will not be rendered. Ensure comparison series data uses the same label/date keys as the primary series.`);
6224
6726
  return;
6225
6727
  }
6226
- const rect = computeComparisonRect({
6728
+ const rect = computeSlotRect({
6227
6729
  horizontal,
6228
6730
  bandPosition,
6229
6731
  slotOffset,
6230
6732
  slotThickness,
6231
- valuePosition,
6232
- baseline,
6733
+ valuePositions: [baseline, valuePosition],
6233
6734
  widthFactor
6234
6735
  });
6235
6736
  rects.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
@@ -6238,8 +6739,8 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6238
6739
  y: rect.y,
6239
6740
  width: rect.width,
6240
6741
  height: rect.height,
6241
- fill,
6242
- opacity
6742
+ fill: resolveFill(entry, datum),
6743
+ opacity: barStyles?.opacity
6243
6744
  }, `${index}-${i}`));
6244
6745
  });
6245
6746
  });
@@ -6251,8 +6752,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6251
6752
  children: rects
6252
6753
  });
6253
6754
  };
6254
- //#endregion
6255
- //#region src/charts/bar-chart/private/band-highlight.tsx
6755
+ // src/charts/bar-chart/private/band-highlight.tsx
6256
6756
  /**
6257
6757
  * Render and report the active band using the chart’s registered scales.
6258
6758
  * @param root0 - Highlight options.
@@ -6311,8 +6811,7 @@ function BandHighlight({ visible, horizontal, onChange }) {
6311
6811
  fill: CATALOG_POINTERS.surfaceSecondary
6312
6812
  });
6313
6813
  }
6314
- //#endregion
6315
- //#region src/charts/bar-chart/private/band-tooltip.tsx
6814
+ // src/charts/bar-chart/private/band-tooltip.tsx
6316
6815
  /**
6317
6816
  * Find a category by its painted center, including outer padding and reversed ranges.
6318
6817
  * @param data - Registered series points.
@@ -6338,7 +6837,8 @@ function nearestBandIndex(data, accessor, scale, position) {
6338
6837
  /**
6339
6838
  * Correct visx's range-based band inversion, which omits outer padding.
6340
6839
  * @param root0 - Registered series selection.
6341
- * @param root0.keys - Visible series keys.
6840
+ * @param root0.keys - Visible series keys, back to front where bars overlap.
6841
+ * @param root0.slots - Where series share slots: the slots of a category, in the order the band lays them out, and the slot each series sits in.
6342
6842
  * @param root0.groupPadding - Padding between grouped bars.
6343
6843
  * @param root0.withTooltips - Whether pointer events update the tooltip.
6344
6844
  * @param root0.onPointerDown - Receives the corrected pointer-down datum.
@@ -6346,12 +6846,13 @@ function nearestBandIndex(data, accessor, scale, position) {
6346
6846
  * @param root0.onPointerMove - Receives the corrected datum under a moving pointer.
6347
6847
  * @return No visual content.
6348
6848
  */
6349
- function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointerUp, onPointerMove }) {
6849
+ function BandTooltip({ keys, slots, groupPadding, withTooltips, onPointerDown, onPointerUp, onPointerMove }) {
6350
6850
  const { xScale, yScale, dataRegistry, horizontal } = (0, react.useContext)(_visx_xychart.DataContext);
6351
- const { showTooltip } = (0, react.useContext)(_visx_xychart.TooltipContext);
6851
+ const { showTooltip, hideTooltip, updateTooltip } = (0, react.useContext)(_visx_xychart.TooltipContext);
6352
6852
  const scale = horizontal ? yScale : xScale;
6353
6853
  const bandwidth = scale?.bandwidth?.() ?? 0;
6354
- const groupScale = (0, react.useMemo)(() => createGroupScale(keys, bandwidth, groupPadding), [
6854
+ const groupScale = (0, react.useMemo)(() => createGroupScale(slots?.keys ?? keys, bandwidth, groupPadding), [
6855
+ slots,
6355
6856
  keys,
6356
6857
  bandwidth,
6357
6858
  groupPadding
@@ -6359,18 +6860,21 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
6359
6860
  const getSelections = (0, react.useCallback)((params) => {
6360
6861
  const point = params?.svgPoint;
6361
6862
  if (!point || !scale?.bandwidth) return [];
6863
+ const position = horizontal ? point.y : point.x;
6362
6864
  const selections = [];
6865
+ const bands = [];
6363
6866
  for (const key of keys) {
6364
6867
  const entry = dataRegistry?.get(key);
6365
6868
  if (!entry) continue;
6366
6869
  const accessor = horizontal ? entry.yAccessor : entry.xAccessor;
6367
- const index = nearestBandIndex(entry.data, accessor, scale, horizontal ? point.y : point.x);
6870
+ const index = nearestBandIndex(entry.data, accessor, scale, position);
6368
6871
  if (index < 0) continue;
6369
6872
  const datum = entry.data[index];
6370
- const start = Number(scale(accessor(datum))) + Number(groupScale(key));
6873
+ const band = Number(scale(accessor(datum)));
6874
+ const start = band + Number(groupScale(slots ? slots.slotOf(key) : key));
6371
6875
  const end = start + groupScale.step();
6372
- const position = horizontal ? point.y : point.x;
6373
6876
  const distance = position >= start && position <= end ? 0 : Math.abs(position - (start + end) / 2);
6877
+ bands.push(band);
6374
6878
  selections.push({
6375
6879
  event: params.event,
6376
6880
  key,
@@ -6381,12 +6885,16 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
6381
6885
  distanceY: horizontal ? distance : 0
6382
6886
  });
6383
6887
  }
6384
- return selections;
6888
+ if (!slots) return selections;
6889
+ const bandDistance = (band) => Math.abs(band + scale.bandwidth() / 2 - position);
6890
+ const hoveredBand = bands.reduce((best, band) => best === void 0 || bandDistance(band) < bandDistance(best) ? band : best, void 0);
6891
+ return selections.filter((_, index) => bands[index] === hoveredBand);
6385
6892
  }, [
6386
6893
  scale,
6387
6894
  dataRegistry,
6388
6895
  horizontal,
6389
6896
  keys,
6897
+ slots,
6390
6898
  groupScale
6391
6899
  ]);
6392
6900
  const handlePointer = (0, react.useCallback)((params) => {
@@ -6396,25 +6904,159 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
6396
6904
  return !best || distance(selection) <= distance(best) ? selection : best;
6397
6905
  }, void 0);
6398
6906
  if (params?.event.type === "pointermove" && nearest) onPointerMove?.(nearest);
6399
- if (withTooltips && params?.event.type !== "pointerup") selections.forEach(showTooltip);
6907
+ if (withTooltips && params?.event.type !== "pointerup") {
6908
+ if (slots) updateTooltip((state) => ({
6909
+ ...state,
6910
+ tooltipData: void 0
6911
+ }));
6912
+ selections.forEach(showTooltip);
6913
+ }
6400
6914
  const callback = params?.event.type === "pointerdown" ? onPointerDown : onPointerUp;
6401
6915
  if (params?.event.type === "pointermove" || !callback) return;
6402
6916
  if (nearest) callback(nearest);
6403
6917
  }, [
6404
6918
  getSelections,
6405
6919
  withTooltips,
6920
+ slots,
6406
6921
  showTooltip,
6922
+ updateTooltip,
6407
6923
  onPointerDown,
6408
6924
  onPointerUp,
6409
6925
  onPointerMove
6410
6926
  ]);
6411
6927
  (0, _visx_xychart.useEventEmitter)("pointermove", withTooltips ? handlePointer : void 0);
6928
+ (0, _visx_xychart.useEventEmitter)("pointerout", withTooltips && slots ? hideTooltip : void 0);
6412
6929
  (0, _visx_xychart.useEventEmitter)("pointerdown", handlePointer);
6413
6930
  (0, _visx_xychart.useEventEmitter)("pointerup", onPointerUp ? handlePointer : void 0);
6414
6931
  return null;
6415
6932
  }
6416
- //#endregion
6417
- //#region src/charts/bar-chart/bar-chart.tsx
6933
+ // src/charts/bar-chart/private/grouped-bars.ts
6934
+ /**
6935
+ * Pairs each comparison series with the primary of its `group`, or with the only primary.
6936
+ *
6937
+ * @param series - The chart's series.
6938
+ * @return The index of each paired comparison's primary, keyed by the comparison's index.
6939
+ */
6940
+ function getComparisonPrimaries(series) {
6941
+ const primaries = series.flatMap((item, index) => item.options?.type === "comparison" ? [] : [{
6942
+ group: item.group,
6943
+ index
6944
+ }]);
6945
+ const primaryByGroup = new Map(primaries.map(({ group, index }) => [group, index]));
6946
+ const onlyPrimary = primaries.length === 1 ? primaries[0].index : void 0;
6947
+ const pairs = /* @__PURE__ */ new Map();
6948
+ series.forEach((item, index) => {
6949
+ const primary = item.options?.type === "comparison" ? primaryByGroup.get(item.group) ?? onlyPrimary : void 0;
6950
+ if (primary !== void 0) pairs.set(index, primary);
6951
+ });
6952
+ return pairs;
6953
+ }
6954
+ /**
6955
+ * The colors a grouped bar chart fills its series with. A comparison takes the lightest tint of its primary's color that keeps 3:1 against the background, and the primary in front of it the shade that keeps 3:1 against that tint. A primary with its own `stroke` keeps it, and a comparison with its own, different `stroke` keeps the pair's colors as given.
6956
+ *
6957
+ * @param series - The chart's series.
6958
+ * @param colors - Each series' resolved color.
6959
+ * @param background - The hex chart background.
6960
+ * @return Each series' fill, by index.
6961
+ */
6962
+ function getGroupedBarColors(series, colors, background) {
6963
+ const barColors = [...colors];
6964
+ getComparisonPrimaries(series).forEach((primary, comparison) => {
6965
+ const base = colors[primary];
6966
+ if (!!series[comparison].options?.stroke && colors[comparison].toLowerCase() !== base.toLowerCase() || !isValidHexColor(base) || !isValidHexColor(background)) return;
6967
+ const tint = tintWithContrast(base, background);
6968
+ barColors[comparison] = tint;
6969
+ if (!series[primary].options?.stroke) barColors[primary] = shadeWithContrast(base, tint, background);
6970
+ });
6971
+ return barColors;
6972
+ }
6973
+ // src/charts/bar-chart/use-bar-colors.ts
6974
+ /**
6975
+ * Reads the colors `BarChart` fills series with, so a custom tooltip or legend can match the bars.
6976
+ *
6977
+ * @return A function from series and a layout to each series' bar color, by index.
6978
+ */
6979
+ function useBarColors() {
6980
+ const { getElementStyles, backgroundColor = BACKGROUND_FALLBACK, theme } = useGlobalChartsContext();
6981
+ const comparisonOpacity = theme.barChart?.barStyles?.comparison?.opacity;
6982
+ return (0, react.useCallback)((series, { layout = "grouped" } = {}) => {
6983
+ const colors = series.map((data, index) => getElementStyles({
6984
+ data,
6985
+ index
6986
+ }).color);
6987
+ if (layout !== "overlap") return comparisonOpacity === void 0 ? getGroupedBarColors(series, colors, backgroundColor) : colors;
6988
+ return getOverlapBarColors(series, colors, [getElementStyles({ index: 0 }).color, getElementStyles({ index: 1 }).color], backgroundColor);
6989
+ }, [
6990
+ getElementStyles,
6991
+ backgroundColor,
6992
+ comparisonOpacity
6993
+ ]);
6994
+ }
6995
+ // src/charts/bar-chart/use-bar-legend-items.ts
6996
+ const isComparison = (data, label) => data.some((series) => series.label === label && series.options?.type === "comparison");
6997
+ /**
6998
+ * Applies what a bar layout changes about a legend: overlap lists every primary before every comparison, as it draws their slots, with every swatch opaque like its bar; a collapsed grouped item takes its comparison's tint, the wider bar that frames the group.
6999
+ *
7000
+ * @param data - The series the items were built from.
7001
+ * @param items - The legend items.
7002
+ * @param layout - The layout the bars are drawn in.
7003
+ * @param seriesColors - Each series' bar color, by index.
7004
+ * @return The legend items.
7005
+ */
7006
+ function forBarLayout(data, items, layout, seriesColors) {
7007
+ if (layout === "overlap") {
7008
+ const opaque = items.map((item) => item.shapeStyle ? {
7009
+ ...item,
7010
+ shapeStyle: {
7011
+ ...item.shapeStyle,
7012
+ opacity: void 0
7013
+ }
7014
+ } : item);
7015
+ const seriesItems = opaque.filter((item) => item.seriesLabels);
7016
+ const firstLabel = (item) => item.seriesLabels?.[0];
7017
+ return [
7018
+ ...seriesItems.filter((item) => !isComparison(data, firstLabel(item))),
7019
+ ...seriesItems.filter((item) => isComparison(data, firstLabel(item))),
7020
+ ...opaque.filter((item) => !item.seriesLabels)
7021
+ ];
7022
+ }
7023
+ return items.map((item) => {
7024
+ if ((item.seriesLabels?.length ?? 0) < 2) return item;
7025
+ const comparisonIndex = data.findIndex((series) => series.options?.type === "comparison" && item.seriesLabels?.includes(series.label));
7026
+ return comparisonIndex === -1 ? item : {
7027
+ ...item,
7028
+ color: seriesColors[comparisonIndex]
7029
+ };
7030
+ });
7031
+ }
7032
+ /**
7033
+ * Builds legend items that match `BarChart`'s bars in a layout, for a custom legend or a chart's own.
7034
+ *
7035
+ * @param data - The series the chart draws.
7036
+ * @param options - The legend options, and the layout the bars are drawn in.
7037
+ * @param legendShape - The shape of the legend swatches.
7038
+ * @return The legend items.
7039
+ */
7040
+ function useBarLegendItems(data, options = {}, legendShape) {
7041
+ const { layout } = options;
7042
+ const getBarColors = useBarColors();
7043
+ const seriesColors = (0, react.useMemo)(() => layout ? getBarColors(data, { layout }) : void 0, [
7044
+ data,
7045
+ layout,
7046
+ getBarColors
7047
+ ]);
7048
+ const items = useChartLegendItems(data, (0, react.useMemo)(() => ({
7049
+ ...options,
7050
+ seriesColors
7051
+ }), [options, seriesColors]), legendShape);
7052
+ return (0, react.useMemo)(() => layout && seriesColors ? forBarLayout(data, items, layout, seriesColors) : items, [
7053
+ data,
7054
+ items,
7055
+ layout,
7056
+ seriesColors
7057
+ ]);
7058
+ }
7059
+ // src/charts/bar-chart/bar-chart.tsx
6418
7060
  const validateData$2 = (data) => {
6419
7061
  if (!data?.length) return (0, _wordpress_i18n.__)("No data available", "jetpack-charts");
6420
7062
  if (data.some((series) => series.data.some((point) => isInvalidReading(point.value, { allowMissing: true }) || !point.label && (!("date" in point && point.date) || isNaN(point.date.getTime()))))) return (0, _wordpress_i18n.__)("Invalid data", "jetpack-charts");
@@ -6425,13 +7067,14 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ (0, react_jsx_runtime
6425
7067
  className: bar_chart_module_default["bar-chart__tooltip-row"],
6426
7068
  children: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%1$s: %2$s", "jetpack-charts"), label, value)
6427
7069
  });
6428
- const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
7070
+ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", layout = "grouped", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
6429
7071
  if (!withTooltips && (withBandHighlight || onBandHighlightChange)) warnOnce("bar-chart-band-highlight-without-tooltips", "BarChart: withBandHighlight and onBandHighlightChange require withTooltips.");
6430
7072
  const legendInteractive = legend.interactive ?? false;
6431
7073
  const legendCollapseGroups = legend.collapseGroups ?? false;
6432
7074
  const legendComparisonItem = legend.comparisonItem ?? false;
6433
7075
  const legendComparisonSeriesItems = legend.comparisonSeriesItems;
6434
7076
  const horizontal = orientation === "horizontal";
7077
+ const isOverlap = layout === "overlap";
6435
7078
  const chartId = useChartId(providedChartId);
6436
7079
  const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
6437
7080
  const isSeriesVisible = (0, react.useCallback)((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
@@ -6441,16 +7084,25 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6441
7084
  enabled: showZeroValues,
6442
7085
  valueAxisLength: horizontal ? width : height
6443
7086
  });
6444
- const legendItems = useChartLegendItems(dataSorted, (0, react.useMemo)(() => ({
7087
+ const legendItems = useBarLegendItems(dataSorted, (0, react.useMemo)(() => ({
6445
7088
  collapseGroups: legendCollapseGroups,
6446
7089
  comparisonItem: legendComparisonItem,
6447
- comparisonSeriesItems: legendComparisonSeriesItems
7090
+ comparisonSeriesItems: legendComparisonSeriesItems,
7091
+ layout
6448
7092
  }), [
6449
7093
  legendCollapseGroups,
6450
7094
  legendComparisonItem,
6451
- legendComparisonSeriesItems
7095
+ legendComparisonSeriesItems,
7096
+ layout
6452
7097
  ]));
6453
- const { getElementStyles } = useGlobalChartsContext();
7098
+ const { getElementStyles, theme: providerTheme } = useGlobalChartsContext();
7099
+ const getBarColors = useBarColors();
7100
+ const barColors = (0, react.useMemo)(() => getBarColors(dataSorted, { layout }), [
7101
+ layout,
7102
+ getBarColors,
7103
+ dataSorted
7104
+ ]);
7105
+ if (providerTheme.barChart?.barStyles?.comparison?.opacity !== void 0) warnOnce("bar-chart-comparison-opacity", "BarChart: theme.barChart.barStyles.comparison.opacity is deprecated. Comparison bars are opaque; leave it unset.");
6454
7106
  const isSeriesRendered = (0, react.useCallback)((series) => isSeriesVisible(series.label), [isSeriesVisible]);
6455
7107
  const hasWholeNumberValues = (0, react.useMemo)(() => hasOnlyWholeNumbers(dataSorted.filter(isSeriesRendered)), [dataSorted, isSeriesRendered]);
6456
7108
  const chartOptions = useBarChartOptions(dataWithVisibleZeros, horizontal, options, isSeriesRendered);
@@ -6479,37 +7131,30 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6479
7131
  return seriesWithVisibility.every(({ isVisible }) => !isVisible);
6480
7132
  }, [seriesWithVisibility]);
6481
7133
  const primaryEntries = (0, react.useMemo)(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
6482
- const totalPoints = Math.max(0, ...primaryEntries.map((e) => e.series.data.length)) * primaryEntries.length;
7134
+ const overlapSlots = useOverlapSlots(isOverlap, seriesWithVisibility);
6483
7135
  const primaryKeys = (0, react.useMemo)(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
6484
- const primarySeries = (0, react.useMemo)(() => primaryEntries.map(({ series }) => series), [primaryEntries]);
6485
- const activateSelectedBar = (0, react.useCallback)((index) => {
6486
- const primaryCount = primaryEntries.length;
6487
- if (!primaryCount) return;
6488
- const dataPointIndex = Math.floor(index / primaryCount);
6489
- const series = primaryEntries[index % primaryCount]?.series;
6490
- const datum = series?.data[dataPointIndex];
6491
- if (series && datum) onDatumActivate?.({
6492
- datum,
6493
- index: dataPointIndex,
6494
- key: series.label
6495
- });
6496
- }, [primaryEntries, onDatumActivate]);
6497
- const visibleSeriesKey = (0, react.useMemo)(() => JSON.stringify(primaryKeys), [primaryKeys]);
7136
+ const stops = useBarStops(overlapSlots, primaryEntries);
7137
+ const { barAt, stopOf } = stops;
7138
+ const activateSelectedBar = (0, react.useCallback)((stop) => {
7139
+ const bar = barAt(stop);
7140
+ if (bar) onDatumActivate?.(bar);
7141
+ }, [barAt, onDatumActivate]);
6498
7142
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown, onChartPointerMove } = useKeyboardNavigation({
6499
7143
  selectedIndex,
6500
7144
  setSelectedIndex,
6501
7145
  isNavigating,
6502
7146
  setIsNavigating,
6503
7147
  chartRef,
6504
- totalPoints,
7148
+ totalPoints: stops.count,
6505
7149
  onActivate: activateSelectedBar,
6506
- visibleSeriesKey
7150
+ visibleSeriesKey: stops.key
6507
7151
  });
6508
7152
  const handlePointerMove = (0, react.useCallback)(({ key, index }) => {
6509
- const seriesIndex = primaryKeys.indexOf(key);
6510
- if (seriesIndex >= 0) onChartPointerMove(index * primaryKeys.length + seriesIndex);
6511
- }, [primaryKeys, onChartPointerMove]);
7153
+ const stop = stopOf(key, index);
7154
+ if (stop !== void 0) onChartPointerMove(stop);
7155
+ }, [stopOf, onChartPointerMove]);
6512
7156
  const comparisonEntries = (0, react.useMemo)(() => {
7157
+ if (isOverlap) return [];
6513
7158
  const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
6514
7159
  label: series.label,
6515
7160
  index
@@ -6525,12 +7170,12 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6525
7170
  entries.push({
6526
7171
  series,
6527
7172
  index,
6528
- primaryKey: primary.label,
6529
- primaryIndex: primary.index
7173
+ primaryKey: primary.label
6530
7174
  });
6531
7175
  });
6532
7176
  return entries;
6533
7177
  }, [
7178
+ isOverlap,
6534
7179
  seriesWithVisibility,
6535
7180
  primaryEntries,
6536
7181
  primaryKeys
@@ -6570,33 +7215,39 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6570
7215
  chartOptions.yScale,
6571
7216
  horizontal
6572
7217
  ]);
6573
- const getBarBackground = (0, react.useCallback)((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? getElementStyles({
6574
- data: dataSorted[index],
6575
- index
6576
- }).color, [
7218
+ const getBarBackground = (0, react.useCallback)((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? barColors[index] ?? "", [
6577
7219
  withPatterns,
6578
- getElementStyles,
6579
- dataSorted,
7220
+ barColors,
6580
7221
  chartId
6581
7222
  ]);
6582
- const resolveComparisonFill = (0, react.useCallback)((entry) => withPatterns ? `url(#${getPatternId(chartId, entry.primaryIndex)})` : getElementStyles({
6583
- data: entry.series,
6584
- index: entry.index
6585
- }).color, [
7223
+ const resolveComparisonFill = (0, react.useCallback)((entry, datum) => withPatterns ? `url(#${getPatternId(chartId, entry.index)})` : datum.color ?? barColors[entry.index] ?? "", [
6586
7224
  withPatterns,
6587
7225
  chartId,
6588
- getElementStyles
7226
+ barColors
6589
7227
  ]);
7228
+ const renderOverlapTooltip = (0, react.useCallback)(({ tooltipData }) => {
7229
+ const nearestDatum = tooltipData?.nearestDatum?.datum;
7230
+ if (!nearestDatum) return null;
7231
+ const datumByKey = tooltipData?.datumByKey ?? {};
7232
+ const categoryLabel = chartOptions.tooltip.labelFormatter(nearestDatum.label || (nearestDatum.date ? nearestDatum.date.getTime() : 0), 0, []);
7233
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7234
+ className: bar_chart_module_default["bar-chart__tooltip"],
7235
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7236
+ className: bar_chart_module_default["bar-chart__tooltip-header"],
7237
+ children: categoryLabel
7238
+ }), dataSorted.flatMap(({ label }) => {
7239
+ const datum = datumByKey[label]?.datum;
7240
+ return datum ? [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderTooltipRow(label, formatReading(datum.value)) }, label)] : [];
7241
+ })]
7242
+ });
7243
+ }, [chartOptions.tooltip, dataSorted]);
6590
7244
  const renderDefaultTooltip = (0, react.useCallback)(({ tooltipData }) => {
6591
7245
  const nearestDatum = tooltipData?.nearestDatum?.datum;
6592
7246
  if (!nearestDatum) return null;
6593
7247
  const primaryKey = tooltipData?.nearestDatum?.key;
6594
7248
  const categoryLabel = chartOptions.tooltip.labelFormatter(nearestDatum.label || (nearestDatum.date ? nearestDatum.date.getTime() : 0), 0, []);
6595
7249
  const comparisonEntry = comparisonEntries.find((entry) => entry.primaryKey === primaryKey);
6596
- const comparisonDatum = comparisonEntry?.series.data.find((point) => {
6597
- const p = point;
6598
- return nearestDatum.label != null ? p.label === nearestDatum.label : !!nearestDatum.date && !!p.date && p.date.getTime() === nearestDatum.date.getTime();
6599
- });
7250
+ const comparisonDatum = comparisonEntry?.series.data.find((point) => isSameCategory(point, nearestDatum));
6600
7251
  if (comparisonEntry && comparisonDatum) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6601
7252
  className: bar_chart_module_default["bar-chart__tooltip"],
6602
7253
  children: [
@@ -6661,26 +7312,35 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6661
7312
  }
6662
7313
  `;
6663
7314
  }, [chartId]);
6664
- const createKeyboardHighlightStyle = (0, react.useCallback)(() => {
6665
- if (selectedIndex === void 0) return "";
6666
- const primaryCount = primaryEntries.length;
6667
- if (!primaryCount) return "";
6668
- const dataPointIndex = Math.floor(selectedIndex / primaryCount);
6669
- const seriesIndex = selectedIndex % primaryCount;
6670
- const seriesData = primaryEntries[seriesIndex]?.series;
6671
- const datum = seriesData?.data[dataPointIndex];
6672
- if (!seriesData || !datum || !isBarRendered(datum)) return "";
6673
- const domBarIndex = primaryEntries.slice(0, seriesIndex).reduce((count, { series }) => count + countRenderedBars(series.data), 0) + countRenderedBars(seriesData.data.slice(0, dataPointIndex));
6674
- return `
6675
- .bar-chart[data-chart-id="bar-chart-${chartId}"] .visx-bar-group .visx-bar:nth-child(${domBarIndex + 1}) {
6676
- stroke: #005fcc;
6677
- stroke-width: 2px;
6678
- }
6679
- `;
7315
+ const overlapBandSlots = (0, react.useMemo)(() => overlapSlots && {
7316
+ keys: overlapSlots.slotKeys,
7317
+ slotOf: overlapSlots.slotOf
7318
+ }, [overlapSlots]);
7319
+ const selectedSlot = (0, react.useMemo)(() => getSelectedSlot(overlapSlots, selectedIndex), [overlapSlots, selectedIndex]);
7320
+ const selectedGroup = (0, react.useMemo)(() => {
7321
+ const stop = overlapSlots || selectedIndex === void 0 ? void 0 : barAt(selectedIndex);
7322
+ if (!stop) return;
7323
+ return membersAt(primaryEntries, stop.datum, stop.key);
6680
7324
  }, [
7325
+ overlapSlots,
6681
7326
  selectedIndex,
6682
- primaryEntries,
6683
- chartId
7327
+ barAt,
7328
+ primaryEntries
7329
+ ]);
7330
+ const selectedMembers = selectedSlot?.members ?? selectedGroup;
7331
+ const selectedBar = (0, react.useMemo)(() => {
7332
+ if (overlapSlots) return selectedSlot;
7333
+ const bar = selectedIndex === void 0 ? void 0 : barAt(selectedIndex);
7334
+ return bar && isBarRendered(bar.datum) ? {
7335
+ data: [bar.datum],
7336
+ slotKey: bar.key,
7337
+ thickness: 1
7338
+ } : void 0;
7339
+ }, [
7340
+ overlapSlots,
7341
+ selectedSlot,
7342
+ selectedIndex,
7343
+ barAt
6684
7344
  ]);
6685
7345
  const error = validateData$2(dataSorted);
6686
7346
  const isDataValid = !error;
@@ -6701,7 +7361,6 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6701
7361
  children: error
6702
7362
  });
6703
7363
  const gridVisibility = gridVisibilityProp ?? chartOptions.gridVisibility;
6704
- const highlightedBarStyle = createKeyboardHighlightStyle();
6705
7364
  const legendPosition = legend.position ?? "bottom";
6706
7365
  const legendElement = showLegend && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
6707
7366
  orientation: legend.orientation ?? "horizontal",
@@ -6781,14 +7440,7 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6781
7440
  tickValues: (horizontal ? void 0 : valueTicks) ?? chartOptions.axis.y.tickValues
6782
7441
  })] })
6783
7442
  }),
6784
- withPatterns && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: dataSorted.map((seriesData, index) => renderPattern(index, getElementStyles({
6785
- data: seriesData,
6786
- index
6787
- }).color)) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: dataSorted.map((seriesData, index) => createPatternBorderStyle(index, getElementStyles({
6788
- data: seriesData,
6789
- index
6790
- }).color)) })] }),
6791
- highlightedBarStyle && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: highlightedBarStyle }),
7443
+ withPatterns && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: barColors.map((color, index) => renderPattern(index, color)) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: barColors.map((color, index) => createPatternBorderStyle(index, color)) })] }),
6792
7444
  allSeriesHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
6793
7445
  x: width / 2,
6794
7446
  y: chartHeight / 2,
@@ -6806,30 +7458,22 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6806
7458
  getElementStyles,
6807
7459
  resolveFill: resolveComparisonFill
6808
7460
  }),
6809
- barClassName ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
6810
- className: "visx-bar-group",
6811
- children: primaryEntries.map(({ series: seriesData, index }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClassifiedBarSeries, {
6812
- dataKey: seriesData.label,
6813
- data: seriesData.data,
6814
- xAccessor: chartOptions.accessors.xAccessor,
6815
- yAccessor: chartOptions.accessors.yAccessor,
6816
- colorAccessor: getBarBackground(index),
6817
- barClassName,
6818
- primaryKeys,
6819
- groupPadding
6820
- }, seriesData.label))
6821
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.BarGroup, {
6822
- padding: groupPadding,
6823
- children: primaryEntries.map(({ series: seriesData, index }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.BarSeries, {
6824
- dataKey: seriesData?.label,
6825
- data: seriesData.data,
6826
- yAccessor: chartOptions.accessors.yAccessor,
6827
- xAccessor: chartOptions.accessors.xAccessor,
6828
- colorAccessor: getBarBackground(index)
6829
- }, seriesData?.label))
7461
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarLayer, {
7462
+ chartId,
7463
+ overlapSlots,
7464
+ selectedBar,
7465
+ primaryEntries,
7466
+ primaryKeys,
7467
+ getBarBackground,
7468
+ barClassName,
7469
+ groupPadding,
7470
+ horizontal,
7471
+ xAccessor: chartOptions.accessors.xAccessor,
7472
+ yAccessor: chartOptions.accessors.yAccessor
6830
7473
  }),
6831
7474
  (withTooltips || onPointerDown || onPointerUp) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BandTooltip, {
6832
- keys: primaryKeys,
7475
+ keys: overlapSlots?.keys ?? primaryKeys,
7476
+ slots: overlapBandSlots,
6833
7477
  groupPadding,
6834
7478
  withTooltips,
6835
7479
  onPointerDown,
@@ -6846,6 +7490,7 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6846
7490
  ...!horizontal && valueTicks ? { tickValues: valueTicks } : {}
6847
7491
  })] })
6848
7492
  }),
7493
+ withTooltips && selectedMembers && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SlotTooltipMembers, { members: selectedMembers }),
6849
7494
  withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
6850
7495
  tooltipPlacement,
6851
7496
  tooltipAnchorTop,
@@ -6853,11 +7498,10 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6853
7498
  detectBounds: true,
6854
7499
  snapTooltipToDatumX: true,
6855
7500
  snapTooltipToDatumY: true,
6856
- renderTooltip: renderTooltip || renderDefaultTooltip,
7501
+ renderTooltip: renderTooltip || (isOverlap ? renderOverlapTooltip : renderDefaultTooltip),
6857
7502
  selectedIndex,
6858
7503
  tooltipRef,
6859
7504
  keyboardFocusedClassName: bar_chart_module_default["bar-chart__tooltip--keyboard-focused"],
6860
- series: primarySeries,
6861
7505
  mode: "individual"
6862
7506
  })
6863
7507
  ]
@@ -6875,8 +7519,7 @@ const BarChartWithProvider = (props) => {
6875
7519
  BarChartWithProvider.displayName = "BarChart";
6876
7520
  const BarChart = attachSubComponents(BarChartWithProvider, { Legend });
6877
7521
  const BarChartResponsive = attachSubComponents(withResponsive(BarChartWithProvider), { Legend });
6878
- //#endregion
6879
- //#region src/charts/bar-list-chart/bar-list-chart.tsx
7522
+ // src/charts/bar-list-chart/bar-list-chart.tsx
6880
7523
  /**
6881
7524
  * Get the bandwidth of a scale
6882
7525
  * @param scale - The scale to get the bandwidth of
@@ -7045,8 +7688,7 @@ const BarListChart = (props) => {
7045
7688
  };
7046
7689
  BarListChart.displayName = "BarListChart";
7047
7690
  const BarListChartResponsive = withResponsive(BarListChart);
7048
- //#endregion
7049
- //#region src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss
7691
+ // src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss
7050
7692
  var conversion_funnel_chart_module_default = {
7051
7693
  "bar-container": "a8ccharts-mGEVca-bar-container",
7052
7694
  "change-indicator": "a8ccharts-mGEVca-change-indicator",
@@ -7065,83 +7707,131 @@ var conversion_funnel_chart_module_default = {
7065
7707
  "main-rate": "a8ccharts-mGEVca-main-rate",
7066
7708
  "step-label": "a8ccharts-mGEVca-step-label",
7067
7709
  "step-rate": "a8ccharts-mGEVca-step-rate",
7710
+ "step-text": "a8ccharts-mGEVca-step-text",
7068
7711
  "stretch": "a8ccharts-mGEVca-stretch",
7069
- "tooltip-content": "a8ccharts-mGEVca-tooltip-content",
7070
- "tooltip-title": "a8ccharts-mGEVca-tooltip-title"
7712
+ "tooltip-label": "a8ccharts-mGEVca-tooltip-label",
7713
+ "tooltip-title": "a8ccharts-mGEVca-tooltip-title",
7714
+ "tooltip-value": "a8ccharts-mGEVca-tooltip-value"
7071
7715
  };
7072
- //#endregion
7073
- //#region src/charts/conversion-funnel-chart/private/use-funnel-selection.ts
7716
+ // src/charts/conversion-funnel-chart/private/use-funnel-selection.ts
7074
7717
  /**
7075
- * Custom hook to manage funnel bar selection state and interactions
7718
+ * Custom hook to manage funnel step selection state
7076
7719
  * @param hideTooltip - Function to hide tooltip when selection is cleared
7077
- * @return Object containing selection state and event handlers
7720
+ * @return Object containing selection state and its setters
7078
7721
  */
7079
7722
  const useFunnelSelection = (hideTooltip) => {
7080
- const [clickedStep, setClickedStep] = (0, react.useState)(null);
7723
+ const [selectedStepId, setSelectedStepId] = (0, react.useState)(null);
7081
7724
  return {
7082
- clickedStep,
7083
- handleBarClick: (0, react.useCallback)((stepId) => {
7084
- if (clickedStep === stepId) {
7085
- setClickedStep(null);
7086
- hideTooltip?.();
7087
- } else setClickedStep(stepId);
7088
- }, [clickedStep, hideTooltip]),
7089
- handleBarKeyDown: (0, react.useCallback)((stepId, event) => {
7090
- if (event.key === "Enter" || event.key === " ") {
7091
- event.preventDefault();
7092
- if (clickedStep === stepId) {
7093
- setClickedStep(null);
7094
- hideTooltip?.();
7095
- } else setClickedStep(stepId);
7096
- } else if (event.key === "Escape") {
7097
- event.preventDefault();
7098
- setClickedStep(null);
7099
- hideTooltip?.();
7100
- }
7101
- }, [clickedStep, hideTooltip]),
7725
+ selectedStepId,
7726
+ selectStep: setSelectedStepId,
7102
7727
  clearSelection: (0, react.useCallback)(() => {
7103
- setClickedStep(null);
7728
+ setSelectedStepId(null);
7104
7729
  hideTooltip?.();
7105
7730
  }, [hideTooltip]),
7106
7731
  getStepState: (0, react.useCallback)((stepId) => ({
7107
- isClicked: clickedStep === stepId,
7108
- isBlurred: clickedStep !== null && clickedStep !== stepId
7109
- }), [clickedStep])
7732
+ isSelected: selectedStepId === stepId,
7733
+ isBlurred: selectedStepId !== null && selectedStepId !== stepId
7734
+ }), [selectedStepId])
7735
+ };
7736
+ };
7737
+ // src/charts/conversion-funnel-chart/private/use-roving-step-focus.ts
7738
+ const getTargetIndex = (key, index, count, isRtl) => {
7739
+ const nextKey = isRtl ? "ArrowLeft" : "ArrowRight";
7740
+ const previousKey = isRtl ? "ArrowRight" : "ArrowLeft";
7741
+ switch (key) {
7742
+ case nextKey: return Math.min(index + 1, count - 1);
7743
+ case previousKey: return Math.max(index - 1, 0);
7744
+ case "Home": return 0;
7745
+ case "End": return count - 1;
7746
+ default: return;
7747
+ }
7748
+ };
7749
+ /**
7750
+ * Roving tabindex for the funnel steps: one Tab stop, and arrow keys, Home and End move focus between steps.
7751
+ *
7752
+ * @param stepIds - Step ids in visual order.
7753
+ * @param selectedStepId - The selected step, which holds the Tab stop until any step has taken focus.
7754
+ * @return Tab index, element registration, focus and key handlers for each step.
7755
+ */
7756
+ const useRovingStepFocus = (stepIds, selectedStepId) => {
7757
+ const [focusedStepId, setFocusedStepId] = (0, react.useState)(null);
7758
+ const stepElements = (0, react.useRef)(/* @__PURE__ */ new Map());
7759
+ const tabStopId = [focusedStepId, selectedStepId].find((id) => id !== null && stepIds.includes(id)) ?? stepIds[0];
7760
+ return {
7761
+ getTabIndex: (0, react.useCallback)((stepId) => stepId === tabStopId ? 0 : -1, [tabStopId]),
7762
+ setStepElement: (0, react.useCallback)((stepId, element) => {
7763
+ if (element) stepElements.current.set(stepId, element);
7764
+ else stepElements.current.delete(stepId);
7765
+ }, []),
7766
+ handleStepFocus: (0, react.useCallback)((stepId) => {
7767
+ setFocusedStepId(stepId);
7768
+ }, []),
7769
+ handleNavigationKey: (0, react.useCallback)((stepId, event) => {
7770
+ if (event.altKey || event.ctrlKey || event.metaKey) return false;
7771
+ const isRtl = getComputedStyle(event.currentTarget).direction === "rtl";
7772
+ const targetIndex = getTargetIndex(event.key, stepIds.indexOf(stepId), stepIds.length, isRtl);
7773
+ if (targetIndex === void 0) return false;
7774
+ event.preventDefault();
7775
+ stepElements.current.get(stepIds[targetIndex])?.focus();
7776
+ return true;
7777
+ }, [stepIds])
7110
7778
  };
7111
7779
  };
7112
- //#endregion
7113
- //#region src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx
7780
+ // src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx
7114
7781
  /** Chart height (px) below which the funnel tightens its gaps so the bars keep their room. */
7115
7782
  const SHORT_CHART_HEIGHT = 180;
7783
+ const formatStepCount = (count) => (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n._n)("%s item", "%s items", count, "jetpack-charts"), formatMetricValue(count));
7784
+ const getDefaultTooltipContent = (step) => ({
7785
+ value: step.count === void 0 ? void 0 : formatStepCount(step.count),
7786
+ rows: [{
7787
+ label: (0, _wordpress_i18n.__)("Conversion rate", "jetpack-charts"),
7788
+ value: formatPercentage(step.rate)
7789
+ }]
7790
+ });
7791
+ const getDefaultTooltipIds = (tooltipId, { rows = [] }) => ({
7792
+ value: `${tooltipId}-value`,
7793
+ rows: rows.map((_, index) => ({
7794
+ label: `${tooltipId}-row-${index}-label`,
7795
+ value: `${tooltipId}-row-${index}-value`
7796
+ }))
7797
+ });
7798
+ const getDefaultTooltipDescriptionIds = (tooltipId, content) => {
7799
+ const ids = getDefaultTooltipIds(tooltipId, content);
7800
+ return [...content.value ? [ids.value] : [], ...ids.rows.flatMap((row) => [row.label, row.value])].join(" ");
7801
+ };
7116
7802
  /**
7117
7803
  * Internal ConversionFunnelChart component with chart registration
7118
7804
  *
7119
- * @param props - Component props
7120
- * @param props.chartId - Optional unique identifier for the chart
7121
- * @param props.mainRate - Main conversion rate to highlight
7122
- * @param props.changeIndicator - Change indicator (e.g., +2%, -1.5%)
7123
- * @param props.steps - Array of funnel steps
7124
- * @param props.loading - Whether the chart is in loading state
7125
- * @param props.animation - Whether to show chart animation on initial render or not
7126
- * @param props.className - Additional CSS class name
7127
- * @param props.ariaLabel - Accessible name for the chart group
7128
- * @param props.height - Height of the chart container. Falls back to style.height if set, otherwise defaults to "100%".
7129
- * @param props.style - Custom styling
7130
- * @param props.renderStepLabel - Custom render function for step labels
7131
- * @param props.renderStepRate - Custom render function for step rates
7132
- * @param props.renderMainMetric - Custom render function for the entire main metric section
7133
- * @param props.renderTooltip - Custom render function for tooltip content
7134
- * @param props.tooltipStyle - Inline styles merged over the tooltip box defaults
7805
+ * @param props - Component props
7806
+ * @param props.chartId - Optional unique identifier for the chart
7807
+ * @param props.mainRate - Main conversion rate to highlight
7808
+ * @param props.changeIndicator - Change indicator (e.g., +2%, -1.5%)
7809
+ * @param props.steps - Array of funnel steps
7810
+ * @param props.loading - Whether the chart is in loading state
7811
+ * @param props.animation - Whether to show chart animation on initial render or not
7812
+ * @param props.className - Additional CSS class name
7813
+ * @param props.ariaLabel - Accessible name for the chart group
7814
+ * @param props.height - Height of the chart container. Falls back to style.height if set, otherwise defaults to "100%".
7815
+ * @param props.style - Custom styling
7816
+ * @param props.renderStepLabel - Custom render function for step labels
7817
+ * @param props.renderStepRate - Custom render function for step rates
7818
+ * @param props.renderMainMetric - Custom render function for the entire main metric section
7819
+ * @param props.renderTooltip - Custom render function for tooltip content
7820
+ * @param props.tooltipStyle - Inline styles merged over the tooltip box defaults
7821
+ * @param props.getTooltipContent - What each step's tooltip shows, which screen readers also read
7135
7822
  * @return JSX element representing the conversion funnel chart
7136
7823
  */
7137
- const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, ariaLabel, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
7824
+ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, ariaLabel, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle, getTooltipContent = getDefaultTooltipContent }) => {
7138
7825
  const chartId = useChartId(providedChartId);
7139
7826
  const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
7140
7827
  const chartRef = (0, react.useRef)(null);
7141
- const selectedBarRef = (0, react.useRef)(null);
7828
+ const isPointerFocusRef = (0, react.useRef)(false);
7142
7829
  const [scopeNode, setScopeNode] = (0, react.useState)(null);
7830
+ const tooltipId = (0, react.useId)();
7143
7831
  const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
7144
- const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
7832
+ const { selectedStepId, selectStep, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
7833
+ const stepIds = (0, react.useMemo)(() => steps?.map((step) => step.id) ?? [], [steps]);
7834
+ const { getTabIndex, setStepElement, handleStepFocus, handleNavigationKey } = useRovingStepFocus(stepIds, selectedStepId);
7145
7835
  const standaloneScopeClass = useStandaloneScopeClass();
7146
7836
  const [measureChartRef, , chartHeight] = useElementSize();
7147
7837
  const gap = chartHeight > 0 && chartHeight < SHORT_CHART_HEIGHT ? "sm" : "xl";
@@ -7150,94 +7840,71 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7150
7840
  setScopeNode(node);
7151
7841
  measureChartRef(node);
7152
7842
  }, [measureChartRef]);
7153
- const clearSelectionAndRef = (0, react.useCallback)(() => {
7154
- clearSelection();
7155
- selectedBarRef.current = null;
7156
- hideTooltip();
7157
- }, [clearSelection, hideTooltip]);
7158
- const showTooltipAt = (0, react.useCallback)((step, x, y) => {
7159
- showTooltip({
7843
+ const selectStepAt = (0, react.useCallback)((step, x, y) => {
7844
+ selectStep(step.id);
7845
+ const bounds = chartRef.current?.getBoundingClientRect();
7846
+ if (bounds) showTooltip({
7160
7847
  tooltipData: step,
7161
- tooltipLeft: x,
7162
- tooltipTop: y - 10
7848
+ tooltipLeft: x - bounds.left,
7849
+ tooltipTop: y - bounds.top - 10
7163
7850
  });
7164
- }, [showTooltip]);
7165
- const getMouseTooltipCoords = (0, react.useCallback)((event) => {
7166
- const bounds = chartRef.current?.getBoundingClientRect();
7167
- if (!bounds) return null;
7168
- return {
7169
- x: event.clientX - bounds.left,
7170
- y: event.clientY - bounds.top
7171
- };
7172
- }, []);
7173
- const getKeyboardTooltipCoords = (0, react.useCallback)((event) => {
7174
- const bounds = chartRef.current?.getBoundingClientRect();
7175
- if (!bounds) return null;
7176
- const rect = event.currentTarget.getBoundingClientRect();
7177
- return {
7178
- x: rect.left + rect.width / 2 - bounds.left,
7179
- y: rect.top - bounds.top
7180
- };
7181
- }, []);
7182
- const handleStepInteraction = (0, react.useCallback)((step, event, interactionType) => {
7183
- selectedBarRef.current = event.currentTarget;
7184
- const { isClicked } = getStepState(step.id);
7185
- if (isClicked) {
7186
- if (interactionType === "click") handleBarClick(step.id);
7187
- else handleBarKeyDown(step.id, event);
7188
- return;
7189
- }
7190
- if (interactionType === "click") {
7191
- handleBarClick(step.id);
7192
- const coords = getMouseTooltipCoords(event);
7193
- if (coords) showTooltipAt(step, coords.x, coords.y);
7194
- } else {
7195
- handleBarKeyDown(step.id, event);
7196
- const coords = getKeyboardTooltipCoords(event);
7197
- if (coords) showTooltipAt(step, coords.x, coords.y);
7198
- }
7199
- }, [
7200
- getStepState,
7201
- handleBarClick,
7202
- handleBarKeyDown,
7203
- showTooltipAt,
7204
- getMouseTooltipCoords,
7205
- getKeyboardTooltipCoords
7206
- ]);
7851
+ }, [selectStep, showTooltip]);
7852
+ const selectStepAtElement = (0, react.useCallback)((step, element) => {
7853
+ const rect = element.getBoundingClientRect();
7854
+ selectStepAt(step, rect.left + rect.width / 2, rect.top);
7855
+ }, [selectStepAt]);
7207
7856
  const stepHandlers = (0, react.useMemo)(() => {
7208
7857
  const handlers = /* @__PURE__ */ new Map();
7209
7858
  steps.forEach((step) => {
7859
+ const onPointerDown = () => {
7860
+ isPointerFocusRef.current = true;
7861
+ };
7210
7862
  const onClick = (event) => {
7211
- event.stopPropagation();
7212
- handleStepInteraction(step, event, "click");
7863
+ isPointerFocusRef.current = false;
7864
+ selectStepAt(step, event.clientX, event.clientY);
7865
+ };
7866
+ const onFocus = (event) => {
7867
+ handleStepFocus(step.id);
7868
+ if (isPointerFocusRef.current) isPointerFocusRef.current = false;
7869
+ else if (step.id !== selectedStepId) selectStepAtElement(step, event.currentTarget);
7213
7870
  };
7214
7871
  const onKeyDown = (event) => {
7215
- if (event.key === "Enter" || event.key === " ") handleStepInteraction(step, event, "keyboard");
7216
- else {
7217
- selectedBarRef.current = event.currentTarget;
7218
- handleBarKeyDown(step.id, event);
7872
+ isPointerFocusRef.current = false;
7873
+ if (handleNavigationKey(step.id, event)) return;
7874
+ if (event.key === "Enter" || event.key === " ") {
7875
+ event.preventDefault();
7876
+ selectStepAtElement(step, event.currentTarget);
7877
+ } else if (event.key === "Escape" && selectedStepId !== null) {
7878
+ event.preventDefault();
7879
+ clearSelection();
7219
7880
  }
7220
7881
  };
7882
+ const ref = (element) => setStepElement(step.id, element);
7221
7883
  handlers.set(step.id, {
7884
+ onPointerDown,
7222
7885
  onClick,
7223
- onKeyDown
7886
+ onKeyDown,
7887
+ onFocus,
7888
+ ref
7224
7889
  });
7225
7890
  });
7226
7891
  return handlers;
7227
7892
  }, [
7228
7893
  steps,
7229
- handleStepInteraction,
7230
- handleBarKeyDown
7894
+ selectedStepId,
7895
+ selectStepAt,
7896
+ selectStepAtElement,
7897
+ clearSelection,
7898
+ handleNavigationKey,
7899
+ handleStepFocus,
7900
+ setStepElement
7231
7901
  ]);
7232
- (0, react.useEffect)(() => {
7233
- const handleDocumentClick = (event) => {
7234
- if (selectedBarRef.current && !selectedBarRef.current.contains(event.target)) clearSelectionAndRef();
7235
- };
7236
- document.addEventListener("mousedown", handleDocumentClick);
7237
- return () => {
7238
- document.removeEventListener("mousedown", handleDocumentClick);
7239
- };
7240
- }, [clearSelectionAndRef]);
7902
+ const handleStepsBlur = (0, react.useCallback)((event) => {
7903
+ if (!event.currentTarget.contains(event.relatedTarget) && document.hasFocus()) {
7904
+ isPointerFocusRef.current = false;
7905
+ clearSelection();
7906
+ }
7907
+ }, [clearSelection]);
7241
7908
  const resolvedHeight = height ?? style?.height ?? "100%";
7242
7909
  const { color: barColor } = getElementStyles ? getElementStyles({ index: 0 }) : { color: "#000000" };
7243
7910
  const isPositiveChange = changeIndicator?.startsWith("+");
@@ -7249,18 +7916,41 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7249
7916
  className: (0, clsx.default)(conversion_funnel_chart_module_default["change-indicator"], conversion_funnel_chart_module_default[isPositiveChange ? "change-indicator--positive" : "change-indicator--negative"]),
7250
7917
  children: changeIndicator
7251
7918
  })] });
7252
- const renderDefaultTooltip = (step) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7253
- direction: "column",
7254
- align: "flex-start",
7255
- gap: "xs",
7256
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7257
- className: conversion_funnel_chart_module_default["tooltip-title"],
7258
- children: step.label
7259
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7260
- className: conversion_funnel_chart_module_default["tooltip-content"],
7261
- children: [formatPercentage(step.rate), ` • ${step.count ?? "no"} items`]
7262
- })]
7263
- });
7919
+ const renderDefaultTooltip = (step, content) => {
7920
+ const ids = getDefaultTooltipIds(tooltipId, content);
7921
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7922
+ direction: "column",
7923
+ gap: "xs",
7924
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7925
+ direction: "row",
7926
+ justify: "space-between",
7927
+ align: "baseline",
7928
+ gap: "sm",
7929
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7930
+ className: conversion_funnel_chart_module_default["tooltip-title"],
7931
+ children: step.label
7932
+ }), content.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7933
+ id: ids.value,
7934
+ className: conversion_funnel_chart_module_default["tooltip-value"],
7935
+ children: content.value
7936
+ })]
7937
+ }), content.rows?.map((row, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7938
+ direction: "row",
7939
+ justify: "space-between",
7940
+ align: "baseline",
7941
+ gap: "sm",
7942
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7943
+ id: ids.rows[index].label,
7944
+ className: conversion_funnel_chart_module_default["tooltip-label"],
7945
+ children: row.label
7946
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7947
+ id: ids.rows[index].value,
7948
+ className: conversion_funnel_chart_module_default["tooltip-value"],
7949
+ children: row.value
7950
+ })]
7951
+ }, row.label))]
7952
+ });
7953
+ };
7264
7954
  const isDataValid = Boolean(steps && steps.length > 0);
7265
7955
  const chartMetadata = (0, react.useMemo)(() => ({
7266
7956
  mainRate,
@@ -7295,6 +7985,26 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7295
7985
  })
7296
7986
  });
7297
7987
  const maxRate = Math.max(...steps.map((step) => step.rate));
7988
+ const tooltipStep = tooltipOpen ? tooltipData : void 0;
7989
+ let tooltipContent = null;
7990
+ let tooltipDescriptionIds = "";
7991
+ if (tooltipStep) {
7992
+ const index = steps.findIndex((s) => s.id === tooltipStep.id);
7993
+ const content = getTooltipContent(tooltipStep, index);
7994
+ if (renderTooltip) {
7995
+ tooltipContent = renderTooltip({
7996
+ step: tooltipStep,
7997
+ index,
7998
+ content,
7999
+ top: tooltipTop,
8000
+ left: tooltipLeft
8001
+ });
8002
+ tooltipDescriptionIds = tooltipId;
8003
+ } else {
8004
+ tooltipContent = renderDefaultTooltip(tooltipStep, content);
8005
+ tooltipDescriptionIds = getDefaultTooltipDescriptionIds(tooltipId, content);
8006
+ }
8007
+ }
7298
8008
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7299
8009
  direction: "column",
7300
8010
  gap,
@@ -7323,10 +8033,16 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7323
8033
  direction: "row",
7324
8034
  align: "flex-end",
7325
8035
  gap: "lg",
8036
+ role: "listbox",
8037
+ "aria-label": (0, _wordpress_i18n.__)("Funnel steps", "jetpack-charts"),
8038
+ "aria-orientation": "horizontal",
8039
+ onBlur: handleStepsBlur,
7326
8040
  className: conversion_funnel_chart_module_default["funnel-container"],
7327
8041
  children: steps.map((step, index) => {
7328
8042
  const barHeight = step.rate / maxRate * 100;
7329
- const { isBlurred } = getStepState(step.id);
8043
+ const { isSelected, isBlurred } = getStepState(step.id);
8044
+ const handlers = stepHandlers.get(step.id);
8045
+ const isDescribedByTooltip = Boolean(tooltipContent && tooltipDescriptionIds) && tooltipStep?.id === step.id;
7330
8046
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7331
8047
  direction: "column",
7332
8048
  className: (0, clsx.default)(conversion_funnel_chart_module_default["funnel-step"], isColorPaletteResolved && conversion_funnel_chart_module_default["funnel-step--animated"], isBlurred && conversion_funnel_chart_module_default["funnel-step--blurred"]),
@@ -7334,6 +8050,8 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7334
8050
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
7335
8051
  direction: "column",
7336
8052
  gap: "xs",
8053
+ className: conversion_funnel_chart_module_default["step-text"],
8054
+ "aria-hidden": "true",
7337
8055
  children: [renderStepLabel ? renderStepLabel({
7338
8056
  step,
7339
8057
  index,
@@ -7353,11 +8071,16 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7353
8071
  direction: "column",
7354
8072
  justify: "flex-end",
7355
8073
  className: conversion_funnel_chart_module_default["bar-container"],
7356
- onClick: stepHandlers.get(step.id)?.onClick,
7357
- onKeyDown: stepHandlers.get(step.id)?.onKeyDown,
7358
- role: "button",
7359
- tabIndex: isBlurred ? -1 : 0,
7360
- "aria-label": step.label,
8074
+ ref: handlers?.ref,
8075
+ onPointerDown: handlers?.onPointerDown,
8076
+ onClick: handlers?.onClick,
8077
+ onKeyDown: handlers?.onKeyDown,
8078
+ onFocus: handlers?.onFocus,
8079
+ role: "option",
8080
+ tabIndex: getTabIndex(step.id),
8081
+ "aria-label": (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%1$s, %2$s", "jetpack-charts"), step.label, formatPercentage(step.rate)),
8082
+ "aria-selected": isSelected,
8083
+ "aria-describedby": isDescribedByTooltip ? tooltipDescriptionIds : void 0,
7361
8084
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7362
8085
  className: (0, clsx.default)(conversion_funnel_chart_module_default["funnel-bar"], { [conversion_funnel_chart_module_default["funnel-bar--animated"]]: animation && !loading && !prefersReducedMotion }),
7363
8086
  style: {
@@ -7369,25 +8092,17 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
7369
8092
  }, step.id);
7370
8093
  })
7371
8094
  })]
7372
- }), tooltipOpen && tooltipData && (() => {
7373
- const tooltipContent = renderTooltip ? renderTooltip({
7374
- step: tooltipData,
7375
- index: steps.findIndex((s) => s.id === tooltipData.id),
7376
- top: tooltipTop,
7377
- left: tooltipLeft
7378
- }) : renderDefaultTooltip(tooltipData);
7379
- if (!tooltipContent) return null;
7380
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
7381
- top: tooltipTop,
7382
- left: tooltipLeft,
7383
- className: standaloneScopeClass,
7384
- style: tooltipStyle,
7385
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7386
- role: "tooltip",
7387
- children: tooltipContent
7388
- })
7389
- });
7390
- })()]
8095
+ }), tooltipContent && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
8096
+ top: tooltipTop,
8097
+ left: tooltipLeft,
8098
+ className: standaloneScopeClass,
8099
+ style: tooltipStyle,
8100
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8101
+ id: tooltipId,
8102
+ "aria-hidden": "true",
8103
+ children: tooltipContent
8104
+ })
8105
+ })]
7391
8106
  });
7392
8107
  };
7393
8108
  /**
@@ -7401,8 +8116,7 @@ const ConversionFunnelChartWithProvider = (props) => {
7401
8116
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GlobalChartsProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversionFunnelChartInternal, { ...props }) });
7402
8117
  };
7403
8118
  ConversionFunnelChartWithProvider.displayName = "ConversionFunnelChart";
7404
- //#endregion
7405
- //#region src/utils/sanitize-html.ts
8119
+ // src/utils/sanitize-html.ts
7406
8120
  /**
7407
8121
  * External dependencies
7408
8122
  */
@@ -7450,11 +8164,9 @@ function sanitizeHtml(html) {
7450
8164
  ]
7451
8165
  });
7452
8166
  }
7453
- //#endregion
7454
- //#region src/charts/geo-chart/geo-chart.module.scss
8167
+ // src/charts/geo-chart/geo-chart.module.scss
7455
8168
  var geo_chart_module_default = { "container": "a8ccharts-8hS2IW-container" };
7456
- //#endregion
7457
- //#region src/charts/geo-chart/private/use-tooltip-position.ts
8169
+ // src/charts/geo-chart/private/use-tooltip-position.ts
7458
8170
  const TOOLTIP_CLASS = "google-visualization-tooltip";
7459
8171
  const isTooltip = (node) => node instanceof HTMLElement && node.classList.contains(TOOLTIP_CLASS);
7460
8172
  /**
@@ -7538,8 +8250,7 @@ function useTooltipPosition(containerRef) {
7538
8250
  };
7539
8251
  }, [containerRef]);
7540
8252
  }
7541
- //#endregion
7542
- //#region src/charts/geo-chart/geo-chart.tsx
8253
+ // src/charts/geo-chart/geo-chart.tsx
7543
8254
  /**
7544
8255
  * External dependencies
7545
8256
  */
@@ -7759,8 +8470,7 @@ const GeoChartWithProvider = (props) => {
7759
8470
  };
7760
8471
  GeoChartWithProvider.displayName = "GeoChart";
7761
8472
  const GeoChartResponsive = withResponsive(GeoChartWithProvider);
7762
- //#endregion
7763
- //#region src/types.ts
8473
+ // src/types.ts
7764
8474
  let GoogleDataTableColumnRoleType = /* @__PURE__ */ function(GoogleDataTableColumnRoleType) {
7765
8475
  GoogleDataTableColumnRoleType["annotation"] = "annotation";
7766
8476
  GoogleDataTableColumnRoleType["annotationText"] = "annotationText";
@@ -7840,8 +8550,7 @@ const pickLabelTextColor = (fill, roles, defaultRole) => {
7840
8550
  if (!isValidHexColor(fillHex)) return defaultRole;
7841
8551
  return pickLabelTextColorForFill(hexToRgb(fillHex), roles, defaultRole);
7842
8552
  };
7843
- //#endregion
7844
- //#region src/charts/heatmap-chart/heatmap-chart.module.scss
8553
+ // src/charts/heatmap-chart/heatmap-chart.module.scss
7845
8554
  var heatmap_chart_module_default = {
7846
8555
  "heatmap-chart": "a8ccharts-O3YMOW-heatmap-chart",
7847
8556
  "heatmap-chart__cell": "a8ccharts-O3YMOW-heatmap-chart__cell",
@@ -7872,8 +8581,7 @@ var heatmap_chart_module_default = {
7872
8581
  "heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
7873
8582
  "heatmap-chart--height-capped": "a8ccharts-O3YMOW-heatmap-chart--height-capped"
7874
8583
  };
7875
- //#endregion
7876
- //#region src/charts/heatmap-chart/private/use-heatmap-colors.ts
8584
+ // src/charts/heatmap-chart/private/use-heatmap-colors.ts
7877
8585
  const isPresent = (value) => value !== null && value !== void 0 && !isNaN(value);
7878
8586
  /**
7879
8587
  * Get the min and max values from heatmap data, ignoring null/NaN and the zeros
@@ -7952,12 +8660,10 @@ const getHeatmapScale = (primary, background, emptyCell) => {
7952
8660
  high
7953
8661
  };
7954
8662
  };
7955
- //#endregion
7956
- //#region src/charts/heatmap-chart/private/heatmap-context.ts
8663
+ // src/charts/heatmap-chart/private/heatmap-context.ts
7957
8664
  /** Shared by the chart and legend without importing back from `heatmap-chart.tsx`. */
7958
8665
  const HeatmapContext = (0, react.createContext)(null);
7959
- //#endregion
7960
- //#region src/charts/heatmap-chart/private/heatmap-legend.tsx
8666
+ // src/charts/heatmap-chart/private/heatmap-legend.tsx
7961
8667
  const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }) => {
7962
8668
  const context = (0, react.useContext)(HeatmapContext);
7963
8669
  const { legend } = useGlobalChartsTheme();
@@ -8001,8 +8707,7 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
8001
8707
  ]
8002
8708
  });
8003
8709
  };
8004
- //#endregion
8005
- //#region src/charts/heatmap-chart/private/column-groups.ts
8710
+ // src/charts/heatmap-chart/private/column-groups.ts
8006
8711
  const isSpan = (span) => Number.isInteger(span) && span > 0;
8007
8712
  /**
8008
8713
  * Validates column groups and lays them over the columns.
@@ -8108,8 +8813,7 @@ const wrapColumnGroups = (layout, bands) => {
8108
8813
  slotSpans
8109
8814
  };
8110
8815
  };
8111
- //#endregion
8112
- //#region src/charts/heatmap-chart/private/fit-compact-cells.ts
8816
+ // src/charts/heatmap-chart/private/fit-compact-cells.ts
8113
8817
  /**
8114
8818
  * Largest whole-pixel square cell, and the band count giving it, for a compact grid in a box.
8115
8819
  *
@@ -8147,8 +8851,7 @@ const fitCompactCells = (input) => {
8147
8851
  cellSize: minCellSize
8148
8852
  };
8149
8853
  };
8150
- //#endregion
8151
- //#region src/charts/heatmap-chart/private/keyboard-navigation.ts
8854
+ // src/charts/heatmap-chart/private/keyboard-navigation.ts
8152
8855
  const ARROW_KEYS = [
8153
8856
  "ArrowLeft",
8154
8857
  "ArrowRight",
@@ -8278,8 +8981,7 @@ const stepCalendarCell = (grid, blocks, from, key) => {
8278
8981
  const before = page.slice(0, at === -1 ? page.length : at).reverse();
8279
8982
  return firstSelectable(grid, after) ?? firstSelectable(grid, before);
8280
8983
  };
8281
- //#endregion
8282
- //#region src/charts/heatmap-chart/heatmap-chart.tsx
8984
+ // src/charts/heatmap-chart/heatmap-chart.tsx
8283
8985
  const CELL_VALUE_MODIFIER = {
8284
8986
  label: void 0,
8285
8987
  "label-inverse": heatmap_chart_module_default["heatmap-chart__cell-value--inverse"],
@@ -8734,8 +9436,7 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ (0, react_jsx_run
8734
9436
  });
8735
9437
  HeatmapChartResponsiveInner.displayName = "HeatmapChart";
8736
9438
  const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
8737
- //#endregion
8738
- //#region src/charts/heatmap-chart/private/civil-day.ts
9439
+ // src/charts/heatmap-chart/private/civil-day.ts
8739
9440
  const DAY_MS = 864e5;
8740
9441
  const KEY_OPTIONS = {
8741
9442
  calendar: "gregory",
@@ -8884,8 +9585,7 @@ const startOfCivilWeek = (date, weekStartsOn) => {
8884
9585
  * @return Columns needed to cover the span, inclusive.
8885
9586
  */
8886
9587
  const civilWeekSpan = (from, to, weekStartsOn) => Math.floor((startOfCivilWeek(to, weekStartsOn).getTime() - startOfCivilWeek(from, weekStartsOn).getTime()) / (7 * DAY_MS)) + 1;
8887
- //#endregion
8888
- //#region src/charts/heatmap-chart/build-calendar-data.ts
9588
+ // src/charts/heatmap-chart/build-calendar-data.ts
8889
9589
  /** Rows that get a weekday label (Mon, Wed, Fri with a Monday week start). */
8890
9590
  const LABELLED_ROWS = [
8891
9591
  0,
@@ -8987,8 +9687,7 @@ const buildCalendarHeatmapData = (series, options = {}) => {
8987
9687
  rowLabels
8988
9688
  };
8989
9689
  };
8990
- //#endregion
8991
- //#region src/charts/heatmap-chart/build-month-calendar-data.ts
9690
+ // src/charts/heatmap-chart/build-month-calendar-data.ts
8992
9691
  /** Week rows per month, fixed so every month block is the same height. */
8993
9692
  const MONTH_ROWS = 6;
8994
9693
  const DAYS_PER_WEEK = 7;
@@ -9070,8 +9769,7 @@ const buildMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
9070
9769
  columnGroups
9071
9770
  };
9072
9771
  };
9073
- //#endregion
9074
- //#region src/charts/heatmap-chart/use-calendar-heatmap-data.ts
9772
+ // src/charts/heatmap-chart/use-calendar-heatmap-data.ts
9075
9773
  /**
9076
9774
  * `buildCalendarHeatmapData` with the locale and zone taken from
9077
9775
  * `GlobalChartsProvider` where the caller names neither.
@@ -9106,8 +9804,7 @@ const useCalendarHeatmapData = (series, options = {}) => {
9106
9804
  gridEnd
9107
9805
  ]);
9108
9806
  };
9109
- //#endregion
9110
- //#region src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts
9807
+ // src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts
9111
9808
  /**
9112
9809
  * `buildMonthCalendarHeatmapData` with the locale taken from `GlobalChartsProvider`
9113
9810
  * where the caller names none.
@@ -9136,8 +9833,7 @@ const useMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
9136
9833
  weekStartsOn
9137
9834
  ]);
9138
9835
  };
9139
- //#endregion
9140
- //#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
9836
+ // ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
9141
9837
  /*!
9142
9838
  * is-plain-object <https://github.com/jonschlinkert/is-plain-object>
9143
9839
  *
@@ -9157,8 +9853,7 @@ function isPlainObject(o) {
9157
9853
  if (prot.hasOwnProperty("isPrototypeOf") === false) return false;
9158
9854
  return true;
9159
9855
  }
9160
- //#endregion
9161
- //#region ../../../node_modules/.pnpm/lower-case@2.0.2/node_modules/lower-case/dist/index.js
9856
+ // ../../../node_modules/.pnpm/lower-case@2.0.2/node_modules/lower-case/dist/index.js
9162
9857
  var require_dist$14 = /* @__PURE__ */ __commonJSMin(((exports) => {
9163
9858
  Object.defineProperty(exports, "__esModule", { value: true });
9164
9859
  exports.lowerCase = exports.localeLowerCase = void 0;
@@ -9213,8 +9908,7 @@ var require_dist$14 = /* @__PURE__ */ __commonJSMin(((exports) => {
9213
9908
  }
9214
9909
  exports.lowerCase = lowerCase;
9215
9910
  }));
9216
- //#endregion
9217
- //#region ../../../node_modules/.pnpm/no-case@3.0.4/node_modules/no-case/dist/index.js
9911
+ // ../../../node_modules/.pnpm/no-case@3.0.4/node_modules/no-case/dist/index.js
9218
9912
  var require_dist$13 = /* @__PURE__ */ __commonJSMin(((exports) => {
9219
9913
  Object.defineProperty(exports, "__esModule", { value: true });
9220
9914
  exports.noCase = void 0;
@@ -9245,8 +9939,7 @@ var require_dist$13 = /* @__PURE__ */ __commonJSMin(((exports) => {
9245
9939
  }, input);
9246
9940
  }
9247
9941
  }));
9248
- //#endregion
9249
- //#region ../../../node_modules/.pnpm/pascal-case@3.1.2/node_modules/pascal-case/dist/index.js
9942
+ // ../../../node_modules/.pnpm/pascal-case@3.1.2/node_modules/pascal-case/dist/index.js
9250
9943
  var require_dist$12 = /* @__PURE__ */ __commonJSMin(((exports) => {
9251
9944
  Object.defineProperty(exports, "__esModule", { value: true });
9252
9945
  exports.pascalCase = exports.pascalCaseTransformMerge = exports.pascalCaseTransform = void 0;
@@ -9272,8 +9965,7 @@ var require_dist$12 = /* @__PURE__ */ __commonJSMin(((exports) => {
9272
9965
  }
9273
9966
  exports.pascalCase = pascalCase;
9274
9967
  }));
9275
- //#endregion
9276
- //#region ../../../node_modules/.pnpm/camel-case@4.1.2/node_modules/camel-case/dist/index.js
9968
+ // ../../../node_modules/.pnpm/camel-case@4.1.2/node_modules/camel-case/dist/index.js
9277
9969
  var require_dist$11 = /* @__PURE__ */ __commonJSMin(((exports) => {
9278
9970
  Object.defineProperty(exports, "__esModule", { value: true });
9279
9971
  exports.camelCase = exports.camelCaseTransformMerge = exports.camelCaseTransform = void 0;
@@ -9295,8 +9987,7 @@ var require_dist$11 = /* @__PURE__ */ __commonJSMin(((exports) => {
9295
9987
  }
9296
9988
  exports.camelCase = camelCase;
9297
9989
  }));
9298
- //#endregion
9299
- //#region ../../../node_modules/.pnpm/upper-case-first@2.0.2/node_modules/upper-case-first/dist/index.js
9990
+ // ../../../node_modules/.pnpm/upper-case-first@2.0.2/node_modules/upper-case-first/dist/index.js
9300
9991
  var require_dist$10 = /* @__PURE__ */ __commonJSMin(((exports) => {
9301
9992
  Object.defineProperty(exports, "__esModule", { value: true });
9302
9993
  exports.upperCaseFirst = void 0;
@@ -9308,8 +9999,7 @@ var require_dist$10 = /* @__PURE__ */ __commonJSMin(((exports) => {
9308
9999
  }
9309
10000
  exports.upperCaseFirst = upperCaseFirst;
9310
10001
  }));
9311
- //#endregion
9312
- //#region ../../../node_modules/.pnpm/capital-case@1.0.4/node_modules/capital-case/dist/index.js
10002
+ // ../../../node_modules/.pnpm/capital-case@1.0.4/node_modules/capital-case/dist/index.js
9313
10003
  var require_dist$9 = /* @__PURE__ */ __commonJSMin(((exports) => {
9314
10004
  Object.defineProperty(exports, "__esModule", { value: true });
9315
10005
  exports.capitalCase = exports.capitalCaseTransform = void 0;
@@ -9329,8 +10019,7 @@ var require_dist$9 = /* @__PURE__ */ __commonJSMin(((exports) => {
9329
10019
  }
9330
10020
  exports.capitalCase = capitalCase;
9331
10021
  }));
9332
- //#endregion
9333
- //#region ../../../node_modules/.pnpm/upper-case@2.0.2/node_modules/upper-case/dist/index.js
10022
+ // ../../../node_modules/.pnpm/upper-case@2.0.2/node_modules/upper-case/dist/index.js
9334
10023
  var require_dist$8 = /* @__PURE__ */ __commonJSMin(((exports) => {
9335
10024
  Object.defineProperty(exports, "__esModule", { value: true });
9336
10025
  exports.upperCase = exports.localeUpperCase = void 0;
@@ -9377,8 +10066,7 @@ var require_dist$8 = /* @__PURE__ */ __commonJSMin(((exports) => {
9377
10066
  }
9378
10067
  exports.upperCase = upperCase;
9379
10068
  }));
9380
- //#endregion
9381
- //#region ../../../node_modules/.pnpm/constant-case@3.0.4/node_modules/constant-case/dist/index.js
10069
+ // ../../../node_modules/.pnpm/constant-case@3.0.4/node_modules/constant-case/dist/index.js
9382
10070
  var require_dist$7 = /* @__PURE__ */ __commonJSMin(((exports) => {
9383
10071
  Object.defineProperty(exports, "__esModule", { value: true });
9384
10072
  exports.constantCase = void 0;
@@ -9394,8 +10082,7 @@ var require_dist$7 = /* @__PURE__ */ __commonJSMin(((exports) => {
9394
10082
  }
9395
10083
  exports.constantCase = constantCase;
9396
10084
  }));
9397
- //#endregion
9398
- //#region ../../../node_modules/.pnpm/dot-case@3.0.4/node_modules/dot-case/dist/index.js
10085
+ // ../../../node_modules/.pnpm/dot-case@3.0.4/node_modules/dot-case/dist/index.js
9399
10086
  var require_dist$6 = /* @__PURE__ */ __commonJSMin(((exports) => {
9400
10087
  Object.defineProperty(exports, "__esModule", { value: true });
9401
10088
  exports.dotCase = void 0;
@@ -9407,8 +10094,7 @@ var require_dist$6 = /* @__PURE__ */ __commonJSMin(((exports) => {
9407
10094
  }
9408
10095
  exports.dotCase = dotCase;
9409
10096
  }));
9410
- //#endregion
9411
- //#region ../../../node_modules/.pnpm/header-case@2.0.4/node_modules/header-case/dist/index.js
10097
+ // ../../../node_modules/.pnpm/header-case@2.0.4/node_modules/header-case/dist/index.js
9412
10098
  var require_dist$5 = /* @__PURE__ */ __commonJSMin(((exports) => {
9413
10099
  Object.defineProperty(exports, "__esModule", { value: true });
9414
10100
  exports.headerCase = void 0;
@@ -9420,8 +10106,7 @@ var require_dist$5 = /* @__PURE__ */ __commonJSMin(((exports) => {
9420
10106
  }
9421
10107
  exports.headerCase = headerCase;
9422
10108
  }));
9423
- //#endregion
9424
- //#region ../../../node_modules/.pnpm/param-case@3.0.4/node_modules/param-case/dist/index.js
10109
+ // ../../../node_modules/.pnpm/param-case@3.0.4/node_modules/param-case/dist/index.js
9425
10110
  var require_dist$4 = /* @__PURE__ */ __commonJSMin(((exports) => {
9426
10111
  Object.defineProperty(exports, "__esModule", { value: true });
9427
10112
  exports.paramCase = void 0;
@@ -9433,8 +10118,7 @@ var require_dist$4 = /* @__PURE__ */ __commonJSMin(((exports) => {
9433
10118
  }
9434
10119
  exports.paramCase = paramCase;
9435
10120
  }));
9436
- //#endregion
9437
- //#region ../../../node_modules/.pnpm/path-case@3.0.4/node_modules/path-case/dist/index.js
10121
+ // ../../../node_modules/.pnpm/path-case@3.0.4/node_modules/path-case/dist/index.js
9438
10122
  var require_dist$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
9439
10123
  Object.defineProperty(exports, "__esModule", { value: true });
9440
10124
  exports.pathCase = void 0;
@@ -9446,8 +10130,7 @@ var require_dist$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
9446
10130
  }
9447
10131
  exports.pathCase = pathCase;
9448
10132
  }));
9449
- //#endregion
9450
- //#region ../../../node_modules/.pnpm/sentence-case@3.0.4/node_modules/sentence-case/dist/index.js
10133
+ // ../../../node_modules/.pnpm/sentence-case@3.0.4/node_modules/sentence-case/dist/index.js
9451
10134
  var require_dist$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
9452
10135
  Object.defineProperty(exports, "__esModule", { value: true });
9453
10136
  exports.sentenceCase = exports.sentenceCaseTransform = void 0;
@@ -9469,8 +10152,7 @@ var require_dist$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
9469
10152
  }
9470
10153
  exports.sentenceCase = sentenceCase;
9471
10154
  }));
9472
- //#endregion
9473
- //#region ../../../node_modules/.pnpm/snake-case@3.0.4/node_modules/snake-case/dist/index.js
10155
+ // ../../../node_modules/.pnpm/snake-case@3.0.4/node_modules/snake-case/dist/index.js
9474
10156
  var require_dist$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
9475
10157
  Object.defineProperty(exports, "__esModule", { value: true });
9476
10158
  exports.snakeCase = void 0;
@@ -9482,8 +10164,7 @@ var require_dist$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
9482
10164
  }
9483
10165
  exports.snakeCase = snakeCase;
9484
10166
  }));
9485
- //#endregion
9486
- //#region ../../../node_modules/.pnpm/change-case@4.1.2/node_modules/change-case/dist/index.js
10167
+ // ../../../node_modules/.pnpm/change-case@4.1.2/node_modules/change-case/dist/index.js
9487
10168
  var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
9488
10169
  Object.defineProperty(exports, "__esModule", { value: true });
9489
10170
  var tslib_1 = require("tslib");
@@ -9499,11 +10180,9 @@ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
9499
10180
  tslib_1.__exportStar(require_dist$2(), exports);
9500
10181
  tslib_1.__exportStar(require_dist$1(), exports);
9501
10182
  }));
9502
- //#endregion
9503
- //#region ../../../node_modules/.pnpm/@wordpress+warning@3.57.0/node_modules/@wordpress/warning/build-module/utils.mjs
10183
+ // ../../../node_modules/.pnpm/@wordpress+warning@3.57.0/node_modules/@wordpress/warning/build-module/utils.mjs
9504
10184
  var logged = /* @__PURE__ */ new Set();
9505
- //#endregion
9506
- //#region ../../../node_modules/.pnpm/@wordpress+warning@3.57.0/node_modules/@wordpress/warning/build-module/index.mjs
10185
+ // ../../../node_modules/.pnpm/@wordpress+warning@3.57.0/node_modules/@wordpress/warning/build-module/index.mjs
9507
10186
  function isDev() {
9508
10187
  return globalThis.SCRIPT_DEBUG === true;
9509
10188
  }
@@ -9516,8 +10195,7 @@ function warning(message) {
9516
10195
  } catch {}
9517
10196
  logged.add(message);
9518
10197
  }
9519
- //#endregion
9520
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
10198
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
9521
10199
  function useUpdateEffect(effect, deps) {
9522
10200
  const mountedRef = (0, react.useRef)(false);
9523
10201
  (0, react.useEffect)(() => {
@@ -9529,8 +10207,7 @@ function useUpdateEffect(effect, deps) {
9529
10207
  }, []);
9530
10208
  }
9531
10209
  var use_update_effect_default = useUpdateEffect;
9532
- //#endregion
9533
- //#region ../../../node_modules/.pnpm/@emotion+sheet@1.4.0/node_modules/@emotion/sheet/dist/emotion-sheet.esm.js
10210
+ // ../../../node_modules/.pnpm/@emotion+sheet@1.4.0/node_modules/@emotion/sheet/dist/emotion-sheet.esm.js
9534
10211
  function sheetForTag(tag) {
9535
10212
  if (tag.sheet) return tag.sheet;
9536
10213
  /* istanbul ignore next */
@@ -9592,8 +10269,7 @@ var StyleSheet = /*#__PURE__*/ function() {
9592
10269
  };
9593
10270
  return StyleSheet;
9594
10271
  }();
9595
- //#endregion
9596
- //#region ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Enum.js
10272
+ // ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Enum.js
9597
10273
  var MS = "-ms-";
9598
10274
  var MOZ = "-moz-";
9599
10275
  var WEBKIT = "-webkit-";
@@ -9603,8 +10279,7 @@ var DECLARATION = "decl";
9603
10279
  var IMPORT = "@import";
9604
10280
  var KEYFRAMES = "@keyframes";
9605
10281
  var LAYER = "@layer";
9606
- //#endregion
9607
- //#region ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Utility.js
10282
+ // ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Utility.js
9608
10283
  /**
9609
10284
  * @param {number}
9610
10285
  * @return {number}
@@ -9707,8 +10382,7 @@ function append(value, array) {
9707
10382
  function combine(array, callback) {
9708
10383
  return array.map(callback).join("");
9709
10384
  }
9710
- //#endregion
9711
- //#region ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Tokenizer.js
10385
+ // ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Tokenizer.js
9712
10386
  var line = 1;
9713
10387
  var column = 1;
9714
10388
  var length = 0;
@@ -9894,8 +10568,7 @@ function identifier(index) {
9894
10568
  while (!token(peek())) next();
9895
10569
  return slice(index, position);
9896
10570
  }
9897
- //#endregion
9898
- //#region ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Parser.js
10571
+ // ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Parser.js
9899
10572
  /**
9900
10573
  * @param {string} value
9901
10574
  * @return {object[]}
@@ -10048,8 +10721,7 @@ function comment(value, root, parent) {
10048
10721
  function declaration(value, root, parent, length) {
10049
10722
  return node(value, root, parent, DECLARATION, substr(value, 0, length), substr(value, length + 1, -1), length);
10050
10723
  }
10051
- //#endregion
10052
- //#region ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Serializer.js
10724
+ // ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Serializer.js
10053
10725
  /**
10054
10726
  * @param {object[]} children
10055
10727
  * @param {function} callback
@@ -10079,8 +10751,7 @@ function stringify(element, index, children, callback) {
10079
10751
  }
10080
10752
  return strlen(children = serialize(element.children, callback)) ? element.return = element.value + "{" + children + "}" : "";
10081
10753
  }
10082
- //#endregion
10083
- //#region ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Middleware.js
10754
+ // ../../../node_modules/.pnpm/stylis@4.2.0/node_modules/stylis/src/Middleware.js
10084
10755
  /**
10085
10756
  * @param {function[]} collection
10086
10757
  * @return {function}
@@ -10104,8 +10775,7 @@ function rulesheet(callback) {
10104
10775
  }
10105
10776
  };
10106
10777
  }
10107
- //#endregion
10108
- //#region ../../../node_modules/.pnpm/@emotion+weak-memoize@0.4.0/node_modules/@emotion/weak-memoize/dist/emotion-weak-memoize.esm.js
10778
+ // ../../../node_modules/.pnpm/@emotion+weak-memoize@0.4.0/node_modules/@emotion/weak-memoize/dist/emotion-weak-memoize.esm.js
10109
10779
  var weakMemoize = function weakMemoize(func) {
10110
10780
  var cache = /* @__PURE__ */ new WeakMap();
10111
10781
  return function(arg) {
@@ -10115,8 +10785,7 @@ var weakMemoize = function weakMemoize(func) {
10115
10785
  return ret;
10116
10786
  };
10117
10787
  };
10118
- //#endregion
10119
- //#region ../../../node_modules/.pnpm/@emotion+memoize@0.9.0/node_modules/@emotion/memoize/dist/emotion-memoize.esm.js
10788
+ // ../../../node_modules/.pnpm/@emotion+memoize@0.9.0/node_modules/@emotion/memoize/dist/emotion-memoize.esm.js
10120
10789
  function memoize(fn) {
10121
10790
  var cache = Object.create(null);
10122
10791
  return function(arg) {
@@ -10124,8 +10793,7 @@ function memoize(fn) {
10124
10793
  return cache[arg];
10125
10794
  };
10126
10795
  }
10127
- //#endregion
10128
- //#region ../../../node_modules/.pnpm/@emotion+cache@11.14.0/node_modules/@emotion/cache/dist/emotion-cache.esm.js
10796
+ // ../../../node_modules/.pnpm/@emotion+cache@11.14.0/node_modules/@emotion/cache/dist/emotion-cache.esm.js
10129
10797
  var isBrowser$2 = typeof document !== "undefined";
10130
10798
  var identifierWithPointTracking = function identifierWithPointTracking(begin, points, index) {
10131
10799
  var previous = 0;
@@ -10383,8 +11051,7 @@ var createCache = function createCache(options) {
10383
11051
  cache.sheet.hydrate(nodesToHydrate);
10384
11052
  return cache;
10385
11053
  };
10386
- //#endregion
10387
- //#region ../../../node_modules/.pnpm/@emotion+utils@1.4.2/node_modules/@emotion/utils/dist/emotion-utils.esm.js
11054
+ // ../../../node_modules/.pnpm/@emotion+utils@1.4.2/node_modules/@emotion/utils/dist/emotion-utils.esm.js
10388
11055
  var isBrowser$1 = typeof document !== "undefined";
10389
11056
  function getRegisteredStyles$1(registered, registeredStyles, classNames) {
10390
11057
  var rawClassName = "";
@@ -10412,8 +11079,7 @@ var insertStyles = function insertStyles(cache, serialized, isStringTag) {
10412
11079
  if (!isBrowser$1 && stylesForSSR.length !== 0) return stylesForSSR;
10413
11080
  }
10414
11081
  };
10415
- //#endregion
10416
- //#region ../../../node_modules/.pnpm/@emotion+hash@0.9.2/node_modules/@emotion/hash/dist/emotion-hash.esm.js
11082
+ // ../../../node_modules/.pnpm/@emotion+hash@0.9.2/node_modules/@emotion/hash/dist/emotion-hash.esm.js
10417
11083
  function murmur2(str) {
10418
11084
  var h = 0;
10419
11085
  var k, i = 0, len = str.length;
@@ -10434,8 +11100,7 @@ function murmur2(str) {
10434
11100
  h = (h & 65535) * 1540483477 + ((h >>> 16) * 59797 << 16);
10435
11101
  return ((h ^ h >>> 15) >>> 0).toString(36);
10436
11102
  }
10437
- //#endregion
10438
- //#region ../../../node_modules/.pnpm/@emotion+unitless@0.10.0/node_modules/@emotion/unitless/dist/emotion-unitless.esm.js
11103
+ // ../../../node_modules/.pnpm/@emotion+unitless@0.10.0/node_modules/@emotion/unitless/dist/emotion-unitless.esm.js
10439
11104
  var unitlessKeys = {
10440
11105
  animationIterationCount: 1,
10441
11106
  aspectRatio: 1,
@@ -10485,8 +11150,7 @@ var unitlessKeys = {
10485
11150
  strokeOpacity: 1,
10486
11151
  strokeWidth: 1
10487
11152
  };
10488
- //#endregion
10489
- //#region ../../../node_modules/.pnpm/@emotion+serialize@1.3.3/node_modules/@emotion/serialize/dist/emotion-serialize.esm.js
11153
+ // ../../../node_modules/.pnpm/@emotion+serialize@1.3.3/node_modules/@emotion/serialize/dist/emotion-serialize.esm.js
10490
11154
  var isDevelopment = false;
10491
11155
  var hyphenateRegex = /[A-Z]|^ms/g;
10492
11156
  var animationRegex = /_EMO_([^_]+?)_([^]*?)_EMO_/g;
@@ -10611,8 +11275,7 @@ function serializeStyles(args, registered, mergedProps) {
10611
11275
  };
10612
11276
  }
10613
11277
  react["useInsertionEffect"] && react["useInsertionEffect"] || react.useLayoutEffect;
10614
- //#endregion
10615
- //#region ../../../node_modules/.pnpm/@emotion+react@11.14.0_@types+react@18.3.31_react@18.3.1/node_modules/@emotion/react/dist/emotion-element-d59e098f.esm.js
11278
+ // ../../../node_modules/.pnpm/@emotion+react@11.14.0_@types+react@19.3.0_react@19.3.0/node_modules/@emotion/react/dist/emotion-element-d59e098f.esm.js
10616
11279
  var isBrowser = typeof document !== "undefined";
10617
11280
  var EmotionCacheContext = /* #__PURE__ */ react.createContext(typeof HTMLElement !== "undefined" ? /* #__PURE__ */ createCache({ key: "css" }) : null);
10618
11281
  EmotionCacheContext.Provider;
@@ -10621,8 +11284,7 @@ var __unsafe_useEmotionCache = function useEmotionCache() {
10621
11284
  };
10622
11285
  if (!isBrowser);
10623
11286
  ({}).hasOwnProperty;
10624
- //#endregion
10625
- //#region ../../../node_modules/.pnpm/@emotion+css@11.13.5/node_modules/@emotion/css/create-instance/dist/emotion-css-create-instance.esm.js
11287
+ // ../../../node_modules/.pnpm/@emotion+css@11.13.5/node_modules/@emotion/css/create-instance/dist/emotion-css-create-instance.esm.js
10626
11288
  function insertWithoutScoping(cache, serialized) {
10627
11289
  if (cache.inserted[serialized.name] === void 0) return cache.insert("", serialized, cache.sheet, true);
10628
11290
  }
@@ -10707,8 +11369,7 @@ var classnames = function classnames(args) {
10707
11369
  }
10708
11370
  return cls;
10709
11371
  };
10710
- //#endregion
10711
- //#region ../../../node_modules/.pnpm/@emotion+css@11.13.5/node_modules/@emotion/css/dist/emotion-css.esm.js
11372
+ // ../../../node_modules/.pnpm/@emotion+css@11.13.5/node_modules/@emotion/css/dist/emotion-css.esm.js
10712
11373
  var _createEmotion = createEmotion({ key: "css" });
10713
11374
  _createEmotion.flush;
10714
11375
  _createEmotion.hydrate;
@@ -10720,8 +11381,7 @@ _createEmotion.keyframes;
10720
11381
  _createEmotion.css;
10721
11382
  _createEmotion.sheet;
10722
11383
  _createEmotion.cache;
10723
- //#endregion
10724
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
11384
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
10725
11385
  var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
10726
11386
  var useCx = () => {
10727
11387
  const cache = __unsafe_useEmotionCache();
@@ -10736,8 +11396,7 @@ var useCx = () => {
10736
11396
  }));
10737
11397
  }, [cache]);
10738
11398
  };
10739
- //#endregion
10740
- //#region ../../../node_modules/.pnpm/memize@2.1.1/node_modules/memize/dist/index.js
11399
+ // ../../../node_modules/.pnpm/memize@2.1.1/node_modules/memize/dist/index.js
10741
11400
  /**
10742
11401
  * Memize options object.
10743
11402
  *
@@ -10827,8 +11486,7 @@ function memize(fn, options) {
10827
11486
  };
10828
11487
  return memoized;
10829
11488
  }
10830
- //#endregion
10831
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
11489
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
10832
11490
  var import_es6 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
10833
11491
  module.exports = function equal(a, b) {
10834
11492
  if (a === b) return true;
@@ -10895,20 +11553,17 @@ var BaseContextSystemProvider = ({ children, value }) => {
10895
11553
  });
10896
11554
  };
10897
11555
  (0, react.memo)(BaseContextSystemProvider);
10898
- //#endregion
10899
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/context/constants.mjs
11556
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/constants.mjs
10900
11557
  var COMPONENT_NAMESPACE = "data-wp-component";
10901
11558
  var CONNECTED_NAMESPACE = "data-wp-c16t";
10902
11559
  var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
10903
- //#endregion
10904
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
11560
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
10905
11561
  var import_dist = require_dist();
10906
11562
  function getStyledClassName(namespace) {
10907
11563
  return `components-${(0, import_dist.paramCase)(namespace)}`;
10908
11564
  }
10909
11565
  var getStyledClassNameFromKey = memize(getStyledClassName);
10910
- //#endregion
10911
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/context/context-connect.mjs
11566
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/context-connect.mjs
10912
11567
  function contextConnect(Component, namespace) {
10913
11568
  return _contextConnect(Component, namespace, { forwardsRef: true });
10914
11569
  }
@@ -10924,16 +11579,14 @@ function _contextConnect(Component, namespace, options) {
10924
11579
  selector: `.${getStyledClassNameFromKey(namespace)}`
10925
11580
  });
10926
11581
  }
10927
- //#endregion
10928
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/context/utils.mjs
11582
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/utils.mjs
10929
11583
  function getNamespace(componentName) {
10930
11584
  return { [COMPONENT_NAMESPACE]: componentName };
10931
11585
  }
10932
11586
  function getConnectedNamespace() {
10933
11587
  return { [CONNECTED_NAMESPACE]: true };
10934
11588
  }
10935
- //#endregion
10936
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
11589
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
10937
11590
  function useContextSystem(props, namespace) {
10938
11591
  const contextSystemProps = useComponentsContext();
10939
11592
  if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
@@ -10954,8 +11607,7 @@ function useContextSystem(props, namespace) {
10954
11607
  finalComponentProps.className = classes;
10955
11608
  return finalComponentProps;
10956
11609
  }
10957
- //#endregion
10958
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
11610
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
10959
11611
  var visuallyHidden = {
10960
11612
  border: 0,
10961
11613
  clip: "rect(1px, 1px, 1px, 1px)",
@@ -10970,8 +11622,7 @@ var visuallyHidden = {
10970
11622
  wordWrap: "normal",
10971
11623
  wordBreak: "normal"
10972
11624
  };
10973
- //#endregion
10974
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
11625
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
10975
11626
  var customAttributeRegExp = /^(data|aria|x)-/i;
10976
11627
  var eventHandlerRegExp = /^on[A-Z]/;
10977
11628
  var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
@@ -11060,8 +11711,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
11060
11711
  });
11061
11712
  }
11062
11713
  var PolymorphicElement = (0, react.forwardRef)(UnforwardedPolymorphicElement);
11063
- //#endregion
11064
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/view/component.mjs
11714
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/view/component.mjs
11065
11715
  function UnforwardedView({ css, ...restProps }, ref) {
11066
11716
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PolymorphicElement, {
11067
11717
  ref,
@@ -11069,8 +11719,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
11069
11719
  });
11070
11720
  }
11071
11721
  var component_default$2 = Object.assign((0, react.forwardRef)(UnforwardedView), { selector: ".components-view" });
11072
- //#endregion
11073
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
11722
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
11074
11723
  function UnconnectedVisuallyHidden(props, forwardedRef) {
11075
11724
  const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
11076
11725
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
@@ -11084,8 +11733,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
11084
11733
  });
11085
11734
  }
11086
11735
  var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
11087
- //#endregion
11088
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
11736
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
11089
11737
  var breakpoints = [
11090
11738
  "40em",
11091
11739
  "52em",
@@ -11123,8 +11771,7 @@ function useResponsiveValue(values, options = {}) {
11123
11771
  const array = values || [];
11124
11772
  return array[index >= array.length ? array.length - 1 : index];
11125
11773
  }
11126
- //#endregion
11127
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/grid/utils.mjs
11774
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/grid/utils.mjs
11128
11775
  var ALIGNMENTS = {
11129
11776
  bottom: {
11130
11777
  alignItems: "flex-end",
@@ -11171,8 +11818,7 @@ var ALIGNMENTS = {
11171
11818
  function getAlignmentProps(alignment) {
11172
11819
  return alignment ? ALIGNMENTS[alignment] ?? {} : {};
11173
11820
  }
11174
- //#endregion
11175
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/grid/hook.mjs
11821
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/grid/hook.mjs
11176
11822
  var STYLE_HASH_ATTRIBUTE = "data-wp-hash";
11177
11823
  function getRuntime() {
11178
11824
  const globalScope = globalThis;
@@ -11316,8 +11962,7 @@ function useGrid(props) {
11316
11962
  }
11317
11963
  };
11318
11964
  }
11319
- //#endregion
11320
- //#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_5beefdda355715e908adfea668830e1f/node_modules/@wordpress/components/build-module/grid/component.mjs
11965
+ // ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/grid/component.mjs
11321
11966
  function UnconnectedGrid(props, forwardedRef) {
11322
11967
  const gridProps = useGrid(props);
11323
11968
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
@@ -11326,8 +11971,7 @@ function UnconnectedGrid(props, forwardedRef) {
11326
11971
  });
11327
11972
  }
11328
11973
  var component_default = contextConnect(UnconnectedGrid, "Grid");
11329
- //#endregion
11330
- //#region src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts
11974
+ // src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts
11331
11975
  /**
11332
11976
  * Fractional layout rounding can put a row's bottom a hair past the container's
11333
11977
  * without any visible clipping. Allow that much slack before hiding a row.
@@ -11410,8 +12054,7 @@ function useFittedRowCount(enabled, rowCount, data) {
11410
12054
  isMeasurable
11411
12055
  };
11412
12056
  }
11413
- //#endregion
11414
- //#region src/charts/leaderboard-chart/hooks/use-leaderboard-legend-items.ts
12057
+ // src/charts/leaderboard-chart/hooks/use-leaderboard-legend-items.ts
11415
12058
  /**
11416
12059
  * Hook to create legend items from leaderboard data
11417
12060
  * @param root0 - Configuration object
@@ -11459,11 +12102,12 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
11459
12102
  withOverlayLabel
11460
12103
  ]);
11461
12104
  }
11462
- //#endregion
11463
- //#region src/charts/leaderboard-chart/leaderboard-chart.module.scss
12105
+ // src/charts/leaderboard-chart/leaderboard-chart.module.scss
11464
12106
  var leaderboard_chart_module_default = {
11465
12107
  "bar": "a8ccharts-GovfoW-bar",
11466
12108
  "bar--animated": "a8ccharts-GovfoW-bar--animated",
12109
+ "bar--negative": "a8ccharts-GovfoW-bar--negative",
12110
+ "barTrack": "a8ccharts-GovfoW-barTrack",
11467
12111
  "barWithLabelContainer": "a8ccharts-GovfoW-barWithLabelContainer",
11468
12112
  "chevron": "a8ccharts-GovfoW-chevron",
11469
12113
  "deltaPlaceholder": "a8ccharts-GovfoW-deltaPlaceholder",
@@ -11490,8 +12134,7 @@ var leaderboard_chart_module_default = {
11490
12134
  "stretch": "a8ccharts-GovfoW-stretch",
11491
12135
  "valueContainer": "a8ccharts-GovfoW-valueContainer"
11492
12136
  };
11493
- //#endregion
11494
- //#region src/charts/leaderboard-chart/leaderboard-chart.tsx
12137
+ // src/charts/leaderboard-chart/leaderboard-chart.tsx
11495
12138
  const ROW_GAP = "var(--a8c-charts-dimension-leaderboard-row-gap, 12px)";
11496
12139
  const COLUMN_GAP = "var(--a8c-charts-dimension-leaderboard-column-gap, 4px)";
11497
12140
  /** Indexed by `Math.sign( delta ) + 1`, so [negative, neutral, positive]. */
@@ -11551,27 +12194,43 @@ const BarLabel = ({ label }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react
11551
12194
  className: leaderboard_chart_module_default.label,
11552
12195
  children: label
11553
12196
  }) : label });
11554
- const BarWithLabel = ({ entry, withComparison, withOverlayLabel, primaryColor, secondaryColor, animation, isPrimaryVisible = true, isComparisonVisible = true }) => {
12197
+ const Bar = ({ share, color, animation, divergingScale }) => {
12198
+ const isNegative = share < 0;
12199
+ const sideMax = divergingScale?.[isNegative ? "negative" : "positive"];
12200
+ const width = sideMax ? Math.abs(share) / sideMax * 100 : Math.abs(share);
12201
+ const bar = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12202
+ className: (0, clsx.default)(leaderboard_chart_module_default.bar, {
12203
+ [leaderboard_chart_module_default["bar--animated"]]: animation,
12204
+ [leaderboard_chart_module_default["bar--negative"]]: divergingScale && isNegative
12205
+ }),
12206
+ style: {
12207
+ width: getBarWidth(width),
12208
+ backgroundColor: color
12209
+ }
12210
+ });
12211
+ if (!divergingScale) return bar;
12212
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
12213
+ className: leaderboard_chart_module_default.barTrack,
12214
+ style: { gridTemplateColumns: `${divergingScale.negative}fr ${divergingScale.positive}fr` },
12215
+ children: bar
12216
+ });
12217
+ };
12218
+ const BarWithLabel = ({ entry, withComparison, withOverlayLabel, primaryColor, secondaryColor, animation, divergingScale, isPrimaryVisible = true, isComparisonVisible = true }) => {
11555
12219
  const showComparisonBar = withComparison && !withOverlayLabel && isComparisonVisible;
12220
+ const bars = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [isPrimaryVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
12221
+ share: entry.currentShare,
12222
+ color: primaryColor,
12223
+ animation,
12224
+ divergingScale
12225
+ }), showComparisonBar && hasPreviousValue(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Bar, {
12226
+ share: entry.previousShare,
12227
+ color: secondaryColor,
12228
+ animation,
12229
+ divergingScale
12230
+ })] });
11556
12231
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11557
12232
  className: (0, clsx.default)(leaderboard_chart_module_default.barWithLabelContainer, { [leaderboard_chart_module_default["is-overlay"]]: withOverlayLabel }),
11558
- children: [
11559
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarLabel, { label: entry.label }),
11560
- isPrimaryVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11561
- className: (0, clsx.default)(leaderboard_chart_module_default.bar, { [leaderboard_chart_module_default["bar--animated"]]: animation }),
11562
- style: {
11563
- width: getBarWidth(entry.currentShare),
11564
- backgroundColor: primaryColor
11565
- }
11566
- }),
11567
- showComparisonBar && hasPreviousValue(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11568
- className: (0, clsx.default)(leaderboard_chart_module_default.bar, { [leaderboard_chart_module_default["bar--animated"]]: animation }),
11569
- style: {
11570
- width: getBarWidth(entry.previousShare),
11571
- backgroundColor: secondaryColor
11572
- }
11573
- })
11574
- ]
12233
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarLabel, { label: entry.label }), bars]
11575
12234
  });
11576
12235
  };
11577
12236
  /**
@@ -11656,6 +12315,26 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
11656
12315
  withComparison,
11657
12316
  withOverlayLabel
11658
12317
  ]);
12318
+ const divergingScale = (0, react.useMemo)(() => {
12319
+ const withComparisonBars = withComparison && !withOverlayLabel;
12320
+ const scale = {
12321
+ negative: 0,
12322
+ positive: 0
12323
+ };
12324
+ for (const entry of data ?? []) {
12325
+ const shares = [entry.currentShare];
12326
+ if (withComparisonBars && hasPreviousValue(entry)) shares.push(entry.previousShare);
12327
+ for (const share of shares) {
12328
+ const side = share < 0 ? "negative" : "positive";
12329
+ scale[side] = Math.max(scale[side], Math.abs(share));
12330
+ }
12331
+ }
12332
+ return scale.negative > 0 ? scale : void 0;
12333
+ }, [
12334
+ data,
12335
+ withComparison,
12336
+ withOverlayLabel
12337
+ ]);
11659
12338
  const isDataValid = Boolean(data && data.length > 0);
11660
12339
  const chartMetadata = (0, react.useMemo)(() => ({
11661
12340
  withComparison,
@@ -11671,6 +12350,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
11671
12350
  const prefersReducedMotion = usePrefersReducedMotion();
11672
12351
  const { contentRef, fittedCount, isMeasurable } = useFittedRowCount(fitRows && !allSeriesHidden, data?.length ?? 0, data);
11673
12352
  const shouldFitRows = fitRows && isMeasurable;
12353
+ const showComparisonColumn = withComparison && isComparisonVisible;
12354
+ const templateColumns = showComparisonColumn && isPrimaryVisible ? "minmax(0, 1fr) auto auto" : "minmax(0, 1fr) auto";
11674
12355
  if (!data || data.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartInstanceContext.Provider, {
11675
12356
  value: { chartId },
11676
12357
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartLayout, {
@@ -11735,13 +12416,12 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
11735
12416
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default, {
11736
12417
  role: "list",
11737
12418
  "aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Leaderboard chart", "jetpack-charts"),
11738
- templateColumns: "minmax(0, 1fr) auto",
12419
+ templateColumns,
11739
12420
  rowGap: ROW_GAP,
11740
12421
  columnGap: COLUMN_GAP,
11741
12422
  "data-leaderboard-grid": true,
11742
12423
  children: data.map((entry, rowIndex) => {
11743
12424
  const rowStyle = shouldFitRows && rowIndex >= fittedCount ? { visibility: "hidden" } : void 0;
11744
- const showComparisonColumn = withComparison && isComparisonVisible;
11745
12425
  const hasPreviousPeriodValue = hasPreviousValue(entry);
11746
12426
  const hasDelta = hasDeltaValue(entry);
11747
12427
  const showComparisonValue = showComparisonColumn && hasDelta;
@@ -11756,13 +12436,12 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
11756
12436
  withOverlayLabel,
11757
12437
  primaryColor: resolvedPrimaryColor,
11758
12438
  secondaryColor: resolvedSecondaryColor,
12439
+ divergingScale,
11759
12440
  isPrimaryVisible,
11760
12441
  isComparisonVisible,
11761
12442
  animation: animation && !loading && !prefersReducedMotion
11762
12443
  })
11763
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
11764
- direction: "row",
11765
- gap: "xs",
12444
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11766
12445
  className: (0, clsx.default)(leaderboard_chart_module_default.valueContainer, { [leaderboard_chart_module_default.overlayLabel]: withOverlayLabel }),
11767
12446
  children: [
11768
12447
  isPrimaryVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, { children: valueFormatter(entry.currentValue) }),
@@ -11843,8 +12522,7 @@ const LeaderboardChartWithProvider = (props) => {
11843
12522
  LeaderboardChartWithProvider.displayName = "LeaderboardChart";
11844
12523
  const LeaderboardChart = attachSubComponents(LeaderboardChartWithProvider, { Legend });
11845
12524
  const LeaderboardChartResponsive = attachSubComponents(withResponsive(LeaderboardChartWithProvider), { Legend });
11846
- //#endregion
11847
- //#region src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts
12525
+ // src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts
11848
12526
  /**
11849
12527
  * Orders arcs the way they appear: clockwise from 12 o'clock, which for a semi-circle is left to right.
11850
12528
  *
@@ -11852,15 +12530,13 @@ const LeaderboardChartResponsive = attachSubComponents(withResponsive(Leaderboar
11852
12530
  * @return A copy of `arcs` sorted by angular midpoint.
11853
12531
  */
11854
12532
  const orderArcsForNavigation = (arcs) => [...arcs].sort((a, b) => a.startAngle + a.endAngle - (b.startAngle + b.endAngle));
11855
- //#endregion
11856
- //#region src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx
12533
+ // src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx
11857
12534
  const PieSelectionAnnouncement = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.VisuallyHidden, {
11858
12535
  role: "status",
11859
12536
  "aria-atomic": "true",
11860
12537
  children: data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data })
11861
12538
  });
11862
- //#endregion
11863
- //#region src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx
12539
+ // src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx
11864
12540
  const TOOLTIP_BOX_STYLE = { zIndex: 3 };
11865
12541
  const PieTooltip = ({ top, left, selectedIndex, tooltipRef, children }) => {
11866
12542
  const standaloneScopeClass = useStandaloneScopeClass();
@@ -11882,8 +12558,7 @@ const PieTooltip = ({ top, left, selectedIndex, tooltipRef, children }) => {
11882
12558
  }, `chart-tooltip-${selectedIndex}`)
11883
12559
  });
11884
12560
  };
11885
- //#endregion
11886
- //#region src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx
12561
+ // src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx
11887
12562
  /**
11888
12563
  * Reports the selected segment: a focused tooltip for a keyboard selection, a pointer tooltip on hover, or a screen reader announcement without tooltips.
11889
12564
  *
@@ -11923,53 +12598,7 @@ const PieSelectionOutput = ({ withTooltips, selectedIndex, selectedData, keyboar
11923
12598
  })
11924
12599
  ] });
11925
12600
  };
11926
- //#endregion
11927
- //#region src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss
11928
- var pie_keyboard_navigation_module_default = {
11929
- "selected-ring__contrast": "a8ccharts-V2HDKq-selected-ring__contrast",
11930
- "selected-ring__focus": "a8ccharts-V2HDKq-selected-ring__focus"
11931
- };
11932
- //#endregion
11933
- //#region src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx
11934
- /**
11935
- * Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
11936
- *
11937
- * @param value - Any string.
11938
- * @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
11939
- */
11940
- const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
11941
- /**
11942
- * Marks the selected segment with a two-tone ring drawn inside its edge, so the SVG edge cannot cut it off.
11943
- *
11944
- * @param {SelectedSegmentRingProps} props - Component props
11945
- * @return {JSX.Element} The ring
11946
- */
11947
- const SelectedSegmentRing = ({ chartId, d }) => {
11948
- const clipId = `pie-selected-ring-clip-${toSvgId(chartId)}`;
11949
- const clipPath = `url(#${clipId})`;
11950
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
11951
- pointerEvents: "none",
11952
- "aria-hidden": "true",
11953
- children: [
11954
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("clipPath", {
11955
- id: clipId,
11956
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d })
11957
- }),
11958
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
11959
- d,
11960
- clipPath,
11961
- className: pie_keyboard_navigation_module_default["selected-ring__contrast"]
11962
- }),
11963
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
11964
- d,
11965
- clipPath,
11966
- className: pie_keyboard_navigation_module_default["selected-ring__focus"]
11967
- })
11968
- ]
11969
- });
11970
- };
11971
- //#endregion
11972
- //#region src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts
12601
+ // src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts
11973
12602
  const usePieKeyboardNavigation = ({ navigationArcs, withTooltips, tooltipOffsetX, tooltipOffsetY }) => {
11974
12603
  const chartRef = (0, react.useRef)(null);
11975
12604
  const svgRef = (0, react.useRef)(null);
@@ -12049,8 +12678,7 @@ const usePieKeyboardNavigation = ({ navigationArcs, withTooltips, tooltipOffsetX
12049
12678
  }
12050
12679
  };
12051
12680
  };
12052
- //#endregion
12053
- //#region src/charts/private/radial-wipe-animation/radial-wipe-animation.tsx
12681
+ // src/charts/private/radial-wipe-animation/radial-wipe-animation.tsx
12054
12682
  /**
12055
12683
  * Renders a SVG mask that creates a radial wipe animation effect.
12056
12684
  *
@@ -12087,8 +12715,7 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
12087
12715
  })
12088
12716
  });
12089
12717
  }
12090
- //#endregion
12091
- //#region src/charts/pie-chart/pie-chart.module.scss
12718
+ // src/charts/pie-chart/pie-chart.module.scss
12092
12719
  var pie_chart_module_default = {
12093
12720
  "pie-chart": "a8ccharts-gnszbG-pie-chart",
12094
12721
  "pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
@@ -12099,8 +12726,7 @@ var pie_chart_module_default = {
12099
12726
  "pie-chart__plot": "a8ccharts-gnszbG-pie-chart__plot",
12100
12727
  "pie-chart--responsive": "a8ccharts-gnszbG-pie-chart--responsive"
12101
12728
  };
12102
- //#endregion
12103
- //#region src/charts/pie-chart/pie-chart.tsx
12729
+ // src/charts/pie-chart/pie-chart.tsx
12104
12730
  /**
12105
12731
  * Default tooltip renderer for pie charts.
12106
12732
  * Renders the default `label: value` tooltip content for the hovered segment.
@@ -12344,9 +12970,11 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
12344
12970
  selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
12345
12971
  top: centerY,
12346
12972
  left: centerX,
12347
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
12973
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedRing, {
12348
12974
  chartId,
12349
- d: path(selectedArc) || ""
12975
+ d: path(selectedArc) || "",
12976
+ side: "inside",
12977
+ testId: "pie-selected-ring"
12350
12978
  })
12351
12979
  }),
12352
12980
  !allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
@@ -12381,8 +13009,7 @@ const PieChartResponsive = attachSubComponents(withResponsive(PieChartWithProvid
12381
13009
  SVG: ChartSVG,
12382
13010
  HTML: ChartHTML
12383
13011
  });
12384
- //#endregion
12385
- //#region src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss
13012
+ // src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss
12386
13013
  var pie_semi_circle_chart_module_default = {
12387
13014
  "label": "a8ccharts-YtTOxW-label",
12388
13015
  "note": "a8ccharts-YtTOxW-note",
@@ -12390,8 +13017,7 @@ var pie_semi_circle_chart_module_default = {
12390
13017
  "pie-semi-circle-chart__plot": "a8ccharts-YtTOxW-pie-semi-circle-chart__plot",
12391
13018
  "pie-semi-circle-chart--responsive": "a8ccharts-YtTOxW-pie-semi-circle-chart--responsive"
12392
13019
  };
12393
- //#endregion
12394
- //#region src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx
13020
+ // src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx
12395
13021
  /**
12396
13022
  * Default tooltip renderer for semi-circle pie charts.
12397
13023
  * Renders the default `label: value` tooltip content for the hovered segment.
@@ -12583,9 +13209,11 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
12583
13209
  selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
12584
13210
  top: height,
12585
13211
  left: width / 2,
12586
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
13212
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedRing, {
12587
13213
  chartId,
12588
- d: path(selectedArc) || ""
13214
+ d: path(selectedArc) || "",
13215
+ side: "inside",
13216
+ testId: "pie-selected-ring"
12589
13217
  })
12590
13218
  }),
12591
13219
  !allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
@@ -12632,14 +13260,12 @@ const PieSemiCircleChartResponsive = attachSubComponents(withResponsive(PieSemiC
12632
13260
  SVG: ChartSVG,
12633
13261
  HTML: ChartHTML
12634
13262
  });
12635
- //#endregion
12636
- //#region src/charts/sparkline/sparkline.module.scss
13263
+ // src/charts/sparkline/sparkline.module.scss
12637
13264
  var sparkline_module_default = {
12638
13265
  "sparkline": "a8ccharts-GtgAVa-sparkline",
12639
13266
  "sparkline--empty": "a8ccharts-GtgAVa-sparkline--empty"
12640
13267
  };
12641
- //#endregion
12642
- //#region src/charts/sparkline/sparkline.tsx
13268
+ // src/charts/sparkline/sparkline.tsx
12643
13269
  const DEFAULT_WIDTH = 100;
12644
13270
  const DEFAULT_HEIGHT = 40;
12645
13271
  /**
@@ -12781,8 +13407,7 @@ SparklineUnresponsive.displayName = "SparklineUnresponsive";
12781
13407
  * Responsive Sparkline chart component
12782
13408
  */
12783
13409
  const Sparkline = withResponsive(SparklineUnresponsive);
12784
- //#endregion
12785
- //#region src/components/trend-indicator/trend-indicator.module.scss
13410
+ // src/components/trend-indicator/trend-indicator.module.scss
12786
13411
  var trend_indicator_module_default = {
12787
13412
  "trend-indicator": "a8ccharts-zR7F7G-trend-indicator",
12788
13413
  "trend-indicator__icon": "a8ccharts-zR7F7G-trend-indicator__icon",
@@ -12791,8 +13416,7 @@ var trend_indicator_module_default = {
12791
13416
  "trend-indicator--neutral": "a8ccharts-zR7F7G-trend-indicator--neutral",
12792
13417
  "trend-indicator--up": "a8ccharts-zR7F7G-trend-indicator--up"
12793
13418
  };
12794
- //#endregion
12795
- //#region src/components/trend-indicator/trend-indicator.tsx
13419
+ // src/components/trend-indicator/trend-indicator.tsx
12796
13420
  const DIRECTION_LABELS = {
12797
13421
  up: "Increase",
12798
13422
  down: "Decrease",
@@ -12835,7 +13459,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
12835
13459
  })]
12836
13460
  });
12837
13461
  }
12838
- //#endregion
12839
13462
  exports.AccessibleTooltip = AccessibleTooltip;
12840
13463
  exports.AreaChart = AreaChartResponsive;
12841
13464
  exports.AreaChartUnresponsive = AreaChart;
@@ -12885,6 +13508,8 @@ exports.parseHslString = parseHslString;
12885
13508
  exports.prefersLightText = prefersLightText;
12886
13509
  exports.relativeLuminance = relativeLuminance;
12887
13510
  exports.resolveCssVariable = resolveCssVariable;
13511
+ exports.useBarColors = useBarColors;
13512
+ exports.useBarLegendItems = useBarLegendItems;
12888
13513
  exports.useCalendarHeatmapData = useCalendarHeatmapData;
12889
13514
  exports.useChartFormatting = useChartFormatting;
12890
13515
  exports.useChartLegendItems = useChartLegendItems;