@automattic/charts 4.11.1 → 4.12.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 (54) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/index.cjs +856 -236
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +19 -13
  5. package/dist/index.d.cts +43 -4
  6. package/dist/index.d.ts +43 -4
  7. package/dist/index.js +855 -237
  8. package/dist/index.js.map +1 -1
  9. package/package.json +9 -9
  10. package/src/charts/bar-chart/bar-chart.tsx +134 -138
  11. package/src/charts/bar-chart/index.ts +3 -0
  12. package/src/charts/bar-chart/private/band-tooltip.tsx +41 -15
  13. package/src/charts/bar-chart/private/bar-layer.tsx +132 -0
  14. package/src/charts/bar-chart/private/comparison-bars-geometry.ts +22 -34
  15. package/src/charts/bar-chart/private/comparison-bars.tsx +9 -18
  16. package/src/charts/bar-chart/private/comparison-constants.ts +4 -10
  17. package/src/charts/bar-chart/private/grouped-bars.ts +68 -0
  18. package/src/charts/bar-chart/private/index.ts +7 -1
  19. package/src/charts/bar-chart/private/overlap-bars.ts +183 -0
  20. package/src/charts/bar-chart/private/selected-bar-ring.tsx +84 -0
  21. package/src/charts/bar-chart/private/slot-tooltip-members.tsx +29 -0
  22. package/src/charts/bar-chart/private/slotted-bar-series.tsx +84 -0
  23. package/src/charts/bar-chart/private/test/comparison-bars-geometry.test.ts +4 -11
  24. package/src/charts/bar-chart/private/test/comparison-bars.test.tsx +2 -3
  25. package/src/charts/bar-chart/private/test/grouped-bars.test.ts +87 -0
  26. package/src/charts/bar-chart/private/test/overlap-bars.test.ts +159 -0
  27. package/src/charts/bar-chart/private/use-bar-stops.ts +89 -0
  28. package/src/charts/bar-chart/private/use-overlap-slots.ts +194 -0
  29. package/src/charts/bar-chart/private/value-domain.ts +0 -10
  30. package/src/charts/bar-chart/test/bar-chart-overlap.test.tsx +347 -0
  31. package/src/charts/bar-chart/test/bar-chart.test.tsx +66 -19
  32. package/src/charts/bar-chart/test/use-bar-legend-items.test.tsx +81 -0
  33. package/src/charts/bar-chart/types.ts +3 -0
  34. package/src/charts/bar-chart/use-bar-colors.ts +46 -0
  35. package/src/charts/bar-chart/use-bar-legend-items.ts +87 -0
  36. package/src/charts/line-chart/line-chart.tsx +22 -17
  37. package/src/charts/line-chart/test/line-chart.test.tsx +165 -1
  38. package/src/charts/pie-chart/pie-chart.tsx +7 -2
  39. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +7 -2
  40. package/src/charts/private/pie-keyboard-navigation/index.ts +0 -1
  41. package/src/charts/private/{pie-keyboard-navigation/pie-keyboard-navigation.module.scss → selected-ring/selected-ring.module.scss} +11 -6
  42. package/src/charts/private/selected-ring/selected-ring.tsx +73 -0
  43. package/src/charts/private/{pie-keyboard-navigation/test/selected-segment-ring.test.ts → selected-ring/test/selected-ring.test.ts} +1 -1
  44. package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +20 -0
  45. package/src/components/legend/hooks/use-chart-legend-items.ts +27 -3
  46. package/src/components/tooltip/xy-chart-tooltip.tsx +3 -2
  47. package/src/index.ts +8 -2
  48. package/src/providers/chart-context/global-charts-provider.tsx +2 -0
  49. package/src/providers/chart-context/test/chart-context.test.tsx +0 -13
  50. package/src/providers/chart-context/themes.ts +0 -1
  51. package/src/providers/chart-context/types.ts +2 -0
  52. package/src/test-utils/selected-bar-ring.ts +14 -0
  53. package/src/types.ts +10 -2
  54. package/src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx +0 -47
package/dist/index.js CHANGED
@@ -1296,10 +1296,7 @@ const defaultTheme = {
1296
1296
  strokeDasharray: "4 4",
1297
1297
  strokeLinecap: "square"
1298
1298
  } } },
1299
- barChart: { barStyles: { comparison: {
1300
- widthFactor: 1.5,
1301
- opacity: .5
1302
- } } },
1299
+ barChart: { barStyles: { comparison: { widthFactor: 1.5 } } },
1303
1300
  sparkline: {
1304
1301
  margin: {
1305
1302
  top: 2,
@@ -1457,6 +1454,7 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
1457
1454
  theme: providerTheme,
1458
1455
  formatting,
1459
1456
  getElementStyles,
1457
+ backgroundColor: colorCache.background,
1460
1458
  toggleSeriesVisibility,
1461
1459
  setSeriesVisibility,
1462
1460
  setChartHiddenSeries,
@@ -1473,6 +1471,7 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
1473
1471
  providerTheme,
1474
1472
  formatting,
1475
1473
  getElementStyles,
1474
+ colorCache.background,
1476
1475
  toggleSeriesVisibility,
1477
1476
  setSeriesVisibility,
1478
1477
  setChartHiddenSeries,
@@ -2297,6 +2296,21 @@ const Legend = forwardRef(({ chartId, items, shape, ...props }, ref) => {
2297
2296
  //#endregion
2298
2297
  //#region src/components/legend/hooks/use-chart-legend-items.ts
2299
2298
  /**
2299
+ * Wraps `getElementStyles` so a swatch takes the color given for its series.
2300
+ * @param getElementStyles - Function to get element styles
2301
+ * @param seriesColors - Each series' swatch color, by index
2302
+ * @return Element styles with the given color
2303
+ */
2304
+ function withSeriesColors(getElementStyles, seriesColors) {
2305
+ return (params) => {
2306
+ const styles = getElementStyles(params);
2307
+ return {
2308
+ ...styles,
2309
+ color: seriesColors[params.index] ?? styles.color
2310
+ };
2311
+ };
2312
+ }
2313
+ /**
2300
2314
  * Formats the value for a data point based on its type and display preference
2301
2315
  * @param point - The data point to format
2302
2316
  * @param showValues - Whether to show values or return empty string
@@ -2508,21 +2522,22 @@ function processPointData(pointData, getElementStyles, showValues, legendValueDi
2508
2522
  * @return Array of legend items ready for display
2509
2523
  */
2510
2524
  function useChartLegendItems(data, options = {}, legendShape) {
2511
- const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, renderGlyph } = options;
2512
- const { getElementStyles } = useGlobalChartsContext();
2525
+ const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, seriesColors, renderGlyph } = options;
2526
+ const { getElementStyles: getSeriesStyles } = useGlobalChartsContext();
2513
2527
  return useMemo(() => {
2514
2528
  if (!data || !Array.isArray(data) || data.length === 0) return [];
2515
2529
  if ("data" in data[0]) {
2516
2530
  const seriesData = data;
2531
+ const getElementStyles = seriesColors ? withSeriesColors(getSeriesStyles, seriesColors) : getSeriesStyles;
2517
2532
  const items = processSeriesData(seriesData, getElementStyles, showValues, withGlyph, glyphSize, collapseGroups, renderGlyph, legendShape);
2518
2533
  if (comparisonSeriesItems) return [...items, ...buildPerSeriesComparisonItems(seriesData, items, comparisonSeriesItems, getElementStyles, legendShape)];
2519
2534
  const comparison = comparisonItem ? buildComparisonLegendItem(seriesData, items, typeof comparisonItem === "string" ? comparisonItem : __("Comparison period", "jetpack-charts"), getElementStyles, legendShape) : null;
2520
2535
  return comparison ? [...items, comparison] : items;
2521
2536
  }
2522
- return processPointData(data, getElementStyles, showValues, legendValueDisplay, withGlyph, glyphSize, renderGlyph, legendShape);
2537
+ return processPointData(data, getSeriesStyles, showValues, legendValueDisplay, withGlyph, glyphSize, renderGlyph, legendShape);
2523
2538
  }, [
2524
2539
  data,
2525
- getElementStyles,
2540
+ getSeriesStyles,
2526
2541
  showValues,
2527
2542
  legendValueDisplay,
2528
2543
  withGlyph,
@@ -2530,6 +2545,7 @@ function useChartLegendItems(data, options = {}, legendShape) {
2530
2545
  collapseGroups,
2531
2546
  comparisonItem,
2532
2547
  comparisonSeriesItems,
2548
+ seriesColors,
2533
2549
  renderGlyph,
2534
2550
  legendShape
2535
2551
  ]);
@@ -3055,17 +3071,19 @@ const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocu
3055
3071
  return;
3056
3072
  }
3057
3073
  hasKeyboardSelection.current = true;
3058
- if (mode === "group") series.forEach((s, index) => {
3059
- if (selectedIndex < s.data.length) {
3060
- const datum = s.data[selectedIndex];
3061
- tooltipContext?.showTooltip({
3062
- datum,
3063
- key: s.label,
3064
- index
3065
- });
3066
- }
3067
- });
3068
- else if (mode === "individual") {
3074
+ if (mode === "group") {
3075
+ closeTooltipNow();
3076
+ series.forEach((s, index) => {
3077
+ if (selectedIndex < s.data.length) {
3078
+ const datum = s.data[selectedIndex];
3079
+ tooltipContext?.showTooltip({
3080
+ datum,
3081
+ key: s.label,
3082
+ index
3083
+ });
3084
+ }
3085
+ });
3086
+ } else if (mode === "individual") {
3069
3087
  if (selectedIndex < tooltipData.length) {
3070
3088
  const tooltipItem = tooltipData[selectedIndex];
3071
3089
  tooltipContext?.showTooltip({
@@ -4812,6 +4830,8 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
4812
4830
  isVisible: !hiddenSeries.has(series.label)
4813
4831
  }));
4814
4832
  }, [dataSorted, hiddenSeries]);
4833
+ const visibleSeries = useMemo(() => dataSorted.filter((series) => isSeriesVisible(series.label)), [dataSorted, isSeriesVisible]);
4834
+ const visibleSeriesKey = useMemo(() => JSON.stringify(visibleSeries.map((series) => series.label)), [visibleSeries]);
4815
4835
  const allSeriesHidden = useMemo(() => {
4816
4836
  return seriesWithVisibility.every(({ isVisible }) => !isVisible);
4817
4837
  }, [seriesWithVisibility]);
@@ -4842,21 +4862,21 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
4842
4862
  options?.yScale
4843
4863
  ]);
4844
4864
  const activateSelectedPoint = useCallback((index) => {
4845
- const series = dataSorted[0];
4846
- const datum = series?.data[index];
4847
- if (series && datum) onDatumActivate?.({
4848
- datum,
4865
+ const series = visibleSeries.find((candidate) => candidate.data[index]);
4866
+ if (series) onDatumActivate?.({
4867
+ datum: series.data[index],
4849
4868
  index,
4850
4869
  key: series.label
4851
4870
  });
4852
- }, [dataSorted, onDatumActivate]);
4871
+ }, [visibleSeries, onDatumActivate]);
4853
4872
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
4854
4873
  selectedIndex,
4855
4874
  setSelectedIndex,
4856
4875
  isNavigating,
4857
4876
  setIsNavigating,
4858
4877
  chartRef,
4859
- totalPoints: dataSorted[0]?.data.length || 0,
4878
+ totalPoints: Math.max(0, ...visibleSeries.map((series) => series.data.length)),
4879
+ visibleSeriesKey,
4860
4880
  onActivate: activateSelectedPoint,
4861
4881
  preventTooltipScroll: tooltipPlacement === "below-axis"
4862
4882
  });
@@ -4875,7 +4895,7 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
4875
4895
  }
4876
4896
  return min <= max ? [min, max] : void 0;
4877
4897
  }, [dataSorted, isSeriesVisible]);
4878
- const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(dataSorted.filter((series) => isSeriesVisible(series.label))), [dataSorted, isSeriesVisible]);
4898
+ const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(visibleSeries), [visibleSeries]);
4879
4899
  const chartOptions = useMemo(() => {
4880
4900
  const fallbackYDomain = getFallbackYDomain(visibleReadingExtent, options?.yScale?.type === "log");
4881
4901
  return {
@@ -4921,11 +4941,7 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
4921
4941
  formatting,
4922
4942
  isSeriesVisible
4923
4943
  ]);
4924
- const bucketInfo = useMemo(() => getBucketInfo(dataSorted.filter((series) => isSeriesVisible(series.label)), options?.axis?.x?.tickResolution), [
4925
- dataSorted,
4926
- isSeriesVisible,
4927
- options?.axis?.x?.tickResolution
4928
- ]);
4944
+ const bucketInfo = useMemo(() => getBucketInfo(visibleSeries, options?.axis?.x?.tickResolution), [visibleSeries, options?.axis?.x?.tickResolution]);
4929
4945
  const tooltipRenderGlyph = useMemo(() => {
4930
4946
  return (props) => {
4931
4947
  const seriesIndex = dataSorted.findIndex((series) => series.label === props.key || series.data.includes(props.datum));
@@ -5155,7 +5171,7 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
5155
5171
  selectedIndex,
5156
5172
  tooltipRef,
5157
5173
  keyboardFocusedClassName: line_chart_module_default["line-chart__tooltip--keyboard-focused"],
5158
- series: dataSorted
5174
+ series: visibleSeries
5159
5175
  }),
5160
5176
  /* @__PURE__ */ jsx(LineChartScalesRef, {
5161
5177
  chartRef: internalChartRef,
@@ -5815,13 +5831,6 @@ const getBarValue = (point) => {
5815
5831
  */
5816
5832
  const isBarRendered = (point) => Number.isFinite(getBarValue(point));
5817
5833
  /**
5818
- * How many bars visx renders for a list of points.
5819
- *
5820
- * @param points - Data points handed to visx.
5821
- * @return The number of points that get a bar.
5822
- */
5823
- const countRenderedBars = (points) => points.filter(isBarRendered).length;
5824
- /**
5825
5834
  * An explicit domain for the value scale, or null to let visx fit one to the data.
5826
5835
  *
5827
5836
  * Zero goes into the domain here rather than through the scale's `zero` flag: visx applies
@@ -6083,8 +6092,7 @@ const createGroupScale = (keys, bandwidth, padding) => scaleBand({
6083
6092
  //#endregion
6084
6093
  //#region src/charts/bar-chart/private/comparison-bars-geometry.ts
6085
6094
  /**
6086
- * Mirrors visx's getScaleBaseline so comparison shadows and primary bars
6087
- * share the same baseline, including out-of-domain zero values.
6095
+ * Mirrors visx's getScaleBaseline so bars drawn outside visx share the baseline of its bars, including out-of-domain zero values.
6088
6096
  *
6089
6097
  * @param {ValueScale} scale - The continuous value scale.
6090
6098
  * @return {number} The baseline output position in pixels.
@@ -6098,36 +6106,33 @@ function getValueScaleBaseline(scale) {
6098
6106
  return Number.isFinite(maybeZero) ? Math.max(maybeZero, minOutput) : minOutput;
6099
6107
  }
6100
6108
  /**
6101
- * Compute the rect for a comparison "shadow" bar, centered on the paired
6102
- * primary bar slot and scaled by `widthFactor`.
6103
- *
6104
- * @param {object} params - Geometry inputs.
6105
- * @param {boolean} params.horizontal - True for a horizontal bar chart, false for vertical.
6106
- * @param {number} params.bandPosition - bandScale(category): start px of the category band.
6107
- * @param {number} params.slotOffset - groupScale(primaryKey): offset of the primary slot within the band.
6108
- * @param {number} params.slotThickness - groupScale.bandwidth(): primary bar thickness in px.
6109
- * @param {number} params.valuePosition - valueScale(value): output px for the bar's data value.
6110
- * @param {number} params.baseline - getValueScaleBaseline(valueScale): zero-line output px.
6111
- * @param {number} params.widthFactor - Shadow thickness multiplier, e.g. 1.5 for 150% width.
6112
- * @return {ComparisonRect} The {x, y, width, height} of the shadow rect.
6113
- */
6114
- function computeComparisonRect(params) {
6115
- const { horizontal, bandPosition, slotOffset, slotThickness, valuePosition, baseline, widthFactor } = params;
6116
- const slotStart = bandPosition + slotOffset;
6117
- const shadowThickness = slotThickness * widthFactor;
6118
- const shadowStart = slotStart + slotThickness / 2 - shadowThickness / 2;
6119
- const valueStart = Math.min(valuePosition, baseline);
6120
- const valueLength = Math.abs(baseline - valuePosition);
6109
+ * Compute the rect that spans `valuePositions` along the value axis, centered on a slot and scaled by `widthFactor` across it.
6110
+ *
6111
+ * @param {object} params - Geometry inputs.
6112
+ * @param {boolean} params.horizontal - True for a horizontal bar chart, false for vertical.
6113
+ * @param {number} params.bandPosition - bandScale(category): start px of the category band.
6114
+ * @param {number} params.slotOffset - groupScale(slotKey): offset of the slot within the band.
6115
+ * @param {number} params.slotThickness - groupScale.bandwidth(): slot thickness in px.
6116
+ * @param {number[]} params.valuePositions - Output px the rect must reach, such as the baseline and each bar's value.
6117
+ * @param {number} params.widthFactor - Thickness multiplier, e.g. 0.5 for half the slot.
6118
+ * @return {SlotRect} The {x, y, width, height} of the rect.
6119
+ */
6120
+ function computeSlotRect(params) {
6121
+ const { horizontal, bandPosition, slotOffset, slotThickness, valuePositions, widthFactor } = params;
6122
+ const thickness = slotThickness * widthFactor;
6123
+ const start = bandPosition + slotOffset + slotThickness / 2 - thickness / 2;
6124
+ const valueStart = Math.min(...valuePositions);
6125
+ const valueLength = Math.max(...valuePositions) - valueStart;
6121
6126
  if (horizontal) return {
6122
6127
  x: valueStart,
6123
- y: shadowStart,
6128
+ y: start,
6124
6129
  width: valueLength,
6125
- height: shadowThickness
6130
+ height: thickness
6126
6131
  };
6127
6132
  return {
6128
- x: shadowStart,
6133
+ x: start,
6129
6134
  y: valueStart,
6130
- width: shadowThickness,
6135
+ width: thickness,
6131
6136
  height: valueLength
6132
6137
  };
6133
6138
  }
@@ -6176,6 +6181,518 @@ const ClassifiedBarSeries = ({ barClassName, primaryKeys, groupPadding, ...props
6176
6181
  renderGlyph
6177
6182
  });
6178
6183
  };
6184
+ //#endregion
6185
+ //#region src/charts/bar-chart/private/slotted-bar-series.tsx
6186
+ const SlottedBarSeries = ({ barClassName, slotKeys, slotKey, thickness, groupPadding, ...props }) => {
6187
+ const { xScale, yScale, horizontal } = useContext(DataContext);
6188
+ const bandScale = horizontal ? yScale : xScale;
6189
+ const valueScale = horizontal ? xScale : yScale;
6190
+ const groupScale = useMemo(() => createGroupScale(slotKeys, bandScale?.bandwidth?.() ?? 0, groupPadding), [
6191
+ slotKeys,
6192
+ bandScale,
6193
+ groupPadding
6194
+ ]);
6195
+ const renderGlyph = useCallback(({ datum, x, y, color }) => {
6196
+ if (!bandScale?.bandwidth || !valueScale) return null;
6197
+ const baseline = getValueScaleBaseline(valueScale);
6198
+ const rect = computeSlotRect({
6199
+ horizontal: !!horizontal,
6200
+ bandPosition: Number(bandScale((horizontal ? props.yAccessor : props.xAccessor)(datum))),
6201
+ slotOffset: groupScale(slotKey) ?? 0,
6202
+ slotThickness: groupScale.bandwidth(),
6203
+ valuePositions: [baseline, horizontal ? x : y],
6204
+ widthFactor: thickness
6205
+ });
6206
+ return /* @__PURE__ */ jsx("rect", {
6207
+ ...rect,
6208
+ className: clsx("visx-bar", barClassName?.(datum)),
6209
+ fill: color
6210
+ });
6211
+ }, [
6212
+ bandScale,
6213
+ valueScale,
6214
+ horizontal,
6215
+ groupScale,
6216
+ slotKey,
6217
+ thickness,
6218
+ props.xAccessor,
6219
+ props.yAccessor,
6220
+ barClassName
6221
+ ]);
6222
+ return /* @__PURE__ */ jsx(GlyphSeries, {
6223
+ ...props,
6224
+ enableEvents: false,
6225
+ renderGlyph
6226
+ });
6227
+ };
6228
+ //#endregion
6229
+ //#region src/charts/private/selected-ring/selected-ring.module.scss
6230
+ var selected_ring_module_default = {
6231
+ "selected-ring__contrast": "a8ccharts-gx1_AW-selected-ring__contrast",
6232
+ "selected-ring__edge": "a8ccharts-gx1_AW-selected-ring__edge",
6233
+ "selected-ring__far": "a8ccharts-gx1_AW-selected-ring__far",
6234
+ "selected-ring__focus": "a8ccharts-gx1_AW-selected-ring__focus"
6235
+ };
6236
+ //#endregion
6237
+ //#region src/charts/private/selected-ring/selected-ring.tsx
6238
+ const TONES = {
6239
+ inside: ["contrast", "focus"],
6240
+ outside: ["focus", "contrast"]
6241
+ };
6242
+ const EVERYWHERE = "M-1e6 -1e6H1e6V1e6H-1e6Z";
6243
+ /**
6244
+ * Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
6245
+ *
6246
+ * @param value - Any string.
6247
+ * @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
6248
+ */
6249
+ const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
6250
+ /**
6251
+ * Marks a selected shape with a focus-colored ring and a contrast ring, so it reads against any fill.
6252
+ *
6253
+ * @param {SelectedRingProps} props - Component props
6254
+ * @return {JSX.Element} The ring
6255
+ */
6256
+ const SelectedRing = ({ chartId, d, side, testId }) => {
6257
+ const clipId = `selected-ring-clip-${toSvgId(chartId)}`;
6258
+ const clipPath = `url(#${clipId})`;
6259
+ const [far, edge] = TONES[side];
6260
+ return /* @__PURE__ */ jsxs("g", {
6261
+ pointerEvents: "none",
6262
+ "aria-hidden": "true",
6263
+ children: [
6264
+ /* @__PURE__ */ jsx("clipPath", {
6265
+ id: clipId,
6266
+ children: side === "inside" ? /* @__PURE__ */ jsx("path", { d }) : /* @__PURE__ */ jsx("path", {
6267
+ d: `${EVERYWHERE} ${d}`,
6268
+ clipRule: "evenodd"
6269
+ })
6270
+ }),
6271
+ /* @__PURE__ */ jsx("path", {
6272
+ d,
6273
+ clipPath,
6274
+ className: clsx(selected_ring_module_default["selected-ring__far"], selected_ring_module_default[`selected-ring__${far}`])
6275
+ }),
6276
+ /* @__PURE__ */ jsx("path", {
6277
+ d,
6278
+ clipPath,
6279
+ className: clsx(selected_ring_module_default["selected-ring__edge"], selected_ring_module_default[`selected-ring__${edge}`])
6280
+ })
6281
+ ]
6282
+ });
6283
+ };
6284
+ //#endregion
6285
+ //#region src/charts/bar-chart/private/selected-bar-ring.tsx
6286
+ /**
6287
+ * Marks the keyboard-selected slot with a two-tone ring outside its edge, so the ring reads against any bar color.
6288
+ *
6289
+ * @param props - Component props.
6290
+ * @param props.chartId - The chart's id, which keeps the clip path unique on a page with several charts.
6291
+ * @param props.selected - The selected slot.
6292
+ * @param props.slotKeys - The slots, in the order the band lays them out.
6293
+ * @param props.groupPadding - The padding between slots.
6294
+ * @param props.horizontal - Whether the bars run horizontally.
6295
+ * @param props.xAccessor - Reads a datum's x value.
6296
+ * @param props.yAccessor - Reads a datum's y value.
6297
+ * @return The ring, or nothing when the slot has no position.
6298
+ */
6299
+ const SelectedBarRing = ({ chartId, selected, slotKeys, groupPadding, horizontal, xAccessor, yAccessor }) => {
6300
+ const context = useContext(DataContext);
6301
+ const bandScale = horizontal ? context?.yScale : context?.xScale;
6302
+ const valueScale = horizontal ? context?.xScale : context?.yScale;
6303
+ const bandwidth = bandScale?.bandwidth?.() ?? 0;
6304
+ const [category] = selected.data;
6305
+ if (!bandScale || !valueScale || !bandwidth || !category) return null;
6306
+ const groupScale = createGroupScale(slotKeys, bandwidth, groupPadding);
6307
+ const slotOffset = groupScale(selected.slotKey);
6308
+ const bandPosition = Number(bandScale((horizontal ? yAccessor : xAccessor)(category)));
6309
+ if (slotOffset == null || !Number.isFinite(bandPosition)) return null;
6310
+ const valuePositions = selected.data.map((datum) => Number(valueScale(Number((horizontal ? xAccessor : yAccessor)(datum)))));
6311
+ const rect = computeSlotRect({
6312
+ horizontal,
6313
+ bandPosition,
6314
+ slotOffset,
6315
+ slotThickness: groupScale.bandwidth(),
6316
+ valuePositions: [getValueScaleBaseline(valueScale), ...valuePositions],
6317
+ widthFactor: selected.thickness
6318
+ });
6319
+ return /* @__PURE__ */ jsx(SelectedRing, {
6320
+ chartId,
6321
+ d: `M${rect.x} ${rect.y}h${rect.width}v${rect.height}h${-rect.width}Z`,
6322
+ side: "outside",
6323
+ testId: "bar-chart-selected-ring"
6324
+ });
6325
+ };
6326
+ //#endregion
6327
+ //#region src/charts/bar-chart/private/bar-layer.tsx
6328
+ /**
6329
+ * 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.
6330
+ *
6331
+ * @param props - Component props.
6332
+ * @param props.chartId - The chart's id, which keeps the ring's clip path unique on a page with several charts.
6333
+ * @param props.overlapSlots - The overlap layout, or undefined for a grouped one.
6334
+ * @param props.selectedBar - The bar or slot the keyboard has selected.
6335
+ * @param props.primaryEntries - The visible primary series, for a grouped layout.
6336
+ * @param props.primaryKeys - Their labels, in group order.
6337
+ * @param props.getBarBackground - Reads a series' bar fill.
6338
+ * @param props.barClassName - Adds classes to a bar.
6339
+ * @param props.groupPadding - The padding between the bars of a category.
6340
+ * @param props.horizontal - Whether the bars run horizontally.
6341
+ * @param props.xAccessor - Reads a datum's x value.
6342
+ * @param props.yAccessor - Reads a datum's y value.
6343
+ * @return The bars.
6344
+ */
6345
+ const BarLayer = ({ chartId, overlapSlots, selectedBar, primaryEntries, primaryKeys, getBarBackground, barClassName, groupPadding, horizontal, xAccessor, yAccessor }) => {
6346
+ let bars;
6347
+ if (overlapSlots) bars = /* @__PURE__ */ jsx("g", {
6348
+ className: "visx-bar-group",
6349
+ children: overlapSlots.entries.map(({ series, index }) => /* @__PURE__ */ jsx(SlottedBarSeries, {
6350
+ dataKey: series.label,
6351
+ data: series.data,
6352
+ xAccessor,
6353
+ yAccessor,
6354
+ colorAccessor: getBarBackground(index),
6355
+ barClassName,
6356
+ slotKeys: overlapSlots.slotKeys,
6357
+ slotKey: overlapSlots.slotOf(series.label),
6358
+ thickness: overlapSlots.thicknessOf(series.label),
6359
+ groupPadding
6360
+ }, series.label))
6361
+ });
6362
+ else if (barClassName) bars = /* @__PURE__ */ jsx("g", {
6363
+ className: "visx-bar-group",
6364
+ children: primaryEntries.map(({ series, index }) => /* @__PURE__ */ jsx(ClassifiedBarSeries, {
6365
+ dataKey: series.label,
6366
+ data: series.data,
6367
+ xAccessor,
6368
+ yAccessor,
6369
+ colorAccessor: getBarBackground(index),
6370
+ barClassName,
6371
+ primaryKeys,
6372
+ groupPadding
6373
+ }, series.label))
6374
+ });
6375
+ else bars = /* @__PURE__ */ jsx(BarGroup, {
6376
+ padding: groupPadding,
6377
+ children: primaryEntries.map(({ series, index }) => /* @__PURE__ */ jsx(BarSeries, {
6378
+ dataKey: series.label,
6379
+ data: series.data,
6380
+ xAccessor,
6381
+ yAccessor,
6382
+ colorAccessor: getBarBackground(index)
6383
+ }, series.label))
6384
+ });
6385
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [bars, selectedBar && /* @__PURE__ */ jsx(SelectedBarRing, {
6386
+ chartId,
6387
+ selected: selectedBar,
6388
+ slotKeys: overlapSlots?.slotKeys ?? primaryKeys,
6389
+ groupPadding,
6390
+ horizontal,
6391
+ xAccessor,
6392
+ yAccessor
6393
+ })] });
6394
+ };
6395
+ //#endregion
6396
+ //#region src/charts/bar-chart/private/slot-tooltip-members.tsx
6397
+ /**
6398
+ * Fills the tooltip with every bar of the keyboard-selected category, and only those.
6399
+ *
6400
+ * The last member shown becomes the tooltip's nearest datum, so the caller lists the keyboard stop last.
6401
+ *
6402
+ * @param props - Component props.
6403
+ * @param props.members - The category's bars, the keyboard stop last.
6404
+ * @param props.index - The selected data point.
6405
+ * @return No visual content.
6406
+ */
6407
+ function SlotTooltipMembers({ members, index }) {
6408
+ const { showTooltip, updateTooltip } = useContext(TooltipContext) ?? {};
6409
+ useEffect(() => {
6410
+ updateTooltip?.((state) => ({
6411
+ ...state,
6412
+ tooltipData: void 0
6413
+ }));
6414
+ members.forEach(({ key, datum }) => showTooltip?.({
6415
+ key,
6416
+ datum,
6417
+ index
6418
+ }));
6419
+ }, [members, index]);
6420
+ return null;
6421
+ }
6422
+ //#endregion
6423
+ //#region src/charts/bar-chart/private/overlap-bars.ts
6424
+ const PRIMARY_SLOT = "primary";
6425
+ const COMPARISON_SLOT = "comparison";
6426
+ const OVERLAP_SLOTS = [PRIMARY_SLOT, COMPARISON_SLOT];
6427
+ const SEARCH_STEPS = 16;
6428
+ /**
6429
+ * 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.
6430
+ *
6431
+ * @param series - The series to place.
6432
+ * @return Each series' placement, by index.
6433
+ */
6434
+ function getOverlapPlacements(series) {
6435
+ const layerByGroup = /* @__PURE__ */ new Map();
6436
+ series.forEach(({ group }) => {
6437
+ if (!layerByGroup.has(group)) layerByGroup.set(group, layerByGroup.size);
6438
+ });
6439
+ const layerCount = layerByGroup.size;
6440
+ return series.map((item) => {
6441
+ const layer = layerByGroup.get(item.group) ?? 0;
6442
+ return {
6443
+ slot: item.options?.type === "comparison" ? COMPARISON_SLOT : PRIMARY_SLOT,
6444
+ layer,
6445
+ thickness: layerCount > 1 ? 1 - layer * .5 / (layerCount - 1) : 1
6446
+ };
6447
+ });
6448
+ }
6449
+ /**
6450
+ * Blends `from` toward `to` and returns the blend nearest the point where `passes` changes, on its passing side.
6451
+ *
6452
+ * @param from - Where the blend starts.
6453
+ * @param to - Where the blend ends.
6454
+ * @param passes - A test that changes at most once along the blend.
6455
+ * @return A hex color.
6456
+ */
6457
+ function blendToEdge(from, to, passes) {
6458
+ const passesAtStart = passes(from);
6459
+ let low = 0;
6460
+ let high = 1;
6461
+ for (let step = 0; step < SEARCH_STEPS; step++) {
6462
+ const middle = (low + high) / 2;
6463
+ if (passes(mixHexColors(from, to, middle)) === passesAtStart) low = middle;
6464
+ else high = middle;
6465
+ }
6466
+ return mixHexColors(from, to, passesAtStart ? low : high);
6467
+ }
6468
+ const awayFrom = (background) => contrastRatio(background, "#000000") >= contrastRatio(background, "#ffffff") ? "#000000" : "#ffffff";
6469
+ const opposite = (end) => end === "#000000" ? "#ffffff" : "#000000";
6470
+ /**
6471
+ * The tone of a color nearest the background that keeps 3:1 against it.
6472
+ *
6473
+ * @param color - A hex color.
6474
+ * @param background - The hex chart background.
6475
+ * @return A hex color.
6476
+ */
6477
+ function tintWithContrast(color, background) {
6478
+ const passes = (tone) => contrastRatio(tone, background) >= 3;
6479
+ return blendToEdge(color, passes(color) ? background : awayFrom(background), passes);
6480
+ }
6481
+ /**
6482
+ * 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.
6483
+ *
6484
+ * @param color - A hex color.
6485
+ * @param under - The hex color of the bar behind it.
6486
+ * @param background - The hex chart background.
6487
+ * @return A hex color.
6488
+ */
6489
+ function shadeWithContrast(color, under, background) {
6490
+ const passes = (tone) => contrastRatio(tone, under) >= 3;
6491
+ const start = contrastRatio(color, background) > contrastRatio(under, background) ? color : under;
6492
+ if (passes(start)) return start;
6493
+ const away = awayFrom(background);
6494
+ return blendToEdge(start, passes(away) ? away : opposite(away), passes);
6495
+ }
6496
+ /**
6497
+ * 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.
6498
+ *
6499
+ * @param series - Every series of the chart.
6500
+ * @param colors - Each series' resolved color.
6501
+ * @param slotColors - The palette color of each slot, primaries first.
6502
+ * @param background - The hex chart background.
6503
+ * @return Each series' fill, by index.
6504
+ */
6505
+ function getOverlapBarColors(series, colors, slotColors, background) {
6506
+ const placements = getOverlapPlacements(series);
6507
+ const barColors = [...colors];
6508
+ OVERLAP_SLOTS.forEach((slot, slotIndex) => {
6509
+ const members = placements.flatMap((placement, index) => placement.slot === slot ? [{
6510
+ index,
6511
+ layer: placement.layer
6512
+ }] : []);
6513
+ if (!members.length) return;
6514
+ const layers = [...new Set(members.map(({ layer }) => layer))].sort((a, b) => a - b);
6515
+ const back = members.find(({ layer }) => layer === layers[0]);
6516
+ const base = back && series[back.index].options?.stroke ? colors[back.index] : slotColors[slotIndex];
6517
+ if (members.some(({ index, layer }) => layer === layers[layers.length - 1] && !!series[index].options?.stroke) || !isValidHexColor(base) || !isValidHexColor(background)) return;
6518
+ const toneByLayer = /* @__PURE__ */ new Map();
6519
+ let under;
6520
+ layers.forEach((layer) => {
6521
+ const tone = under === void 0 ? tintWithContrast(base, background) : shadeWithContrast(base, under, background);
6522
+ toneByLayer.set(layer, tone);
6523
+ under = tone;
6524
+ });
6525
+ members.forEach(({ index, layer }) => {
6526
+ barColors[index] = toneByLayer.get(layer) ?? colors[index];
6527
+ });
6528
+ });
6529
+ return barColors;
6530
+ }
6531
+ //#endregion
6532
+ //#region src/charts/bar-chart/private/use-overlap-slots.ts
6533
+ /**
6534
+ * Whether two data points sit at the same category: the same label, or the same date.
6535
+ *
6536
+ * @param point - A data point.
6537
+ * @param category - The data point naming the category.
6538
+ * @return Whether `point` is at `category`.
6539
+ */
6540
+ function isSameCategory(point, category) {
6541
+ return category.label != null ? point.label === category.label : !!category.date && !!point.date && point.date.getTime() === category.date.getTime();
6542
+ }
6543
+ /**
6544
+ * Lays out the visible series of an overlap layout in slots and layers.
6545
+ *
6546
+ * @param enabled - Whether the chart draws an overlap layout.
6547
+ * @param seriesWithVisibility - Every series, with its index and whether it is visible.
6548
+ * @return The layout, or undefined when the chart is not an overlap layout.
6549
+ */
6550
+ function useOverlapSlots(enabled, seriesWithVisibility) {
6551
+ return useMemo(() => {
6552
+ if (!enabled) return;
6553
+ const visible = seriesWithVisibility.filter(({ isVisible }) => isVisible);
6554
+ const placements = getOverlapPlacements(visible.map(({ series }) => series));
6555
+ const placed = visible.map(({ series, index }, position) => ({
6556
+ entry: {
6557
+ series,
6558
+ index
6559
+ },
6560
+ placement: placements[position]
6561
+ })).sort((a, b) => a.placement.layer - b.placement.layer);
6562
+ const entries = placed.map(({ entry }) => entry);
6563
+ const placementByKey = new Map(placed.map(({ entry, placement }) => [entry.series.label, placement]));
6564
+ const slotOf = (key) => placementByKey.get(key)?.slot ?? "primary";
6565
+ const thicknessOf = (key) => placementByKey.get(key)?.thickness ?? 1;
6566
+ const hasPrimaries = seriesWithVisibility.some(({ series }) => series.options?.type !== "comparison");
6567
+ const showsComparisons = entries.some(({ series }) => slotOf(series.label) === COMPARISON_SLOT);
6568
+ const slotKeys = [...hasPrimaries ? [PRIMARY_SLOT] : [], ...showsComparisons ? [COMPARISON_SLOT] : []];
6569
+ return {
6570
+ entries,
6571
+ keys: entries.map(({ series }) => series.label),
6572
+ slotKeys,
6573
+ slotOf,
6574
+ thicknessOf,
6575
+ positions: getStopPositions(entries, slotKeys, slotOf)
6576
+ };
6577
+ }, [enabled, seriesWithVisibility]);
6578
+ }
6579
+ /**
6580
+ * The category a data point sits at, as a key two points share when `isSameCategory` holds.
6581
+ *
6582
+ * @param point - A data point.
6583
+ * @return The category key.
6584
+ */
6585
+ function categoryKey(point) {
6586
+ return point.label != null ? `label:${point.label}` : `date:${point.date?.getTime()}`;
6587
+ }
6588
+ /**
6589
+ * Lists a stop for every slot at every category that slot draws a bar at, category by category.
6590
+ *
6591
+ * @param entries - The visible series, back to front.
6592
+ * @param slotKeys - The slots, in band order.
6593
+ * @param slotOf - The slot a series sits in.
6594
+ * @return The positions, in keyboard order.
6595
+ */
6596
+ function getStopPositions(entries, slotKeys, slotOf) {
6597
+ const categories = /* @__PURE__ */ new Map();
6598
+ entries.forEach(({ series }) => {
6599
+ series.data.forEach((datum, dataPointIndex) => {
6600
+ const key = categoryKey(datum);
6601
+ const slots = categories.get(key) ?? /* @__PURE__ */ new Map();
6602
+ categories.set(key, slots);
6603
+ if (!isBarRendered(datum)) return;
6604
+ const slotKey = slotOf(series.label);
6605
+ slots.set(slotKey, {
6606
+ slotKey,
6607
+ key: series.label,
6608
+ datum,
6609
+ dataPointIndex
6610
+ });
6611
+ });
6612
+ });
6613
+ const ordered = [...categories.values()].filter((slots) => slots.size > 0);
6614
+ if (ordered.every((slots) => [...slots.values()].every(({ datum }) => datum.label == null && datum.date))) {
6615
+ const time = (slots) => [...slots.values()][0].datum.date?.getTime() ?? 0;
6616
+ ordered.sort((a, b) => time(a) - time(b));
6617
+ }
6618
+ return ordered.flatMap((slots) => slotKeys.flatMap((slotKey) => {
6619
+ const position = slots.get(slotKey);
6620
+ return position ? [position] : [];
6621
+ }));
6622
+ }
6623
+ /**
6624
+ * The slot a keyboard index selects, and every bar at its category.
6625
+ *
6626
+ * @param slots - The overlap layout.
6627
+ * @param selectedIndex - The keyboard index into `slots.positions`.
6628
+ * @return The selected slot, or undefined when nothing is selected or drawn there.
6629
+ */
6630
+ function getSelectedSlot(slots, selectedIndex) {
6631
+ const position = selectedIndex === void 0 ? void 0 : slots?.positions[selectedIndex];
6632
+ if (!slots || !position) return;
6633
+ const { slotKey, key: stopKey, datum: category, dataPointIndex } = position;
6634
+ const members = slots.entries.flatMap(({ series }) => {
6635
+ const datum = series.data.find((point) => isSameCategory(point, category));
6636
+ return datum ? [{
6637
+ key: series.label,
6638
+ datum
6639
+ }] : [];
6640
+ });
6641
+ const slotBars = members.filter(({ key, datum }) => isBarRendered(datum) && slots.slotOf(key) === slotKey);
6642
+ return {
6643
+ data: slotBars.map(({ datum }) => datum),
6644
+ slotKey,
6645
+ thickness: Math.max(...slotBars.map(({ key }) => slots.thicknessOf(key))),
6646
+ index: dataPointIndex,
6647
+ members: [...members.filter(({ key }) => key !== stopKey), ...members.filter(({ key }) => key === stopKey)]
6648
+ };
6649
+ }
6650
+ //#endregion
6651
+ //#region src/charts/bar-chart/private/use-bar-stops.ts
6652
+ /**
6653
+ * Lays out the keyboard stops: one per slot and category in an overlap layout, else one per primary bar, series-major within each category.
6654
+ *
6655
+ * @param overlapSlots - The overlap layout, or undefined for a grouped one.
6656
+ * @param primaryEntries - The visible primary series.
6657
+ * @return The stops.
6658
+ */
6659
+ function useBarStops(overlapSlots, primaryEntries) {
6660
+ const series = useMemo(() => overlapSlots ? [] : primaryEntries.map((entry) => entry.series), [overlapSlots, primaryEntries]);
6661
+ return {
6662
+ count: overlapSlots?.positions.length ?? Math.max(0, ...series.map((item) => item.data.length)) * series.length,
6663
+ series,
6664
+ key: useMemo(() => JSON.stringify(overlapSlots?.keys ?? series.map((item) => item.label)), [overlapSlots, series]),
6665
+ barAt: useCallback((stop) => {
6666
+ if (overlapSlots) {
6667
+ const position = overlapSlots.positions[stop];
6668
+ return position && {
6669
+ datum: position.datum,
6670
+ index: position.dataPointIndex,
6671
+ key: position.key
6672
+ };
6673
+ }
6674
+ if (!series.length) return;
6675
+ const index = Math.floor(stop / series.length);
6676
+ const item = series[stop % series.length];
6677
+ const datum = item?.data[index];
6678
+ return item && datum ? {
6679
+ datum,
6680
+ index,
6681
+ key: item.label
6682
+ } : void 0;
6683
+ }, [overlapSlots, series]),
6684
+ stopOf: useCallback((seriesKey, dataPointIndex) => {
6685
+ if (overlapSlots) {
6686
+ const hovered = overlapSlots.entries.find((entry) => entry.series.label === seriesKey)?.series.data[dataPointIndex];
6687
+ const slotKey = overlapSlots.slotOf(seriesKey);
6688
+ const stop = hovered ? overlapSlots.positions.findIndex((position) => position.slotKey === slotKey && isSameCategory(position.datum, hovered)) : -1;
6689
+ return stop >= 0 ? stop : void 0;
6690
+ }
6691
+ const seriesIndex = series.findIndex((item) => item.label === seriesKey);
6692
+ return seriesIndex >= 0 ? dataPointIndex * series.length + seriesIndex : void 0;
6693
+ }, [overlapSlots, series])
6694
+ };
6695
+ }
6179
6696
  /**
6180
6697
  * Upper clamp on the computed group padding, so bars can never collapse to zero width
6181
6698
  * even at very large `widthFactor` values.
@@ -6211,9 +6728,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6211
6728
  data: series,
6212
6729
  index
6213
6730
  });
6214
- const opacity = barStyles?.opacity ?? .5;
6215
6731
  const widthFactor = barStyles?.widthFactor ?? 1.5;
6216
- const fill = resolveFill(entry);
6217
6732
  series.data.forEach((datum, i) => {
6218
6733
  const bandPosition = Number(bandScale(bandAccessor(datum)));
6219
6734
  const valuePosition = Number(valueScale(Number(valueAccessor(datum))));
@@ -6221,13 +6736,12 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6221
6736
  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.`);
6222
6737
  return;
6223
6738
  }
6224
- const rect = computeComparisonRect({
6739
+ const rect = computeSlotRect({
6225
6740
  horizontal,
6226
6741
  bandPosition,
6227
6742
  slotOffset,
6228
6743
  slotThickness,
6229
- valuePosition,
6230
- baseline,
6744
+ valuePositions: [baseline, valuePosition],
6231
6745
  widthFactor
6232
6746
  });
6233
6747
  rects.push(/* @__PURE__ */ jsx("rect", {
@@ -6236,8 +6750,8 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
6236
6750
  y: rect.y,
6237
6751
  width: rect.width,
6238
6752
  height: rect.height,
6239
- fill,
6240
- opacity
6753
+ fill: resolveFill(entry, datum),
6754
+ opacity: barStyles?.opacity
6241
6755
  }, `${index}-${i}`));
6242
6756
  });
6243
6757
  });
@@ -6336,7 +6850,8 @@ function nearestBandIndex(data, accessor, scale, position) {
6336
6850
  /**
6337
6851
  * Correct visx's range-based band inversion, which omits outer padding.
6338
6852
  * @param root0 - Registered series selection.
6339
- * @param root0.keys - Visible series keys.
6853
+ * @param root0.keys - Visible series keys, back to front where bars overlap.
6854
+ * @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.
6340
6855
  * @param root0.groupPadding - Padding between grouped bars.
6341
6856
  * @param root0.withTooltips - Whether pointer events update the tooltip.
6342
6857
  * @param root0.onPointerDown - Receives the corrected pointer-down datum.
@@ -6344,12 +6859,13 @@ function nearestBandIndex(data, accessor, scale, position) {
6344
6859
  * @param root0.onPointerMove - Receives the corrected datum under a moving pointer.
6345
6860
  * @return No visual content.
6346
6861
  */
6347
- function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointerUp, onPointerMove }) {
6862
+ function BandTooltip({ keys, slots, groupPadding, withTooltips, onPointerDown, onPointerUp, onPointerMove }) {
6348
6863
  const { xScale, yScale, dataRegistry, horizontal } = useContext(DataContext);
6349
- const { showTooltip } = useContext(TooltipContext);
6864
+ const { showTooltip, hideTooltip, updateTooltip } = useContext(TooltipContext);
6350
6865
  const scale = horizontal ? yScale : xScale;
6351
6866
  const bandwidth = scale?.bandwidth?.() ?? 0;
6352
- const groupScale = useMemo(() => createGroupScale(keys, bandwidth, groupPadding), [
6867
+ const groupScale = useMemo(() => createGroupScale(slots?.keys ?? keys, bandwidth, groupPadding), [
6868
+ slots,
6353
6869
  keys,
6354
6870
  bandwidth,
6355
6871
  groupPadding
@@ -6357,18 +6873,21 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
6357
6873
  const getSelections = useCallback((params) => {
6358
6874
  const point = params?.svgPoint;
6359
6875
  if (!point || !scale?.bandwidth) return [];
6876
+ const position = horizontal ? point.y : point.x;
6360
6877
  const selections = [];
6878
+ const bands = [];
6361
6879
  for (const key of keys) {
6362
6880
  const entry = dataRegistry?.get(key);
6363
6881
  if (!entry) continue;
6364
6882
  const accessor = horizontal ? entry.yAccessor : entry.xAccessor;
6365
- const index = nearestBandIndex(entry.data, accessor, scale, horizontal ? point.y : point.x);
6883
+ const index = nearestBandIndex(entry.data, accessor, scale, position);
6366
6884
  if (index < 0) continue;
6367
6885
  const datum = entry.data[index];
6368
- const start = Number(scale(accessor(datum))) + Number(groupScale(key));
6886
+ const band = Number(scale(accessor(datum)));
6887
+ const start = band + Number(groupScale(slots ? slots.slotOf(key) : key));
6369
6888
  const end = start + groupScale.step();
6370
- const position = horizontal ? point.y : point.x;
6371
6889
  const distance = position >= start && position <= end ? 0 : Math.abs(position - (start + end) / 2);
6890
+ bands.push(band);
6372
6891
  selections.push({
6373
6892
  event: params.event,
6374
6893
  key,
@@ -6379,12 +6898,16 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
6379
6898
  distanceY: horizontal ? distance : 0
6380
6899
  });
6381
6900
  }
6382
- return selections;
6901
+ if (!slots) return selections;
6902
+ const bandDistance = (band) => Math.abs(band + scale.bandwidth() / 2 - position);
6903
+ const hoveredBand = bands.reduce((best, band) => best === void 0 || bandDistance(band) < bandDistance(best) ? band : best, void 0);
6904
+ return selections.filter((_, index) => bands[index] === hoveredBand);
6383
6905
  }, [
6384
6906
  scale,
6385
6907
  dataRegistry,
6386
6908
  horizontal,
6387
6909
  keys,
6910
+ slots,
6388
6911
  groupScale
6389
6912
  ]);
6390
6913
  const handlePointer = useCallback((params) => {
@@ -6394,24 +6917,162 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
6394
6917
  return !best || distance(selection) <= distance(best) ? selection : best;
6395
6918
  }, void 0);
6396
6919
  if (params?.event.type === "pointermove" && nearest) onPointerMove?.(nearest);
6397
- if (withTooltips && params?.event.type !== "pointerup") selections.forEach(showTooltip);
6920
+ if (withTooltips && params?.event.type !== "pointerup") {
6921
+ if (slots) updateTooltip((state) => ({
6922
+ ...state,
6923
+ tooltipData: void 0
6924
+ }));
6925
+ selections.forEach(showTooltip);
6926
+ }
6398
6927
  const callback = params?.event.type === "pointerdown" ? onPointerDown : onPointerUp;
6399
6928
  if (params?.event.type === "pointermove" || !callback) return;
6400
6929
  if (nearest) callback(nearest);
6401
6930
  }, [
6402
6931
  getSelections,
6403
6932
  withTooltips,
6933
+ slots,
6404
6934
  showTooltip,
6935
+ updateTooltip,
6405
6936
  onPointerDown,
6406
6937
  onPointerUp,
6407
6938
  onPointerMove
6408
6939
  ]);
6409
6940
  useEventEmitter("pointermove", withTooltips ? handlePointer : void 0);
6941
+ useEventEmitter("pointerout", withTooltips && slots ? hideTooltip : void 0);
6410
6942
  useEventEmitter("pointerdown", handlePointer);
6411
6943
  useEventEmitter("pointerup", onPointerUp ? handlePointer : void 0);
6412
6944
  return null;
6413
6945
  }
6414
6946
  //#endregion
6947
+ //#region src/charts/bar-chart/private/grouped-bars.ts
6948
+ /**
6949
+ * Pairs each comparison series with the primary of its `group`, or with the only primary.
6950
+ *
6951
+ * @param series - The chart's series.
6952
+ * @return The index of each paired comparison's primary, keyed by the comparison's index.
6953
+ */
6954
+ function getComparisonPrimaries(series) {
6955
+ const primaries = series.flatMap((item, index) => item.options?.type === "comparison" ? [] : [{
6956
+ group: item.group,
6957
+ index
6958
+ }]);
6959
+ const primaryByGroup = new Map(primaries.map(({ group, index }) => [group, index]));
6960
+ const onlyPrimary = primaries.length === 1 ? primaries[0].index : void 0;
6961
+ const pairs = /* @__PURE__ */ new Map();
6962
+ series.forEach((item, index) => {
6963
+ const primary = item.options?.type === "comparison" ? primaryByGroup.get(item.group) ?? onlyPrimary : void 0;
6964
+ if (primary !== void 0) pairs.set(index, primary);
6965
+ });
6966
+ return pairs;
6967
+ }
6968
+ /**
6969
+ * 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.
6970
+ *
6971
+ * @param series - The chart's series.
6972
+ * @param colors - Each series' resolved color.
6973
+ * @param background - The hex chart background.
6974
+ * @return Each series' fill, by index.
6975
+ */
6976
+ function getGroupedBarColors(series, colors, background) {
6977
+ const barColors = [...colors];
6978
+ getComparisonPrimaries(series).forEach((primary, comparison) => {
6979
+ const base = colors[primary];
6980
+ if (!!series[comparison].options?.stroke && colors[comparison].toLowerCase() !== base.toLowerCase() || !isValidHexColor(base) || !isValidHexColor(background)) return;
6981
+ const tint = tintWithContrast(base, background);
6982
+ barColors[comparison] = tint;
6983
+ if (!series[primary].options?.stroke) barColors[primary] = shadeWithContrast(base, tint, background);
6984
+ });
6985
+ return barColors;
6986
+ }
6987
+ //#endregion
6988
+ //#region src/charts/bar-chart/use-bar-colors.ts
6989
+ /**
6990
+ * Reads the colors `BarChart` fills series with, so a custom tooltip or legend can match the bars.
6991
+ *
6992
+ * @return A function from series and a layout to each series' bar color, by index.
6993
+ */
6994
+ function useBarColors() {
6995
+ const { getElementStyles, backgroundColor = BACKGROUND_FALLBACK, theme } = useGlobalChartsContext();
6996
+ const comparisonOpacity = theme.barChart?.barStyles?.comparison?.opacity;
6997
+ return useCallback((series, { layout = "grouped" } = {}) => {
6998
+ const colors = series.map((data, index) => getElementStyles({
6999
+ data,
7000
+ index
7001
+ }).color);
7002
+ if (layout !== "overlap") return comparisonOpacity === void 0 ? getGroupedBarColors(series, colors, backgroundColor) : colors;
7003
+ return getOverlapBarColors(series, colors, [getElementStyles({ index: 0 }).color, getElementStyles({ index: 1 }).color], backgroundColor);
7004
+ }, [
7005
+ getElementStyles,
7006
+ backgroundColor,
7007
+ comparisonOpacity
7008
+ ]);
7009
+ }
7010
+ //#endregion
7011
+ //#region src/charts/bar-chart/use-bar-legend-items.ts
7012
+ const isComparison = (data, label) => data.some((series) => series.label === label && series.options?.type === "comparison");
7013
+ /**
7014
+ * 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.
7015
+ *
7016
+ * @param data - The series the items were built from.
7017
+ * @param items - The legend items.
7018
+ * @param layout - The layout the bars are drawn in.
7019
+ * @param seriesColors - Each series' bar color, by index.
7020
+ * @return The legend items.
7021
+ */
7022
+ function forBarLayout(data, items, layout, seriesColors) {
7023
+ if (layout === "overlap") {
7024
+ const opaque = items.map((item) => item.shapeStyle ? {
7025
+ ...item,
7026
+ shapeStyle: {
7027
+ ...item.shapeStyle,
7028
+ opacity: void 0
7029
+ }
7030
+ } : item);
7031
+ const seriesItems = opaque.filter((item) => item.seriesLabels);
7032
+ const firstLabel = (item) => item.seriesLabels?.[0];
7033
+ return [
7034
+ ...seriesItems.filter((item) => !isComparison(data, firstLabel(item))),
7035
+ ...seriesItems.filter((item) => isComparison(data, firstLabel(item))),
7036
+ ...opaque.filter((item) => !item.seriesLabels)
7037
+ ];
7038
+ }
7039
+ return items.map((item) => {
7040
+ if ((item.seriesLabels?.length ?? 0) < 2) return item;
7041
+ const comparisonIndex = data.findIndex((series) => series.options?.type === "comparison" && item.seriesLabels?.includes(series.label));
7042
+ return comparisonIndex === -1 ? item : {
7043
+ ...item,
7044
+ color: seriesColors[comparisonIndex]
7045
+ };
7046
+ });
7047
+ }
7048
+ /**
7049
+ * Builds legend items that match `BarChart`'s bars in a layout, for a custom legend or a chart's own.
7050
+ *
7051
+ * @param data - The series the chart draws.
7052
+ * @param options - The legend options, and the layout the bars are drawn in.
7053
+ * @param legendShape - The shape of the legend swatches.
7054
+ * @return The legend items.
7055
+ */
7056
+ function useBarLegendItems(data, options = {}, legendShape) {
7057
+ const { layout } = options;
7058
+ const getBarColors = useBarColors();
7059
+ const seriesColors = useMemo(() => layout ? getBarColors(data, { layout }) : void 0, [
7060
+ data,
7061
+ layout,
7062
+ getBarColors
7063
+ ]);
7064
+ const items = useChartLegendItems(data, useMemo(() => ({
7065
+ ...options,
7066
+ seriesColors
7067
+ }), [options, seriesColors]), legendShape);
7068
+ return useMemo(() => layout && seriesColors ? forBarLayout(data, items, layout, seriesColors) : items, [
7069
+ data,
7070
+ items,
7071
+ layout,
7072
+ seriesColors
7073
+ ]);
7074
+ }
7075
+ //#endregion
6415
7076
  //#region src/charts/bar-chart/bar-chart.tsx
6416
7077
  const validateData$2 = (data) => {
6417
7078
  if (!data?.length) return __("No data available", "jetpack-charts");
@@ -6423,13 +7084,14 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ jsx("div", {
6423
7084
  className: bar_chart_module_default["bar-chart__tooltip-row"],
6424
7085
  children: sprintf(__("%1$s: %2$s", "jetpack-charts"), label, value)
6425
7086
  });
6426
- 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 }) => {
7087
+ 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 }) => {
6427
7088
  if (!withTooltips && (withBandHighlight || onBandHighlightChange)) warnOnce("bar-chart-band-highlight-without-tooltips", "BarChart: withBandHighlight and onBandHighlightChange require withTooltips.");
6428
7089
  const legendInteractive = legend.interactive ?? false;
6429
7090
  const legendCollapseGroups = legend.collapseGroups ?? false;
6430
7091
  const legendComparisonItem = legend.comparisonItem ?? false;
6431
7092
  const legendComparisonSeriesItems = legend.comparisonSeriesItems;
6432
7093
  const horizontal = orientation === "horizontal";
7094
+ const isOverlap = layout === "overlap";
6433
7095
  const chartId = useChartId(providedChartId);
6434
7096
  const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
6435
7097
  const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
@@ -6439,16 +7101,25 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6439
7101
  enabled: showZeroValues,
6440
7102
  valueAxisLength: horizontal ? width : height
6441
7103
  });
6442
- const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({
7104
+ const legendItems = useBarLegendItems(dataSorted, useMemo(() => ({
6443
7105
  collapseGroups: legendCollapseGroups,
6444
7106
  comparisonItem: legendComparisonItem,
6445
- comparisonSeriesItems: legendComparisonSeriesItems
7107
+ comparisonSeriesItems: legendComparisonSeriesItems,
7108
+ layout
6446
7109
  }), [
6447
7110
  legendCollapseGroups,
6448
7111
  legendComparisonItem,
6449
- legendComparisonSeriesItems
7112
+ legendComparisonSeriesItems,
7113
+ layout
6450
7114
  ]));
6451
- const { getElementStyles } = useGlobalChartsContext();
7115
+ const { getElementStyles, theme: providerTheme } = useGlobalChartsContext();
7116
+ const getBarColors = useBarColors();
7117
+ const barColors = useMemo(() => getBarColors(dataSorted, { layout }), [
7118
+ layout,
7119
+ getBarColors,
7120
+ dataSorted
7121
+ ]);
7122
+ 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.");
6452
7123
  const isSeriesRendered = useCallback((series) => isSeriesVisible(series.label), [isSeriesVisible]);
6453
7124
  const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(dataSorted.filter(isSeriesRendered)), [dataSorted, isSeriesRendered]);
6454
7125
  const chartOptions = useBarChartOptions(dataWithVisibleZeros, horizontal, options, isSeriesRendered);
@@ -6477,37 +7148,30 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6477
7148
  return seriesWithVisibility.every(({ isVisible }) => !isVisible);
6478
7149
  }, [seriesWithVisibility]);
6479
7150
  const primaryEntries = useMemo(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
6480
- const totalPoints = Math.max(0, ...primaryEntries.map((e) => e.series.data.length)) * primaryEntries.length;
7151
+ const overlapSlots = useOverlapSlots(isOverlap, seriesWithVisibility);
6481
7152
  const primaryKeys = useMemo(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
6482
- const primarySeries = useMemo(() => primaryEntries.map(({ series }) => series), [primaryEntries]);
6483
- const activateSelectedBar = useCallback((index) => {
6484
- const primaryCount = primaryEntries.length;
6485
- if (!primaryCount) return;
6486
- const dataPointIndex = Math.floor(index / primaryCount);
6487
- const series = primaryEntries[index % primaryCount]?.series;
6488
- const datum = series?.data[dataPointIndex];
6489
- if (series && datum) onDatumActivate?.({
6490
- datum,
6491
- index: dataPointIndex,
6492
- key: series.label
6493
- });
6494
- }, [primaryEntries, onDatumActivate]);
6495
- const visibleSeriesKey = useMemo(() => JSON.stringify(primaryKeys), [primaryKeys]);
7153
+ const stops = useBarStops(overlapSlots, primaryEntries);
7154
+ const { barAt, stopOf } = stops;
7155
+ const activateSelectedBar = useCallback((stop) => {
7156
+ const bar = barAt(stop);
7157
+ if (bar) onDatumActivate?.(bar);
7158
+ }, [barAt, onDatumActivate]);
6496
7159
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown, onChartPointerMove } = useKeyboardNavigation({
6497
7160
  selectedIndex,
6498
7161
  setSelectedIndex,
6499
7162
  isNavigating,
6500
7163
  setIsNavigating,
6501
7164
  chartRef,
6502
- totalPoints,
7165
+ totalPoints: stops.count,
6503
7166
  onActivate: activateSelectedBar,
6504
- visibleSeriesKey
7167
+ visibleSeriesKey: stops.key
6505
7168
  });
6506
7169
  const handlePointerMove = useCallback(({ key, index }) => {
6507
- const seriesIndex = primaryKeys.indexOf(key);
6508
- if (seriesIndex >= 0) onChartPointerMove(index * primaryKeys.length + seriesIndex);
6509
- }, [primaryKeys, onChartPointerMove]);
7170
+ const stop = stopOf(key, index);
7171
+ if (stop !== void 0) onChartPointerMove(stop);
7172
+ }, [stopOf, onChartPointerMove]);
6510
7173
  const comparisonEntries = useMemo(() => {
7174
+ if (isOverlap) return [];
6511
7175
  const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
6512
7176
  label: series.label,
6513
7177
  index
@@ -6523,12 +7187,12 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6523
7187
  entries.push({
6524
7188
  series,
6525
7189
  index,
6526
- primaryKey: primary.label,
6527
- primaryIndex: primary.index
7190
+ primaryKey: primary.label
6528
7191
  });
6529
7192
  });
6530
7193
  return entries;
6531
7194
  }, [
7195
+ isOverlap,
6532
7196
  seriesWithVisibility,
6533
7197
  primaryEntries,
6534
7198
  primaryKeys
@@ -6568,23 +7232,32 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6568
7232
  chartOptions.yScale,
6569
7233
  horizontal
6570
7234
  ]);
6571
- const getBarBackground = useCallback((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? getElementStyles({
6572
- data: dataSorted[index],
6573
- index
6574
- }).color, [
7235
+ const getBarBackground = useCallback((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? barColors[index] ?? "", [
6575
7236
  withPatterns,
6576
- getElementStyles,
6577
- dataSorted,
7237
+ barColors,
6578
7238
  chartId
6579
7239
  ]);
6580
- const resolveComparisonFill = useCallback((entry) => withPatterns ? `url(#${getPatternId(chartId, entry.primaryIndex)})` : getElementStyles({
6581
- data: entry.series,
6582
- index: entry.index
6583
- }).color, [
7240
+ const resolveComparisonFill = useCallback((entry, datum) => withPatterns ? `url(#${getPatternId(chartId, entry.index)})` : datum.color ?? barColors[entry.index] ?? "", [
6584
7241
  withPatterns,
6585
7242
  chartId,
6586
- getElementStyles
7243
+ barColors
6587
7244
  ]);
7245
+ const renderOverlapTooltip = useCallback(({ tooltipData }) => {
7246
+ const nearestDatum = tooltipData?.nearestDatum?.datum;
7247
+ if (!nearestDatum) return null;
7248
+ const datumByKey = tooltipData?.datumByKey ?? {};
7249
+ const categoryLabel = chartOptions.tooltip.labelFormatter(nearestDatum.label || (nearestDatum.date ? nearestDatum.date.getTime() : 0), 0, []);
7250
+ return /* @__PURE__ */ jsxs("div", {
7251
+ className: bar_chart_module_default["bar-chart__tooltip"],
7252
+ children: [/* @__PURE__ */ jsx("div", {
7253
+ className: bar_chart_module_default["bar-chart__tooltip-header"],
7254
+ children: categoryLabel
7255
+ }), dataSorted.flatMap(({ label }) => {
7256
+ const datum = datumByKey[label]?.datum;
7257
+ return datum ? [/* @__PURE__ */ jsx(Fragment, { children: renderTooltipRow(label, formatReading(datum.value)) }, label)] : [];
7258
+ })]
7259
+ });
7260
+ }, [chartOptions.tooltip, dataSorted]);
6588
7261
  const renderDefaultTooltip = useCallback(({ tooltipData }) => {
6589
7262
  const nearestDatum = tooltipData?.nearestDatum?.datum;
6590
7263
  if (!nearestDatum) return null;
@@ -6659,26 +7332,24 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6659
7332
  }
6660
7333
  `;
6661
7334
  }, [chartId]);
6662
- const createKeyboardHighlightStyle = useCallback(() => {
6663
- if (selectedIndex === void 0) return "";
6664
- const primaryCount = primaryEntries.length;
6665
- if (!primaryCount) return "";
6666
- const dataPointIndex = Math.floor(selectedIndex / primaryCount);
6667
- const seriesIndex = selectedIndex % primaryCount;
6668
- const seriesData = primaryEntries[seriesIndex]?.series;
6669
- const datum = seriesData?.data[dataPointIndex];
6670
- if (!seriesData || !datum || !isBarRendered(datum)) return "";
6671
- const domBarIndex = primaryEntries.slice(0, seriesIndex).reduce((count, { series }) => count + countRenderedBars(series.data), 0) + countRenderedBars(seriesData.data.slice(0, dataPointIndex));
6672
- return `
6673
- .bar-chart[data-chart-id="bar-chart-${chartId}"] .visx-bar-group .visx-bar:nth-child(${domBarIndex + 1}) {
6674
- stroke: #005fcc;
6675
- stroke-width: 2px;
6676
- }
6677
- `;
7335
+ const overlapBandSlots = useMemo(() => overlapSlots && {
7336
+ keys: overlapSlots.slotKeys,
7337
+ slotOf: overlapSlots.slotOf
7338
+ }, [overlapSlots]);
7339
+ const selectedSlot = useMemo(() => getSelectedSlot(overlapSlots, selectedIndex), [overlapSlots, selectedIndex]);
7340
+ const selectedBar = useMemo(() => {
7341
+ if (overlapSlots) return selectedSlot;
7342
+ const bar = selectedIndex === void 0 ? void 0 : barAt(selectedIndex);
7343
+ return bar && isBarRendered(bar.datum) ? {
7344
+ data: [bar.datum],
7345
+ slotKey: bar.key,
7346
+ thickness: 1
7347
+ } : void 0;
6678
7348
  }, [
7349
+ overlapSlots,
7350
+ selectedSlot,
6679
7351
  selectedIndex,
6680
- primaryEntries,
6681
- chartId
7352
+ barAt
6682
7353
  ]);
6683
7354
  const error = validateData$2(dataSorted);
6684
7355
  const isDataValid = !error;
@@ -6699,7 +7370,6 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6699
7370
  children: error
6700
7371
  });
6701
7372
  const gridVisibility = gridVisibilityProp ?? chartOptions.gridVisibility;
6702
- const highlightedBarStyle = createKeyboardHighlightStyle();
6703
7373
  const legendPosition = legend.position ?? "bottom";
6704
7374
  const legendElement = showLegend && /* @__PURE__ */ jsx(Legend, {
6705
7375
  orientation: legend.orientation ?? "horizontal",
@@ -6779,14 +7449,7 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6779
7449
  tickValues: (horizontal ? void 0 : valueTicks) ?? chartOptions.axis.y.tickValues
6780
7450
  })] })
6781
7451
  }),
6782
- withPatterns && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("defs", { children: dataSorted.map((seriesData, index) => renderPattern(index, getElementStyles({
6783
- data: seriesData,
6784
- index
6785
- }).color)) }), /* @__PURE__ */ jsx("style", { children: dataSorted.map((seriesData, index) => createPatternBorderStyle(index, getElementStyles({
6786
- data: seriesData,
6787
- index
6788
- }).color)) })] }),
6789
- highlightedBarStyle && /* @__PURE__ */ jsx("style", { children: highlightedBarStyle }),
7452
+ withPatterns && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("defs", { children: barColors.map((color, index) => renderPattern(index, color)) }), /* @__PURE__ */ jsx("style", { children: barColors.map((color, index) => createPatternBorderStyle(index, color)) })] }),
6790
7453
  allSeriesHidden ? /* @__PURE__ */ jsx(SvgEmptyState, {
6791
7454
  x: width / 2,
6792
7455
  y: chartHeight / 2,
@@ -6804,30 +7467,22 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6804
7467
  getElementStyles,
6805
7468
  resolveFill: resolveComparisonFill
6806
7469
  }),
6807
- barClassName ? /* @__PURE__ */ jsx("g", {
6808
- className: "visx-bar-group",
6809
- children: primaryEntries.map(({ series: seriesData, index }) => /* @__PURE__ */ jsx(ClassifiedBarSeries, {
6810
- dataKey: seriesData.label,
6811
- data: seriesData.data,
6812
- xAccessor: chartOptions.accessors.xAccessor,
6813
- yAccessor: chartOptions.accessors.yAccessor,
6814
- colorAccessor: getBarBackground(index),
6815
- barClassName,
6816
- primaryKeys,
6817
- groupPadding
6818
- }, seriesData.label))
6819
- }) : /* @__PURE__ */ jsx(BarGroup, {
6820
- padding: groupPadding,
6821
- children: primaryEntries.map(({ series: seriesData, index }) => /* @__PURE__ */ jsx(BarSeries, {
6822
- dataKey: seriesData?.label,
6823
- data: seriesData.data,
6824
- yAccessor: chartOptions.accessors.yAccessor,
6825
- xAccessor: chartOptions.accessors.xAccessor,
6826
- colorAccessor: getBarBackground(index)
6827
- }, seriesData?.label))
7470
+ /* @__PURE__ */ jsx(BarLayer, {
7471
+ chartId,
7472
+ overlapSlots,
7473
+ selectedBar,
7474
+ primaryEntries,
7475
+ primaryKeys,
7476
+ getBarBackground,
7477
+ barClassName,
7478
+ groupPadding,
7479
+ horizontal,
7480
+ xAccessor: chartOptions.accessors.xAccessor,
7481
+ yAccessor: chartOptions.accessors.yAccessor
6828
7482
  }),
6829
7483
  (withTooltips || onPointerDown || onPointerUp) && /* @__PURE__ */ jsx(BandTooltip, {
6830
- keys: primaryKeys,
7484
+ keys: overlapSlots?.keys ?? primaryKeys,
7485
+ slots: overlapBandSlots,
6831
7486
  groupPadding,
6832
7487
  withTooltips,
6833
7488
  onPointerDown,
@@ -6844,6 +7499,10 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6844
7499
  ...!horizontal && valueTicks ? { tickValues: valueTicks } : {}
6845
7500
  })] })
6846
7501
  }),
7502
+ withTooltips && selectedSlot && /* @__PURE__ */ jsx(SlotTooltipMembers, {
7503
+ members: selectedSlot.members,
7504
+ index: selectedSlot.index
7505
+ }),
6847
7506
  withTooltips && /* @__PURE__ */ jsx(XYChartTooltip, {
6848
7507
  tooltipPlacement,
6849
7508
  tooltipAnchorTop,
@@ -6851,11 +7510,11 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
6851
7510
  detectBounds: true,
6852
7511
  snapTooltipToDatumX: true,
6853
7512
  snapTooltipToDatumY: true,
6854
- renderTooltip: renderTooltip || renderDefaultTooltip,
7513
+ renderTooltip: renderTooltip || (isOverlap ? renderOverlapTooltip : renderDefaultTooltip),
6855
7514
  selectedIndex,
6856
7515
  tooltipRef,
6857
7516
  keyboardFocusedClassName: bar_chart_module_default["bar-chart__tooltip--keyboard-focused"],
6858
- series: primarySeries,
7517
+ series: stops.series,
6859
7518
  mode: "individual"
6860
7519
  })
6861
7520
  ]
@@ -9219,7 +9878,7 @@ function warning(message) {
9219
9878
  logged.add(message);
9220
9879
  }
9221
9880
  //#endregion
9222
- //#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
9881
+ //#region ../../../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
9223
9882
  function useUpdateEffect(effect, deps) {
9224
9883
  const mountedRef = useRef$1(false);
9225
9884
  useEffect$1(() => {
@@ -10267,7 +10926,7 @@ function serializeStyles(args, registered, mergedProps) {
10267
10926
  }
10268
10927
  React["useInsertionEffect"] && React["useInsertionEffect"] || React.useLayoutEffect;
10269
10928
  //#endregion
10270
- //#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-f0de968e.browser.esm.js
10929
+ //#region ../../../node_modules/.pnpm/@emotion+react@11.14.0_@types+react@19.3.0_react@19.3.0/node_modules/@emotion/react/dist/emotion-element-f0de968e.browser.esm.js
10271
10930
  var EmotionCacheContext = /* #__PURE__ */ React.createContext(typeof HTMLElement !== "undefined" ? /* #__PURE__ */ createCache({ key: "css" }) : null);
10272
10931
  EmotionCacheContext.Provider;
10273
10932
  var __unsafe_useEmotionCache = function useEmotionCache() {
@@ -10374,7 +11033,7 @@ _createEmotion.css;
10374
11033
  _createEmotion.sheet;
10375
11034
  _createEmotion.cache;
10376
11035
  //#endregion
10377
- //#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
11036
+ //#region ../../../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
10378
11037
  var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
10379
11038
  var useCx = () => {
10380
11039
  const cache = __unsafe_useEmotionCache();
@@ -10481,7 +11140,7 @@ function memize(fn, options) {
10481
11140
  return memoized;
10482
11141
  }
10483
11142
  //#endregion
10484
- //#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
11143
+ //#region ../../../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
10485
11144
  var import_es6 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
10486
11145
  module.exports = function equal(a, b) {
10487
11146
  if (a === b) return true;
@@ -10549,18 +11208,18 @@ var BaseContextSystemProvider = ({ children, value }) => {
10549
11208
  };
10550
11209
  memo(BaseContextSystemProvider);
10551
11210
  //#endregion
10552
- //#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
11211
+ //#region ../../../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
10553
11212
  var COMPONENT_NAMESPACE = "data-wp-component";
10554
11213
  var CONNECTED_NAMESPACE = "data-wp-c16t";
10555
11214
  var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
10556
11215
  //#endregion
10557
- //#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
11216
+ //#region ../../../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
10558
11217
  function getStyledClassName(namespace) {
10559
11218
  return `components-${paramCase(namespace)}`;
10560
11219
  }
10561
11220
  var getStyledClassNameFromKey = memize(getStyledClassName);
10562
11221
  //#endregion
10563
- //#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
11222
+ //#region ../../../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
10564
11223
  function contextConnect(Component, namespace) {
10565
11224
  return _contextConnect(Component, namespace, { forwardsRef: true });
10566
11225
  }
@@ -10577,7 +11236,7 @@ function _contextConnect(Component, namespace, options) {
10577
11236
  });
10578
11237
  }
10579
11238
  //#endregion
10580
- //#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
11239
+ //#region ../../../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
10581
11240
  function getNamespace(componentName) {
10582
11241
  return { [COMPONENT_NAMESPACE]: componentName };
10583
11242
  }
@@ -10585,7 +11244,7 @@ function getConnectedNamespace() {
10585
11244
  return { [CONNECTED_NAMESPACE]: true };
10586
11245
  }
10587
11246
  //#endregion
10588
- //#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
11247
+ //#region ../../../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
10589
11248
  function useContextSystem(props, namespace) {
10590
11249
  const contextSystemProps = useComponentsContext();
10591
11250
  if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
@@ -10607,7 +11266,7 @@ function useContextSystem(props, namespace) {
10607
11266
  return finalComponentProps;
10608
11267
  }
10609
11268
  //#endregion
10610
- //#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
11269
+ //#region ../../../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
10611
11270
  var visuallyHidden = {
10612
11271
  border: 0,
10613
11272
  clip: "rect(1px, 1px, 1px, 1px)",
@@ -10623,7 +11282,7 @@ var visuallyHidden = {
10623
11282
  wordBreak: "normal"
10624
11283
  };
10625
11284
  //#endregion
10626
- //#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
11285
+ //#region ../../../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
10627
11286
  var customAttributeRegExp = /^(data|aria|x)-/i;
10628
11287
  var eventHandlerRegExp = /^on[A-Z]/;
10629
11288
  var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
@@ -10713,7 +11372,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
10713
11372
  }
10714
11373
  var PolymorphicElement = forwardRef$1(UnforwardedPolymorphicElement);
10715
11374
  //#endregion
10716
- //#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
11375
+ //#region ../../../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
10717
11376
  function UnforwardedView({ css, ...restProps }, ref) {
10718
11377
  return /* @__PURE__ */ jsx(PolymorphicElement, {
10719
11378
  ref,
@@ -10722,7 +11381,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
10722
11381
  }
10723
11382
  var component_default$2 = Object.assign(forwardRef$1(UnforwardedView), { selector: ".components-view" });
10724
11383
  //#endregion
10725
- //#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
11384
+ //#region ../../../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
10726
11385
  function UnconnectedVisuallyHidden(props, forwardedRef) {
10727
11386
  const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
10728
11387
  return /* @__PURE__ */ jsx(component_default$2, {
@@ -10737,7 +11396,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
10737
11396
  }
10738
11397
  var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
10739
11398
  //#endregion
10740
- //#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
11399
+ //#region ../../../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
10741
11400
  var breakpoints = [
10742
11401
  "40em",
10743
11402
  "52em",
@@ -10776,7 +11435,7 @@ function useResponsiveValue(values, options = {}) {
10776
11435
  return array[index >= array.length ? array.length - 1 : index];
10777
11436
  }
10778
11437
  //#endregion
10779
- //#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
11438
+ //#region ../../../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
10780
11439
  var ALIGNMENTS = {
10781
11440
  bottom: {
10782
11441
  alignItems: "flex-end",
@@ -10824,7 +11483,7 @@ function getAlignmentProps(alignment) {
10824
11483
  return alignment ? ALIGNMENTS[alignment] ?? {} : {};
10825
11484
  }
10826
11485
  //#endregion
10827
- //#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
11486
+ //#region ../../../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
10828
11487
  var STYLE_HASH_ATTRIBUTE = "data-wp-hash";
10829
11488
  function getRuntime() {
10830
11489
  const globalScope = globalThis;
@@ -10969,7 +11628,7 @@ function useGrid(props) {
10969
11628
  };
10970
11629
  }
10971
11630
  //#endregion
10972
- //#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
11631
+ //#region ../../../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
10973
11632
  function UnconnectedGrid(props, forwardedRef) {
10974
11633
  const gridProps = useGrid(props);
10975
11634
  return /* @__PURE__ */ jsx(component_default$2, {
@@ -11576,51 +12235,6 @@ const PieSelectionOutput = ({ withTooltips, selectedIndex, selectedData, keyboar
11576
12235
  ] });
11577
12236
  };
11578
12237
  //#endregion
11579
- //#region src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss
11580
- var pie_keyboard_navigation_module_default = {
11581
- "selected-ring__contrast": "a8ccharts-V2HDKq-selected-ring__contrast",
11582
- "selected-ring__focus": "a8ccharts-V2HDKq-selected-ring__focus"
11583
- };
11584
- //#endregion
11585
- //#region src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx
11586
- /**
11587
- * Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
11588
- *
11589
- * @param value - Any string.
11590
- * @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
11591
- */
11592
- const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
11593
- /**
11594
- * Marks the selected segment with a two-tone ring drawn inside its edge, so the SVG edge cannot cut it off.
11595
- *
11596
- * @param {SelectedSegmentRingProps} props - Component props
11597
- * @return {JSX.Element} The ring
11598
- */
11599
- const SelectedSegmentRing = ({ chartId, d }) => {
11600
- const clipId = `pie-selected-ring-clip-${toSvgId(chartId)}`;
11601
- const clipPath = `url(#${clipId})`;
11602
- return /* @__PURE__ */ jsxs("g", {
11603
- pointerEvents: "none",
11604
- "aria-hidden": "true",
11605
- children: [
11606
- /* @__PURE__ */ jsx("clipPath", {
11607
- id: clipId,
11608
- children: /* @__PURE__ */ jsx("path", { d })
11609
- }),
11610
- /* @__PURE__ */ jsx("path", {
11611
- d,
11612
- clipPath,
11613
- className: pie_keyboard_navigation_module_default["selected-ring__contrast"]
11614
- }),
11615
- /* @__PURE__ */ jsx("path", {
11616
- d,
11617
- clipPath,
11618
- className: pie_keyboard_navigation_module_default["selected-ring__focus"]
11619
- })
11620
- ]
11621
- });
11622
- };
11623
- //#endregion
11624
12238
  //#region src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts
11625
12239
  const usePieKeyboardNavigation = ({ navigationArcs, withTooltips, tooltipOffsetX, tooltipOffsetY }) => {
11626
12240
  const chartRef = useRef(null);
@@ -11996,9 +12610,11 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
11996
12610
  selectedArc && /* @__PURE__ */ jsx(Group, {
11997
12611
  top: centerY,
11998
12612
  left: centerX,
11999
- children: /* @__PURE__ */ jsx(SelectedSegmentRing, {
12613
+ children: /* @__PURE__ */ jsx(SelectedRing, {
12000
12614
  chartId,
12001
- d: path(selectedArc) || ""
12615
+ d: path(selectedArc) || "",
12616
+ side: "inside",
12617
+ testId: "pie-selected-ring"
12002
12618
  })
12003
12619
  }),
12004
12620
  !allSegmentsHidden && /* @__PURE__ */ jsxs(Group, {
@@ -12235,9 +12851,11 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
12235
12851
  selectedArc && /* @__PURE__ */ jsx(Group, {
12236
12852
  top: height,
12237
12853
  left: width / 2,
12238
- children: /* @__PURE__ */ jsx(SelectedSegmentRing, {
12854
+ children: /* @__PURE__ */ jsx(SelectedRing, {
12239
12855
  chartId,
12240
- d: path(selectedArc) || ""
12856
+ d: path(selectedArc) || "",
12857
+ side: "inside",
12858
+ testId: "pie-selected-ring"
12241
12859
  })
12242
12860
  }),
12243
12861
  !allSegmentsHidden && /* @__PURE__ */ jsxs(Group, {
@@ -12488,6 +13106,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
12488
13106
  });
12489
13107
  }
12490
13108
  //#endregion
12491
- export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TooltipBox, TrendIndicator, XYChartTooltip, buildCalendarHeatmapData, buildMonthCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, useMonthCalendarHeatmapData, validateHexColor };
13109
+ export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TooltipBox, TrendIndicator, XYChartTooltip, buildCalendarHeatmapData, buildMonthCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useBarColors, useBarLegendItems, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, useMonthCalendarHeatmapData, validateHexColor };
12492
13110
 
12493
13111
  //# sourceMappingURL=index.js.map