@automattic/charts 0.31.0 → 0.32.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,35 +5,48 @@ 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.32.0] - 2025-09-02
9
+ ### Added
10
+ - Charts: adds controls for label visibility [#45040]
11
+
12
+ ### Changed
13
+ - Charts: format percentage values to be prettier [#45032]
14
+ - Charts: Use a global context provider for theme configuration in all stories [#45028]
15
+ - Charts: use getStringWidth for label size calculations [#45030]
16
+ - Fix the conversion-funnel-chart component exportation [#45033]
17
+
18
+ ### Fixed
19
+ - All charts were affected due to z-index. [#45043]
20
+
8
21
  ## [0.31.0] - 2025-09-01
9
22
  ### Added
10
- - Charts: adds an agents.md file to project root [#44954]
11
- - Charts: Refactor shared components, hooks and utils [#44971]
12
- - Charts: Stable colors for series groups [#44730]
13
- - Refactor Pie Chart to improve readability. [#44989]
23
+ - Add an agents.md file to project root. [#44954]
24
+ - Ensure stable colors for series groups. [#44730]
25
+ - Pie Chart: Refactor to improve readability. [#44989]
14
26
 
15
27
  ### Changed
16
- - Enhanced ConversionFunnelChart with render props and TooltipInPortal [#45019]
28
+ - Enhance ConversionFunnelChart with render props and TooltipInPortal. [#45019]
29
+ - Refactor shared components, hooks and utils. [#44971]
17
30
 
18
31
  ### Fixed
19
- - Charts: fix label background colour and text colour [#44990]
20
- - Refactored leaderboard chart to remove progressbar. [#44982]
32
+ - Fix label background and text color. [#44990]
33
+ - Refactor leaderboard chart to remove progress bar. [#44982]
21
34
 
22
35
  ## [0.30.0] - 2025-08-27
23
36
  ### Added
24
37
  - Export ConversionFunnelChart for usage outside. [#44952]
25
38
 
26
39
  ### Changed
27
- - Consolidate sample data across Storybook stories for consistency and maintainability [#44903]
40
+ - Storybook: Consolidate sample data across stories for consistency and maintainability. [#44903]
28
41
 
29
42
  ## [0.29.0] - 2025-08-25
30
43
  ### Changed
31
- - Charts: Consolidate and clean up pie chart composition API. [#44856]
44
+ - Consolidate and clean up pie chart composition API. [#44856]
32
45
 
33
46
  ## [0.28.0] - 2025-08-21
34
47
  ### Added
35
- - Charts: Add composition legend to pie family charts. [#44796]
36
- - Charts: Add theme to global context and use instead of that from theme provider [#44809]
48
+ - Add composition legend to pie family charts. [#44796]
49
+ - Add theme to global context and use instead of that from theme provider. [#44809]
37
50
 
38
51
  ## [0.27.0] - 2025-08-18
39
52
  ### Added
@@ -46,7 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
46
59
  - Line Chart: Add comparison style to theme. [#44676]
47
60
 
48
61
  ### Changed
49
- - Updated legend positioning and alignment. [#44747]
62
+ - Update legend positioning and alignment. [#44747]
50
63
  - Update package dependencies. [#44701]
51
64
 
52
65
  ## [0.25.0] - 2025-08-11
@@ -405,6 +418,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
405
418
  - Fixed lints following ESLint rule changes for TS [#40584]
406
419
  - Fixing a bug in Chart storybook data. [#40640]
407
420
 
421
+ [0.32.0]: https://github.com/Automattic/charts/compare/v0.31.0...v0.32.0
408
422
  [0.31.0]: https://github.com/Automattic/charts/compare/v0.30.0...v0.31.0
409
423
  [0.30.0]: https://github.com/Automattic/charts/compare/v0.29.0...v0.30.0
410
424
  [0.29.0]: https://github.com/Automattic/charts/compare/v0.28.0...v0.29.0
@@ -12,6 +12,7 @@ require('fast-deep-equal');
12
12
  require('@visx/xychart');
13
13
  require('date-fns');
14
14
  require('@automattic/number-formatters');
15
+ var formatPercentage = require('../../utils/format-percentage.js');
15
16
  require('@visx/text');
16
17
  require('deepmerge');
17
18
  var colorUtils = require('../../utils/color-utils.js');
@@ -187,9 +188,9 @@ const ConversionFunnelChart = ({ mainRate, changeIndicator, steps, loading = fal
187
188
  ...style,
188
189
  };
189
190
  // Default main metric rendering function
190
- const renderDefaultMainMetric = () => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("span", { className: conversionFunnelChart_module.default['main-rate'], children: [mainRate.toFixed(1), "%"] }), changeIndicator && (jsxRuntime.jsx("span", { className: conversionFunnelChart_module.default['change-indicator'], children: changeIndicator }))] }));
191
+ const renderDefaultMainMetric = () => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: conversionFunnelChart_module.default['main-rate'], children: formatPercentage.formatPercentage(mainRate) }), changeIndicator && (jsxRuntime.jsx("span", { className: conversionFunnelChart_module.default['change-indicator'], children: changeIndicator }))] }));
191
192
  // Default tooltip rendering function
192
- const renderDefaultTooltip = (step) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: conversionFunnelChart_module.default['tooltip-title'], children: step.label }), jsxRuntime.jsxs("div", { className: conversionFunnelChart_module.default['tooltip-content'], children: [step.rate.toFixed(1), "%", step.count && ` • ${step.count.toLocaleString()} items`] })] }));
193
+ const renderDefaultTooltip = (step) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: conversionFunnelChart_module.default['tooltip-title'], children: step.label }), jsxRuntime.jsxs("div", { className: conversionFunnelChart_module.default['tooltip-content'], children: [formatPercentage.formatPercentage(step.rate), step.count && ` • ${step.count.toLocaleString()} items`] })] }));
193
194
  // Handle empty or undefined data
194
195
  if (!steps || steps.length === 0) {
195
196
  return (jsxRuntime.jsx("div", { className: clsx(conversionFunnelChart_module.default.conversionFunnelChart, loading && conversionFunnelChart_module.default.loading, className), style: chartStyle, children: jsxRuntime.jsx("div", { className: conversionFunnelChart_module.default['empty-state'], children: loading ? 'Loading...' : 'No data available' }) }));
@@ -216,7 +217,7 @@ const ConversionFunnelChart = ({ mainRate, changeIndicator, steps, loading = fal
216
217
  step,
217
218
  index,
218
219
  className: conversionFunnelChart_module.default['step-rate'],
219
- })) : (jsxRuntime.jsxs("span", { className: conversionFunnelChart_module.default['step-rate'], children: [step.rate.toFixed(1), "%"] }))] }), jsxRuntime.jsx("div", { className: clsx(conversionFunnelChart_module.default['bar-container'], isClicked && conversionFunnelChart_module.default.selected, isBlurred && conversionFunnelChart_module.default.disabled), onClick: stepHandlers.get(step.id)?.onClick, onKeyDown: stepHandlers.get(step.id)?.onKeyDown, role: "button", tabIndex: isBlurred ? -1 : 0, "aria-label": step.label, children: jsxRuntime.jsx("div", { className: clsx(conversionFunnelChart_module.default['funnel-bar'], isClicked && conversionFunnelChart_module.default.selected), style: {
220
+ })) : (jsxRuntime.jsx("span", { className: conversionFunnelChart_module.default['step-rate'], children: formatPercentage.formatPercentage(step.rate) }))] }), jsxRuntime.jsx("div", { className: clsx(conversionFunnelChart_module.default['bar-container'], isClicked && conversionFunnelChart_module.default.selected, isBlurred && conversionFunnelChart_module.default.disabled), onClick: stepHandlers.get(step.id)?.onClick, onKeyDown: stepHandlers.get(step.id)?.onKeyDown, role: "button", tabIndex: isBlurred ? -1 : 0, "aria-label": step.label, children: jsxRuntime.jsx("div", { className: clsx(conversionFunnelChart_module.default['funnel-bar'], isClicked && conversionFunnelChart_module.default.selected), style: {
220
221
  height: `${barHeight}%`,
221
222
  backgroundColor: primaryColor,
222
223
  } }) })] }, step.id));
@@ -3,6 +3,7 @@
3
3
  var leaderboardChart = require('./leaderboard-chart.js');
4
4
  require('date-fns');
5
5
  var formatMetricValue = require('../../utils/format-metric-value.js');
6
+ require('@automattic/number-formatters');
6
7
  require('@visx/text');
7
8
  require('deepmerge');
8
9
 
@@ -14,6 +14,7 @@ require('@visx/tooltip');
14
14
  require('@visx/xychart');
15
15
  require('date-fns');
16
16
  var formatMetricValue = require('../../utils/format-metric-value.js');
17
+ require('@automattic/number-formatters');
17
18
  require('@visx/text');
18
19
  require('deepmerge');
19
20
  require('@visx/scale');
@@ -8,6 +8,7 @@ require('@visx/tooltip');
8
8
  require('@visx/xychart');
9
9
  require('date-fns');
10
10
  require('@automattic/number-formatters');
11
+ var formatPercentage = require('../../../utils/format-percentage.js');
11
12
  require('@visx/text');
12
13
  var getStyles = require('../../../utils/get-styles.js');
13
14
  require('deepmerge');
@@ -25,7 +26,7 @@ function formatPointValue(point, showValues) {
25
26
  return '';
26
27
  }
27
28
  if ('percentage' in point) {
28
- return `${point.percentage}%`;
29
+ return formatPercentage.formatPercentage(point.percentage);
29
30
  }
30
31
  else if ('value' in point) {
31
32
  return point.value.toString();
@@ -18,7 +18,7 @@ var useGlobalChartsTheme = require('../../providers/chart-context/hooks/use-glob
18
18
  var createComposition = require('../../utils/create-composition.js');
19
19
  require('date-fns');
20
20
  require('@automattic/number-formatters');
21
- require('@visx/text');
21
+ var text = require('@visx/text');
22
22
  require('deepmerge');
23
23
  require('@visx/scale');
24
24
  var useElementHeight = require('../../hooks/use-element-height.js');
@@ -60,7 +60,7 @@ const validateData = (data) => {
60
60
  * @param {PieChartProps} props - Component props
61
61
  * @return {JSX.Element} The rendered chart component
62
62
  */
63
- const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legendOrientation = 'horizontal', legendPosition = 'bottom', legendAlignment = 'center', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, children = null, }) => {
63
+ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legendOrientation = 'horizontal', legendPosition = 'bottom', legendAlignment = 'center', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, showLabels = true, children = null, }) => {
64
64
  const providerTheme = useGlobalChartsTheme.useGlobalChartsTheme();
65
65
  const chartId = useChartId.useChartId(providedChartId);
66
66
  const [legendRef, legendHeight] = useElementHeight.useElementHeight();
@@ -138,11 +138,11 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
138
138
  }
139
139
  // Estimate text width more accurately for background sizing
140
140
  const fontSize = 12;
141
- const estimatedTextWidth = arc.data.label.length * fontSize * 0.6; // Rough estimate
141
+ const estimatedTextWidth = text.getStringWidth(arc.data.label, { fontSize });
142
142
  const labelPadding = 6;
143
143
  const backgroundWidth = estimatedTextWidth + labelPadding * 2;
144
144
  const backgroundHeight = fontSize + labelPadding * 2;
145
- return (jsxRuntime.jsxs("g", { children: [jsxRuntime.jsx("path", { ...pathProps }), hasSpaceForLabel && (jsxRuntime.jsxs("g", { children: [providerTheme.labelBackgroundColor && (jsxRuntime.jsx("rect", { x: centroidX - backgroundWidth / 2, y: centroidY - backgroundHeight / 2, width: backgroundWidth, height: backgroundHeight, fill: providerTheme.labelBackgroundColor, rx: 4, ry: 4, pointerEvents: "none" })), jsxRuntime.jsx("text", { x: centroidX, y: centroidY, dy: ".33em", fill: providerTheme.labelTextColor || '#333', fontSize: fontSize, textAnchor: "middle", pointerEvents: "none", children: arc.data.label })] }))] }, `arc-${index}`));
145
+ return (jsxRuntime.jsxs("g", { children: [jsxRuntime.jsx("path", { ...pathProps }), showLabels && hasSpaceForLabel && (jsxRuntime.jsxs("g", { children: [providerTheme.labelBackgroundColor && (jsxRuntime.jsx("rect", { x: centroidX - backgroundWidth / 2, y: centroidY - backgroundHeight / 2, width: backgroundWidth, height: backgroundHeight, fill: providerTheme.labelBackgroundColor, rx: 4, ry: 4, pointerEvents: "none" })), jsxRuntime.jsx("text", { x: centroidX, y: centroidY, dy: ".33em", fill: providerTheme.labelTextColor || '#333', fontSize: fontSize, textAnchor: "middle", pointerEvents: "none", children: arc.data.label })] }))] }, `arc-${index}`));
146
146
  });
147
147
  } }), svgChildren] }) }), showLegend && (jsxRuntime.jsx(legend.Legend, { orientation: legendOrientation, position: legendPosition, alignment: legendAlignment, className: pieChart_module.default['pie-chart-legend'], shape: legendShape, ref: legendRef, chartId: chartId })), withTooltips && tooltipOpen && tooltipData && (jsxRuntime.jsx(baseTooltip.BaseTooltip, { data: tooltipData, top: tooltipTop || 0, left: tooltipLeft || 0, style: {
148
148
  transform: 'translate(-50%, -100%)',
@@ -1 +1 @@
1
- .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}.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_barWithLabelContainer__9RE0U{align-items:center;display:grid;grid-template-columns:1fr;row-gap:6px}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5{grid-template:"overlap" 1fr/1fr}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5>*{grid-area:overlap}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5 .leaderboard-chart-module_label__7ZUu0{padding-left:8px}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_bar__CnJvg{background-color:var(--bar-color,#3858e9);border-radius:var(--bar-border,9999px);height:100%;min-height:6px;transition:width .3s ease-in-out;z-index:-1}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_primaryBar__iybII{--bar-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_secondaryBar__A7tLz{--bar-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_overlayLabel__pRqSh{align-items:center}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb{font-family:var(--funnel-font-family,"SF Pro Text")}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb.conversion-funnel-chart-module_loading__Kw-iZ{opacity:.6;pointer-events:none}.conversion-funnel-chart-module_main-metric__8mIwV{align-items:baseline;display:flex;gap:8px;margin-bottom:24px}.conversion-funnel-chart-module_main-rate__D93Ub{color:#1e1e1e;font-size:18px}.conversion-funnel-chart-module_change-indicator__QWypV,.conversion-funnel-chart-module_main-rate__D93Ub{font-family:var(--funnel-font-family,"SF Pro Text");font-style:normal;font-weight:500;line-height:20px;margin:0;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_change-indicator__QWypV{color:var(--change-indicator-color,#008a20);font-size:13px}.conversion-funnel-chart-module_funnel-container__RR7xa{align-items:flex-end;display:flex;gap:16px;height:200px;width:100%}.conversion-funnel-chart-module_funnel-step__VIVzt{display:flex;flex:1 1 0;flex-direction:column;height:100%;min-width:0;transition:all .3s ease}.conversion-funnel-chart-module_funnel-step__VIVzt.conversion-funnel-chart-module_blurred__Ax4cu{opacity:.3}.conversion-funnel-chart-module_step-header__bUrZ0{margin-bottom:24px}.conversion-funnel-chart-module_step-label__SCy8F{color:#757575;display:block;font-family:var(--step-font-family,"SF Pro");font-size:12px;font-style:normal;font-weight:400;line-height:16px;margin:0 0 2px;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_step-rate__A0irB{color:#1e1e1e;display:block;font-family:var(--step-font-family,"SF Pro");font-size:13px;font-style:normal;font-weight:500;line-height:20px;margin:0}.conversion-funnel-chart-module_bar-container__5Dl5-{align-items:flex-end;background-color:var(--light-background-color,rgba(79,70,229,.08));border-radius:4px;cursor:pointer;display:flex;flex:1;position:relative;transition:all .2s ease}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_selected__W40FY{background-color:var(--light-background-color,rgba(79,70,229,.15))}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_disabled__Reovk{cursor:pointer}.conversion-funnel-chart-module_funnel-bar__tG5m3{background-color:var(--primary-color,#4f46e5);border-radius:4px 4px 0 0;min-height:4px;transition:all .3s ease;width:100%}.conversion-funnel-chart-module_funnel-bar__tG5m3.conversion-funnel-chart-module_selected__W40FY{box-shadow:0 4px 16px rgba(0,0,0,.2);filter:brightness(1.1)}.conversion-funnel-chart-module_tooltip-wrapper__NohPt{align-items:flex-start;background:var(--black-white-white,#fff);border-bottom:1px solid var(--Gray-Gray-5,#dcdcde);border-radius:4px!important;box-shadow:0 1px 3px 0 rgba(0,0,0,.15),0 3px 9px 0 rgba(0,0,0,.12)!important;display:inline-flex;flex-direction:column;gap:4px;justify-content:center;padding:12px!important}.conversion-funnel-chart-module_tooltip-title__hjZr3{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:16px}.conversion-funnel-chart-module_tooltip-content__ocwAP{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:13px;font-style:normal;font-weight:500;line-height:20px}.conversion-funnel-chart-module_empty-state__9c0ps{color:#6b7280;font-size:16px;padding:48px 24px;text-align:center}.base-legend-module_legend--horizontal__AELBv{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.base-legend-module_legend--vertical__fX8uQ{display:flex;flex-direction:column;gap:8px}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-start__DEe0w{align-items:flex-start}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-center__WBKF9{align-items:center}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-end__JfwMn{align-items:flex-end}.base-legend-module_legend--position-top__8Y73K{position:relative}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend--position-bottom__TVM-I{position:relative}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend-item__Vflwq{align-items:center;display:flex;font-size:.875rem}.base-legend-module_legend-item-label__2H65K{align-items:center;display:flex;gap:.5rem}.base-legend-module_legend-item-value__DTZlT{font-weight:500}.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%)}.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}
1
+ .base-legend-module_legend--horizontal__AELBv{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.base-legend-module_legend--vertical__fX8uQ{display:flex;flex-direction:column;gap:8px}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-start__DEe0w{align-items:flex-start}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-center__WBKF9{align-items:center}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-end__JfwMn{align-items:flex-end}.base-legend-module_legend--position-top__8Y73K{position:relative}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend--position-bottom__TVM-I{position:relative}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend-item__Vflwq{align-items:center;display:flex;font-size:.875rem}.base-legend-module_legend-item-label__2H65K{align-items:center;display:flex;gap:.5rem}.base-legend-module_legend-item-value__DTZlT{font-weight:500}.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%)}.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}.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_barWithLabelContainer__9RE0U{align-items:center;display:grid;grid-template-columns:1fr;isolation:isolate;row-gap:6px}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5{grid-template:"overlap" 1fr/1fr}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5>*{grid-area:overlap}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5 .leaderboard-chart-module_label__7ZUu0{padding-left:8px}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_bar__CnJvg{background-color:var(--bar-color,#3858e9);border-radius:var(--bar-border,9999px);height:100%;min-height:6px;transition:width .3s ease-in-out;z-index:-1}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_primaryBar__iybII{--bar-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_secondaryBar__A7tLz{--bar-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_overlayLabel__pRqSh{align-items:center}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb{font-family:var(--funnel-font-family,"SF Pro Text")}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb.conversion-funnel-chart-module_loading__Kw-iZ{opacity:.6;pointer-events:none}.conversion-funnel-chart-module_main-metric__8mIwV{align-items:baseline;display:flex;gap:8px;margin-bottom:24px}.conversion-funnel-chart-module_main-rate__D93Ub{color:#1e1e1e;font-size:18px}.conversion-funnel-chart-module_change-indicator__QWypV,.conversion-funnel-chart-module_main-rate__D93Ub{font-family:var(--funnel-font-family,"SF Pro Text");font-style:normal;font-weight:500;line-height:20px;margin:0;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_change-indicator__QWypV{color:var(--change-indicator-color,#008a20);font-size:13px}.conversion-funnel-chart-module_funnel-container__RR7xa{align-items:flex-end;display:flex;gap:16px;height:200px;width:100%}.conversion-funnel-chart-module_funnel-step__VIVzt{display:flex;flex:1 1 0;flex-direction:column;height:100%;min-width:0;transition:all .3s ease}.conversion-funnel-chart-module_funnel-step__VIVzt.conversion-funnel-chart-module_blurred__Ax4cu{opacity:.3}.conversion-funnel-chart-module_step-header__bUrZ0{margin-bottom:24px}.conversion-funnel-chart-module_step-label__SCy8F{color:#757575;display:block;font-family:var(--step-font-family,"SF Pro");font-size:12px;font-style:normal;font-weight:400;line-height:16px;margin:0 0 2px;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_step-rate__A0irB{color:#1e1e1e;display:block;font-family:var(--step-font-family,"SF Pro");font-size:13px;font-style:normal;font-weight:500;line-height:20px;margin:0}.conversion-funnel-chart-module_bar-container__5Dl5-{align-items:flex-end;background-color:var(--light-background-color,rgba(79,70,229,.08));border-radius:4px;cursor:pointer;display:flex;flex:1;position:relative;transition:all .2s ease}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_selected__W40FY{background-color:var(--light-background-color,rgba(79,70,229,.15))}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_disabled__Reovk{cursor:pointer}.conversion-funnel-chart-module_funnel-bar__tG5m3{background-color:var(--primary-color,#4f46e5);border-radius:4px 4px 0 0;min-height:4px;transition:all .3s ease;width:100%}.conversion-funnel-chart-module_funnel-bar__tG5m3.conversion-funnel-chart-module_selected__W40FY{box-shadow:0 4px 16px rgba(0,0,0,.2);filter:brightness(1.1)}.conversion-funnel-chart-module_tooltip-wrapper__NohPt{align-items:flex-start;background:var(--black-white-white,#fff);border-bottom:1px solid var(--Gray-Gray-5,#dcdcde);border-radius:4px!important;box-shadow:0 1px 3px 0 rgba(0,0,0,.15),0 3px 9px 0 rgba(0,0,0,.12)!important;display:inline-flex;flex-direction:column;gap:4px;justify-content:center;padding:12px!important}.conversion-funnel-chart-module_tooltip-title__hjZr3{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:16px}.conversion-funnel-chart-module_tooltip-content__ocwAP{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:13px;font-style:normal;font-weight:500;line-height:20px}.conversion-funnel-chart-module_empty-state__9c0ps{color:#6b7280;font-size:16px;padding:48px 24px;text-align:center}
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var numberFormatters = require('@automattic/number-formatters');
4
+
5
+ /**
6
+ * Format a percentage value with smart decimal handling.
7
+ * Uses @automattic/number-formatters for consistent formatting.
8
+ * Removes unnecessary trailing zeros and caps at 2 decimal places.
9
+ *
10
+ * @param value - The percentage value (0-100 range)
11
+ * @return Formatted percentage string (e.g., "30%", "30.1%", "30.25%")
12
+ */
13
+ const formatPercentage = (value) => {
14
+ // Use formatNumber with percentage style, but convert from 0-100 range to 0-1 range
15
+ return numberFormatters.formatNumber(value / 100, {
16
+ numberFormatOptions: {
17
+ style: 'percent',
18
+ minimumFractionDigits: 0,
19
+ maximumFractionDigits: 2,
20
+ },
21
+ });
22
+ };
23
+
24
+ exports.formatPercentage = formatPercentage;
@@ -8,6 +8,7 @@ import 'fast-deep-equal';
8
8
  import '@visx/xychart';
9
9
  import 'date-fns';
10
10
  import '@automattic/number-formatters';
11
+ import { formatPercentage } from '../../utils/format-percentage.js';
11
12
  import '@visx/text';
12
13
  import 'deepmerge';
13
14
  import { hexToRgba } from '../../utils/color-utils.js';
@@ -183,9 +184,9 @@ const ConversionFunnelChart = ({ mainRate, changeIndicator, steps, loading = fal
183
184
  ...style,
184
185
  };
185
186
  // Default main metric rendering function
186
- const renderDefaultMainMetric = () => (jsxs(Fragment, { children: [jsxs("span", { className: styles['main-rate'], children: [mainRate.toFixed(1), "%"] }), changeIndicator && (jsx("span", { className: styles['change-indicator'], children: changeIndicator }))] }));
187
+ const renderDefaultMainMetric = () => (jsxs(Fragment, { children: [jsx("span", { className: styles['main-rate'], children: formatPercentage(mainRate) }), changeIndicator && (jsx("span", { className: styles['change-indicator'], children: changeIndicator }))] }));
187
188
  // Default tooltip rendering function
188
- const renderDefaultTooltip = (step) => (jsxs(Fragment, { children: [jsx("div", { className: styles['tooltip-title'], children: step.label }), jsxs("div", { className: styles['tooltip-content'], children: [step.rate.toFixed(1), "%", step.count && ` • ${step.count.toLocaleString()} items`] })] }));
189
+ const renderDefaultTooltip = (step) => (jsxs(Fragment, { children: [jsx("div", { className: styles['tooltip-title'], children: step.label }), jsxs("div", { className: styles['tooltip-content'], children: [formatPercentage(step.rate), step.count && ` • ${step.count.toLocaleString()} items`] })] }));
189
190
  // Handle empty or undefined data
190
191
  if (!steps || steps.length === 0) {
191
192
  return (jsx("div", { className: clsx(styles.conversionFunnelChart, loading && styles.loading, className), style: chartStyle, children: jsx("div", { className: styles['empty-state'], children: loading ? 'Loading...' : 'No data available' }) }));
@@ -212,7 +213,7 @@ const ConversionFunnelChart = ({ mainRate, changeIndicator, steps, loading = fal
212
213
  step,
213
214
  index,
214
215
  className: styles['step-rate'],
215
- })) : (jsxs("span", { className: styles['step-rate'], children: [step.rate.toFixed(1), "%"] }))] }), jsx("div", { className: clsx(styles['bar-container'], isClicked && styles.selected, isBlurred && styles.disabled), onClick: stepHandlers.get(step.id)?.onClick, onKeyDown: stepHandlers.get(step.id)?.onKeyDown, role: "button", tabIndex: isBlurred ? -1 : 0, "aria-label": step.label, children: jsx("div", { className: clsx(styles['funnel-bar'], isClicked && styles.selected), style: {
216
+ })) : (jsx("span", { className: styles['step-rate'], children: formatPercentage(step.rate) }))] }), jsx("div", { className: clsx(styles['bar-container'], isClicked && styles.selected, isBlurred && styles.disabled), onClick: stepHandlers.get(step.id)?.onClick, onKeyDown: stepHandlers.get(step.id)?.onKeyDown, role: "button", tabIndex: isBlurred ? -1 : 0, "aria-label": step.label, children: jsx("div", { className: clsx(styles['funnel-bar'], isClicked && styles.selected), style: {
216
217
  height: `${barHeight}%`,
217
218
  backgroundColor: primaryColor,
218
219
  } }) })] }, step.id));
@@ -1,5 +1,6 @@
1
1
  export { LeaderboardChart } from './leaderboard-chart.js';
2
2
  import 'date-fns';
3
3
  export { formatMetricValue } from '../../utils/format-metric-value.js';
4
+ import '@automattic/number-formatters';
4
5
  import '@visx/text';
5
6
  import 'deepmerge';
@@ -10,6 +10,7 @@ import '@visx/tooltip';
10
10
  import '@visx/xychart';
11
11
  import 'date-fns';
12
12
  import { formatMetricValue } from '../../utils/format-metric-value.js';
13
+ import '@automattic/number-formatters';
13
14
  import '@visx/text';
14
15
  import 'deepmerge';
15
16
  import '@visx/scale';
@@ -6,6 +6,7 @@ import '@visx/tooltip';
6
6
  import '@visx/xychart';
7
7
  import 'date-fns';
8
8
  import '@automattic/number-formatters';
9
+ import { formatPercentage } from '../../../utils/format-percentage.js';
9
10
  import '@visx/text';
10
11
  import { getItemShapeStyles, getSeriesStroke } from '../../../utils/get-styles.js';
11
12
  import 'deepmerge';
@@ -23,7 +24,7 @@ function formatPointValue(point, showValues) {
23
24
  return '';
24
25
  }
25
26
  if ('percentage' in point) {
26
- return `${point.percentage}%`;
27
+ return formatPercentage(point.percentage);
27
28
  }
28
29
  else if ('value' in point) {
29
30
  return point.value.toString();
@@ -14,7 +14,7 @@ import { useGlobalChartsTheme } from '../../providers/chart-context/hooks/use-gl
14
14
  import { attachSubComponents } from '../../utils/create-composition.js';
15
15
  import 'date-fns';
16
16
  import '@automattic/number-formatters';
17
- import '@visx/text';
17
+ import { getStringWidth } from '@visx/text';
18
18
  import 'deepmerge';
19
19
  import '@visx/scale';
20
20
  import { useElementHeight } from '../../hooks/use-element-height.js';
@@ -56,7 +56,7 @@ const validateData = (data) => {
56
56
  * @param {PieChartProps} props - Component props
57
57
  * @return {JSX.Element} The rendered chart component
58
58
  */
59
- const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legendOrientation = 'horizontal', legendPosition = 'bottom', legendAlignment = 'center', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, children = null, }) => {
59
+ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legendOrientation = 'horizontal', legendPosition = 'bottom', legendAlignment = 'center', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, showLabels = true, children = null, }) => {
60
60
  const providerTheme = useGlobalChartsTheme();
61
61
  const chartId = useChartId(providedChartId);
62
62
  const [legendRef, legendHeight] = useElementHeight();
@@ -134,11 +134,11 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
134
134
  }
135
135
  // Estimate text width more accurately for background sizing
136
136
  const fontSize = 12;
137
- const estimatedTextWidth = arc.data.label.length * fontSize * 0.6; // Rough estimate
137
+ const estimatedTextWidth = getStringWidth(arc.data.label, { fontSize });
138
138
  const labelPadding = 6;
139
139
  const backgroundWidth = estimatedTextWidth + labelPadding * 2;
140
140
  const backgroundHeight = fontSize + labelPadding * 2;
141
- return (jsxs("g", { children: [jsx("path", { ...pathProps }), hasSpaceForLabel && (jsxs("g", { children: [providerTheme.labelBackgroundColor && (jsx("rect", { x: centroidX - backgroundWidth / 2, y: centroidY - backgroundHeight / 2, width: backgroundWidth, height: backgroundHeight, fill: providerTheme.labelBackgroundColor, rx: 4, ry: 4, pointerEvents: "none" })), jsx("text", { x: centroidX, y: centroidY, dy: ".33em", fill: providerTheme.labelTextColor || '#333', fontSize: fontSize, textAnchor: "middle", pointerEvents: "none", children: arc.data.label })] }))] }, `arc-${index}`));
141
+ return (jsxs("g", { children: [jsx("path", { ...pathProps }), showLabels && hasSpaceForLabel && (jsxs("g", { children: [providerTheme.labelBackgroundColor && (jsx("rect", { x: centroidX - backgroundWidth / 2, y: centroidY - backgroundHeight / 2, width: backgroundWidth, height: backgroundHeight, fill: providerTheme.labelBackgroundColor, rx: 4, ry: 4, pointerEvents: "none" })), jsx("text", { x: centroidX, y: centroidY, dy: ".33em", fill: providerTheme.labelTextColor || '#333', fontSize: fontSize, textAnchor: "middle", pointerEvents: "none", children: arc.data.label })] }))] }, `arc-${index}`));
142
142
  });
143
143
  } }), svgChildren] }) }), showLegend && (jsx(Legend, { orientation: legendOrientation, position: legendPosition, alignment: legendAlignment, className: styles['pie-chart-legend'], shape: legendShape, ref: legendRef, chartId: chartId })), withTooltips && tooltipOpen && tooltipData && (jsx(BaseTooltip, { data: tooltipData, top: tooltipTop || 0, left: tooltipLeft || 0, style: {
144
144
  transform: 'translate(-50%, -100%)',
@@ -1 +1 @@
1
- .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}.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_barWithLabelContainer__9RE0U{align-items:center;display:grid;grid-template-columns:1fr;row-gap:6px}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5{grid-template:"overlap" 1fr/1fr}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5>*{grid-area:overlap}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5 .leaderboard-chart-module_label__7ZUu0{padding-left:8px}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_bar__CnJvg{background-color:var(--bar-color,#3858e9);border-radius:var(--bar-border,9999px);height:100%;min-height:6px;transition:width .3s ease-in-out;z-index:-1}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_primaryBar__iybII{--bar-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_secondaryBar__A7tLz{--bar-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_overlayLabel__pRqSh{align-items:center}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb{font-family:var(--funnel-font-family,"SF Pro Text")}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb.conversion-funnel-chart-module_loading__Kw-iZ{opacity:.6;pointer-events:none}.conversion-funnel-chart-module_main-metric__8mIwV{align-items:baseline;display:flex;gap:8px;margin-bottom:24px}.conversion-funnel-chart-module_main-rate__D93Ub{color:#1e1e1e;font-size:18px}.conversion-funnel-chart-module_change-indicator__QWypV,.conversion-funnel-chart-module_main-rate__D93Ub{font-family:var(--funnel-font-family,"SF Pro Text");font-style:normal;font-weight:500;line-height:20px;margin:0;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_change-indicator__QWypV{color:var(--change-indicator-color,#008a20);font-size:13px}.conversion-funnel-chart-module_funnel-container__RR7xa{align-items:flex-end;display:flex;gap:16px;height:200px;width:100%}.conversion-funnel-chart-module_funnel-step__VIVzt{display:flex;flex:1 1 0;flex-direction:column;height:100%;min-width:0;transition:all .3s ease}.conversion-funnel-chart-module_funnel-step__VIVzt.conversion-funnel-chart-module_blurred__Ax4cu{opacity:.3}.conversion-funnel-chart-module_step-header__bUrZ0{margin-bottom:24px}.conversion-funnel-chart-module_step-label__SCy8F{color:#757575;display:block;font-family:var(--step-font-family,"SF Pro");font-size:12px;font-style:normal;font-weight:400;line-height:16px;margin:0 0 2px;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_step-rate__A0irB{color:#1e1e1e;display:block;font-family:var(--step-font-family,"SF Pro");font-size:13px;font-style:normal;font-weight:500;line-height:20px;margin:0}.conversion-funnel-chart-module_bar-container__5Dl5-{align-items:flex-end;background-color:var(--light-background-color,rgba(79,70,229,.08));border-radius:4px;cursor:pointer;display:flex;flex:1;position:relative;transition:all .2s ease}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_selected__W40FY{background-color:var(--light-background-color,rgba(79,70,229,.15))}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_disabled__Reovk{cursor:pointer}.conversion-funnel-chart-module_funnel-bar__tG5m3{background-color:var(--primary-color,#4f46e5);border-radius:4px 4px 0 0;min-height:4px;transition:all .3s ease;width:100%}.conversion-funnel-chart-module_funnel-bar__tG5m3.conversion-funnel-chart-module_selected__W40FY{box-shadow:0 4px 16px rgba(0,0,0,.2);filter:brightness(1.1)}.conversion-funnel-chart-module_tooltip-wrapper__NohPt{align-items:flex-start;background:var(--black-white-white,#fff);border-bottom:1px solid var(--Gray-Gray-5,#dcdcde);border-radius:4px!important;box-shadow:0 1px 3px 0 rgba(0,0,0,.15),0 3px 9px 0 rgba(0,0,0,.12)!important;display:inline-flex;flex-direction:column;gap:4px;justify-content:center;padding:12px!important}.conversion-funnel-chart-module_tooltip-title__hjZr3{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:16px}.conversion-funnel-chart-module_tooltip-content__ocwAP{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:13px;font-style:normal;font-weight:500;line-height:20px}.conversion-funnel-chart-module_empty-state__9c0ps{color:#6b7280;font-size:16px;padding:48px 24px;text-align:center}.base-legend-module_legend--horizontal__AELBv{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.base-legend-module_legend--vertical__fX8uQ{display:flex;flex-direction:column;gap:8px}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-start__DEe0w{align-items:flex-start}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-center__WBKF9{align-items:center}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-end__JfwMn{align-items:flex-end}.base-legend-module_legend--position-top__8Y73K{position:relative}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend--position-bottom__TVM-I{position:relative}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend-item__Vflwq{align-items:center;display:flex;font-size:.875rem}.base-legend-module_legend-item-label__2H65K{align-items:center;display:flex;gap:.5rem}.base-legend-module_legend-item-value__DTZlT{font-weight:500}.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%)}.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}
1
+ .base-legend-module_legend--horizontal__AELBv{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.base-legend-module_legend--vertical__fX8uQ{display:flex;flex-direction:column;gap:8px}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-start__DEe0w{align-items:flex-start}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-center__WBKF9{align-items:center}.base-legend-module_legend--vertical__fX8uQ.base-legend-module_legend--alignment-end__JfwMn{align-items:flex-end}.base-legend-module_legend--position-top__8Y73K{position:relative}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-top__8Y73K.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend--position-bottom__TVM-I{position:relative}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-start__DEe0w{justify-content:flex-start}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-center__WBKF9{justify-content:center}.base-legend-module_legend--position-bottom__TVM-I.base-legend-module_legend--alignment-end__JfwMn{justify-content:flex-end}.base-legend-module_legend-item__Vflwq{align-items:center;display:flex;font-size:.875rem}.base-legend-module_legend-item-label__2H65K{align-items:center;display:flex;gap:.5rem}.base-legend-module_legend-item-value__DTZlT{font-weight:500}.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%)}.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}.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_barWithLabelContainer__9RE0U{align-items:center;display:grid;grid-template-columns:1fr;isolation:isolate;row-gap:6px}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5{grid-template:"overlap" 1fr/1fr}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5>*{grid-area:overlap}.leaderboard-chart-module_barWithLabelContainer__9RE0U.leaderboard-chart-module_is-overlay__Fqdi5 .leaderboard-chart-module_label__7ZUu0{padding-left:8px}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_bar__CnJvg{background-color:var(--bar-color,#3858e9);border-radius:var(--bar-border,9999px);height:100%;min-height:6px;transition:width .3s ease-in-out;z-index:-1}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_primaryBar__iybII{--bar-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_barWithLabelContainer__9RE0U .leaderboard-chart-module_secondaryBar__A7tLz{--bar-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_overlayLabel__pRqSh{align-items:center}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb{font-family:var(--funnel-font-family,"SF Pro Text")}.conversion-funnel-chart-module_conversionFunnelChart__-9Qsb.conversion-funnel-chart-module_loading__Kw-iZ{opacity:.6;pointer-events:none}.conversion-funnel-chart-module_main-metric__8mIwV{align-items:baseline;display:flex;gap:8px;margin-bottom:24px}.conversion-funnel-chart-module_main-rate__D93Ub{color:#1e1e1e;font-size:18px}.conversion-funnel-chart-module_change-indicator__QWypV,.conversion-funnel-chart-module_main-rate__D93Ub{font-family:var(--funnel-font-family,"SF Pro Text");font-style:normal;font-weight:500;line-height:20px;margin:0;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_change-indicator__QWypV{color:var(--change-indicator-color,#008a20);font-size:13px}.conversion-funnel-chart-module_funnel-container__RR7xa{align-items:flex-end;display:flex;gap:16px;height:200px;width:100%}.conversion-funnel-chart-module_funnel-step__VIVzt{display:flex;flex:1 1 0;flex-direction:column;height:100%;min-width:0;transition:all .3s ease}.conversion-funnel-chart-module_funnel-step__VIVzt.conversion-funnel-chart-module_blurred__Ax4cu{opacity:.3}.conversion-funnel-chart-module_step-header__bUrZ0{margin-bottom:24px}.conversion-funnel-chart-module_step-label__SCy8F{color:#757575;display:block;font-family:var(--step-font-family,"SF Pro");font-size:12px;font-style:normal;font-weight:400;line-height:16px;margin:0 0 2px;overflow:hidden;text-overflow:ellipsis}.conversion-funnel-chart-module_step-rate__A0irB{color:#1e1e1e;display:block;font-family:var(--step-font-family,"SF Pro");font-size:13px;font-style:normal;font-weight:500;line-height:20px;margin:0}.conversion-funnel-chart-module_bar-container__5Dl5-{align-items:flex-end;background-color:var(--light-background-color,rgba(79,70,229,.08));border-radius:4px;cursor:pointer;display:flex;flex:1;position:relative;transition:all .2s ease}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_selected__W40FY{background-color:var(--light-background-color,rgba(79,70,229,.15))}.conversion-funnel-chart-module_bar-container__5Dl5-.conversion-funnel-chart-module_disabled__Reovk{cursor:pointer}.conversion-funnel-chart-module_funnel-bar__tG5m3{background-color:var(--primary-color,#4f46e5);border-radius:4px 4px 0 0;min-height:4px;transition:all .3s ease;width:100%}.conversion-funnel-chart-module_funnel-bar__tG5m3.conversion-funnel-chart-module_selected__W40FY{box-shadow:0 4px 16px rgba(0,0,0,.2);filter:brightness(1.1)}.conversion-funnel-chart-module_tooltip-wrapper__NohPt{align-items:flex-start;background:var(--black-white-white,#fff);border-bottom:1px solid var(--Gray-Gray-5,#dcdcde);border-radius:4px!important;box-shadow:0 1px 3px 0 rgba(0,0,0,.15),0 3px 9px 0 rgba(0,0,0,.12)!important;display:inline-flex;flex-direction:column;gap:4px;justify-content:center;padding:12px!important}.conversion-funnel-chart-module_tooltip-title__hjZr3{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:16px}.conversion-funnel-chart-module_tooltip-content__ocwAP{color:#1e1e1e;font-family:SF Pro,sans-serif;font-size:13px;font-style:normal;font-weight:500;line-height:20px}.conversion-funnel-chart-module_empty-state__9c0ps{color:#6b7280;font-size:16px;padding:48px 24px;text-align:center}
@@ -0,0 +1,22 @@
1
+ import { formatNumber } from '@automattic/number-formatters';
2
+
3
+ /**
4
+ * Format a percentage value with smart decimal handling.
5
+ * Uses @automattic/number-formatters for consistent formatting.
6
+ * Removes unnecessary trailing zeros and caps at 2 decimal places.
7
+ *
8
+ * @param value - The percentage value (0-100 range)
9
+ * @return Formatted percentage string (e.g., "30%", "30.1%", "30.25%")
10
+ */
11
+ const formatPercentage = (value) => {
12
+ // Use formatNumber with percentage style, but convert from 0-100 range to 0-1 range
13
+ return formatNumber(value / 100, {
14
+ numberFormatOptions: {
15
+ style: 'percent',
16
+ minimumFractionDigits: 0,
17
+ maximumFractionDigits: 2,
18
+ },
19
+ });
20
+ };
21
+
22
+ export { formatPercentage };
@@ -28,6 +28,10 @@ interface PieChartProps extends BaseChartProps<DataPointPercentage[]> {
28
28
  * A value between 0 and 1, where 0 means no corner radius.
29
29
  */
30
30
  cornerScale?: number;
31
+ /**
32
+ * Whether to show labels on pie segments. Defaults to true.
33
+ */
34
+ showLabels?: boolean;
31
35
  /**
32
36
  * Use the children prop to render additional elements on the chart.
33
37
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/charts",
3
- "version": "0.31.0",
3
+ "version": "0.32.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": {