@automattic/charts 0.23.0 → 0.25.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.25.0] - 2025-08-11
9
+ ### Added
10
+ - Add internationalization. [#44652]
11
+
12
+ ### Changed
13
+ - Improve legend functionality and tidy up some legend layout issues. [#44573]
14
+ - Update package dependencies. [#44677]
15
+
16
+ ### Removed
17
+ - Remove redundant internal chart ID. [#44728]
18
+
19
+ ### Fixed
20
+ - Fix legend alignment issues for right-aligned vertical legends. [#44622]
21
+
22
+ ## [0.24.0] - 2025-08-04
23
+ ### Added
24
+ - Add Conversion Funnel Chart document to Storybook index page. [#44548]
25
+
26
+ ### Fixed
27
+ - Tests: Specify locale in tooltip tests. [#44594]
28
+
29
+ ## [0.23.1] - 2025-08-01
30
+ ### Fixed
31
+ - Line Chart: Improve pointer event types. [#44510]
32
+
8
33
  ## [0.23.0] - 2025-07-30
9
34
  ### Added
10
35
  - Add component ConversionFunnelChart. [#44433]
@@ -336,6 +361,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
336
361
  - Fixed lints following ESLint rule changes for TS [#40584]
337
362
  - Fixing a bug in Chart storybook data. [#40640]
338
363
 
364
+ [0.25.0]: https://github.com/Automattic/charts/compare/v0.24.0...v0.25.0
365
+ [0.24.0]: https://github.com/Automattic/charts/compare/v0.23.1...v0.24.0
366
+ [0.23.1]: https://github.com/Automattic/charts/compare/v0.23.0...v0.23.1
339
367
  [0.23.0]: https://github.com/Automattic/charts/compare/v0.22.0...v0.23.0
340
368
  [0.22.0]: https://github.com/Automattic/charts/compare/v0.21.0...v0.22.0
341
369
  [0.21.0]: https://github.com/Automattic/charts/compare/v0.20.0...v0.21.0
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var pattern = require('@visx/pattern');
7
7
  var xychart = require('@visx/xychart');
8
+ var i18n = require('@wordpress/i18n');
8
9
  var clsx = require('clsx');
9
10
  var react = require('react');
10
11
  var chartContext = require('../../providers/chart-context/chart-context.js');
@@ -38,8 +39,6 @@ const validateData = (data) => {
38
39
  const getPatternId = (chartId, index) => `bar-pattern-${chartId}-${index}`;
39
40
  const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400, className, margin, withTooltips = false, showLegend = false, legendOrientation = 'horizontal', legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', legendShape = 'rect', gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = 'vertical', withPatterns = false, showZeroValues = false, }) => {
40
41
  const horizontal = orientation === 'horizontal';
41
- // Generate a unique chart ID to avoid pattern conflicts with multiple charts
42
- const internalChartId = react.useId();
43
42
  const chartId = utils.useChartId(providedChartId);
44
43
  const providerTheme = themeProvider.useChartTheme();
45
44
  const theme = themeProvider.useXYChartTheme(data);
@@ -68,8 +67,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
68
67
  });
69
68
  const getColor = react.useCallback((seriesData, index) => seriesData?.options?.stroke || theme.colors[index % theme.colors.length], [theme]);
70
69
  const getBarBackground = react.useCallback((index) => () => withPatterns
71
- ? `url(#${getPatternId(internalChartId, index)})`
72
- : getColor(dataSorted[index], index), [withPatterns, getColor, dataSorted, internalChartId]);
70
+ ? `url(#${getPatternId(chartId, index)})`
71
+ : getColor(dataSorted[index], index), [withPatterns, getColor, dataSorted, chartId]);
73
72
  const renderDefaultTooltip = react.useCallback(({ tooltipData }) => {
74
73
  const nearestDatum = tooltipData?.nearestDatum?.datum;
75
74
  if (!nearestDatum)
@@ -78,7 +77,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
78
77
  }, [chartOptions.tooltip]);
79
78
  const renderPattern = react.useCallback((index, color) => {
80
79
  const patternType = index % 4;
81
- const id = getPatternId(internalChartId, index);
80
+ const id = getPatternId(chartId, index);
82
81
  const commonProps = {
83
82
  id,
84
83
  stroke: 'white',
@@ -96,16 +95,16 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
96
95
  case 3:
97
96
  return jsxRuntime.jsx(pattern.PatternHexagons, { ...commonProps, size: 8, height: 3 }, id);
98
97
  }
99
- }, [internalChartId]);
98
+ }, [chartId]);
100
99
  const createPatternBorderStyle = react.useCallback((index, color) => {
101
- const patternId = getPatternId(internalChartId, index);
100
+ const patternId = getPatternId(chartId, index);
102
101
  return `
103
102
  .visx-bar[fill="url(#${patternId})"] {
104
103
  stroke: ${color};
105
104
  stroke-width: 1;
106
105
  }
107
106
  `;
108
- }, [internalChartId]);
107
+ }, [chartId]);
109
108
  const createKeyboardHighlightStyle = react.useCallback(() => {
110
109
  if (selectedIndex === undefined)
111
110
  return '';
@@ -151,7 +150,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
151
150
  }
152
151
  const gridVisibility = gridVisibilityProp ?? chartOptions.gridVisibility;
153
152
  const highlightedBarStyle = createKeyboardHighlightStyle();
154
- return (jsxRuntime.jsxs("div", { className: clsx('bar-chart', barChart_module.default['bar-chart'], className), "data-testid": "bar-chart", role: "grid", "aria-label": "bar chart", style: {
153
+ return (jsxRuntime.jsxs("div", { className: clsx('bar-chart', barChart_module.default['bar-chart'], className), "data-testid": "bar-chart", role: "grid", "aria-label": i18n.__('Bar chart', 'jetpack-charts'), style: {
155
154
  width,
156
155
  height,
157
156
  display: 'flex',
@@ -18,20 +18,24 @@ const orientationToFlexDirection = {
18
18
  * Base legend component that displays color-coded items with labels based on visx LegendOrdinal.
19
19
  * We avoid using LegendOrdinal directly to enable support for advanced features such as interactivity.
20
20
  */
21
- const BaseLegend = react.forwardRef(({ items, className, orientation = 'horizontal', alignmentHorizontal = 'center', alignmentVertical = 'bottom', shape = 'rect', fill = utils.valueOrIdentityString, size = utils.valueOrIdentityString, labelFormat = utils.valueOrIdentity, labelTransform = utils.labelTransformFactory, shapeWidth = 16, shapeHeight = 16, shapeMargin = '2px 4px 2px 0', labelAlign = 'left', labelFlex = '1', labelMargin = '0 4px', itemMargin = '0', itemDirection = 'row', legendLabelProps, ...legendItemProps }, ref) => {
21
+ const BaseLegend = react.forwardRef(({ items, className, orientation = 'horizontal', alignmentHorizontal = 'center', alignmentVertical = 'bottom', shape = 'rect', fill = utils.valueOrIdentityString, size = utils.valueOrIdentityString, labelFormat = utils.valueOrIdentity, labelTransform = utils.labelTransformFactory, shapeWidth = 16, shapeHeight = 16, shapeMargin = '2px 4px 2px 0', labelAlign = 'left', labelFlex = '0 0 auto', // Use natural width instead of expanding to fill space
22
+ labelMargin = '0 4px', itemMargin = '0', itemDirection = 'row', legendLabelProps, ...legendItemProps }, ref) => {
22
23
  const theme = themeProvider.useChartTheme();
23
24
  const legendScale = scale.scaleOrdinal({
24
25
  domain: items.map(item => item.label),
25
26
  range: items.map(item => item.color),
26
27
  });
27
28
  const domain = legendScale.domain();
29
+ // For right-aligned vertical legends, use row-reverse to align text consistently
28
30
  const getShapeStyle = react.useCallback(({ index }) => {
29
31
  return items[index]?.shapeStyle ?? theme.legendShapeStyles?.[index] ?? {};
30
32
  }, [items, theme]);
31
33
  return (jsxRuntime.jsx(legend.LegendOrdinal, { scale: legendScale, labelFormat: labelFormat, labelTransform: labelTransform, children: labels => (jsxRuntime.jsx("div", { ref: ref, role: "list", "data-testid": `legend-${orientation}`, className: clsx(legend_module.default.legend, legend_module.default[`legend--${orientation}`], legend_module.default[`legend--horizontal-align-${alignmentHorizontal}`], legend_module.default[`legend--vertical-align-${alignmentVertical}`], className), style: {
32
34
  flexDirection: orientationToFlexDirection[orientation],
33
35
  ...theme.legendContainerStyles,
34
- }, children: labels.map((label, i) => (jsxRuntime.jsxs(legend.LegendItem, { className: legend_module.default['legend-item'], "data-testid": "legend-item", margin: itemMargin, flexDirection: itemDirection, ...legendItemProps, children: [items[i]?.renderGlyph ? (jsxRuntime.jsx("svg", { width: items[i]?.glyphSize * 2, height: items[i]?.glyphSize * 2, "data-testid": "legend-glyph", children: jsxRuntime.jsx(group.Group, { children: items[i]?.renderGlyph({
36
+ }, children: labels.map((label, i) => (jsxRuntime.jsxs(legend.LegendItem, { className: legend_module.default['legend-item'], "data-testid": "legend-item", margin: itemMargin, flexDirection: orientation === 'vertical' && alignmentHorizontal === 'right'
37
+ ? 'row-reverse'
38
+ : itemDirection, ...legendItemProps, children: [items[i]?.renderGlyph ? (jsxRuntime.jsx("svg", { width: items[i]?.glyphSize * 2, height: items[i]?.glyphSize * 2, "data-testid": "legend-glyph", children: jsxRuntime.jsx(group.Group, { children: items[i]?.renderGlyph({
35
39
  key: `legend-glyph-${label.text}`,
36
40
  datum: {},
37
41
  index: i,
@@ -44,7 +48,7 @@ const BaseLegend = react.forwardRef(({ items, className, orientation = 'horizont
44
48
  flex: labelFlex,
45
49
  margin: labelMargin,
46
50
  ...theme.legendLabelStyles,
47
- }, ...legendLabelProps, children: [label.text, items.find(item => item.label === label.text)?.value && (jsxRuntime.jsx("span", { className: legend_module.default['legend-item-value'], children: items.find(item => item.label === label.text)?.value }))] })] }, `legend-${label.text}-${i}`))) })) }));
51
+ }, ...legendLabelProps, children: [label.text, items.find(item => item.label === label.text)?.value && (jsxRuntime.jsxs("span", { className: legend_module.default['legend-item-value'], children: ['\u00A0', items.find(item => item.label === label.text)?.value] }))] })] }, `legend-${label.text}-${i}`))) })) }));
48
52
  });
49
53
 
50
54
  exports.BaseLegend = BaseLegend;
@@ -2,6 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var styles = {"legend--horizontal":"legend-module_legend--horizontal__IUN13","legend--vertical":"legend-module_legend--vertical__Scfzo","legend--vertical-align-top":"legend-module_legend--vertical-align-top__l6G1I","legend--horizontal-align-left":"legend-module_legend--horizontal-align-left__w2O7z","legend--horizontal-align-center":"legend-module_legend--horizontal-align-center__Fmcxd","legend--horizontal-align-right":"legend-module_legend--horizontal-align-right__tKgER","legend--vertical-align-bottom":"legend-module_legend--vertical-align-bottom__UzHCY","legend-item":"legend-module_legend-item__feemn","legend-item-label":"legend-module_legend-item-label__ksx6I","legend-item-value":"legend-module_legend-item-value__d9x1j"};
5
+ var styles = {"legend--horizontal":"legend-module_legend--horizontal__IUN13","legend--vertical":"legend-module_legend--vertical__Scfzo","legend--horizontal-align-left":"legend-module_legend--horizontal-align-left__w2O7z","legend--horizontal-align-center":"legend-module_legend--horizontal-align-center__Fmcxd","legend--horizontal-align-right":"legend-module_legend--horizontal-align-right__tKgER","legend--vertical-align-top":"legend-module_legend--vertical-align-top__l6G1I","legend--vertical-align-bottom":"legend-module_legend--vertical-align-bottom__UzHCY","legend-item":"legend-module_legend-item__feemn","legend-item-label":"legend-module_legend-item-label__ksx6I","legend-item-value":"legend-module_legend-item-value__d9x1j"};
6
6
 
7
7
  exports.default = styles;
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
+ var i18n = require('@wordpress/i18n');
6
7
  var clsx = require('clsx');
7
8
  var Gridicon = require('gridicons');
8
9
  var react = require('react');
@@ -50,10 +51,10 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
50
51
  width: `${POPOVER_BUTTON_SIZE}px`,
51
52
  height: `${POPOVER_BUTTON_SIZE}px`,
52
53
  transform: `translate(${POPOVER_BUTTON_SIZE / 2}px, 0)`,
53
- }, "aria-label": title || 'View details', children: renderLabel({ title, subtitle }) }), jsxRuntime.jsx("div", { ref: popoverRef, id: popoverId, ...{ popover: 'auto' }, className: clsx(lineChart_module.default['line-chart__annotation-label-popover'], isPositioned && lineChart_module.default['line-chart__annotation-label-popover--visible'], isBrowserSafari && lineChart_module.default['line-chart__annotation-label-popover--safari']), "data-testid": "line-chart-annotation-label-popover", children: jsxRuntime.jsxs("div", { className: lineChart_module.default['line-chart__annotation-label-popover-header'], children: [jsxRuntime.jsx("div", { className: lineChart_module.default['line-chart__annotation-label-popover-content'], children: renderLabelPopover({ title, subtitle }) }), jsxRuntime.jsx("button", { ...{
54
+ }, "aria-label": title || i18n.__('View details', 'jetpack-charts'), children: renderLabel({ title, subtitle }) }), jsxRuntime.jsx("div", { ref: popoverRef, id: popoverId, ...{ popover: 'auto' }, className: clsx(lineChart_module.default['line-chart__annotation-label-popover'], isPositioned && lineChart_module.default['line-chart__annotation-label-popover--visible'], isBrowserSafari && lineChart_module.default['line-chart__annotation-label-popover--safari']), "data-testid": "line-chart-annotation-label-popover", children: jsxRuntime.jsxs("div", { className: lineChart_module.default['line-chart__annotation-label-popover-header'], children: [jsxRuntime.jsx("div", { className: lineChart_module.default['line-chart__annotation-label-popover-content'], children: renderLabelPopover({ title, subtitle }) }), jsxRuntime.jsx("button", { ...{
54
55
  popovertarget: popoverId,
55
56
  popovertargetaction: 'hide',
56
- }, className: lineChart_module.default['line-chart__annotation-label-popover-close-button'], "aria-label": "Close", children: jsxRuntime.jsx(Gridicon, { icon: "cross", size: 16 }) })] }) })] }));
57
+ }, className: lineChart_module.default['line-chart__annotation-label-popover-close-button'], "aria-label": i18n.__('Close', 'jetpack-charts'), children: jsxRuntime.jsx(Gridicon, { icon: "cross", size: 16 }) })] }) })] }));
57
58
  };
58
59
 
59
60
  exports.POPOVER_BUTTON_SIZE = POPOVER_BUTTON_SIZE;
@@ -8,6 +8,7 @@ var numberFormatters = require('@automattic/number-formatters');
8
8
  var curve = require('@visx/curve');
9
9
  var gradient = require('@visx/gradient');
10
10
  var xychart = require('@visx/xychart');
11
+ var i18n = require('@wordpress/i18n');
11
12
  var clsx = require('clsx');
12
13
  var chartContext = require('../../providers/chart-context/chart-context.js');
13
14
  var utils = require('../../providers/chart-context/utils.js');
@@ -136,7 +137,6 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
136
137
  const LineChartInternal = react.forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legendOrientation = 'horizontal', legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', renderGlyph = defaultRenderGlyph, glyphStyle = {}, legendShape = 'line', withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, options = {}, onPointerDown = undefined, onPointerUp = undefined, onPointerMove = undefined, onPointerOut = undefined, children, }, ref) => {
137
138
  const providerTheme = themeProvider.useChartTheme();
138
139
  const theme = themeProvider.useXYChartTheme(data);
139
- const internalChartId = react.useId(); // Ensure unique ids for gradient fill.
140
140
  const chartId = utils.useChartId(providedChartId);
141
141
  const [legendRef, legendHeight] = useElementHeight.useElementHeight();
142
142
  const chartRef = react.useRef(null);
@@ -234,7 +234,7 @@ const LineChartInternal = react.forwardRef(({ data, chartId: providedChartId, wi
234
234
  display: 'flex',
235
235
  flexDirection: showLegend && legendAlignmentVertical === 'top' ? 'column-reverse' : 'column',
236
236
  position: 'relative',
237
- }, children: [jsxRuntime.jsx("div", { role: "grid", "aria-label": "line chart", tabIndex: 0, onKeyDown: onChartKeyDown, onFocus: onChartFocus, onBlur: onChartBlur, ref: chartRef, children: jsxRuntime.jsxs(xychart.XYChart, { theme: theme, width: width, height: height - (showLegend ? legendHeight : 0), margin: {
237
+ }, children: [jsxRuntime.jsx("div", { role: "grid", "aria-label": i18n.__('Line chart', 'jetpack-charts'), tabIndex: 0, onKeyDown: onChartKeyDown, onFocus: onChartFocus, onBlur: onChartBlur, ref: chartRef, children: jsxRuntime.jsxs(xychart.XYChart, { theme: theme, width: width, height: height - (showLegend ? legendHeight : 0), margin: {
238
238
  ...defaultMargin,
239
239
  ...margin,
240
240
  ...(showLegend && legendAlignmentVertical === 'top'
@@ -247,8 +247,8 @@ const LineChartInternal = react.forwardRef(({ data, chartId: providedChartId, wi
247
247
  const lineProps = seriesData.options?.seriesLineStyle ??
248
248
  providerTheme?.seriesLineStyles?.[index % providerTheme.seriesLineStyles.length] ??
249
249
  {};
250
- return (jsxRuntime.jsxs("g", { children: [withStartGlyphs && (jsxRuntime.jsx(StartGlyph, { index: index, data: seriesData, color: stroke, renderGlyph: providerTheme.glyphs?.[index] ?? renderGlyph, accessors: accessors, glyphStyle: glyphStyle })), withGradientFill && (jsxRuntime.jsx(gradient.LinearGradient, { id: `area-gradient-${internalChartId}-${index + 1}`, from: stroke, fromOpacity: 0.4, toOpacity: 0.1, to: theme.backgroundColor, ...seriesData.options?.gradient, "data-testid": "line-gradient" })), jsxRuntime.jsx(xychart.AreaSeries, { dataKey: seriesData?.label, data: seriesData.data, ...accessors, fill: withGradientFill
251
- ? `url(#area-gradient-${internalChartId}-${index + 1})`
250
+ return (jsxRuntime.jsxs("g", { children: [withStartGlyphs && (jsxRuntime.jsx(StartGlyph, { index: index, data: seriesData, color: stroke, renderGlyph: providerTheme.glyphs?.[index] ?? renderGlyph, accessors: accessors, glyphStyle: glyphStyle })), withGradientFill && (jsxRuntime.jsx(gradient.LinearGradient, { id: `area-gradient-${chartId}-${index + 1}`, from: stroke, fromOpacity: 0.4, toOpacity: 0.1, to: theme.backgroundColor, ...seriesData.options?.gradient, "data-testid": "line-gradient" })), jsxRuntime.jsx(xychart.AreaSeries, { dataKey: seriesData?.label, data: seriesData.data, ...accessors, fill: withGradientFill
251
+ ? `url(#area-gradient-${chartId}-${index + 1})`
252
252
  : 'transparent', renderLine: true, curve: getCurveType(curveType, smoothing), lineProps: lineProps }, seriesData?.label)] }, seriesData?.label || index));
253
253
  }), withTooltips && (jsxRuntime.jsx(accessibleTooltip.AccessibleTooltip, { detectBounds: true, snapTooltipToDatumX: true, snapTooltipToDatumY: true, showSeriesGlyphs: true, renderTooltip: renderTooltip, renderGlyph: tooltipRenderGlyph, glyphStyle: glyphStyle, showVerticalCrosshair: withTooltipCrosshairs?.showVertical, showHorizontalCrosshair: withTooltipCrosshairs?.showHorizontal, selectedIndex: selectedIndex, tooltipRef: tooltipRef, keyboardFocusedClassName: lineChart_module.default['line-chart__tooltip--keyboard-focused'], series: dataSorted })), jsxRuntime.jsx(LineChartScalesRef, { chartRef: internalChartRef, width: width, height: height, margin: margin })] }) }), showLegend && (jsxRuntime.jsx(legend.Legend, { items: legendItems, orientation: legendOrientation, alignmentHorizontal: legendAlignmentHorizontal, alignmentVertical: legendAlignmentVertical, className: lineChart_module.default['line-chart-legend'], shape: legendShape, chartId: chartId, ref: legendRef })), children] }) }));
254
254
  });
@@ -48,7 +48,7 @@ const validateData = (data) => {
48
48
  * @param {PieChartProps} props - Component props
49
49
  * @return {JSX.Element} The rendered chart component
50
50
  */
51
- const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend, legendOrientation, legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, children = null, }) => {
51
+ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legendOrientation = 'horizontal', legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, children = null, }) => {
52
52
  const providerTheme = themeProvider.useChartTheme();
53
53
  const chartId = utils.useChartId(providedChartId);
54
54
  const [legendRef, legendHeight] = useElementHeight.useElementHeight();
@@ -15,6 +15,7 @@ var utils = require('../../providers/chart-context/utils.js');
15
15
  var themeProvider = require('../../providers/theme/theme-provider.js');
16
16
  var legend = require('../legend/legend.js');
17
17
  require('../legend/base-legend.js');
18
+ var useChartLegendData = require('../legend/use-chart-legend-data.js');
18
19
  var useElementHeight = require('../shared/use-element-height.js');
19
20
  var withResponsive = require('../shared/with-responsive.js');
20
21
  var baseTooltip = require('../tooltip/base-tooltip.js');
@@ -72,12 +73,10 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width = 40
72
73
  // Use the color property from the data object as a last resort. The theme provides colours by default.
73
74
  fill: (d) => d.color || providerTheme.colors[d.index % providerTheme.colors.length],
74
75
  }), [providerTheme.colors]);
75
- // Create legend items with color from accessors (which respects item.color)
76
- const legendItems = react.useMemo(() => data.map((item, index) => ({
77
- label: item.label,
78
- value: item.valueDisplay || item.value.toString(),
79
- color: accessors.fill({ ...item, index }),
80
- })), [data, accessors]);
76
+ // Memoize legend options to prevent unnecessary re-calculations
77
+ const legendOptions = react.useMemo(() => ({ showValues: true }), []);
78
+ // Create legend items using the reusable hook
79
+ const legendItems = useChartLegendData.useChartLegendData(data, providerTheme, legendOptions);
81
80
  // Memoize metadata to prevent unnecessary re-registration
82
81
  const chartMetadata = react.useMemo(() => ({
83
82
  thickness,
@@ -112,10 +111,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width = 40
112
111
  label: tooltipData.label,
113
112
  value: tooltipData.value,
114
113
  valueDisplay: tooltipData.valueDisplay,
115
- }, top: tooltipTop || 0, left: tooltipLeft || 0 })), showLegend && (jsxRuntime.jsx(legend.Legend, { items: legendItems, orientation: legendOrientation, alignmentHorizontal: legendAlignmentHorizontal, alignmentVertical: legendAlignmentVertical, className: clsx(pieSemiCircleChart_module.default['pie-semi-circle-chart-legend'], {
116
- [pieSemiCircleChart_module.default['is-on-top']]: legendAlignmentVertical === 'top',
117
- [pieSemiCircleChart_module.default['is-on-bottom']]: legendAlignmentVertical === 'bottom',
118
- }), shape: legendShape, ref: legendRef, chartId: chartId }))] }));
114
+ }, top: tooltipTop || 0, left: tooltipLeft || 0 })), showLegend && (jsxRuntime.jsx(legend.Legend, { items: legendItems, orientation: legendOrientation, alignmentHorizontal: legendAlignmentHorizontal, alignmentVertical: legendAlignmentVertical, shape: legendShape, ref: legendRef, chartId: chartId }))] }));
119
115
  };
120
116
  const PieSemiCircleChart = props => (jsxRuntime.jsx(chartContext.ChartProvider, { children: jsxRuntime.jsx(PieSemiCircleChartInternal, { ...props }) }));
121
117
  PieSemiCircleChart.displayName = 'PieSemiCircleChart';
@@ -2,6 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var styles = {"pie-semi-circle-chart":"pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9","pie-semi-circle-chart-legend":"pie-semi-circle-chart-module_pie-semi-circle-chart-legend__c8W1Y","is-on-top":"pie-semi-circle-chart-module_is-on-top__BamnZ","is-on-bottom":"pie-semi-circle-chart-module_is-on-bottom__NyS5q","label":"pie-semi-circle-chart-module_label__nPqOg","note":"pie-semi-circle-chart-module_note__LpBZQ"};
5
+ var styles = {"pie-semi-circle-chart":"pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9","label":"pie-semi-circle-chart-module_label__nPqOg","note":"pie-semi-circle-chart-module_note__LpBZQ"};
6
6
 
7
7
  exports.default = styles;
@@ -1 +1 @@
1
- .legend-module_legend--horizontal__IUN13{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.legend-module_legend--vertical__Scfzo{display:flex;flex-direction:column;gap:8px}.legend-module_legend--vertical-align-top__l6G1I{position:relative}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend--vertical-align-bottom__UzHCY{position:relative}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend-item__feemn{align-items:center;display:flex;font-size:.875rem}.legend-module_legend-item-label__ksx6I{align-items:center;display:flex;gap:.5rem}.legend-module_legend-item-value__d9x1j{font-weight:500}.bar-chart-module_bar-chart__lmYNi{display:flex;flex-direction:column}.bar-chart-module_bar-chart__lmYNi svg{overflow:visible}.bar-chart-module_bar-chart-legend__vgKKq{margin-top:1rem}.line-chart-module_line-chart__ITM3d{display:flex;flex-direction:column}.line-chart-module_line-chart__ITM3d svg{overflow:visible}.line-chart-module_line-chart__annotation-label-popover__TqNZk,.line-chart-module_line-chart__tooltip__aqcme{background:#fff;padding:.5rem}.line-chart-module_line-chart__tooltip-date__4Dzab{font-weight:700;padding-bottom:10px}.line-chart-module_line-chart__tooltip-row__6A37G{align-items:center;display:flex;justify-content:space-between;padding:4px 0}.line-chart-module_line-chart__tooltip-label__IvnFF{font-weight:500;padding-right:1rem}.line-chart-module_line-chart__annotations-overlay__4nR2p{left:0;overflow:visible;pointer-events:none;position:absolute;top:0}.line-chart-module_line-chart__annotation-label__OmgiT{pointer-events:auto}.line-chart-module_line-chart__annotation-label-trigger-button__mcIb3{align-items:center;background:none;border:none;cursor:pointer;display:flex;justify-content:center;padding:0;pointer-events:auto}.line-chart-module_line-chart__annotation-label-popover__TqNZk{background:#fff;border:none;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);font-size:14px;margin:.5rem;min-width:125px;position:fixed;visibility:hidden}.line-chart-module_line-chart__annotation-label-popover--visible__dE0cV{visibility:visible}.line-chart-module_line-chart__annotation-label-popover--safari__i3NHT{margin:auto;position:static}.line-chart-module_line-chart__annotation-label-popover-header__Owypo{align-items:start;display:flex;flex-direction:row;justify-content:space-between}.line-chart-module_line-chart__annotation-label-popover-content__vtgQt{padding:.5rem}.line-chart-module_line-chart__annotation-label-popover-close-button__i8KUc{align-items:center;background:none;border:none;cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;width:44px}.visx-tooltip-glyph svg{height:10px;width:10px}.base-tooltip-module_tooltip__OfX6n{background-color:rgba(0,0,0,.85);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);color:#fff;font-size:14px;padding:.5rem;pointer-events:none;position:absolute;transform:translate(-50%,-100%)}.pie-chart-module_pie-chart__R12Vh{display:flex;flex-direction:column;overflow:hidden}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9{display:flex;flex-direction:column;text-align:center}.pie-semi-circle-chart-module_pie-semi-circle-chart-legend__c8W1Y.pie-semi-circle-chart-module_is-on-top__BamnZ{margin-bottom:1rem}.pie-semi-circle-chart-module_pie-semi-circle-chart-legend__c8W1Y.pie-semi-circle-chart-module_is-on-bottom__NyS5q{margin-top:1rem}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_label__nPqOg{font-size:16px;font-weight:600;margin-bottom:0}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_note__LpBZQ{font-size:14px;margin-top:0}.leaderboard-chart-module_leaderboardChart__zxakP{transition:opacity .3s ease-in-out}.leaderboard-chart-module_leaderboardChart__zxakP.leaderboard-chart-module_loading__-AGv-{opacity:.5}.leaderboard-chart-module_progressContainer__BZGbj{display:flex;flex-direction:column;gap:6px}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj{background-color:transparent;border-radius:2px;height:6px;overflow:hidden;transition:width .3s ease-in-out;width:100%}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj>div{background-color:var(--progress-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_primaryBar__iybII{--progress-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_secondaryBar__A7tLz{--progress-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}
1
+ .legend-module_legend--horizontal__IUN13{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.legend-module_legend--vertical__Scfzo{display:flex;flex-direction:column;gap:8px}.legend-module_legend--vertical__Scfzo.legend-module_legend--horizontal-align-left__w2O7z{align-items:flex-start}.legend-module_legend--vertical__Scfzo.legend-module_legend--horizontal-align-center__Fmcxd{align-items:center}.legend-module_legend--vertical__Scfzo.legend-module_legend--horizontal-align-right__tKgER{align-items:flex-end}.legend-module_legend--vertical-align-top__l6G1I{position:relative}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend--vertical-align-bottom__UzHCY{position:relative}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend-item__feemn{align-items:center;display:flex;font-size:.875rem}.legend-module_legend-item-label__ksx6I{align-items:center;display:flex;gap:.5rem}.legend-module_legend-item-value__d9x1j{font-weight:500}.bar-chart-module_bar-chart__lmYNi{display:flex;flex-direction:column}.bar-chart-module_bar-chart__lmYNi svg{overflow:visible}.bar-chart-module_bar-chart-legend__vgKKq{margin-top:1rem}.line-chart-module_line-chart__ITM3d{display:flex;flex-direction:column}.line-chart-module_line-chart__ITM3d svg{overflow:visible}.line-chart-module_line-chart__annotation-label-popover__TqNZk,.line-chart-module_line-chart__tooltip__aqcme{background:#fff;padding:.5rem}.line-chart-module_line-chart__tooltip-date__4Dzab{font-weight:700;padding-bottom:10px}.line-chart-module_line-chart__tooltip-row__6A37G{align-items:center;display:flex;justify-content:space-between;padding:4px 0}.line-chart-module_line-chart__tooltip-label__IvnFF{font-weight:500;padding-right:1rem}.line-chart-module_line-chart__annotations-overlay__4nR2p{left:0;overflow:visible;pointer-events:none;position:absolute;top:0}.line-chart-module_line-chart__annotation-label__OmgiT{pointer-events:auto}.line-chart-module_line-chart__annotation-label-trigger-button__mcIb3{align-items:center;background:none;border:none;cursor:pointer;display:flex;justify-content:center;padding:0;pointer-events:auto}.line-chart-module_line-chart__annotation-label-popover__TqNZk{background:#fff;border:none;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);font-size:14px;margin:.5rem;min-width:125px;position:fixed;visibility:hidden}.line-chart-module_line-chart__annotation-label-popover--visible__dE0cV{visibility:visible}.line-chart-module_line-chart__annotation-label-popover--safari__i3NHT{margin:auto;position:static}.line-chart-module_line-chart__annotation-label-popover-header__Owypo{align-items:start;display:flex;flex-direction:row;justify-content:space-between}.line-chart-module_line-chart__annotation-label-popover-content__vtgQt{padding:.5rem}.line-chart-module_line-chart__annotation-label-popover-close-button__i8KUc{align-items:center;background:none;border:none;cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;width:44px}.visx-tooltip-glyph svg{height:10px;width:10px}.base-tooltip-module_tooltip__OfX6n{background-color:rgba(0,0,0,.85);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);color:#fff;font-size:14px;padding:.5rem;pointer-events:none;position:absolute;transform:translate(-50%,-100%)}.pie-chart-module_pie-chart__R12Vh{display:flex;flex-direction:column;overflow:hidden}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9{display:flex;flex-direction:column;text-align:center}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_label__nPqOg{font-size:16px;font-weight:600;margin-bottom:0}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_note__LpBZQ{font-size:14px;margin-top:0}.leaderboard-chart-module_leaderboardChart__zxakP{transition:opacity .3s ease-in-out}.leaderboard-chart-module_leaderboardChart__zxakP.leaderboard-chart-module_loading__-AGv-{opacity:.5}.leaderboard-chart-module_progressContainer__BZGbj{display:flex;flex-direction:column;gap:6px}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj{background-color:transparent;border-radius:2px;height:6px;overflow:hidden;transition:width .3s ease-in-out;width:100%}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj>div{background-color:var(--progress-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_primaryBar__iybII{--progress-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_secondaryBar__A7tLz{--progress-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}
@@ -1,8 +1,9 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { PatternHexagons, PatternWaves, PatternCircles, PatternLines } from '@visx/pattern';
3
3
  import { XYChart, Grid, BarGroup, BarSeries, Axis } from '@visx/xychart';
4
+ import { __ } from '@wordpress/i18n';
4
5
  import clsx from 'clsx';
5
- import { useContext, useId, useRef, useState, useCallback, useMemo } from 'react';
6
+ import { useContext, useRef, useState, useCallback, useMemo } from 'react';
6
7
  import { ChartContext, ChartProvider } from '../../providers/chart-context/chart-context.js';
7
8
  import { useChartId, useChartRegistration } from '../../providers/chart-context/utils.js';
8
9
  import { useChartTheme, useXYChartTheme } from '../../providers/theme/theme-provider.js';
@@ -34,8 +35,6 @@ const validateData = (data) => {
34
35
  const getPatternId = (chartId, index) => `bar-pattern-${chartId}-${index}`;
35
36
  const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400, className, margin, withTooltips = false, showLegend = false, legendOrientation = 'horizontal', legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', legendShape = 'rect', gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = 'vertical', withPatterns = false, showZeroValues = false, }) => {
36
37
  const horizontal = orientation === 'horizontal';
37
- // Generate a unique chart ID to avoid pattern conflicts with multiple charts
38
- const internalChartId = useId();
39
38
  const chartId = useChartId(providedChartId);
40
39
  const providerTheme = useChartTheme();
41
40
  const theme = useXYChartTheme(data);
@@ -64,8 +63,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
64
63
  });
65
64
  const getColor = useCallback((seriesData, index) => seriesData?.options?.stroke || theme.colors[index % theme.colors.length], [theme]);
66
65
  const getBarBackground = useCallback((index) => () => withPatterns
67
- ? `url(#${getPatternId(internalChartId, index)})`
68
- : getColor(dataSorted[index], index), [withPatterns, getColor, dataSorted, internalChartId]);
66
+ ? `url(#${getPatternId(chartId, index)})`
67
+ : getColor(dataSorted[index], index), [withPatterns, getColor, dataSorted, chartId]);
69
68
  const renderDefaultTooltip = useCallback(({ tooltipData }) => {
70
69
  const nearestDatum = tooltipData?.nearestDatum?.datum;
71
70
  if (!nearestDatum)
@@ -74,7 +73,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
74
73
  }, [chartOptions.tooltip]);
75
74
  const renderPattern = useCallback((index, color) => {
76
75
  const patternType = index % 4;
77
- const id = getPatternId(internalChartId, index);
76
+ const id = getPatternId(chartId, index);
78
77
  const commonProps = {
79
78
  id,
80
79
  stroke: 'white',
@@ -92,16 +91,16 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
92
91
  case 3:
93
92
  return jsx(PatternHexagons, { ...commonProps, size: 8, height: 3 }, id);
94
93
  }
95
- }, [internalChartId]);
94
+ }, [chartId]);
96
95
  const createPatternBorderStyle = useCallback((index, color) => {
97
- const patternId = getPatternId(internalChartId, index);
96
+ const patternId = getPatternId(chartId, index);
98
97
  return `
99
98
  .visx-bar[fill="url(#${patternId})"] {
100
99
  stroke: ${color};
101
100
  stroke-width: 1;
102
101
  }
103
102
  `;
104
- }, [internalChartId]);
103
+ }, [chartId]);
105
104
  const createKeyboardHighlightStyle = useCallback(() => {
106
105
  if (selectedIndex === undefined)
107
106
  return '';
@@ -147,7 +146,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
147
146
  }
148
147
  const gridVisibility = gridVisibilityProp ?? chartOptions.gridVisibility;
149
148
  const highlightedBarStyle = createKeyboardHighlightStyle();
150
- return (jsxs("div", { className: clsx('bar-chart', styles['bar-chart'], className), "data-testid": "bar-chart", role: "grid", "aria-label": "bar chart", style: {
149
+ return (jsxs("div", { className: clsx('bar-chart', styles['bar-chart'], className), "data-testid": "bar-chart", role: "grid", "aria-label": __('Bar chart', 'jetpack-charts'), style: {
151
150
  width,
152
151
  height,
153
152
  display: 'flex',
@@ -16,20 +16,24 @@ const orientationToFlexDirection = {
16
16
  * Base legend component that displays color-coded items with labels based on visx LegendOrdinal.
17
17
  * We avoid using LegendOrdinal directly to enable support for advanced features such as interactivity.
18
18
  */
19
- const BaseLegend = forwardRef(({ items, className, orientation = 'horizontal', alignmentHorizontal = 'center', alignmentVertical = 'bottom', shape = 'rect', fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform = labelTransformFactory, shapeWidth = 16, shapeHeight = 16, shapeMargin = '2px 4px 2px 0', labelAlign = 'left', labelFlex = '1', labelMargin = '0 4px', itemMargin = '0', itemDirection = 'row', legendLabelProps, ...legendItemProps }, ref) => {
19
+ const BaseLegend = forwardRef(({ items, className, orientation = 'horizontal', alignmentHorizontal = 'center', alignmentVertical = 'bottom', shape = 'rect', fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform = labelTransformFactory, shapeWidth = 16, shapeHeight = 16, shapeMargin = '2px 4px 2px 0', labelAlign = 'left', labelFlex = '0 0 auto', // Use natural width instead of expanding to fill space
20
+ labelMargin = '0 4px', itemMargin = '0', itemDirection = 'row', legendLabelProps, ...legendItemProps }, ref) => {
20
21
  const theme = useChartTheme();
21
22
  const legendScale = scaleOrdinal({
22
23
  domain: items.map(item => item.label),
23
24
  range: items.map(item => item.color),
24
25
  });
25
26
  const domain = legendScale.domain();
27
+ // For right-aligned vertical legends, use row-reverse to align text consistently
26
28
  const getShapeStyle = useCallback(({ index }) => {
27
29
  return items[index]?.shapeStyle ?? theme.legendShapeStyles?.[index] ?? {};
28
30
  }, [items, theme]);
29
31
  return (jsx(LegendOrdinal, { scale: legendScale, labelFormat: labelFormat, labelTransform: labelTransform, children: labels => (jsx("div", { ref: ref, role: "list", "data-testid": `legend-${orientation}`, className: clsx(styles.legend, styles[`legend--${orientation}`], styles[`legend--horizontal-align-${alignmentHorizontal}`], styles[`legend--vertical-align-${alignmentVertical}`], className), style: {
30
32
  flexDirection: orientationToFlexDirection[orientation],
31
33
  ...theme.legendContainerStyles,
32
- }, children: labels.map((label, i) => (jsxs(LegendItem, { className: styles['legend-item'], "data-testid": "legend-item", margin: itemMargin, flexDirection: itemDirection, ...legendItemProps, children: [items[i]?.renderGlyph ? (jsx("svg", { width: items[i]?.glyphSize * 2, height: items[i]?.glyphSize * 2, "data-testid": "legend-glyph", children: jsx(Group, { children: items[i]?.renderGlyph({
34
+ }, children: labels.map((label, i) => (jsxs(LegendItem, { className: styles['legend-item'], "data-testid": "legend-item", margin: itemMargin, flexDirection: orientation === 'vertical' && alignmentHorizontal === 'right'
35
+ ? 'row-reverse'
36
+ : itemDirection, ...legendItemProps, children: [items[i]?.renderGlyph ? (jsx("svg", { width: items[i]?.glyphSize * 2, height: items[i]?.glyphSize * 2, "data-testid": "legend-glyph", children: jsx(Group, { children: items[i]?.renderGlyph({
33
37
  key: `legend-glyph-${label.text}`,
34
38
  datum: {},
35
39
  index: i,
@@ -42,7 +46,7 @@ const BaseLegend = forwardRef(({ items, className, orientation = 'horizontal', a
42
46
  flex: labelFlex,
43
47
  margin: labelMargin,
44
48
  ...theme.legendLabelStyles,
45
- }, ...legendLabelProps, children: [label.text, items.find(item => item.label === label.text)?.value && (jsx("span", { className: styles['legend-item-value'], children: items.find(item => item.label === label.text)?.value }))] })] }, `legend-${label.text}-${i}`))) })) }));
49
+ }, ...legendLabelProps, children: [label.text, items.find(item => item.label === label.text)?.value && (jsxs("span", { className: styles['legend-item-value'], children: ['\u00A0', items.find(item => item.label === label.text)?.value] }))] })] }, `legend-${label.text}-${i}`))) })) }));
46
50
  });
47
51
 
48
52
  export { BaseLegend };
@@ -1,3 +1,3 @@
1
- var styles = {"legend--horizontal":"legend-module_legend--horizontal__IUN13","legend--vertical":"legend-module_legend--vertical__Scfzo","legend--vertical-align-top":"legend-module_legend--vertical-align-top__l6G1I","legend--horizontal-align-left":"legend-module_legend--horizontal-align-left__w2O7z","legend--horizontal-align-center":"legend-module_legend--horizontal-align-center__Fmcxd","legend--horizontal-align-right":"legend-module_legend--horizontal-align-right__tKgER","legend--vertical-align-bottom":"legend-module_legend--vertical-align-bottom__UzHCY","legend-item":"legend-module_legend-item__feemn","legend-item-label":"legend-module_legend-item-label__ksx6I","legend-item-value":"legend-module_legend-item-value__d9x1j"};
1
+ var styles = {"legend--horizontal":"legend-module_legend--horizontal__IUN13","legend--vertical":"legend-module_legend--vertical__Scfzo","legend--horizontal-align-left":"legend-module_legend--horizontal-align-left__w2O7z","legend--horizontal-align-center":"legend-module_legend--horizontal-align-center__Fmcxd","legend--horizontal-align-right":"legend-module_legend--horizontal-align-right__tKgER","legend--vertical-align-top":"legend-module_legend--vertical-align-top__l6G1I","legend--vertical-align-bottom":"legend-module_legend--vertical-align-bottom__UzHCY","legend-item":"legend-module_legend-item__feemn","legend-item-label":"legend-module_legend-item-label__ksx6I","legend-item-value":"legend-module_legend-item-value__d9x1j"};
2
2
 
3
3
  export { styles as default };
@@ -1,4 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { __ } from '@wordpress/i18n';
2
3
  import clsx from 'clsx';
3
4
  import Gridicon from 'gridicons';
4
5
  import { useId, useRef, useState, useEffect } from 'react';
@@ -46,10 +47,10 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
46
47
  width: `${POPOVER_BUTTON_SIZE}px`,
47
48
  height: `${POPOVER_BUTTON_SIZE}px`,
48
49
  transform: `translate(${POPOVER_BUTTON_SIZE / 2}px, 0)`,
49
- }, "aria-label": title || 'View details', children: renderLabel({ title, subtitle }) }), jsx("div", { ref: popoverRef, id: popoverId, ...{ popover: 'auto' }, className: clsx(styles['line-chart__annotation-label-popover'], isPositioned && styles['line-chart__annotation-label-popover--visible'], isBrowserSafari && styles['line-chart__annotation-label-popover--safari']), "data-testid": "line-chart-annotation-label-popover", children: jsxs("div", { className: styles['line-chart__annotation-label-popover-header'], children: [jsx("div", { className: styles['line-chart__annotation-label-popover-content'], children: renderLabelPopover({ title, subtitle }) }), jsx("button", { ...{
50
+ }, "aria-label": title || __('View details', 'jetpack-charts'), children: renderLabel({ title, subtitle }) }), jsx("div", { ref: popoverRef, id: popoverId, ...{ popover: 'auto' }, className: clsx(styles['line-chart__annotation-label-popover'], isPositioned && styles['line-chart__annotation-label-popover--visible'], isBrowserSafari && styles['line-chart__annotation-label-popover--safari']), "data-testid": "line-chart-annotation-label-popover", children: jsxs("div", { className: styles['line-chart__annotation-label-popover-header'], children: [jsx("div", { className: styles['line-chart__annotation-label-popover-content'], children: renderLabelPopover({ title, subtitle }) }), jsx("button", { ...{
50
51
  popovertarget: popoverId,
51
52
  popovertargetaction: 'hide',
52
- }, className: styles['line-chart__annotation-label-popover-close-button'], "aria-label": "Close", children: jsx(Gridicon, { icon: "cross", size: 16 }) })] }) })] }));
53
+ }, className: styles['line-chart__annotation-label-popover-close-button'], "aria-label": __('Close', 'jetpack-charts'), children: jsx(Gridicon, { icon: "cross", size: 16 }) })] }) })] }));
53
54
  };
54
55
 
55
56
  export { POPOVER_BUTTON_SIZE, LineChartAnnotationLabelWithPopover as default };
@@ -1,9 +1,10 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { forwardRef, useId, useRef, useState, useImperativeHandle, useMemo, useContext, createElement } from 'react';
2
+ import { forwardRef, useRef, useState, useImperativeHandle, useMemo, useContext, createElement } from 'react';
3
3
  import { formatNumberCompact } from '@automattic/number-formatters';
4
4
  import { curveCatmullRom, curveLinear, curveMonotoneX } from '@visx/curve';
5
5
  import { LinearGradient } from '@visx/gradient';
6
6
  import { XYChart, Grid, Axis, AreaSeries, DataContext } from '@visx/xychart';
7
+ import { __ } from '@wordpress/i18n';
7
8
  import clsx from 'clsx';
8
9
  import { ChartContext, ChartProvider } from '../../providers/chart-context/chart-context.js';
9
10
  import { useChartId, useChartRegistration } from '../../providers/chart-context/utils.js';
@@ -132,7 +133,6 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
132
133
  const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legendOrientation = 'horizontal', legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', renderGlyph = defaultRenderGlyph, glyphStyle = {}, legendShape = 'line', withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, options = {}, onPointerDown = undefined, onPointerUp = undefined, onPointerMove = undefined, onPointerOut = undefined, children, }, ref) => {
133
134
  const providerTheme = useChartTheme();
134
135
  const theme = useXYChartTheme(data);
135
- const internalChartId = useId(); // Ensure unique ids for gradient fill.
136
136
  const chartId = useChartId(providedChartId);
137
137
  const [legendRef, legendHeight] = useElementHeight();
138
138
  const chartRef = useRef(null);
@@ -230,7 +230,7 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
230
230
  display: 'flex',
231
231
  flexDirection: showLegend && legendAlignmentVertical === 'top' ? 'column-reverse' : 'column',
232
232
  position: 'relative',
233
- }, children: [jsx("div", { role: "grid", "aria-label": "line chart", tabIndex: 0, onKeyDown: onChartKeyDown, onFocus: onChartFocus, onBlur: onChartBlur, ref: chartRef, children: jsxs(XYChart, { theme: theme, width: width, height: height - (showLegend ? legendHeight : 0), margin: {
233
+ }, children: [jsx("div", { role: "grid", "aria-label": __('Line chart', 'jetpack-charts'), tabIndex: 0, onKeyDown: onChartKeyDown, onFocus: onChartFocus, onBlur: onChartBlur, ref: chartRef, children: jsxs(XYChart, { theme: theme, width: width, height: height - (showLegend ? legendHeight : 0), margin: {
234
234
  ...defaultMargin,
235
235
  ...margin,
236
236
  ...(showLegend && legendAlignmentVertical === 'top'
@@ -243,8 +243,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
243
243
  const lineProps = seriesData.options?.seriesLineStyle ??
244
244
  providerTheme?.seriesLineStyles?.[index % providerTheme.seriesLineStyles.length] ??
245
245
  {};
246
- return (jsxs("g", { children: [withStartGlyphs && (jsx(StartGlyph, { index: index, data: seriesData, color: stroke, renderGlyph: providerTheme.glyphs?.[index] ?? renderGlyph, accessors: accessors, glyphStyle: glyphStyle })), withGradientFill && (jsx(LinearGradient, { id: `area-gradient-${internalChartId}-${index + 1}`, from: stroke, fromOpacity: 0.4, toOpacity: 0.1, to: theme.backgroundColor, ...seriesData.options?.gradient, "data-testid": "line-gradient" })), jsx(AreaSeries, { dataKey: seriesData?.label, data: seriesData.data, ...accessors, fill: withGradientFill
247
- ? `url(#area-gradient-${internalChartId}-${index + 1})`
246
+ return (jsxs("g", { children: [withStartGlyphs && (jsx(StartGlyph, { index: index, data: seriesData, color: stroke, renderGlyph: providerTheme.glyphs?.[index] ?? renderGlyph, accessors: accessors, glyphStyle: glyphStyle })), withGradientFill && (jsx(LinearGradient, { id: `area-gradient-${chartId}-${index + 1}`, from: stroke, fromOpacity: 0.4, toOpacity: 0.1, to: theme.backgroundColor, ...seriesData.options?.gradient, "data-testid": "line-gradient" })), jsx(AreaSeries, { dataKey: seriesData?.label, data: seriesData.data, ...accessors, fill: withGradientFill
247
+ ? `url(#area-gradient-${chartId}-${index + 1})`
248
248
  : 'transparent', renderLine: true, curve: getCurveType(curveType, smoothing), lineProps: lineProps }, seriesData?.label)] }, seriesData?.label || index));
249
249
  }), withTooltips && (jsx(AccessibleTooltip, { detectBounds: true, snapTooltipToDatumX: true, snapTooltipToDatumY: true, showSeriesGlyphs: true, renderTooltip: renderTooltip, renderGlyph: tooltipRenderGlyph, glyphStyle: glyphStyle, showVerticalCrosshair: withTooltipCrosshairs?.showVertical, showHorizontalCrosshair: withTooltipCrosshairs?.showHorizontal, selectedIndex: selectedIndex, tooltipRef: tooltipRef, keyboardFocusedClassName: styles['line-chart__tooltip--keyboard-focused'], series: dataSorted })), jsx(LineChartScalesRef, { chartRef: internalChartRef, width: width, height: height, margin: margin })] }) }), showLegend && (jsx(Legend, { items: legendItems, orientation: legendOrientation, alignmentHorizontal: legendAlignmentHorizontal, alignmentVertical: legendAlignmentVertical, className: styles['line-chart-legend'], shape: legendShape, chartId: chartId, ref: legendRef })), children] }) }));
250
250
  });
@@ -44,7 +44,7 @@ const validateData = (data) => {
44
44
  * @param {PieChartProps} props - Component props
45
45
  * @return {JSX.Element} The rendered chart component
46
46
  */
47
- const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend, legendOrientation, legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, children = null, }) => {
47
+ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legendOrientation = 'horizontal', legendAlignmentHorizontal = 'center', legendAlignmentVertical = 'bottom', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, children = null, }) => {
48
48
  const providerTheme = useChartTheme();
49
49
  const chartId = useChartId(providedChartId);
50
50
  const [legendRef, legendHeight] = useElementHeight();
@@ -11,6 +11,7 @@ import { useChartId, useChartRegistration } from '../../providers/chart-context/
11
11
  import { useChartTheme } from '../../providers/theme/theme-provider.js';
12
12
  import { Legend } from '../legend/legend.js';
13
13
  import '../legend/base-legend.js';
14
+ import { useChartLegendData } from '../legend/use-chart-legend-data.js';
14
15
  import { useElementHeight } from '../shared/use-element-height.js';
15
16
  import { withResponsive } from '../shared/with-responsive.js';
16
17
  import { BaseTooltip } from '../tooltip/base-tooltip.js';
@@ -68,12 +69,10 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width = 40
68
69
  // Use the color property from the data object as a last resort. The theme provides colours by default.
69
70
  fill: (d) => d.color || providerTheme.colors[d.index % providerTheme.colors.length],
70
71
  }), [providerTheme.colors]);
71
- // Create legend items with color from accessors (which respects item.color)
72
- const legendItems = useMemo(() => data.map((item, index) => ({
73
- label: item.label,
74
- value: item.valueDisplay || item.value.toString(),
75
- color: accessors.fill({ ...item, index }),
76
- })), [data, accessors]);
72
+ // Memoize legend options to prevent unnecessary re-calculations
73
+ const legendOptions = useMemo(() => ({ showValues: true }), []);
74
+ // Create legend items using the reusable hook
75
+ const legendItems = useChartLegendData(data, providerTheme, legendOptions);
77
76
  // Memoize metadata to prevent unnecessary re-registration
78
77
  const chartMetadata = useMemo(() => ({
79
78
  thickness,
@@ -108,10 +107,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width = 40
108
107
  label: tooltipData.label,
109
108
  value: tooltipData.value,
110
109
  valueDisplay: tooltipData.valueDisplay,
111
- }, top: tooltipTop || 0, left: tooltipLeft || 0 })), showLegend && (jsx(Legend, { items: legendItems, orientation: legendOrientation, alignmentHorizontal: legendAlignmentHorizontal, alignmentVertical: legendAlignmentVertical, className: clsx(styles['pie-semi-circle-chart-legend'], {
112
- [styles['is-on-top']]: legendAlignmentVertical === 'top',
113
- [styles['is-on-bottom']]: legendAlignmentVertical === 'bottom',
114
- }), shape: legendShape, ref: legendRef, chartId: chartId }))] }));
110
+ }, top: tooltipTop || 0, left: tooltipLeft || 0 })), showLegend && (jsx(Legend, { items: legendItems, orientation: legendOrientation, alignmentHorizontal: legendAlignmentHorizontal, alignmentVertical: legendAlignmentVertical, shape: legendShape, ref: legendRef, chartId: chartId }))] }));
115
111
  };
116
112
  const PieSemiCircleChart = props => (jsx(ChartProvider, { children: jsx(PieSemiCircleChartInternal, { ...props }) }));
117
113
  PieSemiCircleChart.displayName = 'PieSemiCircleChart';
@@ -1,3 +1,3 @@
1
- var styles = {"pie-semi-circle-chart":"pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9","pie-semi-circle-chart-legend":"pie-semi-circle-chart-module_pie-semi-circle-chart-legend__c8W1Y","is-on-top":"pie-semi-circle-chart-module_is-on-top__BamnZ","is-on-bottom":"pie-semi-circle-chart-module_is-on-bottom__NyS5q","label":"pie-semi-circle-chart-module_label__nPqOg","note":"pie-semi-circle-chart-module_note__LpBZQ"};
1
+ var styles = {"pie-semi-circle-chart":"pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9","label":"pie-semi-circle-chart-module_label__nPqOg","note":"pie-semi-circle-chart-module_note__LpBZQ"};
2
2
 
3
3
  export { styles as default };
@@ -1 +1 @@
1
- .legend-module_legend--horizontal__IUN13{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.legend-module_legend--vertical__Scfzo{display:flex;flex-direction:column;gap:8px}.legend-module_legend--vertical-align-top__l6G1I{position:relative}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend--vertical-align-bottom__UzHCY{position:relative}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend-item__feemn{align-items:center;display:flex;font-size:.875rem}.legend-module_legend-item-label__ksx6I{align-items:center;display:flex;gap:.5rem}.legend-module_legend-item-value__d9x1j{font-weight:500}.bar-chart-module_bar-chart__lmYNi{display:flex;flex-direction:column}.bar-chart-module_bar-chart__lmYNi svg{overflow:visible}.bar-chart-module_bar-chart-legend__vgKKq{margin-top:1rem}.line-chart-module_line-chart__ITM3d{display:flex;flex-direction:column}.line-chart-module_line-chart__ITM3d svg{overflow:visible}.line-chart-module_line-chart__annotation-label-popover__TqNZk,.line-chart-module_line-chart__tooltip__aqcme{background:#fff;padding:.5rem}.line-chart-module_line-chart__tooltip-date__4Dzab{font-weight:700;padding-bottom:10px}.line-chart-module_line-chart__tooltip-row__6A37G{align-items:center;display:flex;justify-content:space-between;padding:4px 0}.line-chart-module_line-chart__tooltip-label__IvnFF{font-weight:500;padding-right:1rem}.line-chart-module_line-chart__annotations-overlay__4nR2p{left:0;overflow:visible;pointer-events:none;position:absolute;top:0}.line-chart-module_line-chart__annotation-label__OmgiT{pointer-events:auto}.line-chart-module_line-chart__annotation-label-trigger-button__mcIb3{align-items:center;background:none;border:none;cursor:pointer;display:flex;justify-content:center;padding:0;pointer-events:auto}.line-chart-module_line-chart__annotation-label-popover__TqNZk{background:#fff;border:none;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);font-size:14px;margin:.5rem;min-width:125px;position:fixed;visibility:hidden}.line-chart-module_line-chart__annotation-label-popover--visible__dE0cV{visibility:visible}.line-chart-module_line-chart__annotation-label-popover--safari__i3NHT{margin:auto;position:static}.line-chart-module_line-chart__annotation-label-popover-header__Owypo{align-items:start;display:flex;flex-direction:row;justify-content:space-between}.line-chart-module_line-chart__annotation-label-popover-content__vtgQt{padding:.5rem}.line-chart-module_line-chart__annotation-label-popover-close-button__i8KUc{align-items:center;background:none;border:none;cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;width:44px}.visx-tooltip-glyph svg{height:10px;width:10px}.base-tooltip-module_tooltip__OfX6n{background-color:rgba(0,0,0,.85);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);color:#fff;font-size:14px;padding:.5rem;pointer-events:none;position:absolute;transform:translate(-50%,-100%)}.pie-chart-module_pie-chart__R12Vh{display:flex;flex-direction:column;overflow:hidden}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9{display:flex;flex-direction:column;text-align:center}.pie-semi-circle-chart-module_pie-semi-circle-chart-legend__c8W1Y.pie-semi-circle-chart-module_is-on-top__BamnZ{margin-bottom:1rem}.pie-semi-circle-chart-module_pie-semi-circle-chart-legend__c8W1Y.pie-semi-circle-chart-module_is-on-bottom__NyS5q{margin-top:1rem}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_label__nPqOg{font-size:16px;font-weight:600;margin-bottom:0}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_note__LpBZQ{font-size:14px;margin-top:0}.leaderboard-chart-module_leaderboardChart__zxakP{transition:opacity .3s ease-in-out}.leaderboard-chart-module_leaderboardChart__zxakP.leaderboard-chart-module_loading__-AGv-{opacity:.5}.leaderboard-chart-module_progressContainer__BZGbj{display:flex;flex-direction:column;gap:6px}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj{background-color:transparent;border-radius:2px;height:6px;overflow:hidden;transition:width .3s ease-in-out;width:100%}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj>div{background-color:var(--progress-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_primaryBar__iybII{--progress-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_secondaryBar__A7tLz{--progress-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}
1
+ .legend-module_legend--horizontal__IUN13{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.legend-module_legend--vertical__Scfzo{display:flex;flex-direction:column;gap:8px}.legend-module_legend--vertical__Scfzo.legend-module_legend--horizontal-align-left__w2O7z{align-items:flex-start}.legend-module_legend--vertical__Scfzo.legend-module_legend--horizontal-align-center__Fmcxd{align-items:center}.legend-module_legend--vertical__Scfzo.legend-module_legend--horizontal-align-right__tKgER{align-items:flex-end}.legend-module_legend--vertical-align-top__l6G1I{position:relative}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-top__l6G1I.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend--vertical-align-bottom__UzHCY{position:relative}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-left__w2O7z{justify-content:flex-start}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-center__Fmcxd{justify-content:center}.legend-module_legend--vertical-align-bottom__UzHCY.legend-module_legend--horizontal-align-right__tKgER{justify-content:flex-end}.legend-module_legend-item__feemn{align-items:center;display:flex;font-size:.875rem}.legend-module_legend-item-label__ksx6I{align-items:center;display:flex;gap:.5rem}.legend-module_legend-item-value__d9x1j{font-weight:500}.bar-chart-module_bar-chart__lmYNi{display:flex;flex-direction:column}.bar-chart-module_bar-chart__lmYNi svg{overflow:visible}.bar-chart-module_bar-chart-legend__vgKKq{margin-top:1rem}.line-chart-module_line-chart__ITM3d{display:flex;flex-direction:column}.line-chart-module_line-chart__ITM3d svg{overflow:visible}.line-chart-module_line-chart__annotation-label-popover__TqNZk,.line-chart-module_line-chart__tooltip__aqcme{background:#fff;padding:.5rem}.line-chart-module_line-chart__tooltip-date__4Dzab{font-weight:700;padding-bottom:10px}.line-chart-module_line-chart__tooltip-row__6A37G{align-items:center;display:flex;justify-content:space-between;padding:4px 0}.line-chart-module_line-chart__tooltip-label__IvnFF{font-weight:500;padding-right:1rem}.line-chart-module_line-chart__annotations-overlay__4nR2p{left:0;overflow:visible;pointer-events:none;position:absolute;top:0}.line-chart-module_line-chart__annotation-label__OmgiT{pointer-events:auto}.line-chart-module_line-chart__annotation-label-trigger-button__mcIb3{align-items:center;background:none;border:none;cursor:pointer;display:flex;justify-content:center;padding:0;pointer-events:auto}.line-chart-module_line-chart__annotation-label-popover__TqNZk{background:#fff;border:none;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);font-size:14px;margin:.5rem;min-width:125px;position:fixed;visibility:hidden}.line-chart-module_line-chart__annotation-label-popover--visible__dE0cV{visibility:visible}.line-chart-module_line-chart__annotation-label-popover--safari__i3NHT{margin:auto;position:static}.line-chart-module_line-chart__annotation-label-popover-header__Owypo{align-items:start;display:flex;flex-direction:row;justify-content:space-between}.line-chart-module_line-chart__annotation-label-popover-content__vtgQt{padding:.5rem}.line-chart-module_line-chart__annotation-label-popover-close-button__i8KUc{align-items:center;background:none;border:none;cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;width:44px}.visx-tooltip-glyph svg{height:10px;width:10px}.base-tooltip-module_tooltip__OfX6n{background-color:rgba(0,0,0,.85);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);color:#fff;font-size:14px;padding:.5rem;pointer-events:none;position:absolute;transform:translate(-50%,-100%)}.pie-chart-module_pie-chart__R12Vh{display:flex;flex-direction:column;overflow:hidden}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9{display:flex;flex-direction:column;text-align:center}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_label__nPqOg{font-size:16px;font-weight:600;margin-bottom:0}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_note__LpBZQ{font-size:14px;margin-top:0}.leaderboard-chart-module_leaderboardChart__zxakP{transition:opacity .3s ease-in-out}.leaderboard-chart-module_leaderboardChart__zxakP.leaderboard-chart-module_loading__-AGv-{opacity:.5}.leaderboard-chart-module_progressContainer__BZGbj{display:flex;flex-direction:column;gap:6px}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj{background-color:transparent;border-radius:2px;height:6px;overflow:hidden;transition:width .3s ease-in-out;width:100%}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj>div{background-color:var(--progress-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_primaryBar__iybII{--progress-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_secondaryBar__A7tLz{--progress-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}
@@ -19,7 +19,7 @@ interface LineChartProps extends BaseChartProps<SeriesData[]> {
19
19
  withStartGlyphs?: boolean;
20
20
  renderGlyph?: <Datum extends object>(props: GlyphProps<Datum>) => ReactNode;
21
21
  glyphStyle?: SVGProps<SVGCircleElement>;
22
- withLegendGlyph: boolean;
22
+ withLegendGlyph?: boolean;
23
23
  withTooltipCrosshairs?: {
24
24
  showVertical?: boolean;
25
25
  showHorizontal?: boolean;
@@ -18,5 +18,5 @@ export { defaultTheme, jetpackTheme, wooTheme } from './providers/theme/themes.j
18
18
  export { default as useChartMouseHandler } from './hooks/use-chart-mouse-handler.js';
19
19
  export { BaseChartProps, ButtonWithPopover, ChartTheme, DataPoint, DataPointDate, DataPointPercentage, GridProps, MultipleDataPointsDate, Optional, OrientationType, PopoverButtonAttributes, PopoverElement, PopoverElementAttributes, ScaleOptions, SeriesData, ToggleEvent } from './types.js';
20
20
  export { RenderTooltipParams } from '@visx/xychart/lib/components/Tooltip';
21
- export { GridStyles, LineStyles } from '@visx/xychart';
21
+ export { EventHandlerParams, GridStyles, LineStyles } from '@visx/xychart';
22
22
  export { ConversionFunnelChartProps, FunnelStep } from './components/conversion-funnel-chart/conversion-funnel-chart.js';
@@ -209,17 +209,17 @@ type BaseChartProps<T = DataPoint | DataPointDate> = {
209
209
  /**
210
210
  * Callback function for pointer down event
211
211
  */
212
- onPointerDown?: (event: EventHandlerParams<object>) => void;
212
+ onPointerDown?: (event: EventHandlerParams<DataPoint | DataPointDate>) => void;
213
213
  /**
214
- * Callback function for pointer down event
214
+ * Callback function for pointer up event
215
215
  */
216
- onPointerUp?: (event: EventHandlerParams<object>) => void;
216
+ onPointerUp?: (event: EventHandlerParams<DataPoint | DataPointDate>) => void;
217
217
  /**
218
- * Callback function for pointer down event
218
+ * Callback function for pointer move event
219
219
  */
220
- onPointerMove?: (event: EventHandlerParams<object>) => void;
220
+ onPointerMove?: (event: EventHandlerParams<DataPoint | DataPointDate>) => void;
221
221
  /**
222
- * Callback function for pointer up event
222
+ * Callback function for pointer out event
223
223
  */
224
224
  onPointerOut?: (event: PointerEvent<Element>) => void;
225
225
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/charts",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Display charts within Automattic products.",
5
5
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/charts/#readme",
6
6
  "bugs": {
@@ -13,23 +13,6 @@
13
13
  },
14
14
  "license": "GPL-2.0-or-later",
15
15
  "author": "Automattic",
16
- "scripts": {
17
- "clean": "rm -rf dist",
18
- "test": "TZ=UTC jest --config=tests/jest.config.cjs",
19
- "test-coverage": "pnpm run test --coverage",
20
- "storybook": "cd ../storybook && pnpm run storybook:dev",
21
- "compile-ts": "tsc --pretty",
22
- "clean-build": "rm -rf dist/",
23
- "typecheck": "tsc --noEmit",
24
- "build": "pnpm run build:prod",
25
- "build:prod": "pnpm run clean && rollup -c --environment NODE_ENV:production",
26
- "build:dev": "rollup -c --environment NODE_ENV:development",
27
- "build:webpack": "pnpm run clean-build && webpack --config webpack.config.cjs --mode production && pnpm run build:types",
28
- "build:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist/types"
29
- },
30
- "main": "./dist/cjs/index.js",
31
- "module": "./dist/mjs/index.js",
32
- "types": "./dist/types/index.d.ts",
33
16
  "sideEffects": [
34
17
  "*.css",
35
18
  "*.scss"
@@ -40,10 +23,10 @@
40
23
  "require": "./dist/cjs/index.js",
41
24
  "types": "./dist/types/index.d.ts"
42
25
  },
43
- "./visx/*": {
44
- "import": "./dist/mjs/visx/*/index.js",
45
- "require": "./dist/cjs/visx/*/index.js",
46
- "types": "./dist/types/visx/*/index.d.ts"
26
+ "./*": {
27
+ "import": "./dist/mjs/components/*/index.js",
28
+ "require": "./dist/cjs/components/*/index.js",
29
+ "types": "./dist/types/components/*/index.d.ts"
47
30
  },
48
31
  "./providers/*": {
49
32
  "import": "./dist/mjs/providers/*/index.js",
@@ -51,14 +34,31 @@
51
34
  "types": "./dist/types/providers/*/index.d.ts"
52
35
  },
53
36
  "./style.css": "./dist/mjs/style.css",
54
- "./*": {
55
- "import": "./dist/mjs/components/*/index.js",
56
- "require": "./dist/cjs/components/*/index.js",
57
- "types": "./dist/types/components/*/index.d.ts"
37
+ "./visx/*": {
38
+ "import": "./dist/mjs/visx/*/index.js",
39
+ "require": "./dist/cjs/visx/*/index.js",
40
+ "types": "./dist/types/visx/*/index.d.ts"
58
41
  }
59
42
  },
43
+ "main": "./dist/cjs/index.js",
44
+ "module": "./dist/mjs/index.js",
45
+ "types": "./dist/types/index.d.ts",
46
+ "scripts": {
47
+ "build": "pnpm run build:prod",
48
+ "build:dev": "rollup -c --environment NODE_ENV:development",
49
+ "build:prod": "pnpm run clean && rollup -c --environment NODE_ENV:production",
50
+ "build:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist/types",
51
+ "build:webpack": "pnpm run clean-build && webpack --config webpack.config.cjs --mode production && pnpm run build:types",
52
+ "clean": "rm -rf dist",
53
+ "clean-build": "rm -rf dist/",
54
+ "compile-ts": "tsc --pretty",
55
+ "storybook": "cd ../storybook && pnpm run storybook:dev",
56
+ "test": "TZ=UTC jest --config=tests/jest.config.cjs",
57
+ "test-coverage": "pnpm run test --coverage",
58
+ "typecheck": "tsc --noEmit"
59
+ },
60
60
  "dependencies": {
61
- "@automattic/number-formatters": "^1.0.9",
61
+ "@automattic/number-formatters": "^1.0.10",
62
62
  "@babel/runtime": "7.27.6",
63
63
  "@react-spring/web": "9.7.5",
64
64
  "@visx/annotation": "^3.12.0",
@@ -76,6 +76,7 @@
76
76
  "@visx/text": "^3.12.0",
77
77
  "@visx/tooltip": "^3.12.0",
78
78
  "@visx/xychart": "^3.12.0",
79
+ "@wordpress/i18n": "^6.0.0",
79
80
  "clsx": "2.1.1",
80
81
  "date-fns": "^4.1.0",
81
82
  "deepmerge": "4.3.1",
@@ -105,8 +106,8 @@
105
106
  "@types/react": "18.3.23",
106
107
  "@types/react-dom": "18.3.7",
107
108
  "@visx/glyph": "3.12.0",
108
- "@wordpress/components": "29.12.0",
109
- "@wordpress/element": "6.26.0",
109
+ "@wordpress/components": "30.0.0",
110
+ "@wordpress/element": "6.27.0",
110
111
  "babel-jest": "30.0.0",
111
112
  "babel-loader": "9.1.2",
112
113
  "css-loader": "^6.7.0",