@automattic/charts 3.0.0 → 3.1.1

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 (63) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/TOKENS.md +3 -3
  3. package/dist/index.cjs +250 -136
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +23 -14
  6. package/dist/index.d.cts +51 -14
  7. package/dist/index.d.ts +51 -14
  8. package/dist/index.js +251 -138
  9. package/dist/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/charts/area-chart/area-chart.tsx +26 -26
  12. package/src/charts/area-chart/private/overlays.tsx +3 -3
  13. package/src/charts/area-chart/test/area-chart.test.tsx +346 -11
  14. package/src/charts/area-chart/types.ts +4 -3
  15. package/src/charts/bar-chart/bar-chart.tsx +21 -15
  16. package/src/charts/bar-chart/private/use-bar-chart-options.ts +19 -12
  17. package/src/charts/bar-chart/test/bar-chart.test.tsx +277 -2
  18. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +6 -6
  19. package/src/charts/geo-chart/geo-chart.module.scss +8 -0
  20. package/src/charts/heatmap-chart/heatmap-chart.module.scss +9 -0
  21. package/src/charts/heatmap-chart/heatmap-chart.tsx +31 -8
  22. package/src/charts/heatmap-chart/private/build-calendar-data.ts +65 -5
  23. package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +125 -0
  24. package/src/charts/heatmap-chart/types.ts +8 -0
  25. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +17 -22
  26. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +107 -1
  27. package/src/charts/line-chart/line-chart.module.scss +2 -2
  28. package/src/charts/line-chart/line-chart.tsx +33 -29
  29. package/src/charts/line-chart/private/line-chart-annotations-overlay.tsx +2 -2
  30. package/src/charts/line-chart/test/line-chart.test.tsx +313 -5
  31. package/src/charts/line-chart/types.ts +4 -3
  32. package/src/charts/pie-chart/pie-chart.tsx +8 -13
  33. package/src/charts/pie-chart/test/pie-chart.test.tsx +73 -1
  34. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +2 -2
  35. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +8 -13
  36. package/src/charts/private/{single-chart-context/single-chart-context.tsx → chart-instance-context/chart-instance-context.ts} +1 -5
  37. package/src/charts/private/chart-instance-context/index.ts +3 -0
  38. package/src/charts/private/{single-chart-context/use-single-chart-context.ts → chart-instance-context/use-chart-instance-context.ts} +1 -3
  39. package/src/charts/private/svg-empty-state/get-all-hidden-message.ts +41 -0
  40. package/src/charts/private/svg-empty-state/index.ts +1 -0
  41. package/src/charts/private/svg-empty-state/test/get-all-hidden-message.test.ts +15 -0
  42. package/src/charts/private/x-zoom/test/x-zoom.test.tsx +2 -2
  43. package/src/charts/private/x-zoom/x-zoom.tsx +2 -2
  44. package/src/components/legend/legend.tsx +4 -4
  45. package/src/components/legend/private/base-legend.module.scss +1 -1
  46. package/src/components/legend/private/base-legend.tsx +67 -18
  47. package/src/components/legend/test/legend.test.tsx +100 -4
  48. package/src/components/tooltip/accessible-tooltip.tsx +13 -2
  49. package/src/components/trend-indicator/trend-indicator.module.scss +1 -1
  50. package/src/hooks/index.ts +1 -1
  51. package/src/hooks/{use-interactive-legend-data.ts → use-legend-visibility-data.ts} +29 -30
  52. package/src/index.ts +3 -1
  53. package/src/providers/chart-context/global-charts-provider.tsx +92 -18
  54. package/src/providers/chart-context/hooks/use-default-hidden-series.ts +47 -0
  55. package/src/providers/chart-context/test/chart-context.test.tsx +142 -0
  56. package/src/providers/chart-context/test/use-default-hidden-series-paint.test.tsx +56 -0
  57. package/src/providers/chart-context/test/use-default-hidden-series.ssr.test.tsx +39 -0
  58. package/src/providers/chart-context/test/use-default-hidden-series.test.tsx +222 -0
  59. package/src/providers/chart-context/types.ts +7 -1
  60. package/src/styles/chart-scope.scss +2 -2
  61. package/src/styles/test/wpds-fallbacks.test.ts +131 -0
  62. package/src/types.ts +12 -0
  63. package/src/charts/private/single-chart-context/index.ts +0 -8
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { getStringWidth as getStringWidth$1 } from "./visx/text/index.js";
2
2
  import { formatNumber, formatNumberCompact } from "@automattic/number-formatters";
3
3
  import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid, Tooltip, TooltipContext, XYChart, buildChartTheme } from "@visx/xychart";
4
- import { __, sprintf } from "@wordpress/i18n";
4
+ import { __, _x, sprintf } from "@wordpress/i18n";
5
5
  import clsx from "clsx";
6
6
  import * as React from "react";
7
7
  import { Children, Fragment, createContext, createContext as createContext$1, createElement, forwardRef, forwardRef as forwardRef$1, isValidElement, memo, useCallback, useCallback as useCallback$1, useContext, useContext as useContext$1, useEffect, useEffect as useEffect$1, useId, useImperativeHandle, useLayoutEffect, useMemo, useMemo as useMemo$1, useRef, useRef as useRef$1, useState, useState as useState$1 } from "react";
@@ -50,17 +50,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
50
50
  enumerable: true
51
51
  }) : target, mod));
52
52
  //#endregion
53
- //#region src/charts/private/single-chart-context/single-chart-context.tsx
53
+ //#region src/charts/private/chart-instance-context/chart-instance-context.ts
54
54
  const ChartInstanceContext = createContext(null);
55
- const SingleChartContext = ChartInstanceContext;
56
55
  //#endregion
57
- //#region src/charts/private/single-chart-context/use-single-chart-context.ts
56
+ //#region src/charts/private/chart-instance-context/use-chart-instance-context.ts
58
57
  const useChartInstanceContext = () => {
59
58
  const context = useContext(ChartInstanceContext);
60
59
  if (!context) throw new Error("useChartInstanceContext must be used within a Chart component");
61
60
  return context;
62
61
  };
63
- const useSingleChartContext = useChartInstanceContext;
64
62
  //#endregion
65
63
  //#region src/styles/chart-scope-class.ts
66
64
  /**
@@ -967,6 +965,7 @@ const GlobalChartsContext = createContext(null);
967
965
  const GlobalChartsProvider = ({ children, theme }) => {
968
966
  const [charts, setCharts] = useState(() => /* @__PURE__ */ new Map());
969
967
  const [hiddenSeries, setHiddenSeries] = useState(() => /* @__PURE__ */ new Map());
968
+ const seededCharts = useRef(/* @__PURE__ */ new Set());
970
969
  const wrapperRef = useRef(null);
971
970
  const [scopeNode, setScopeNode] = useState(null);
972
971
  const setWrapperNode = useCallback((node) => {
@@ -1069,18 +1068,41 @@ const GlobalChartsProvider = ({ children, theme }) => {
1069
1068
  shapeStyles: isSeriesData ? getItemShapeStyles(data, index, providerTheme, legendShape) : {}
1070
1069
  };
1071
1070
  }, [providerTheme, resolveColor]);
1072
- const toggleSeriesVisibility = useCallback((chartId, seriesLabel) => {
1071
+ const updateHiddenSeries = useCallback((chartId, update) => {
1073
1072
  setHiddenSeries((prev) => {
1073
+ const current = prev.get(chartId);
1074
+ const next = update(new Set(current ?? []));
1075
+ if (!current && next.size === 0) return prev;
1076
+ if (current && current.size === next.size && [...next].every((label) => current.has(label))) return prev;
1074
1077
  const newMap = new Map(prev);
1075
- const chartHidden = newMap.get(chartId) || /* @__PURE__ */ new Set();
1076
- const newSet = new Set(chartHidden);
1077
- if (newSet.has(seriesLabel)) newSet.delete(seriesLabel);
1078
- else newSet.add(seriesLabel);
1079
- if (newSet.size === 0) newMap.delete(chartId);
1080
- else newMap.set(chartId, newSet);
1078
+ if (next.size === 0) newMap.delete(chartId);
1079
+ else newMap.set(chartId, next);
1081
1080
  return newMap;
1082
1081
  });
1083
1082
  }, []);
1083
+ const toggleSeriesVisibility = useCallback((chartId, seriesLabel) => {
1084
+ updateHiddenSeries(chartId, (current) => {
1085
+ if (current.has(seriesLabel)) current.delete(seriesLabel);
1086
+ else current.add(seriesLabel);
1087
+ return current;
1088
+ });
1089
+ }, [updateHiddenSeries]);
1090
+ const setSeriesVisibility = useCallback((chartId, seriesLabel, visible) => {
1091
+ updateHiddenSeries(chartId, (current) => {
1092
+ if (visible) current.delete(seriesLabel);
1093
+ else current.add(seriesLabel);
1094
+ return current;
1095
+ });
1096
+ }, [updateHiddenSeries]);
1097
+ const setChartHiddenSeries = useCallback((chartId, seriesLabels) => {
1098
+ updateHiddenSeries(chartId, () => new Set(seriesLabels));
1099
+ }, [updateHiddenSeries]);
1100
+ const hasSeededChart = useCallback((chartId) => seededCharts.current.has(chartId), []);
1101
+ const seedChartHiddenSeries = useCallback((chartId, seriesLabels) => {
1102
+ if (seededCharts.current.has(chartId)) return;
1103
+ seededCharts.current.add(chartId);
1104
+ setChartHiddenSeries(chartId, seriesLabels);
1105
+ }, [setChartHiddenSeries]);
1084
1106
  const isSeriesVisible = useCallback((chartId, seriesLabel) => {
1085
1107
  const chartHidden = hiddenSeries.get(chartId);
1086
1108
  return !chartHidden || !chartHidden.has(seriesLabel);
@@ -1097,6 +1119,10 @@ const GlobalChartsProvider = ({ children, theme }) => {
1097
1119
  theme: providerTheme,
1098
1120
  getElementStyles,
1099
1121
  toggleSeriesVisibility,
1122
+ setSeriesVisibility,
1123
+ setChartHiddenSeries,
1124
+ seedChartHiddenSeries,
1125
+ hasSeededChart,
1100
1126
  isSeriesVisible,
1101
1127
  getHiddenSeries,
1102
1128
  isColorPaletteResolved
@@ -1108,6 +1134,10 @@ const GlobalChartsProvider = ({ children, theme }) => {
1108
1134
  providerTheme,
1109
1135
  getElementStyles,
1110
1136
  toggleSeriesVisibility,
1137
+ setSeriesVisibility,
1138
+ setChartHiddenSeries,
1139
+ seedChartHiddenSeries,
1140
+ hasSeededChart,
1111
1141
  isSeriesVisible,
1112
1142
  getHiddenSeries,
1113
1143
  isColorPaletteResolved
@@ -1506,12 +1536,12 @@ const useDataWithPercentages = (data) => {
1506
1536
  }, [data]);
1507
1537
  };
1508
1538
  //#endregion
1509
- //#region src/hooks/use-interactive-legend-data.ts
1539
+ //#region src/hooks/use-legend-visibility-data.ts
1510
1540
  /**
1511
- * Custom hook to filter and recalculate chart data for interactive legends.
1541
+ * Custom hook to filter and recalculate chart data based on series visibility.
1512
1542
  *
1513
- * When interactive legends are enabled, this hook:
1514
- * 1. Filters data to show only visible series based on legend selection
1543
+ * Regardless of whether the legend is interactive (clickable), this hook:
1544
+ * 1. Filters data to show only visible series (visibility can also be set programmatically)
1515
1545
  * 2. Recalculates percentages so visible segments total 100%
1516
1546
  * 3. Tracks whether all segments are hidden to show empty state
1517
1547
  *
@@ -1520,10 +1550,9 @@ const useDataWithPercentages = (data) => {
1520
1550
  *
1521
1551
  * @example
1522
1552
  * ```tsx
1523
- * const { visibleData, allSegmentsHidden, legendData } = useInteractiveLegendData({
1553
+ * const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
1524
1554
  * data: chartData,
1525
1555
  * chartId: 'my-pie-chart',
1526
- * legendInteractive: true,
1527
1556
  * isSeriesVisible: (id, label) => context.isSeriesVisible(id, label),
1528
1557
  * });
1529
1558
  *
@@ -1538,16 +1567,15 @@ const useDataWithPercentages = (data) => {
1538
1567
  * return <PieChart data={visibleData} />;
1539
1568
  * ```
1540
1569
  *
1541
- * @param params - Configuration object for the hook
1542
- * @param params.data - The chart data to filter
1543
- * @param params.chartId - Unique identifier for the chart (required for interactive mode)
1544
- * @param params.legendInteractive - Whether to enable interactive filtering
1545
- * @param params.isSeriesVisible - Function to check series visibility
1570
+ * @param params - Configuration object for the hook
1571
+ * @param params.data - The chart data to filter
1572
+ * @param params.chartId - Unique identifier for the chart (required for filtering)
1573
+ * @param params.isSeriesVisible - Function to check series visibility
1546
1574
  * @return Object containing visibleData, allSegmentsHidden flag, and legendData with recalculated percentages
1547
1575
  */
1548
- const useInteractiveLegendData = ({ data, chartId, legendInteractive, isSeriesVisible }) => {
1576
+ const useLegendVisibilityData = ({ data, chartId, isSeriesVisible }) => {
1549
1577
  const visibleData = useMemo(() => {
1550
- if (!chartId || !legendInteractive) return data;
1578
+ if (!chartId) return data;
1551
1579
  const filtered = data.filter((segment) => isSeriesVisible(chartId, segment.label));
1552
1580
  if (filtered.length === 0) return [];
1553
1581
  const totalValue = filtered.reduce((sum, segment) => sum + segment.value, 0);
@@ -1558,16 +1586,15 @@ const useInteractiveLegendData = ({ data, chartId, legendInteractive, isSeriesVi
1558
1586
  }, [
1559
1587
  data,
1560
1588
  chartId,
1561
- isSeriesVisible,
1562
- legendInteractive
1589
+ isSeriesVisible
1563
1590
  ]);
1564
1591
  return {
1565
1592
  visibleData,
1566
1593
  allSegmentsHidden: useMemo(() => {
1567
- return legendInteractive && visibleData.length === 0;
1568
- }, [legendInteractive, visibleData]),
1594
+ return visibleData.length === 0 && data.length > 0;
1595
+ }, [visibleData, data]),
1569
1596
  legendData: useMemo(() => {
1570
- if (!legendInteractive || !chartId) return data;
1597
+ if (!chartId) return data;
1571
1598
  const visibleDataMap = new Map(visibleData.map((d) => [d.label, d]));
1572
1599
  return data.map((segment) => {
1573
1600
  if (!isSeriesVisible(chartId, segment.label)) return segment;
@@ -1576,7 +1603,6 @@ const useInteractiveLegendData = ({ data, chartId, legendInteractive, isSeriesVi
1576
1603
  }, [
1577
1604
  data,
1578
1605
  visibleData,
1579
- legendInteractive,
1580
1606
  chartId,
1581
1607
  isSeriesVisible
1582
1608
  ])
@@ -1706,12 +1732,22 @@ const LegendText = ({ text, textOverflow, maxWidth }) => {
1706
1732
  children: text
1707
1733
  });
1708
1734
  };
1735
+ const getLegendItemAriaLabel = (text, value, visible, interactive) => {
1736
+ const accessibleText = value != null && value !== "" ? sprintf(_x("%1$s, %2$s", "legend item label and value", "jetpack-charts"), text, String(value)) : text;
1737
+ if (interactive) {
1738
+ if (visible) return sprintf(_x("%s: visible. Toggle visibility.", "visible interactive legend item", "jetpack-charts"), accessibleText);
1739
+ return sprintf(_x("%s: hidden. Toggle visibility.", "hidden interactive legend item", "jetpack-charts"), accessibleText);
1740
+ }
1741
+ if (visible) return;
1742
+ return sprintf(_x("%s: hidden", "hidden non-interactive legend item", "jetpack-charts"), accessibleText);
1743
+ };
1709
1744
  const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", alignment = "center", shape = "rect", fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform = labelTransformFactory, itemStyles, itemClassName, labelStyles, labelClassName, shapeStyles, render, interactive = false, chartId }, ref) => {
1710
1745
  const { margin: itemMargin = "0", flexDirection: itemDirection = "row" } = itemStyles ?? {};
1711
1746
  const { justifyContent: labelJustifyContent = "flex-start", flex: labelFlex = "0 0 auto", margin: labelMargin = "0 4px", maxWidth, textOverflow = "wrap" } = labelStyles ?? {};
1712
1747
  const { width: shapeWidth = 16, height: shapeHeight = 16, margin: shapeMargin = "2px 4px 2px 0" } = shapeStyles ?? {};
1713
1748
  const theme = useGlobalChartsTheme();
1714
1749
  const context = useContext(GlobalChartsContext);
1750
+ const chartInstanceContext = useContext(ChartInstanceContext);
1715
1751
  const standaloneScopeClass = useStandaloneScopeClass();
1716
1752
  const legendScale = scaleOrdinal({
1717
1753
  domain: items.map((item) => item.label),
@@ -1722,9 +1758,7 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
1722
1758
  const handleLegendClick = useCallback((seriesLabels) => {
1723
1759
  if (interactive && chartId && context) {
1724
1760
  const representativeVisible = context.isSeriesVisible(chartId, seriesLabels[0]);
1725
- seriesLabels.forEach((label) => {
1726
- if (context.isSeriesVisible(chartId, label) === representativeVisible) context.toggleSeriesVisibility(chartId, label);
1727
- });
1761
+ seriesLabels.forEach((label) => context.setSeriesVisibility(chartId, label, !representativeVisible));
1728
1762
  }
1729
1763
  }, [
1730
1764
  interactive,
@@ -1732,11 +1766,12 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
1732
1766
  context
1733
1767
  ]);
1734
1768
  const isSeriesVisible = useCallback((seriesLabel) => {
1735
- if (!interactive || !chartId || !context) return true;
1769
+ if (chartInstanceContext?.isSeriesVisible) return chartInstanceContext.isSeriesVisible(seriesLabel);
1770
+ if (!chartId || !context) return true;
1736
1771
  return context.isSeriesVisible(chartId, seriesLabel);
1737
1772
  }, [
1738
- interactive,
1739
1773
  chartId,
1774
+ chartInstanceContext,
1740
1775
  context
1741
1776
  ]);
1742
1777
  const createClickHandler = useCallback((seriesLabels) => {
@@ -1764,7 +1799,7 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
1764
1799
  align: orientation === "vertical" ? flexAlignment : void 0,
1765
1800
  justify: orientation === "horizontal" ? flexAlignment : void 0,
1766
1801
  wrap: orientation === "horizontal" ? "wrap" : void 0,
1767
- role: "list",
1802
+ role: interactive ? void 0 : "list",
1768
1803
  className: clsx(standaloneScopeClass, base_legend_module_default.legend, className),
1769
1804
  style: theme.legend?.containerStyles,
1770
1805
  children: labels.map((label, i) => {
@@ -1779,10 +1814,10 @@ const BaseLegend = forwardRef(({ items, className, orientation = "horizontal", a
1779
1814
  flexDirection: orientation === "vertical" && alignment === "end" ? "row-reverse" : itemDirection,
1780
1815
  onClick: handleClick,
1781
1816
  onKeyDown: handleKeyDown,
1782
- role: interactive ? "button" : void 0,
1817
+ role: interactive ? "button" : "listitem",
1783
1818
  tabIndex: interactive ? 0 : void 0,
1784
1819
  "aria-pressed": interactive ? visible : void 0,
1785
- "aria-label": interactive ? `${label.text}: ${visible ? "visible" : "hidden"}. Toggle visibility.` : void 0,
1820
+ "aria-label": getLegendItemAriaLabel(label.text, matchedItem?.value, visible, interactive),
1786
1821
  children: [items[i]?.renderGlyph ? /* @__PURE__ */ jsx("svg", {
1787
1822
  width: items[i]?.glyphSize * 2,
1788
1823
  height: items[i]?.glyphSize * 2,
@@ -1844,8 +1879,8 @@ const defaultShapeByChartType = {
1844
1879
  };
1845
1880
  const Legend = forwardRef(({ chartId, items, shape, ...props }, ref) => {
1846
1881
  const context = useContext(GlobalChartsContext);
1847
- const singleChartContext = useContext(SingleChartContext);
1848
- const contextChartId = chartId ?? singleChartContext?.chartId;
1882
+ const chartInstanceContext = useContext(ChartInstanceContext);
1883
+ const contextChartId = chartId ?? chartInstanceContext?.chartId;
1849
1884
  const chartData = useMemo(() => contextChartId && context ? context.getChartData(contextChartId) : void 0, [contextChartId, context]);
1850
1885
  const contextItems = chartData?.legendItems;
1851
1886
  const resolvedShape = shape ?? (chartData?.chartType ? defaultShapeByChartType[chartData.chartType] : void 0);
@@ -2085,11 +2120,16 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
2085
2120
  }
2086
2121
  return flattened;
2087
2122
  }, [series, mode]);
2123
+ const hasKeyboardSelection = useRef(false);
2088
2124
  useEffect(() => {
2089
2125
  if (selectedIndex === void 0) {
2090
- tooltipContext?.hideTooltip();
2126
+ if (hasKeyboardSelection.current) {
2127
+ hasKeyboardSelection.current = false;
2128
+ tooltipContext?.hideTooltip();
2129
+ }
2091
2130
  return;
2092
2131
  }
2132
+ hasKeyboardSelection.current = true;
2093
2133
  if (mode === "group") series.forEach((s, index) => {
2094
2134
  if (selectedIndex < s.data.length) {
2095
2135
  const datum = s.data[selectedIndex];
@@ -2197,6 +2237,43 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
2197
2237
  };
2198
2238
  };
2199
2239
  //#endregion
2240
+ //#region src/providers/chart-context/hooks/use-default-hidden-series.ts
2241
+ const useIsomorphicLayoutEffect$1 = typeof window !== "undefined" ? useLayoutEffect : useEffect;
2242
+ /**
2243
+ * Seeds a chart's hidden series once per chart ID, the first time the provider
2244
+ * sees that ID.
2245
+ *
2246
+ * The provider owns the record of what has been seeded, not this hook: a
2247
+ * mount-scoped one would re-apply the defaults on every remount, and a chart
2248
+ * remounts for reasons the reader never thinks of as a new chart — switching
2249
+ * between line and bar, tabbing away and back, a resize flipping tabs into a
2250
+ * dropdown. Each of those would throw away the series they had just revealed.
2251
+ *
2252
+ * @param chartId - The chart ID passed to the provider's visibility methods.
2253
+ * @param seriesLabels - Labels to hide when this chart ID is first seen. Later values are ignored.
2254
+ * @return The resolved hidden-series set.
2255
+ */
2256
+ const useDefaultHiddenSeries = (chartId, seriesLabels) => {
2257
+ const { getHiddenSeries, seedChartHiddenSeries, hasSeededChart } = useGlobalChartsContext();
2258
+ const labelsRef = useRef(seriesLabels);
2259
+ labelsRef.current = seriesLabels;
2260
+ const hasSeriesLabels = seriesLabels !== void 0;
2261
+ const shouldUseDefaults = hasSeriesLabels && !hasSeededChart(chartId);
2262
+ useIsomorphicLayoutEffect$1(() => {
2263
+ if (labelsRef.current === void 0) return;
2264
+ seedChartHiddenSeries(chartId, labelsRef.current);
2265
+ }, [
2266
+ chartId,
2267
+ hasSeriesLabels,
2268
+ seedChartHiddenSeries
2269
+ ]);
2270
+ return useMemo(() => shouldUseDefaults ? new Set(labelsRef.current) : getHiddenSeries(chartId), [
2271
+ shouldUseDefaults,
2272
+ getHiddenSeries,
2273
+ chartId
2274
+ ]);
2275
+ };
2276
+ //#endregion
2200
2277
  //#region src/charts/private/chart-composition/chart-svg.tsx
2201
2278
  /**
2202
2279
  * Compound component for SVG children in charts.
@@ -2410,6 +2487,27 @@ const SvgEmptyState = ({ x, y, width, height, children }) => {
2410
2487
  });
2411
2488
  };
2412
2489
  //#endregion
2490
+ //#region src/charts/private/svg-empty-state/get-all-hidden-message.ts
2491
+ /**
2492
+ * Return the empty-state message for a chart whose items are all hidden.
2493
+ *
2494
+ * Each translation call has a distinct gettext context. This prevents Terser
2495
+ * from folding conditional calls into one call with a conditional msgid, which
2496
+ * would make the strings unavailable to static translation extraction.
2497
+ *
2498
+ * @param interactive - Whether the legend can be used to show hidden items.
2499
+ * @param itemType - The chart-specific name for its data items.
2500
+ * @return The translated empty-state message.
2501
+ */
2502
+ const getAllHiddenMessage = (interactive, itemType) => {
2503
+ if (itemType === "segments") {
2504
+ if (interactive) return _x("All segments are hidden. Click legend items to show data.", "chart empty state: interactive segments", "jetpack-charts");
2505
+ return _x("All segments are hidden.", "chart empty state: segments", "jetpack-charts");
2506
+ }
2507
+ if (interactive) return _x("All series are hidden. Click legend items to show data.", "chart empty state: interactive series", "jetpack-charts");
2508
+ return _x("All series are hidden.", "chart empty state: series", "jetpack-charts");
2509
+ };
2510
+ //#endregion
2413
2511
  //#region src/charts/private/time-axis.ts
2414
2512
  const X_TICK_WIDTH = 60;
2415
2513
  const getCurveType = (type, smoothing) => {
@@ -2937,7 +3035,7 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
2937
3035
  //#endregion
2938
3036
  //#region src/charts/line-chart/private/line-chart-annotations-overlay.tsx
2939
3037
  const LineChartAnnotationsOverlay = ({ children }) => {
2940
- const { chartRef, chartWidth, chartHeight } = useSingleChartContext();
3038
+ const { chartRef, chartWidth, chartHeight } = useChartInstanceContext();
2941
3039
  const [scales, setScales] = useState(null);
2942
3040
  const [scalesStable, setScalesStable] = useState(false);
2943
3041
  const createScaleSignature = useCallback((scaleData) => {
@@ -3322,7 +3420,7 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
3322
3420
  ]);
3323
3421
  return null;
3324
3422
  };
3325
- const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, zoomable = false, rescaleYOnVisibilityChange = true, children, gridVisibility, gap = "md" }, ref) => {
3423
+ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
3326
3424
  const legendInteractive = legend.interactive ?? false;
3327
3425
  const legendCollapseGroups = legend.collapseGroups ?? false;
3328
3426
  const legendShape = legend.shape ?? "line";
@@ -3331,6 +3429,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3331
3429
  const theme = useXYChartTheme(data);
3332
3430
  const resolvedBackgroundColor = theme.backgroundColor ?? providerTheme.backgroundColor;
3333
3431
  const chartId = useChartId(providedChartId);
3432
+ const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
3433
+ const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
3334
3434
  const chartRef = useRef(null);
3335
3435
  const [selectedIndex, setSelectedIndex] = useState(void 0);
3336
3436
  const [isNavigating, setIsNavigating] = useState(false);
@@ -3358,29 +3458,19 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3358
3458
  }
3359
3459
  }), [internalChartRef]);
3360
3460
  const dataSorted = useChartDataTransform(data);
3361
- const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
3461
+ const { getElementStyles } = useGlobalChartsContext();
3362
3462
  const seriesWithVisibility = useMemo(() => {
3363
- if (!chartId || !legendInteractive) return dataSorted.map((series, index) => ({
3364
- series,
3365
- index,
3366
- isVisible: true
3367
- }));
3368
3463
  return dataSorted.map((series, index) => ({
3369
3464
  series,
3370
3465
  index,
3371
- isVisible: isSeriesVisible(chartId, series.label)
3466
+ isVisible: !hiddenSeries.has(series.label)
3372
3467
  }));
3373
- }, [
3374
- dataSorted,
3375
- chartId,
3376
- isSeriesVisible,
3377
- legendInteractive
3378
- ]);
3468
+ }, [dataSorted, hiddenSeries]);
3379
3469
  const allSeriesHidden = useMemo(() => {
3380
3470
  return seriesWithVisibility.every(({ isVisible }) => !isVisible);
3381
3471
  }, [seriesWithVisibility]);
3382
3472
  const stableYDomain = useMemo(() => {
3383
- if (!legendInteractive || rescaleYOnVisibilityChange) return;
3473
+ if (rescaleYOnVisibilityChange) return;
3384
3474
  let min = Infinity;
3385
3475
  let max = -Infinity;
3386
3476
  for (const series of dataSorted) for (const point of series.data ?? []) {
@@ -3391,11 +3481,7 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3391
3481
  }
3392
3482
  }
3393
3483
  return min < max ? [min, max] : void 0;
3394
- }, [
3395
- legendInteractive,
3396
- rescaleYOnVisibilityChange,
3397
- dataSorted
3398
- ]);
3484
+ }, [rescaleYOnVisibilityChange, dataSorted]);
3399
3485
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
3400
3486
  selectedIndex,
3401
3487
  setSelectedIndex,
@@ -3405,8 +3491,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3405
3491
  totalPoints: dataSorted[0]?.data.length || 0
3406
3492
  });
3407
3493
  const chartOptions = useMemo(() => {
3408
- const { tickResolution, ...xAxisOptions } = options?.axis?.x ?? {};
3409
- const formatter = xAxisOptions.tickFormat || getFormatter(dataSorted, tickResolution);
3494
+ const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
3495
+ const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
3410
3496
  return {
3411
3497
  axis: {
3412
3498
  x: {
@@ -3519,10 +3605,11 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3519
3605
  chartId,
3520
3606
  interactive: legendInteractive
3521
3607
  });
3522
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
3608
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
3523
3609
  value: {
3524
3610
  chartId,
3525
3611
  chartRef: internalChartRef,
3612
+ isSeriesVisible,
3526
3613
  chartWidth: width,
3527
3614
  chartHeight: measuredChartHeight || 0
3528
3615
  },
@@ -3577,7 +3664,7 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3577
3664
  y: chartHeight / 2,
3578
3665
  width,
3579
3666
  height: chartHeight,
3580
- children: __("All series are hidden. Click legend items to show data.", "jetpack-charts")
3667
+ children: getAllHiddenMessage(legendInteractive, "series")
3581
3668
  }) : null,
3582
3669
  /* @__PURE__ */ jsx(ZoomClip, {
3583
3670
  active: zoomable && !!zoom.domain,
@@ -3779,7 +3866,7 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
3779
3866
  };
3780
3867
  //#endregion
3781
3868
  //#region src/charts/area-chart/area-chart.tsx
3782
- const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange, rescaleYOnLegendToggle, children, gridVisibility, gap = "md" }, ref) => {
3869
+ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange, rescaleYOnLegendToggle, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
3783
3870
  const legendInteractive = legend.interactive ?? false;
3784
3871
  const legendShape = legend.shape ?? "rect";
3785
3872
  const legendPosition = legend.position ?? "bottom";
@@ -3787,6 +3874,8 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3787
3874
  const providerTheme = useGlobalChartsTheme();
3788
3875
  const theme = useXYChartTheme(data);
3789
3876
  const chartId = useChartId(providedChartId);
3877
+ const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
3878
+ const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
3790
3879
  const chartRef = useRef(null);
3791
3880
  const [selectedIndex, setSelectedIndex] = useState(void 0);
3792
3881
  const [isNavigating, setIsNavigating] = useState(false);
@@ -3814,24 +3903,14 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3814
3903
  }
3815
3904
  }), [internalChartRef]);
3816
3905
  const dataSorted = useChartDataTransform(data);
3817
- const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
3906
+ const { getElementStyles } = useGlobalChartsContext();
3818
3907
  const seriesWithVisibility = useMemo(() => {
3819
- if (!chartId || !legendInteractive) return dataSorted.map((series, index) => ({
3820
- series,
3821
- index,
3822
- isVisible: true
3823
- }));
3824
3908
  return dataSorted.map((series, index) => ({
3825
3909
  series,
3826
3910
  index,
3827
- isVisible: isSeriesVisible(chartId, series.label)
3911
+ isVisible: !hiddenSeries.has(series.label)
3828
3912
  }));
3829
- }, [
3830
- dataSorted,
3831
- chartId,
3832
- isSeriesVisible,
3833
- legendInteractive
3834
- ]);
3913
+ }, [dataSorted, hiddenSeries]);
3835
3914
  const allSeriesHidden = useMemo(() => seriesWithVisibility.every(({ isVisible }) => !isVisible), [seriesWithVisibility]);
3836
3915
  const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
3837
3916
  selectedIndex,
@@ -3842,7 +3921,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3842
3921
  totalPoints: dataSorted[0]?.data.length || 0
3843
3922
  });
3844
3923
  const fixedYDomain = useMemo(() => {
3845
- if (rescaleYOnVisibility || !legendInteractive || !dataSorted.length || !dataSorted[0].data.length || stacked && stackOffset !== "none") return;
3924
+ if (rescaleYOnVisibility || !dataSorted.length || !dataSorted[0].data.length || stacked && stackOffset !== "none") return;
3846
3925
  if (stacked) {
3847
3926
  const numPoints = Math.max(...dataSorted.map((s) => s.data.length));
3848
3927
  let posMax = 0;
@@ -3876,12 +3955,11 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3876
3955
  dataSorted,
3877
3956
  stacked,
3878
3957
  stackOffset,
3879
- legendInteractive,
3880
3958
  rescaleYOnVisibility
3881
3959
  ]);
3882
3960
  const chartOptions = useMemo(() => {
3883
- const { tickResolution, ...xAxisOptions } = options?.axis?.x ?? {};
3884
- const formatter = xAxisOptions.tickFormat || getFormatter(dataSorted, tickResolution);
3961
+ const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
3962
+ const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
3885
3963
  return {
3886
3964
  axis: {
3887
3965
  x: {
@@ -3953,7 +4031,6 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3953
4031
  const zeroYAccessor = useCallback(() => 0, []);
3954
4032
  const visibleLabels = useMemo(() => new Set(seriesWithVisibility.filter((s) => s.isVisible).map((s) => s.series.label)), [seriesWithVisibility]);
3955
4033
  const filteredRenderTooltip = useCallback((params) => {
3956
- if (!legendInteractive) return renderTooltip(params);
3957
4034
  const datumByKey = params?.tooltipData?.datumByKey;
3958
4035
  if (!datumByKey) return renderTooltip(params);
3959
4036
  const filtered = Object.fromEntries(Object.entries(datumByKey).filter(([key]) => visibleLabels.has(key)));
@@ -3971,11 +4048,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
3971
4048
  nearestDatum: nextNearest
3972
4049
  }
3973
4050
  });
3974
- }, [
3975
- renderTooltip,
3976
- legendInteractive,
3977
- visibleLabels
3978
- ]);
4051
+ }, [renderTooltip, visibleLabels]);
3979
4052
  const resolvedFillOpacity = fillOpacity ?? (stacked ? .85 : .4);
3980
4053
  const resolvedWithStroke = withStroke ?? !stacked;
3981
4054
  if (error) return /* @__PURE__ */ jsx("div", {
@@ -4006,7 +4079,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
4006
4079
  dataKey: seriesData?.label,
4007
4080
  data: seriesData.data,
4008
4081
  xAccessor: accessors.xAccessor,
4009
- yAccessor: isVisible || !legendInteractive ? accessors.yAccessor : zeroYAccessor,
4082
+ yAccessor: isVisible ? accessors.yAccessor : zeroYAccessor,
4010
4083
  fill: color,
4011
4084
  fillOpacity: resolvedFillOpacity,
4012
4085
  ...stacked ? {} : {
@@ -4019,10 +4092,11 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
4019
4092
  }
4020
4093
  }, seriesData?.label || index);
4021
4094
  };
4022
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
4095
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
4023
4096
  value: {
4024
4097
  chartId,
4025
4098
  chartRef: internalChartRef,
4099
+ isSeriesVisible,
4026
4100
  chartWidth: width,
4027
4101
  chartHeight: measuredChartHeight || 0
4028
4102
  },
@@ -4077,7 +4151,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
4077
4151
  y: chartHeight / 2,
4078
4152
  width,
4079
4153
  height: chartHeight,
4080
- children: __("All series are hidden. Click legend items to show data.", "jetpack-charts")
4154
+ children: getAllHiddenMessage(legendInteractive, "series")
4081
4155
  }) : null,
4082
4156
  /* @__PURE__ */ jsxs(ZoomClip, {
4083
4157
  active: zoomable,
@@ -4354,11 +4428,13 @@ const getGroupPadding = (scale) => {
4354
4428
  function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = ALL_RENDERED) {
4355
4429
  const stableOptions = useDeepMemo(options);
4356
4430
  const axisConfig = useMemo(() => {
4357
- const { labelOverflow: xLabelOverflow, tickResolution: xTickResolution, ...xAxisOptions } = stableOptions.axis?.x || {};
4358
- const { labelOverflow: yLabelOverflow, tickResolution: yTickResolution, ...yAxisOptions } = stableOptions.axis?.y || {};
4431
+ const { labelOverflow: xLabelOverflow, tickResolution: xTickResolution, tickFormat: xTickFormat, ...xAxisOptions } = stableOptions.axis?.x || {};
4432
+ const { labelOverflow: yLabelOverflow, tickResolution: yTickResolution, tickFormat: yTickFormat, ...yAxisOptions } = stableOptions.axis?.y || {};
4359
4433
  return {
4360
4434
  xLabelOverflow,
4361
4435
  yLabelOverflow,
4436
+ xTickFormat,
4437
+ yTickFormat,
4362
4438
  xAxisOptions,
4363
4439
  yAxisOptions,
4364
4440
  tickResolution: horizontal ? yTickResolution : xTickResolution
@@ -4418,7 +4494,7 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
4418
4494
  isSeriesRendered
4419
4495
  ]);
4420
4496
  return useMemo(() => {
4421
- const { xTickFormat, yTickFormat, tooltipLabelFormatter: defaultTooltipLabelFormatter, xAccessor, yAccessor, gridVisibility, xScale: baseXScale, yScale: baseYScale } = defaultOptions[horizontal ? "horizontal" : "vertical"];
4497
+ const { xTickFormat: defaultXTickFormat, yTickFormat: defaultYTickFormat, tooltipLabelFormatter: defaultTooltipLabelFormatter, xAccessor, yAccessor, gridVisibility, xScale: baseXScale, yScale: baseYScale } = defaultOptions[horizontal ? "horizontal" : "vertical"];
4422
4498
  let valueScaleDomainOverride = {};
4423
4499
  if (data.some((s) => s.options?.type === "comparison")) {
4424
4500
  if (!(!horizontal ? stableOptions.yScale?.domain : stableOptions.xScale?.domain)) {
@@ -4443,11 +4519,11 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
4443
4519
  ...stableOptions.yScale || {},
4444
4520
  ...!horizontal ? valueScaleDomainOverride : {}
4445
4521
  };
4446
- const { xLabelOverflow, yLabelOverflow, xAxisOptions, yAxisOptions } = axisConfig;
4447
- const providedToolTipLabelFormatter = horizontal ? yAxisOptions.tickFormat : xAxisOptions.tickFormat;
4522
+ const { xLabelOverflow, yLabelOverflow, xTickFormat, yTickFormat, xAxisOptions, yAxisOptions } = axisConfig;
4523
+ const dateAxisTickFormat = horizontal ? yTickFormat : xTickFormat;
4448
4524
  const { timeAxis } = defaultOptions;
4449
4525
  const dateAxisOptions = horizontal ? yAxisOptions : xAxisOptions;
4450
- const bandTickValues = timeAxis && !dateAxisOptions.tickFormat ? getBandTickValues(timeAxis.domain, timeAxis.tickFormatter, dateAxisOptions.numTicks ?? DEFAULT_NUM_TICKS) : null;
4526
+ const bandTickValues = timeAxis && !dateAxisTickFormat ? getBandTickValues(timeAxis.domain, timeAxis.tickFormatter, dateAxisOptions.numTicks ?? DEFAULT_NUM_TICKS) : null;
4451
4527
  const dateAxisTickValues = bandTickValues ? { tickValues: bandTickValues } : {};
4452
4528
  return {
4453
4529
  gridVisibility,
@@ -4461,7 +4537,7 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
4461
4537
  x: {
4462
4538
  orientation: "bottom",
4463
4539
  numTicks: DEFAULT_NUM_TICKS,
4464
- tickFormat: xTickFormat,
4540
+ tickFormat: xTickFormat || defaultXTickFormat,
4465
4541
  ...horizontal ? {} : dateAxisTickValues,
4466
4542
  ...xLabelOverflow === "ellipsis" ? { tickComponent: TruncatedXTickComponent } : {},
4467
4543
  ...xAxisOptions
@@ -4469,14 +4545,14 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
4469
4545
  y: {
4470
4546
  orientation: "left",
4471
4547
  numTicks: DEFAULT_NUM_TICKS,
4472
- tickFormat: yTickFormat,
4548
+ tickFormat: yTickFormat || defaultYTickFormat,
4473
4549
  ...horizontal ? dateAxisTickValues : {},
4474
4550
  ...yLabelOverflow === "ellipsis" ? { tickComponent: TruncatedYTickComponent } : {},
4475
4551
  ...yAxisOptions
4476
4552
  }
4477
4553
  },
4478
4554
  barGroup: { padding: getGroupPadding(horizontal ? yScale : xScale) },
4479
- tooltip: { labelFormatter: providedToolTipLabelFormatter || defaultTooltipLabelFormatter }
4555
+ tooltip: { labelFormatter: dateAxisTickFormat || defaultTooltipLabelFormatter }
4480
4556
  };
4481
4557
  }, [
4482
4558
  defaultOptions,
@@ -4631,11 +4707,13 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ jsx("div", {
4631
4707
  className: bar_chart_module_default["bar-chart__tooltip-row"],
4632
4708
  children: sprintf(__("%1$s: %2$s", "jetpack-charts"), label, value)
4633
4709
  });
4634
- const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, animation, children, gap = "md" }) => {
4710
+ const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, defaultHiddenSeries, animation, children, gap = "md" }) => {
4635
4711
  const legendInteractive = legend.interactive ?? false;
4636
4712
  const legendCollapseGroups = legend.collapseGroups ?? false;
4637
4713
  const horizontal = orientation === "horizontal";
4638
4714
  const chartId = useChartId(providedChartId);
4715
+ const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
4716
+ const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
4639
4717
  const theme = useXYChartTheme(data);
4640
4718
  const dataSorted = useChartDataTransform(data);
4641
4719
  const dataWithVisibleZeros = useZeroValueDisplay(dataSorted, {
@@ -4643,12 +4721,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
4643
4721
  valueAxisLength: horizontal ? width : height
4644
4722
  });
4645
4723
  const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({ collapseGroups: legendCollapseGroups }), [legendCollapseGroups]));
4646
- const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
4647
- const isSeriesRendered = useCallback((series) => !chartId || !legendInteractive || isSeriesVisible(chartId, series.label), [
4648
- chartId,
4649
- legendInteractive,
4650
- isSeriesVisible
4651
- ]);
4724
+ const { getElementStyles } = useGlobalChartsContext();
4725
+ const isSeriesRendered = useCallback((series) => isSeriesVisible(series.label), [isSeriesVisible]);
4652
4726
  const chartOptions = useBarChartOptions(dataWithVisibleZeros, horizontal, options, isSeriesRendered);
4653
4727
  const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme, horizontal);
4654
4728
  const chartRef = useRef(null);
@@ -4884,9 +4958,10 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
4884
4958
  chartId,
4885
4959
  interactive: legendInteractive
4886
4960
  });
4887
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
4961
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
4888
4962
  value: {
4889
4963
  chartId,
4964
+ isSeriesVisible,
4890
4965
  chartWidth: width,
4891
4966
  chartHeight: measuredChartHeight || 0
4892
4967
  },
@@ -4945,7 +5020,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
4945
5020
  y: chartHeight / 2,
4946
5021
  width,
4947
5022
  height: chartHeight,
4948
- children: __("All series are hidden. Click legend items to show data.", "jetpack-charts")
5023
+ children: getAllHiddenMessage(legendInteractive, "series")
4949
5024
  }) : null,
4950
5025
  /* @__PURE__ */ jsx(ComparisonBars, {
4951
5026
  comparisonEntries,
@@ -5758,12 +5833,27 @@ const GeoChartWithProvider = (props) => {
5758
5833
  GeoChartWithProvider.displayName = "GeoChart";
5759
5834
  const GeoChartResponsive = withResponsive(GeoChartWithProvider);
5760
5835
  //#endregion
5836
+ //#region src/types.ts
5837
+ let GoogleDataTableColumnRoleType = /* @__PURE__ */ function(GoogleDataTableColumnRoleType) {
5838
+ GoogleDataTableColumnRoleType["annotation"] = "annotation";
5839
+ GoogleDataTableColumnRoleType["annotationText"] = "annotationText";
5840
+ GoogleDataTableColumnRoleType["certainty"] = "certainty";
5841
+ GoogleDataTableColumnRoleType["emphasis"] = "emphasis";
5842
+ GoogleDataTableColumnRoleType["interval"] = "interval";
5843
+ GoogleDataTableColumnRoleType["scope"] = "scope";
5844
+ GoogleDataTableColumnRoleType["style"] = "style";
5845
+ GoogleDataTableColumnRoleType["tooltip"] = "tooltip";
5846
+ GoogleDataTableColumnRoleType["domain"] = "domain";
5847
+ return GoogleDataTableColumnRoleType;
5848
+ }({});
5849
+ //#endregion
5761
5850
  //#region src/charts/heatmap-chart/heatmap-chart.module.scss
5762
5851
  var heatmap_chart_module_default = {
5763
5852
  "heatmap-chart": "a8ccharts-O3YMOW-heatmap-chart",
5764
5853
  "heatmap-chart__cell": "a8ccharts-O3YMOW-heatmap-chart__cell",
5765
5854
  "heatmap-chart__cell--filled": "a8ccharts-O3YMOW-heatmap-chart__cell--filled",
5766
5855
  "heatmap-chart__cell--hidden": "a8ccharts-O3YMOW-heatmap-chart__cell--hidden",
5856
+ "heatmap-chart__cell--placeholder": "a8ccharts-O3YMOW-heatmap-chart__cell--placeholder",
5767
5857
  "heatmap-chart__cell--selected": "a8ccharts-O3YMOW-heatmap-chart__cell--selected",
5768
5858
  "heatmap-chart__cell--strong": "a8ccharts-O3YMOW-heatmap-chart__cell--strong",
5769
5859
  "heatmap-chart__cell-value": "a8ccharts-O3YMOW-heatmap-chart__cell-value",
@@ -5819,6 +5909,22 @@ const LABELLED_ROWS = [
5819
5909
  2,
5820
5910
  4
5821
5911
  ];
5912
+ /**
5913
+ * Resolve one grid bound: an unparseable or narrowing value falls back to the
5914
+ * series' own bound, so the grid can only ever be widened.
5915
+ *
5916
+ * @param bound - Requested bound as `yyyy-MM-dd`, if any.
5917
+ * @param fallback - The series' own bound on this side.
5918
+ * @param direction - Which way the bound is allowed to move.
5919
+ * @return The bound to draw to.
5920
+ */
5921
+ const widenTo = (bound, fallback, direction) => {
5922
+ if (!bound) return fallback;
5923
+ const parsed = parseISO(bound);
5924
+ if (isNaN(parsed.getTime())) return fallback;
5925
+ if (direction === "earlier") return parsed < fallback ? parsed : fallback;
5926
+ return parsed > fallback ? parsed : fallback;
5927
+ };
5822
5928
  const toDate = (point) => {
5823
5929
  if (point.date instanceof Date && !isNaN(point.date.getTime())) return point.date;
5824
5930
  if (point.dateString) {
@@ -5846,10 +5952,14 @@ const buildCalendarHeatmapData = (series, options = {}) => {
5846
5952
  if (date < minDate) minDate = date;
5847
5953
  if (date > maxDate) maxDate = date;
5848
5954
  }
5849
- const gridStart = startOfWeek(minDate, { weekStartsOn });
5850
- const weekCount = differenceInCalendarWeeks(maxDate, gridStart, { weekStartsOn }) + 1;
5851
5955
  const minDayKey = format(minDate, "yyyy-MM-dd");
5852
5956
  const maxDayKey = format(maxDate, "yyyy-MM-dd");
5957
+ const gridMinDate = widenTo(options.gridSpan?.start, minDate, "earlier");
5958
+ const gridMaxDate = widenTo(options.gridSpan?.end, maxDate, "later");
5959
+ const gridMaxDayKey = format(gridMaxDate, "yyyy-MM-dd");
5960
+ const gridStart = startOfWeek(gridMinDate, { weekStartsOn });
5961
+ const gridMinDayKey = format(gridMinDate < minDate ? gridStart : gridMinDate, "yyyy-MM-dd");
5962
+ const weekCount = differenceInCalendarWeeks(gridMaxDate, gridStart, { weekStartsOn }) + 1;
5853
5963
  const rowLabels = Array.from({ length: 7 }, (_, row) => LABELLED_ROWS.includes(row) ? format(addDays(gridStart, row), "EEE") : "");
5854
5964
  const MIN_FIRST_MONTH_WEEKS = 2;
5855
5965
  const firstMonth = gridStart.getMonth();
@@ -5871,7 +5981,9 @@ const buildCalendarHeatmapData = (series, options = {}) => {
5871
5981
  label: format(day, "EEE, MMM d, yyyy"),
5872
5982
  value: valueByDay.has(key) ? valueByDay.get(key) : null
5873
5983
  };
5874
- if (hideOutOfRangeDays && (key < minDayKey || key > maxDayKey)) cell.hidden = true;
5984
+ if (key < gridMinDayKey || key > gridMaxDayKey) {
5985
+ if (hideOutOfRangeDays) cell.hidden = true;
5986
+ } else if (key < minDayKey || key > maxDayKey) cell.placeholder = true;
5875
5987
  cells.push(cell);
5876
5988
  }
5877
5989
  data.push({
@@ -5978,7 +6090,10 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
5978
6090
  setSelectedIndex(void 0);
5979
6091
  hideTooltip();
5980
6092
  }, [hideTooltip]);
5981
- const isCellHidden = useCallback((col, row) => data[col]?.data[row]?.hidden === true, [data]);
6093
+ const isCellInert = useCallback((col, row) => {
6094
+ const cell = data[col]?.data[row];
6095
+ return cell?.hidden === true || cell?.placeholder === true;
6096
+ }, [data]);
5982
6097
  const onChartKeyDown = useCallback((event) => {
5983
6098
  if (![
5984
6099
  "ArrowLeft",
@@ -5995,7 +6110,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
5995
6110
  }
5996
6111
  event.preventDefault();
5997
6112
  if (selectedIndex === void 0) {
5998
- for (let index = 0; index < columns * rows; index++) if (!isCellHidden(Math.floor(index / rows), index % rows)) {
6113
+ for (let index = 0; index < columns * rows; index++) if (!isCellInert(Math.floor(index / rows), index % rows)) {
5999
6114
  setSelectedIndex(index);
6000
6115
  return;
6001
6116
  }
@@ -6012,7 +6127,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6012
6127
  do {
6013
6128
  col += stepCol;
6014
6129
  row += stepRow;
6015
- } while (col >= 0 && col < columns && row >= 0 && row < rows && isCellHidden(col, row));
6130
+ } while (col >= 0 && col < columns && row >= 0 && row < rows && isCellInert(col, row));
6016
6131
  if (col < 0 || col >= columns || row < 0 || row >= rows) return;
6017
6132
  setSelectedIndex(col * rows + row);
6018
6133
  }, [
@@ -6020,7 +6135,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6020
6135
  columns,
6021
6136
  selectedIndex,
6022
6137
  hideTooltip,
6023
- isCellHidden
6138
+ isCellInert
6024
6139
  ]);
6025
6140
  const handleCellMouseMove = useCallback((event) => {
6026
6141
  if (!withTooltips) return;
@@ -6092,7 +6207,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6092
6207
  const heightCapped = !compact && Boolean(maxCellHeight);
6093
6208
  return /* @__PURE__ */ jsx(HeatmapContext.Provider, {
6094
6209
  value: heatmapContext,
6095
- children: /* @__PURE__ */ jsx(SingleChartContext.Provider, {
6210
+ children: /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
6096
6211
  value: { chartId },
6097
6212
  children: /* @__PURE__ */ jsxs(ChartLayout, {
6098
6213
  legendPosition: "bottom",
@@ -6144,6 +6259,10 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6144
6259
  "aria-hidden": "true",
6145
6260
  className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--hidden"])
6146
6261
  }, `cell-${columnIndex}-${rowIndex}`);
6262
+ if (cell?.placeholder) return /* @__PURE__ */ jsx("div", {
6263
+ "aria-hidden": "true",
6264
+ className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--placeholder"])
6265
+ }, `cell-${columnIndex}-${rowIndex}`);
6147
6266
  const value = cell?.value ?? null;
6148
6267
  const present = isPresent(value);
6149
6268
  const normalized = present ? getNormalizedValue(value, extent) : 0;
@@ -8777,29 +8896,25 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8777
8896
  legendLabels
8778
8897
  });
8779
8898
  const isPrimaryVisible = useMemo(() => {
8780
- if (!chartId || !legendInteractive || legendItems.length === 0) return true;
8899
+ if (legendItems.length === 0) return true;
8781
8900
  return isSeriesVisible(chartId, legendItems[0].label);
8782
8901
  }, [
8783
8902
  chartId,
8784
- legendInteractive,
8785
8903
  legendItems,
8786
8904
  isSeriesVisible
8787
8905
  ]);
8788
8906
  const isComparisonVisible = useMemo(() => {
8789
- if (!chartId || !legendInteractive || legendItems.length < 2) return true;
8907
+ if (legendItems.length < 2) return true;
8790
8908
  return isSeriesVisible(chartId, legendItems[1].label);
8791
8909
  }, [
8792
8910
  chartId,
8793
- legendInteractive,
8794
8911
  legendItems,
8795
8912
  isSeriesVisible
8796
8913
  ]);
8797
8914
  const allSeriesHidden = useMemo(() => {
8798
- if (!legendInteractive) return false;
8799
8915
  if (withComparison && !withOverlayLabel) return !isPrimaryVisible && !isComparisonVisible;
8800
8916
  return !isPrimaryVisible;
8801
8917
  }, [
8802
- legendInteractive,
8803
8918
  isPrimaryVisible,
8804
8919
  isComparisonVisible,
8805
8920
  withComparison,
@@ -8818,7 +8933,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8818
8933
  const prefersReducedMotion = usePrefersReducedMotion();
8819
8934
  const { contentRef, fittedCount, isMeasurable } = useFittedRowCount(fitRows && !allSeriesHidden, data?.length ?? 0, data);
8820
8935
  const shouldFitRows = fitRows && isMeasurable;
8821
- if (!data || data.length === 0) return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
8936
+ if (!data || data.length === 0) return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
8822
8937
  value: { chartId },
8823
8938
  children: /* @__PURE__ */ jsx(ChartLayout, {
8824
8939
  legendPosition,
@@ -8853,7 +8968,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8853
8968
  chartId,
8854
8969
  interactive: legendInteractive
8855
8970
  });
8856
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
8971
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
8857
8972
  value: { chartId },
8858
8973
  children: /* @__PURE__ */ jsx(ChartLayout, {
8859
8974
  legendPosition,
@@ -8878,7 +8993,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8878
8993
  children: __("Not enough space to display data", "jetpack-charts")
8879
8994
  }), allSeriesHidden ? /* @__PURE__ */ jsx("div", {
8880
8995
  className: leaderboard_chart_module_default.emptyState,
8881
- children: __("All series are hidden. Click legend items to show data.", "jetpack-charts")
8996
+ children: getAllHiddenMessage(legendInteractive, "series")
8882
8997
  }) : /* @__PURE__ */ jsx(component_default, {
8883
8998
  templateColumns: "minmax(0, 1fr) auto",
8884
8999
  rowGap,
@@ -9068,10 +9183,9 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
9068
9183
  hideTooltip();
9069
9184
  }, [withTooltips, hideTooltip]);
9070
9185
  const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
9071
- const { visibleData, allSegmentsHidden, legendData } = useInteractiveLegendData({
9186
+ const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
9072
9187
  data: useDataWithPercentages(data),
9073
9188
  chartId,
9074
- legendInteractive,
9075
9189
  isSeriesVisible
9076
9190
  });
9077
9191
  const legendItems = useChartLegendItems(legendData, useMemo(() => ({
@@ -9132,7 +9246,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
9132
9246
  chartId,
9133
9247
  interactive: legendInteractive
9134
9248
  });
9135
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
9249
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
9136
9250
  value: { chartId },
9137
9251
  children: /* @__PURE__ */ jsx(ChartLayout, {
9138
9252
  legendPosition,
@@ -9189,7 +9303,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
9189
9303
  y: 0,
9190
9304
  width,
9191
9305
  height,
9192
- children: __("All segments are hidden. Click legend items to show data.", "jetpack-charts")
9306
+ children: getAllHiddenMessage(legendInteractive, "segments")
9193
9307
  }) : /* @__PURE__ */ jsx(Pie, {
9194
9308
  data: dataWithIndex,
9195
9309
  pieValue: accessors.value,
@@ -9361,10 +9475,9 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
9361
9475
  }, [handleMouseMove]);
9362
9476
  const { isValid, message } = validateData(data);
9363
9477
  const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
9364
- const { visibleData, allSegmentsHidden, legendData } = useInteractiveLegendData({
9478
+ const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
9365
9479
  data: useDataWithPercentages(data),
9366
9480
  chartId,
9367
- legendInteractive,
9368
9481
  isSeriesVisible
9369
9482
  });
9370
9483
  const accessors = useMemo(() => ({
@@ -9431,7 +9544,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
9431
9544
  chartId,
9432
9545
  interactive: legendInteractive
9433
9546
  });
9434
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
9547
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
9435
9548
  value: { chartId },
9436
9549
  children: /* @__PURE__ */ jsx(ChartLayout, {
9437
9550
  legendPosition,
@@ -9484,7 +9597,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
9484
9597
  y: -radius / 2,
9485
9598
  width,
9486
9599
  height,
9487
- children: __("All segments are hidden. Click legend items to show data.", "jetpack-charts")
9600
+ children: getAllHiddenMessage(legendInteractive, "segments")
9488
9601
  }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
9489
9602
  /* @__PURE__ */ jsx(Pie, {
9490
9603
  data: dataWithIndex,
@@ -9746,6 +9859,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
9746
9859
  });
9747
9860
  }
9748
9861
  //#endregion
9749
- 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, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, parseRgbString, prefersLightText, relativeLuminance, resolveCssVariable, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
9862
+ export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, parseRgbString, prefersLightText, relativeLuminance, resolveCssVariable, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
9750
9863
 
9751
9864
  //# sourceMappingURL=index.js.map