@automattic/charts 3.0.0 → 3.1.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 (62) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/TOKENS.md +3 -3
  3. package/dist/index.cjs +235 -123
  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 +236 -125
  9. package/dist/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/charts/area-chart/area-chart.tsx +24 -24
  12. package/src/charts/area-chart/private/overlays.tsx +3 -3
  13. package/src/charts/area-chart/test/area-chart.test.tsx +301 -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/test/bar-chart.test.tsx +255 -2
  17. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +6 -6
  18. package/src/charts/geo-chart/geo-chart.module.scss +8 -0
  19. package/src/charts/heatmap-chart/heatmap-chart.module.scss +9 -0
  20. package/src/charts/heatmap-chart/heatmap-chart.tsx +31 -8
  21. package/src/charts/heatmap-chart/private/build-calendar-data.ts +65 -5
  22. package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +125 -0
  23. package/src/charts/heatmap-chart/types.ts +8 -0
  24. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +17 -22
  25. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +107 -1
  26. package/src/charts/line-chart/line-chart.module.scss +2 -2
  27. package/src/charts/line-chart/line-chart.tsx +31 -27
  28. package/src/charts/line-chart/private/line-chart-annotations-overlay.tsx +2 -2
  29. package/src/charts/line-chart/test/line-chart.test.tsx +262 -5
  30. package/src/charts/line-chart/types.ts +4 -3
  31. package/src/charts/pie-chart/pie-chart.tsx +8 -13
  32. package/src/charts/pie-chart/test/pie-chart.test.tsx +73 -1
  33. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +2 -2
  34. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +8 -13
  35. package/src/charts/private/{single-chart-context/single-chart-context.tsx → chart-instance-context/chart-instance-context.ts} +1 -5
  36. package/src/charts/private/chart-instance-context/index.ts +3 -0
  37. package/src/charts/private/{single-chart-context/use-single-chart-context.ts → chart-instance-context/use-chart-instance-context.ts} +1 -3
  38. package/src/charts/private/svg-empty-state/get-all-hidden-message.ts +41 -0
  39. package/src/charts/private/svg-empty-state/index.ts +1 -0
  40. package/src/charts/private/svg-empty-state/test/get-all-hidden-message.test.ts +15 -0
  41. package/src/charts/private/x-zoom/test/x-zoom.test.tsx +2 -2
  42. package/src/charts/private/x-zoom/x-zoom.tsx +2 -2
  43. package/src/components/legend/legend.tsx +4 -4
  44. package/src/components/legend/private/base-legend.module.scss +1 -1
  45. package/src/components/legend/private/base-legend.tsx +67 -18
  46. package/src/components/legend/test/legend.test.tsx +100 -4
  47. package/src/components/tooltip/accessible-tooltip.tsx +13 -2
  48. package/src/components/trend-indicator/trend-indicator.module.scss +1 -1
  49. package/src/hooks/index.ts +1 -1
  50. package/src/hooks/{use-interactive-legend-data.ts → use-legend-visibility-data.ts} +29 -30
  51. package/src/index.ts +3 -1
  52. package/src/providers/chart-context/global-charts-provider.tsx +92 -18
  53. package/src/providers/chart-context/hooks/use-default-hidden-series.ts +47 -0
  54. package/src/providers/chart-context/test/chart-context.test.tsx +142 -0
  55. package/src/providers/chart-context/test/use-default-hidden-series-paint.test.tsx +56 -0
  56. package/src/providers/chart-context/test/use-default-hidden-series.ssr.test.tsx +39 -0
  57. package/src/providers/chart-context/test/use-default-hidden-series.test.tsx +222 -0
  58. package/src/providers/chart-context/types.ts +7 -1
  59. package/src/styles/chart-scope.scss +2 -2
  60. package/src/styles/test/wpds-fallbacks.test.ts +131 -0
  61. package/src/types.ts +12 -0
  62. 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,
@@ -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,7 +3955,6 @@ 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(() => {
@@ -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,
@@ -4631,11 +4705,13 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ jsx("div", {
4631
4705
  className: bar_chart_module_default["bar-chart__tooltip-row"],
4632
4706
  children: sprintf(__("%1$s: %2$s", "jetpack-charts"), label, value)
4633
4707
  });
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" }) => {
4708
+ 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
4709
  const legendInteractive = legend.interactive ?? false;
4636
4710
  const legendCollapseGroups = legend.collapseGroups ?? false;
4637
4711
  const horizontal = orientation === "horizontal";
4638
4712
  const chartId = useChartId(providedChartId);
4713
+ const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
4714
+ const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
4639
4715
  const theme = useXYChartTheme(data);
4640
4716
  const dataSorted = useChartDataTransform(data);
4641
4717
  const dataWithVisibleZeros = useZeroValueDisplay(dataSorted, {
@@ -4643,12 +4719,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
4643
4719
  valueAxisLength: horizontal ? width : height
4644
4720
  });
4645
4721
  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
- ]);
4722
+ const { getElementStyles } = useGlobalChartsContext();
4723
+ const isSeriesRendered = useCallback((series) => isSeriesVisible(series.label), [isSeriesVisible]);
4652
4724
  const chartOptions = useBarChartOptions(dataWithVisibleZeros, horizontal, options, isSeriesRendered);
4653
4725
  const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme, horizontal);
4654
4726
  const chartRef = useRef(null);
@@ -4884,9 +4956,10 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
4884
4956
  chartId,
4885
4957
  interactive: legendInteractive
4886
4958
  });
4887
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
4959
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
4888
4960
  value: {
4889
4961
  chartId,
4962
+ isSeriesVisible,
4890
4963
  chartWidth: width,
4891
4964
  chartHeight: measuredChartHeight || 0
4892
4965
  },
@@ -4945,7 +5018,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
4945
5018
  y: chartHeight / 2,
4946
5019
  width,
4947
5020
  height: chartHeight,
4948
- children: __("All series are hidden. Click legend items to show data.", "jetpack-charts")
5021
+ children: getAllHiddenMessage(legendInteractive, "series")
4949
5022
  }) : null,
4950
5023
  /* @__PURE__ */ jsx(ComparisonBars, {
4951
5024
  comparisonEntries,
@@ -5758,12 +5831,27 @@ const GeoChartWithProvider = (props) => {
5758
5831
  GeoChartWithProvider.displayName = "GeoChart";
5759
5832
  const GeoChartResponsive = withResponsive(GeoChartWithProvider);
5760
5833
  //#endregion
5834
+ //#region src/types.ts
5835
+ let GoogleDataTableColumnRoleType = /* @__PURE__ */ function(GoogleDataTableColumnRoleType) {
5836
+ GoogleDataTableColumnRoleType["annotation"] = "annotation";
5837
+ GoogleDataTableColumnRoleType["annotationText"] = "annotationText";
5838
+ GoogleDataTableColumnRoleType["certainty"] = "certainty";
5839
+ GoogleDataTableColumnRoleType["emphasis"] = "emphasis";
5840
+ GoogleDataTableColumnRoleType["interval"] = "interval";
5841
+ GoogleDataTableColumnRoleType["scope"] = "scope";
5842
+ GoogleDataTableColumnRoleType["style"] = "style";
5843
+ GoogleDataTableColumnRoleType["tooltip"] = "tooltip";
5844
+ GoogleDataTableColumnRoleType["domain"] = "domain";
5845
+ return GoogleDataTableColumnRoleType;
5846
+ }({});
5847
+ //#endregion
5761
5848
  //#region src/charts/heatmap-chart/heatmap-chart.module.scss
5762
5849
  var heatmap_chart_module_default = {
5763
5850
  "heatmap-chart": "a8ccharts-O3YMOW-heatmap-chart",
5764
5851
  "heatmap-chart__cell": "a8ccharts-O3YMOW-heatmap-chart__cell",
5765
5852
  "heatmap-chart__cell--filled": "a8ccharts-O3YMOW-heatmap-chart__cell--filled",
5766
5853
  "heatmap-chart__cell--hidden": "a8ccharts-O3YMOW-heatmap-chart__cell--hidden",
5854
+ "heatmap-chart__cell--placeholder": "a8ccharts-O3YMOW-heatmap-chart__cell--placeholder",
5767
5855
  "heatmap-chart__cell--selected": "a8ccharts-O3YMOW-heatmap-chart__cell--selected",
5768
5856
  "heatmap-chart__cell--strong": "a8ccharts-O3YMOW-heatmap-chart__cell--strong",
5769
5857
  "heatmap-chart__cell-value": "a8ccharts-O3YMOW-heatmap-chart__cell-value",
@@ -5819,6 +5907,22 @@ const LABELLED_ROWS = [
5819
5907
  2,
5820
5908
  4
5821
5909
  ];
5910
+ /**
5911
+ * Resolve one grid bound: an unparseable or narrowing value falls back to the
5912
+ * series' own bound, so the grid can only ever be widened.
5913
+ *
5914
+ * @param bound - Requested bound as `yyyy-MM-dd`, if any.
5915
+ * @param fallback - The series' own bound on this side.
5916
+ * @param direction - Which way the bound is allowed to move.
5917
+ * @return The bound to draw to.
5918
+ */
5919
+ const widenTo = (bound, fallback, direction) => {
5920
+ if (!bound) return fallback;
5921
+ const parsed = parseISO(bound);
5922
+ if (isNaN(parsed.getTime())) return fallback;
5923
+ if (direction === "earlier") return parsed < fallback ? parsed : fallback;
5924
+ return parsed > fallback ? parsed : fallback;
5925
+ };
5822
5926
  const toDate = (point) => {
5823
5927
  if (point.date instanceof Date && !isNaN(point.date.getTime())) return point.date;
5824
5928
  if (point.dateString) {
@@ -5846,10 +5950,14 @@ const buildCalendarHeatmapData = (series, options = {}) => {
5846
5950
  if (date < minDate) minDate = date;
5847
5951
  if (date > maxDate) maxDate = date;
5848
5952
  }
5849
- const gridStart = startOfWeek(minDate, { weekStartsOn });
5850
- const weekCount = differenceInCalendarWeeks(maxDate, gridStart, { weekStartsOn }) + 1;
5851
5953
  const minDayKey = format(minDate, "yyyy-MM-dd");
5852
5954
  const maxDayKey = format(maxDate, "yyyy-MM-dd");
5955
+ const gridMinDate = widenTo(options.gridSpan?.start, minDate, "earlier");
5956
+ const gridMaxDate = widenTo(options.gridSpan?.end, maxDate, "later");
5957
+ const gridMaxDayKey = format(gridMaxDate, "yyyy-MM-dd");
5958
+ const gridStart = startOfWeek(gridMinDate, { weekStartsOn });
5959
+ const gridMinDayKey = format(gridMinDate < minDate ? gridStart : gridMinDate, "yyyy-MM-dd");
5960
+ const weekCount = differenceInCalendarWeeks(gridMaxDate, gridStart, { weekStartsOn }) + 1;
5853
5961
  const rowLabels = Array.from({ length: 7 }, (_, row) => LABELLED_ROWS.includes(row) ? format(addDays(gridStart, row), "EEE") : "");
5854
5962
  const MIN_FIRST_MONTH_WEEKS = 2;
5855
5963
  const firstMonth = gridStart.getMonth();
@@ -5871,7 +5979,9 @@ const buildCalendarHeatmapData = (series, options = {}) => {
5871
5979
  label: format(day, "EEE, MMM d, yyyy"),
5872
5980
  value: valueByDay.has(key) ? valueByDay.get(key) : null
5873
5981
  };
5874
- if (hideOutOfRangeDays && (key < minDayKey || key > maxDayKey)) cell.hidden = true;
5982
+ if (key < gridMinDayKey || key > gridMaxDayKey) {
5983
+ if (hideOutOfRangeDays) cell.hidden = true;
5984
+ } else if (key < minDayKey || key > maxDayKey) cell.placeholder = true;
5875
5985
  cells.push(cell);
5876
5986
  }
5877
5987
  data.push({
@@ -5978,7 +6088,10 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
5978
6088
  setSelectedIndex(void 0);
5979
6089
  hideTooltip();
5980
6090
  }, [hideTooltip]);
5981
- const isCellHidden = useCallback((col, row) => data[col]?.data[row]?.hidden === true, [data]);
6091
+ const isCellInert = useCallback((col, row) => {
6092
+ const cell = data[col]?.data[row];
6093
+ return cell?.hidden === true || cell?.placeholder === true;
6094
+ }, [data]);
5982
6095
  const onChartKeyDown = useCallback((event) => {
5983
6096
  if (![
5984
6097
  "ArrowLeft",
@@ -5995,7 +6108,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
5995
6108
  }
5996
6109
  event.preventDefault();
5997
6110
  if (selectedIndex === void 0) {
5998
- for (let index = 0; index < columns * rows; index++) if (!isCellHidden(Math.floor(index / rows), index % rows)) {
6111
+ for (let index = 0; index < columns * rows; index++) if (!isCellInert(Math.floor(index / rows), index % rows)) {
5999
6112
  setSelectedIndex(index);
6000
6113
  return;
6001
6114
  }
@@ -6012,7 +6125,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6012
6125
  do {
6013
6126
  col += stepCol;
6014
6127
  row += stepRow;
6015
- } while (col >= 0 && col < columns && row >= 0 && row < rows && isCellHidden(col, row));
6128
+ } while (col >= 0 && col < columns && row >= 0 && row < rows && isCellInert(col, row));
6016
6129
  if (col < 0 || col >= columns || row < 0 || row >= rows) return;
6017
6130
  setSelectedIndex(col * rows + row);
6018
6131
  }, [
@@ -6020,7 +6133,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6020
6133
  columns,
6021
6134
  selectedIndex,
6022
6135
  hideTooltip,
6023
- isCellHidden
6136
+ isCellInert
6024
6137
  ]);
6025
6138
  const handleCellMouseMove = useCallback((event) => {
6026
6139
  if (!withTooltips) return;
@@ -6092,7 +6205,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6092
6205
  const heightCapped = !compact && Boolean(maxCellHeight);
6093
6206
  return /* @__PURE__ */ jsx(HeatmapContext.Provider, {
6094
6207
  value: heatmapContext,
6095
- children: /* @__PURE__ */ jsx(SingleChartContext.Provider, {
6208
+ children: /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
6096
6209
  value: { chartId },
6097
6210
  children: /* @__PURE__ */ jsxs(ChartLayout, {
6098
6211
  legendPosition: "bottom",
@@ -6144,6 +6257,10 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
6144
6257
  "aria-hidden": "true",
6145
6258
  className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--hidden"])
6146
6259
  }, `cell-${columnIndex}-${rowIndex}`);
6260
+ if (cell?.placeholder) return /* @__PURE__ */ jsx("div", {
6261
+ "aria-hidden": "true",
6262
+ className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--placeholder"])
6263
+ }, `cell-${columnIndex}-${rowIndex}`);
6147
6264
  const value = cell?.value ?? null;
6148
6265
  const present = isPresent(value);
6149
6266
  const normalized = present ? getNormalizedValue(value, extent) : 0;
@@ -8777,29 +8894,25 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8777
8894
  legendLabels
8778
8895
  });
8779
8896
  const isPrimaryVisible = useMemo(() => {
8780
- if (!chartId || !legendInteractive || legendItems.length === 0) return true;
8897
+ if (legendItems.length === 0) return true;
8781
8898
  return isSeriesVisible(chartId, legendItems[0].label);
8782
8899
  }, [
8783
8900
  chartId,
8784
- legendInteractive,
8785
8901
  legendItems,
8786
8902
  isSeriesVisible
8787
8903
  ]);
8788
8904
  const isComparisonVisible = useMemo(() => {
8789
- if (!chartId || !legendInteractive || legendItems.length < 2) return true;
8905
+ if (legendItems.length < 2) return true;
8790
8906
  return isSeriesVisible(chartId, legendItems[1].label);
8791
8907
  }, [
8792
8908
  chartId,
8793
- legendInteractive,
8794
8909
  legendItems,
8795
8910
  isSeriesVisible
8796
8911
  ]);
8797
8912
  const allSeriesHidden = useMemo(() => {
8798
- if (!legendInteractive) return false;
8799
8913
  if (withComparison && !withOverlayLabel) return !isPrimaryVisible && !isComparisonVisible;
8800
8914
  return !isPrimaryVisible;
8801
8915
  }, [
8802
- legendInteractive,
8803
8916
  isPrimaryVisible,
8804
8917
  isComparisonVisible,
8805
8918
  withComparison,
@@ -8818,7 +8931,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8818
8931
  const prefersReducedMotion = usePrefersReducedMotion();
8819
8932
  const { contentRef, fittedCount, isMeasurable } = useFittedRowCount(fitRows && !allSeriesHidden, data?.length ?? 0, data);
8820
8933
  const shouldFitRows = fitRows && isMeasurable;
8821
- if (!data || data.length === 0) return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
8934
+ if (!data || data.length === 0) return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
8822
8935
  value: { chartId },
8823
8936
  children: /* @__PURE__ */ jsx(ChartLayout, {
8824
8937
  legendPosition,
@@ -8853,7 +8966,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8853
8966
  chartId,
8854
8967
  interactive: legendInteractive
8855
8968
  });
8856
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
8969
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
8857
8970
  value: { chartId },
8858
8971
  children: /* @__PURE__ */ jsx(ChartLayout, {
8859
8972
  legendPosition,
@@ -8878,7 +8991,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
8878
8991
  children: __("Not enough space to display data", "jetpack-charts")
8879
8992
  }), allSeriesHidden ? /* @__PURE__ */ jsx("div", {
8880
8993
  className: leaderboard_chart_module_default.emptyState,
8881
- children: __("All series are hidden. Click legend items to show data.", "jetpack-charts")
8994
+ children: getAllHiddenMessage(legendInteractive, "series")
8882
8995
  }) : /* @__PURE__ */ jsx(component_default, {
8883
8996
  templateColumns: "minmax(0, 1fr) auto",
8884
8997
  rowGap,
@@ -9068,10 +9181,9 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
9068
9181
  hideTooltip();
9069
9182
  }, [withTooltips, hideTooltip]);
9070
9183
  const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
9071
- const { visibleData, allSegmentsHidden, legendData } = useInteractiveLegendData({
9184
+ const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
9072
9185
  data: useDataWithPercentages(data),
9073
9186
  chartId,
9074
- legendInteractive,
9075
9187
  isSeriesVisible
9076
9188
  });
9077
9189
  const legendItems = useChartLegendItems(legendData, useMemo(() => ({
@@ -9132,7 +9244,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
9132
9244
  chartId,
9133
9245
  interactive: legendInteractive
9134
9246
  });
9135
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
9247
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
9136
9248
  value: { chartId },
9137
9249
  children: /* @__PURE__ */ jsx(ChartLayout, {
9138
9250
  legendPosition,
@@ -9189,7 +9301,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
9189
9301
  y: 0,
9190
9302
  width,
9191
9303
  height,
9192
- children: __("All segments are hidden. Click legend items to show data.", "jetpack-charts")
9304
+ children: getAllHiddenMessage(legendInteractive, "segments")
9193
9305
  }) : /* @__PURE__ */ jsx(Pie, {
9194
9306
  data: dataWithIndex,
9195
9307
  pieValue: accessors.value,
@@ -9361,10 +9473,9 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
9361
9473
  }, [handleMouseMove]);
9362
9474
  const { isValid, message } = validateData(data);
9363
9475
  const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
9364
- const { visibleData, allSegmentsHidden, legendData } = useInteractiveLegendData({
9476
+ const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
9365
9477
  data: useDataWithPercentages(data),
9366
9478
  chartId,
9367
- legendInteractive,
9368
9479
  isSeriesVisible
9369
9480
  });
9370
9481
  const accessors = useMemo(() => ({
@@ -9431,7 +9542,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
9431
9542
  chartId,
9432
9543
  interactive: legendInteractive
9433
9544
  });
9434
- return /* @__PURE__ */ jsx(SingleChartContext.Provider, {
9545
+ return /* @__PURE__ */ jsx(ChartInstanceContext.Provider, {
9435
9546
  value: { chartId },
9436
9547
  children: /* @__PURE__ */ jsx(ChartLayout, {
9437
9548
  legendPosition,
@@ -9484,7 +9595,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
9484
9595
  y: -radius / 2,
9485
9596
  width,
9486
9597
  height,
9487
- children: __("All segments are hidden. Click legend items to show data.", "jetpack-charts")
9598
+ children: getAllHiddenMessage(legendInteractive, "segments")
9488
9599
  }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
9489
9600
  /* @__PURE__ */ jsx(Pie, {
9490
9601
  data: dataWithIndex,
@@ -9746,6 +9857,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
9746
9857
  });
9747
9858
  }
9748
9859
  //#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 };
9860
+ 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
9861
 
9751
9862
  //# sourceMappingURL=index.js.map