@automattic/charts 0.56.7 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/AGENTS.md +28 -98
  2. package/CHANGELOG.md +30 -0
  3. package/dist/charts/bar-chart/index.cjs +7 -6
  4. package/dist/charts/bar-chart/index.cjs.map +1 -1
  5. package/dist/charts/bar-chart/index.css +12 -24
  6. package/dist/charts/bar-chart/index.css.map +1 -1
  7. package/dist/charts/bar-chart/index.d.cts +3 -4
  8. package/dist/charts/bar-chart/index.d.ts +3 -4
  9. package/dist/charts/bar-chart/index.js +6 -5
  10. package/dist/charts/bar-list-chart/index.cjs +8 -7
  11. package/dist/charts/bar-list-chart/index.cjs.map +1 -1
  12. package/dist/charts/bar-list-chart/index.css +12 -24
  13. package/dist/charts/bar-list-chart/index.css.map +1 -1
  14. package/dist/charts/bar-list-chart/index.d.cts +3 -3
  15. package/dist/charts/bar-list-chart/index.d.ts +3 -3
  16. package/dist/charts/bar-list-chart/index.js +7 -6
  17. package/dist/charts/conversion-funnel-chart/index.cjs +5 -6
  18. package/dist/charts/conversion-funnel-chart/index.cjs.map +1 -1
  19. package/dist/charts/conversion-funnel-chart/index.css +0 -94
  20. package/dist/charts/conversion-funnel-chart/index.css.map +1 -1
  21. package/dist/charts/conversion-funnel-chart/index.d.cts +1 -1
  22. package/dist/charts/conversion-funnel-chart/index.d.ts +1 -1
  23. package/dist/charts/conversion-funnel-chart/index.js +4 -5
  24. package/dist/charts/geo-chart/index.cjs +4 -4
  25. package/dist/charts/geo-chart/index.css +0 -94
  26. package/dist/charts/geo-chart/index.css.map +1 -1
  27. package/dist/charts/geo-chart/index.d.cts +1 -1
  28. package/dist/charts/geo-chart/index.d.ts +1 -1
  29. package/dist/charts/geo-chart/index.js +3 -3
  30. package/dist/charts/leaderboard-chart/index.cjs +7 -6
  31. package/dist/charts/leaderboard-chart/index.cjs.map +1 -1
  32. package/dist/charts/leaderboard-chart/index.css +20 -33
  33. package/dist/charts/leaderboard-chart/index.css.map +1 -1
  34. package/dist/charts/leaderboard-chart/index.d.cts +3 -3
  35. package/dist/charts/leaderboard-chart/index.d.ts +3 -3
  36. package/dist/charts/leaderboard-chart/index.js +6 -5
  37. package/dist/charts/line-chart/index.cjs +7 -6
  38. package/dist/charts/line-chart/index.cjs.map +1 -1
  39. package/dist/charts/line-chart/index.css +12 -24
  40. package/dist/charts/line-chart/index.css.map +1 -1
  41. package/dist/charts/line-chart/index.d.cts +3 -4
  42. package/dist/charts/line-chart/index.d.ts +3 -4
  43. package/dist/charts/line-chart/index.js +6 -5
  44. package/dist/charts/pie-chart/index.cjs +7 -7
  45. package/dist/charts/pie-chart/index.css +12 -24
  46. package/dist/charts/pie-chart/index.css.map +1 -1
  47. package/dist/charts/pie-chart/index.d.cts +7 -13
  48. package/dist/charts/pie-chart/index.d.ts +7 -13
  49. package/dist/charts/pie-chart/index.js +6 -6
  50. package/dist/charts/pie-semi-circle-chart/index.cjs +7 -7
  51. package/dist/charts/pie-semi-circle-chart/index.css +12 -24
  52. package/dist/charts/pie-semi-circle-chart/index.css.map +1 -1
  53. package/dist/charts/pie-semi-circle-chart/index.d.cts +7 -13
  54. package/dist/charts/pie-semi-circle-chart/index.d.ts +7 -13
  55. package/dist/charts/pie-semi-circle-chart/index.js +6 -6
  56. package/dist/charts/sparkline/index.cjs +8 -7
  57. package/dist/charts/sparkline/index.cjs.map +1 -1
  58. package/dist/charts/sparkline/index.css +12 -24
  59. package/dist/charts/sparkline/index.css.map +1 -1
  60. package/dist/charts/sparkline/index.js +7 -6
  61. package/dist/{chunk-RFSHE3HL.js → chunk-2I67QUIV.js} +84 -431
  62. package/dist/chunk-2I67QUIV.js.map +1 -0
  63. package/dist/{chunk-OMS5QIJN.js → chunk-2ICEEQOC.js} +31 -25
  64. package/dist/chunk-2ICEEQOC.js.map +1 -0
  65. package/dist/{chunk-GWBS65VC.js → chunk-4B7BL2DD.js} +3 -3
  66. package/dist/{chunk-7FDQGBY7.js → chunk-4OXMTKAL.js} +24 -24
  67. package/dist/chunk-4OXMTKAL.js.map +1 -0
  68. package/dist/{chunk-SSFFCBCF.js → chunk-B6NLZFRW.js} +32 -26
  69. package/dist/chunk-B6NLZFRW.js.map +1 -0
  70. package/dist/{chunk-3EXJP67N.cjs → chunk-BBAUQOW6.cjs} +9 -9
  71. package/dist/{chunk-3EXJP67N.cjs.map → chunk-BBAUQOW6.cjs.map} +1 -1
  72. package/dist/{chunk-NQJE2CC7.cjs → chunk-CMMHCTBX.cjs} +45 -45
  73. package/dist/chunk-CMMHCTBX.cjs.map +1 -0
  74. package/dist/{chunk-O2JIANHK.cjs → chunk-CPPXJATQ.cjs} +51 -45
  75. package/dist/chunk-CPPXJATQ.cjs.map +1 -0
  76. package/dist/{chunk-MDRCAGKZ.js → chunk-DKU775VC.js} +3 -3
  77. package/dist/{chunk-BXFD7JIG.cjs → chunk-GRA7Y2ZG.cjs} +46 -46
  78. package/dist/chunk-GRA7Y2ZG.cjs.map +1 -0
  79. package/dist/{chunk-TE63Y5PX.js → chunk-JJIMABHT.js} +10 -3
  80. package/dist/chunk-JJIMABHT.js.map +1 -0
  81. package/dist/{chunk-KHQPN77E.js → chunk-KJHWXOCZ.js} +4 -4
  82. package/dist/{chunk-6CCZL2JJ.js → chunk-KRWGSOJ2.js} +30 -2
  83. package/dist/chunk-KRWGSOJ2.js.map +1 -0
  84. package/dist/{chunk-VPAEBI2F.js → chunk-LTFH7SEG.js} +24 -24
  85. package/dist/chunk-LTFH7SEG.js.map +1 -0
  86. package/dist/{chunk-E62LCBGD.js → chunk-MUNOKLLE.js} +3 -3
  87. package/dist/{chunk-ZVGEDXDP.cjs → chunk-MXGLYWVP.cjs} +10 -3
  88. package/dist/chunk-MXGLYWVP.cjs.map +1 -0
  89. package/dist/{chunk-55ZCOYDF.cjs → chunk-OYC34VTO.cjs} +252 -827
  90. package/dist/chunk-OYC34VTO.cjs.map +1 -0
  91. package/dist/{chunk-CAFJRZPZ.cjs → chunk-PQL5I3F6.cjs} +17 -17
  92. package/dist/{chunk-CAFJRZPZ.cjs.map → chunk-PQL5I3F6.cjs.map} +1 -1
  93. package/dist/{chunk-UFRBUT2D.cjs → chunk-REZTQ4PH.cjs} +87 -24
  94. package/dist/chunk-REZTQ4PH.cjs.map +1 -0
  95. package/dist/{chunk-RCY6XLGU.cjs → chunk-TZRUHQOH.cjs} +36 -8
  96. package/dist/chunk-TZRUHQOH.cjs.map +1 -0
  97. package/dist/{chunk-XD2HV7M5.js → chunk-UTYVIOWZ.js} +226 -801
  98. package/dist/chunk-UTYVIOWZ.js.map +1 -0
  99. package/dist/{chunk-YAXY5L7I.cjs → chunk-W2LDIX26.cjs} +5 -5
  100. package/dist/{chunk-YAXY5L7I.cjs.map → chunk-W2LDIX26.cjs.map} +1 -1
  101. package/dist/{chunk-K6TGILHX.cjs → chunk-WSG64BVN.cjs} +6 -6
  102. package/dist/{chunk-K6TGILHX.cjs.map → chunk-WSG64BVN.cjs.map} +1 -1
  103. package/dist/chunk-WTQYGUNF.js +400 -0
  104. package/dist/chunk-WTQYGUNF.js.map +1 -0
  105. package/dist/{chunk-YDVHT7GS.cjs → chunk-WYK7EL5R.cjs} +100 -447
  106. package/dist/chunk-WYK7EL5R.cjs.map +1 -0
  107. package/dist/{chunk-X7JL2NYJ.cjs → chunk-XC4KHJYX.cjs} +51 -45
  108. package/dist/chunk-XC4KHJYX.cjs.map +1 -0
  109. package/dist/chunk-XVBH5XHE.cjs +400 -0
  110. package/dist/chunk-XVBH5XHE.cjs.map +1 -0
  111. package/dist/{chunk-IS5YYLTV.js → chunk-YAFQVVDI.js} +85 -22
  112. package/dist/chunk-YAFQVVDI.js.map +1 -0
  113. package/dist/components/legend/index.cjs +4 -3
  114. package/dist/components/legend/index.cjs.map +1 -1
  115. package/dist/components/legend/index.css +12 -24
  116. package/dist/components/legend/index.css.map +1 -1
  117. package/dist/components/legend/index.d.cts +4 -4
  118. package/dist/components/legend/index.d.ts +4 -4
  119. package/dist/components/legend/index.js +3 -2
  120. package/dist/components/tooltip/index.d.cts +1 -1
  121. package/dist/components/tooltip/index.d.ts +1 -1
  122. package/dist/hooks/index.cjs +3 -5
  123. package/dist/hooks/index.cjs.map +1 -1
  124. package/dist/hooks/index.css +0 -94
  125. package/dist/hooks/index.css.map +1 -1
  126. package/dist/hooks/index.d.cts +9 -13
  127. package/dist/hooks/index.d.ts +9 -13
  128. package/dist/hooks/index.js +2 -4
  129. package/dist/index.cjs +18 -17
  130. package/dist/index.cjs.map +1 -1
  131. package/dist/index.css +20 -33
  132. package/dist/index.css.map +1 -1
  133. package/dist/index.d.cts +6 -6
  134. package/dist/index.d.ts +6 -6
  135. package/dist/index.js +17 -16
  136. package/dist/{leaderboard-chart-COtgamhe.d.cts → leaderboard-chart-BSbg0ufV.d.cts} +3 -11
  137. package/dist/{leaderboard-chart-BSgEw_Um.d.ts → leaderboard-chart-odEYxxEC.d.ts} +3 -11
  138. package/dist/{legend-C9ahiwOt.d.cts → legend-DFkosEvC.d.cts} +1 -1
  139. package/dist/{legend-jjMmhSg3.d.ts → legend-DLswHhOk.d.ts} +1 -1
  140. package/dist/providers/index.cjs +3 -3
  141. package/dist/providers/index.css +0 -94
  142. package/dist/providers/index.css.map +1 -1
  143. package/dist/providers/index.d.cts +3 -3
  144. package/dist/providers/index.d.ts +3 -3
  145. package/dist/providers/index.js +2 -2
  146. package/dist/{themes-CVR5rmIs.d.cts → themes-D0qc5JaW.d.cts} +2 -2
  147. package/dist/{themes-DQzmaSze.d.ts → themes-itO4Ht5g.d.ts} +2 -2
  148. package/dist/{types-BBwg4Evw.d.cts → types-B5f6XQ7Q.d.cts} +1 -1
  149. package/dist/{types-DQNnq5Fr.d.ts → types-BsHooDbM.d.ts} +1 -1
  150. package/dist/{types-C05PdDJa.d.cts → types-BuSrRM4p.d.ts} +15 -23
  151. package/dist/{types-CzdN7rUe.d.cts → types-ChOUI9-N.d.cts} +90 -46
  152. package/dist/{types-CzdN7rUe.d.ts → types-ChOUI9-N.d.ts} +90 -46
  153. package/dist/{types-C05PdDJa.d.ts → types-Dfw9VOKI.d.cts} +15 -23
  154. package/dist/utils/index.cjs +2 -2
  155. package/dist/utils/index.d.cts +1 -1
  156. package/dist/utils/index.d.ts +1 -1
  157. package/dist/utils/index.js +1 -1
  158. package/package.json +10 -8
  159. package/src/charts/bar-chart/bar-chart.tsx +19 -19
  160. package/src/charts/bar-chart/test/bar-chart.test.tsx +78 -31
  161. package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +2 -2
  162. package/src/charts/leaderboard-chart/hooks/use-leaderboard-legend-items.ts +0 -2
  163. package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +9 -10
  164. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +124 -102
  165. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +61 -33
  166. package/src/charts/leaderboard-chart/test/use-leaderboard-legend-items.test.tsx +2 -5
  167. package/src/charts/leaderboard-chart/types.ts +2 -15
  168. package/src/charts/line-chart/line-chart.tsx +18 -17
  169. package/src/charts/line-chart/test/line-chart.test.tsx +49 -27
  170. package/src/charts/line-chart/types.ts +0 -1
  171. package/src/charts/pie-chart/pie-chart.tsx +23 -23
  172. package/src/charts/pie-chart/test/composition-api.test.tsx +41 -0
  173. package/src/charts/pie-chart/test/pie-chart.test.tsx +9 -9
  174. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +21 -24
  175. package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +33 -5
  176. package/src/charts/private/chart-composition/index.ts +2 -0
  177. package/src/charts/private/chart-composition/render-legend-slot.ts +22 -0
  178. package/src/charts/private/chart-composition/test/render-legend-slot.test.tsx +60 -0
  179. package/src/charts/private/chart-composition/test/use-chart-children.test.tsx +91 -0
  180. package/src/charts/private/chart-composition/use-chart-children.ts +34 -2
  181. package/src/components/legend/private/base-legend.module.scss +19 -37
  182. package/src/components/legend/private/base-legend.tsx +32 -24
  183. package/src/components/legend/test/legend.test.tsx +148 -52
  184. package/src/components/legend/types.ts +23 -24
  185. package/src/hooks/index.ts +0 -1
  186. package/src/hooks/test/use-zero-value-display.test.tsx +206 -0
  187. package/src/hooks/use-zero-value-display.ts +52 -23
  188. package/src/providers/chart-context/test/chart-context.test.tsx +12 -6
  189. package/src/providers/chart-context/themes.ts +6 -4
  190. package/src/types.ts +93 -44
  191. package/src/utils/date-parsing.ts +10 -1
  192. package/src/utils/get-styles.ts +1 -1
  193. package/src/utils/test/date-parsing.test.ts +12 -0
  194. package/src/utils/test/get-styles.test.ts +12 -10
  195. package/src/utils/test/resolve-css-var.test.ts +2 -2
  196. package/tsup.config.ts +1 -1
  197. package/dist/chunk-55ZCOYDF.cjs.map +0 -1
  198. package/dist/chunk-6CCZL2JJ.js.map +0 -1
  199. package/dist/chunk-7FDQGBY7.js.map +0 -1
  200. package/dist/chunk-BXFD7JIG.cjs.map +0 -1
  201. package/dist/chunk-IS5YYLTV.js.map +0 -1
  202. package/dist/chunk-KNIMXN6Z.js +0 -51
  203. package/dist/chunk-KNIMXN6Z.js.map +0 -1
  204. package/dist/chunk-NQJE2CC7.cjs.map +0 -1
  205. package/dist/chunk-O2JIANHK.cjs.map +0 -1
  206. package/dist/chunk-OMS5QIJN.js.map +0 -1
  207. package/dist/chunk-RCY6XLGU.cjs.map +0 -1
  208. package/dist/chunk-RFSHE3HL.js.map +0 -1
  209. package/dist/chunk-SSFFCBCF.js.map +0 -1
  210. package/dist/chunk-SUDERBUA.cjs +0 -51
  211. package/dist/chunk-SUDERBUA.cjs.map +0 -1
  212. package/dist/chunk-TE63Y5PX.js.map +0 -1
  213. package/dist/chunk-UFRBUT2D.cjs.map +0 -1
  214. package/dist/chunk-VPAEBI2F.js.map +0 -1
  215. package/dist/chunk-X7JL2NYJ.cjs.map +0 -1
  216. package/dist/chunk-XD2HV7M5.js.map +0 -1
  217. package/dist/chunk-YDVHT7GS.cjs.map +0 -1
  218. package/dist/chunk-ZVGEDXDP.cjs.map +0 -1
  219. package/src/hooks/use-has-legend-child.ts +0 -22
  220. /package/dist/{chunk-GWBS65VC.js.map → chunk-4B7BL2DD.js.map} +0 -0
  221. /package/dist/{chunk-MDRCAGKZ.js.map → chunk-DKU775VC.js.map} +0 -0
  222. /package/dist/{chunk-KHQPN77E.js.map → chunk-KJHWXOCZ.js.map} +0 -0
  223. /package/dist/{chunk-E62LCBGD.js.map → chunk-MUNOKLLE.js.map} +0 -0
@@ -1,32 +1,24 @@
1
1
  import { LegendOrdinal } from '@visx/legend';
2
+ import { j as LegendPosition, h as LegendItemStyles, i as LegendLabelStyles, k as LegendShapeStyles } from './types-ChOUI9-N.cjs';
2
3
  import { GlyphProps, LineStyles } from '@visx/xychart';
3
4
  import { ComponentProps, ReactNode, CSSProperties } from 'react';
4
5
 
5
- type LegendOrdinalProps = Omit<ComponentProps<typeof LegendOrdinal>, 'scale' | 'direction'>;
6
- type BaseLegendProps = Omit<LegendOrdinalProps, 'shapeStyle'> & {
6
+ type VisxLegendProps = Pick<ComponentProps<typeof LegendOrdinal>, 'className' | 'shape' | 'fill' | 'size' | 'labelFormat' | 'labelTransform'>;
7
+ type BaseLegendProps = VisxLegendProps & {
7
8
  items: BaseLegendItem[];
8
9
  orientation?: 'horizontal' | 'vertical';
9
- /**
10
- * TODO: Add 'left' | 'right' positioning support in future implementation
11
- */
12
- position?: 'top' | 'bottom';
10
+ position?: LegendPosition;
13
11
  alignment?: 'start' | 'center' | 'end';
14
- /**
15
- * Maximum width for legend items. When set, text overflow behavior is controlled by textOverflow prop.
16
- * Should be a CSS value string (e.g. '200px', '50%', '10rem')
17
- */
18
- maxWidth?: string;
19
- /**
20
- * Controls how text behaves when it exceeds maxWidth.
21
- * - 'ellipsis': Truncate with ellipsis (ideal for widgets/small devices)
22
- * - 'wrap': Wrap text to multiple lines (default, ideal for larger displays)
23
- */
24
- textOverflow?: 'ellipsis' | 'wrap';
25
- /**
26
- * Additional CSS class name for legend items.
27
- * This allows consumers to customize individual legend item styling.
28
- */
29
- legendItemClassName?: string;
12
+ /** Additional CSS class name for legend items. */
13
+ itemClassName?: string;
14
+ /** CSS styles for each legend item (margin, flexDirection). */
15
+ itemStyles?: LegendItemStyles;
16
+ /** Additional CSS class name for legend labels. */
17
+ labelClassName?: string;
18
+ /** CSS styles for legend labels (justifyContent, flex, margin). */
19
+ labelStyles?: LegendLabelStyles;
20
+ /** Styles for legend shapes (width, height, margin). */
21
+ shapeStyles?: LegendShapeStyles;
30
22
  /**
31
23
  * Function for rendering a custom legend layout.
32
24
  */
@@ -47,7 +39,7 @@ type LegendProps = Omit<BaseLegendProps, 'items'> & {
47
39
  };
48
40
  type BaseLegendItem = {
49
41
  label: string;
50
- value: number | string;
42
+ value?: number | string;
51
43
  color: string;
52
44
  glyphSize?: number;
53
45
  renderGlyph?: <Datum extends object>(props: GlyphProps<Datum>) => ReactNode;
@@ -18,7 +18,7 @@
18
18
 
19
19
 
20
20
 
21
- var _chunkZVGEDXDPcjs = require('../chunk-ZVGEDXDP.cjs');
21
+ var _chunkMXGLYWVPcjs = require('../chunk-MXGLYWVP.cjs');
22
22
  require('../chunk-EMMSS5I5.cjs');
23
23
 
24
24
 
@@ -40,5 +40,5 @@ require('../chunk-EMMSS5I5.cjs');
40
40
 
41
41
 
42
42
 
43
- exports.attachSubComponents = _chunkZVGEDXDPcjs.attachSubComponents; exports.formatMetricValue = _chunkZVGEDXDPcjs.formatMetricValue; exports.formatPercentage = _chunkZVGEDXDPcjs.formatPercentage; exports.getColorDistance = _chunkZVGEDXDPcjs.getColorDistance; exports.getItemShapeStyles = _chunkZVGEDXDPcjs.getItemShapeStyles; exports.getLongestTickWidth = _chunkZVGEDXDPcjs.getLongestTickWidth; exports.getSeriesLineStyles = _chunkZVGEDXDPcjs.getSeriesLineStyles; exports.getSeriesStroke = _chunkZVGEDXDPcjs.getSeriesStroke; exports.hexToRgba = _chunkZVGEDXDPcjs.hexToRgba; exports.isSafari = _chunkZVGEDXDPcjs.isSafari; exports.isValidHexColor = _chunkZVGEDXDPcjs.isValidHexColor; exports.lightenHexColor = _chunkZVGEDXDPcjs.lightenHexColor; exports.mergeThemes = _chunkZVGEDXDPcjs.mergeThemes; exports.normalizeColorToHex = _chunkZVGEDXDPcjs.normalizeColorToHex; exports.parseAsLocalDate = _chunkZVGEDXDPcjs.parseAsLocalDate; exports.parseHslString = _chunkZVGEDXDPcjs.parseHslString; exports.parseRgbString = _chunkZVGEDXDPcjs.parseRgbString; exports.resolveCssVariable = _chunkZVGEDXDPcjs.resolveCssVariable; exports.validateHexColor = _chunkZVGEDXDPcjs.validateHexColor;
43
+ exports.attachSubComponents = _chunkMXGLYWVPcjs.attachSubComponents; exports.formatMetricValue = _chunkMXGLYWVPcjs.formatMetricValue; exports.formatPercentage = _chunkMXGLYWVPcjs.formatPercentage; exports.getColorDistance = _chunkMXGLYWVPcjs.getColorDistance; exports.getItemShapeStyles = _chunkMXGLYWVPcjs.getItemShapeStyles; exports.getLongestTickWidth = _chunkMXGLYWVPcjs.getLongestTickWidth; exports.getSeriesLineStyles = _chunkMXGLYWVPcjs.getSeriesLineStyles; exports.getSeriesStroke = _chunkMXGLYWVPcjs.getSeriesStroke; exports.hexToRgba = _chunkMXGLYWVPcjs.hexToRgba; exports.isSafari = _chunkMXGLYWVPcjs.isSafari; exports.isValidHexColor = _chunkMXGLYWVPcjs.isValidHexColor; exports.lightenHexColor = _chunkMXGLYWVPcjs.lightenHexColor; exports.mergeThemes = _chunkMXGLYWVPcjs.mergeThemes; exports.normalizeColorToHex = _chunkMXGLYWVPcjs.normalizeColorToHex; exports.parseAsLocalDate = _chunkMXGLYWVPcjs.parseAsLocalDate; exports.parseHslString = _chunkMXGLYWVPcjs.parseHslString; exports.parseRgbString = _chunkMXGLYWVPcjs.parseRgbString; exports.resolveCssVariable = _chunkMXGLYWVPcjs.resolveCssVariable; exports.validateHexColor = _chunkMXGLYWVPcjs.validateHexColor;
44
44
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  export { M as MetricValueType, f as formatMetricValue } from '../format-metric-value-MXm5DtQ_.cjs';
2
2
  import { TickFormatter } from '@visx/axis';
3
3
  import { AnyD3Scale, ScaleInput } from '@visx/scale';
4
- import { j as SeriesData, C as ChartTheme, b as CompleteChartTheme } from '../types-CzdN7rUe.cjs';
4
+ import { o as SeriesData, b as ChartTheme, c as CompleteChartTheme } from '../types-ChOUI9-N.cjs';
5
5
  import { LegendShape } from '@visx/legend/lib/types';
6
6
  import { LineStyles } from '@visx/xychart';
7
7
  import '@visx/annotation/lib/components/CircleSubject';
@@ -1,7 +1,7 @@
1
1
  export { M as MetricValueType, f as formatMetricValue } from '../format-metric-value-MXm5DtQ_.js';
2
2
  import { TickFormatter } from '@visx/axis';
3
3
  import { AnyD3Scale, ScaleInput } from '@visx/scale';
4
- import { j as SeriesData, C as ChartTheme, b as CompleteChartTheme } from '../types-CzdN7rUe.js';
4
+ import { o as SeriesData, b as ChartTheme, c as CompleteChartTheme } from '../types-ChOUI9-N.js';
5
5
  import { LegendShape } from '@visx/legend/lib/types';
6
6
  import { LineStyles } from '@visx/xychart';
7
7
  import '@visx/annotation/lib/components/CircleSubject';
@@ -18,7 +18,7 @@ import {
18
18
  parseRgbString,
19
19
  resolveCssVariable,
20
20
  validateHexColor
21
- } from "../chunk-TE63Y5PX.js";
21
+ } from "../chunk-JJIMABHT.js";
22
22
  import "../chunk-G3PMV62Z.js";
23
23
  export {
24
24
  attachSubComponents,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/charts",
3
- "version": "0.56.7",
3
+ "version": "0.58.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": {
@@ -177,10 +177,10 @@
177
177
  "storybook": "cd ../storybook && pnpm run storybook:dev",
178
178
  "test": "TZ=UTC jest --config=tests/jest.config.cjs",
179
179
  "test-coverage": "pnpm run test --coverage",
180
- "typecheck": "tsc --noEmit"
180
+ "typecheck": "tsgo --noEmit"
181
181
  },
182
182
  "dependencies": {
183
- "@automattic/number-formatters": "^1.1.0",
183
+ "@automattic/number-formatters": "^1.1.2",
184
184
  "@babel/runtime": "7.28.6",
185
185
  "@react-spring/web": "9.7.5",
186
186
  "@visx/annotation": "^3.12.0",
@@ -200,8 +200,8 @@
200
200
  "@visx/vendor": "^3.12.0",
201
201
  "@visx/xychart": "^3.12.0",
202
202
  "@wordpress/i18n": "^6.0.0",
203
- "@wordpress/theme": "0.7.0",
204
- "@wordpress/ui": "0.7.0",
203
+ "@wordpress/theme": "0.8.0",
204
+ "@wordpress/ui": "0.8.0",
205
205
  "clsx": "2.1.1",
206
206
  "date-fns": "^4.1.0",
207
207
  "deepmerge": "4.3.1",
@@ -224,21 +224,23 @@
224
224
  "@types/jest": "^30.0.0",
225
225
  "@types/react": "18.3.28",
226
226
  "@types/react-dom": "18.3.7",
227
+ "@typescript/native-preview": "7.0.0-dev.20260225.1",
227
228
  "@visx/glyph": "3.12.0",
228
- "@wordpress/components": "32.2.0",
229
- "@wordpress/element": "6.40.0",
229
+ "@wordpress/components": "32.3.0",
230
+ "@wordpress/element": "6.41.0",
230
231
  "babel-jest": "30.2.0",
231
232
  "babel-plugin-react-remove-properties": "^0.3.1",
232
233
  "esbuild": "0.25.9",
233
234
  "esbuild-plugin-babel": "^0.2.3",
234
235
  "esbuild-sass-plugin": "^3.1.0",
236
+ "identity-obj-proxy": "^3.0.0",
235
237
  "jest": "30.2.0",
236
238
  "jest-extended": "7.0.0",
237
239
  "postcss": "8.5.6",
238
240
  "postcss-modules": "6.0.1",
239
241
  "react": "18.3.1",
240
242
  "react-dom": "18.3.1",
241
- "sass-embedded": "1.97.2",
243
+ "sass-embedded": "1.97.3",
242
244
  "storybook": "10.2.11",
243
245
  "tsup": "8.5.1",
244
246
  "typescript": "5.9.3"
@@ -13,7 +13,6 @@ import {
13
13
  useZeroValueDisplay,
14
14
  useChartMargin,
15
15
  useElementSize,
16
- useHasLegendChild,
17
16
  usePrefersReducedMotion,
18
17
  } from '../../hooks';
19
18
  import {
@@ -25,6 +24,7 @@ import {
25
24
  GlobalChartsContext,
26
25
  } from '../../providers';
27
26
  import { attachSubComponents } from '../../utils';
27
+ import { useChartChildren, renderLegendSlot } from '../private/chart-composition';
28
28
  import { SingleChartContext } from '../private/single-chart-context';
29
29
  import { withResponsive } from '../private/with-responsive';
30
30
  import styles from './bar-chart.module.scss';
@@ -39,7 +39,6 @@ export interface BarChartProps extends BaseChartProps< SeriesData[] > {
39
39
  orientation?: 'horizontal' | 'vertical';
40
40
  withPatterns?: boolean;
41
41
  showZeroValues?: boolean;
42
- legendInteractive?: boolean;
43
42
  children?: ReactNode;
44
43
  }
45
44
 
@@ -85,24 +84,18 @@ const BarChartInternal: FC< BarChartProps > = ( {
85
84
  margin,
86
85
  withTooltips = false,
87
86
  showLegend = false,
88
- legendOrientation = 'horizontal',
89
- legendPosition = 'bottom',
90
- legendAlignment = 'center',
91
- legendMaxWidth,
92
- legendTextOverflow = 'wrap',
93
- legendItemClassName,
94
- legendShape = 'rect',
87
+ legend = {},
95
88
  gridVisibility: gridVisibilityProp,
96
89
  renderTooltip,
97
90
  options = {},
98
91
  orientation = 'vertical',
99
92
  withPatterns = false,
100
93
  showZeroValues = false,
101
- legendInteractive = false,
102
94
  animation,
103
95
  children,
104
96
  gap = 'md',
105
97
  } ) => {
98
+ const legendInteractive = legend.interactive ?? false;
106
99
  const horizontal = orientation === 'horizontal';
107
100
  const chartId = useChartId( providedChartId );
108
101
  const theme = useXYChartTheme( data );
@@ -110,8 +103,10 @@ const BarChartInternal: FC< BarChartProps > = ( {
110
103
  const dataSorted = useChartDataTransform( data );
111
104
 
112
105
  // Transform data to add a small value for zero bars to make them visible
106
+ // For vertical bars, height determines bar pixel height; for horizontal bars, width does
113
107
  const dataWithVisibleZeros = useZeroValueDisplay( dataSorted, {
114
108
  enabled: showZeroValues,
109
+ valueAxisLength: horizontal ? width : height,
115
110
  } );
116
111
 
117
112
  // Create legend items using the reusable hook
@@ -121,8 +116,9 @@ const BarChartInternal: FC< BarChartProps > = ( {
121
116
  const [ svgWrapperRef, , svgWrapperHeight ] = useElementSize< HTMLDivElement >();
122
117
  const chartRef = useRef< HTMLDivElement >( null );
123
118
 
124
- // Check if children contain a Legend component (composition pattern)
125
- const hasLegendChild = useHasLegendChild( children );
119
+ // Process children for composition API (Legend, etc.)
120
+ const { legendChildren, nonLegendChildren } = useChartChildren( children, 'BarChart' );
121
+ const hasLegendChild = legendChildren.length > 0;
126
122
 
127
123
  // Use the measured SVG wrapper height, falling back to the passed height if provided.
128
124
  // When there's a legend (via prop or composition), we must wait for measurement because
@@ -325,16 +321,18 @@ const BarChartInternal: FC< BarChartProps > = ( {
325
321
  const gridVisibility = gridVisibilityProp ?? chartOptions.gridVisibility;
326
322
  const highlightedBarStyle = createKeyboardHighlightStyle();
327
323
 
324
+ const legendPosition = legend.position ?? 'bottom';
328
325
  const legendElement = showLegend && (
329
326
  <Legend
330
- orientation={ legendOrientation }
327
+ orientation={ legend.orientation ?? 'horizontal' }
331
328
  position={ legendPosition }
332
- alignment={ legendAlignment }
333
- maxWidth={ legendMaxWidth }
334
- textOverflow={ legendTextOverflow }
335
- legendItemClassName={ legendItemClassName }
329
+ alignment={ legend.alignment ?? 'center' }
330
+ labelStyles={ legend.labelStyles }
331
+ itemClassName={ legend.itemClassName }
332
+ itemStyles={ legend.itemStyles }
333
+ shapeStyles={ legend.shapeStyles }
336
334
  className={ styles[ 'bar-chart__legend' ] }
337
- shape={ legendShape }
335
+ shape={ legend.shape ?? 'rect' }
338
336
  chartId={ chartId }
339
337
  interactive={ legendInteractive }
340
338
  />
@@ -369,6 +367,7 @@ const BarChartInternal: FC< BarChartProps > = ( {
369
367
  data-chart-id={ `bar-chart-${ chartId }` }
370
368
  >
371
369
  { legendPosition === 'top' && legendElement }
370
+ { renderLegendSlot( legendChildren, 'top' ) }
372
371
 
373
372
  <div
374
373
  className={ styles[ 'bar-chart__svg-wrapper' ] }
@@ -482,8 +481,9 @@ const BarChartInternal: FC< BarChartProps > = ( {
482
481
  </div>
483
482
 
484
483
  { legendPosition === 'bottom' && legendElement }
484
+ { renderLegendSlot( legendChildren, 'bottom' ) }
485
485
 
486
- { children }
486
+ { nonLegendChildren }
487
487
  </Stack>
488
488
  </SingleChartContext.Provider>
489
489
  );
@@ -26,10 +26,12 @@ describe( 'BarChart', () => {
26
26
  ],
27
27
  };
28
28
 
29
- const renderWithTheme = ( props = {} ) => {
29
+ const renderWithTheme = ( props = {}, children = undefined ) => {
30
30
  return render(
31
31
  <GlobalChartsProvider>
32
- <BarChart { ...defaultProps } { ...props } />
32
+ <BarChart { ...defaultProps } { ...props }>
33
+ { children }
34
+ </BarChart>
33
35
  </GlobalChartsProvider>
34
36
  );
35
37
  };
@@ -123,39 +125,54 @@ describe( 'BarChart', () => {
123
125
  } );
124
126
 
125
127
  describe( 'Legend', () => {
128
+ const multiSeriesData = [
129
+ {
130
+ label: 'Series A',
131
+ data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
132
+ options: {},
133
+ },
134
+ {
135
+ label: 'Series B',
136
+ data: [ { date: new Date( '2024-01-01' ), value: 20, label: 'Jan 1' } ],
137
+ options: {},
138
+ },
139
+ ];
140
+
126
141
  test( 'shows legend when showLegend is true', () => {
127
- renderWithTheme( {
128
- showLegend: true,
129
- data: [
130
- {
131
- label: 'Series A',
132
- data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
133
- options: {},
134
- },
135
- {
136
- label: 'Series B',
137
- data: [ { date: new Date( '2024-01-01' ), value: 20, label: 'Jan 1' } ],
138
- options: {},
139
- },
140
- ],
141
- } );
142
+ renderWithTheme( { showLegend: true, data: multiSeriesData } );
142
143
  expect( screen.getByText( 'Series A' ) ).toBeInTheDocument();
143
144
  expect( screen.getByText( 'Series B' ) ).toBeInTheDocument();
144
145
  } );
145
146
 
146
147
  test( 'hides legend when showLegend is false', () => {
147
- renderWithTheme( {
148
- showLegend: false,
149
- data: [
150
- {
151
- label: 'Series A',
152
- data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
153
- options: {},
154
- },
155
- ],
156
- } );
148
+ renderWithTheme( { showLegend: false, data: multiSeriesData } );
157
149
  expect( screen.queryByText( 'Series A' ) ).not.toBeInTheDocument();
158
150
  } );
151
+
152
+ test( 'renders composition legend as child component', () => {
153
+ renderWithTheme( { data: multiSeriesData }, <BarChart.Legend /> );
154
+
155
+ expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength( 2 );
156
+ expect( screen.getByText( 'Series A' ) ).toBeInTheDocument();
157
+ expect( screen.getByText( 'Series B' ) ).toBeInTheDocument();
158
+ } );
159
+
160
+ test( 'renders composition legend regardless of showLegend value', () => {
161
+ renderWithTheme( { data: multiSeriesData, showLegend: false }, <BarChart.Legend /> );
162
+
163
+ expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength( 2 );
164
+ } );
165
+
166
+ test( 'renders composition legend in top position', () => {
167
+ renderWithTheme( { data: multiSeriesData }, <BarChart.Legend position="top" /> );
168
+
169
+ // Legend should appear before the chart content in DOM order
170
+ expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength( 2 );
171
+ const html = document.body.innerHTML;
172
+ expect( html.indexOf( 'data-testid="legend-horizontal"' ) ).toBeLessThan(
173
+ html.indexOf( 'role="grid"' )
174
+ );
175
+ } );
159
176
  } );
160
177
 
161
178
  describe( 'Grid Visibility', () => {
@@ -562,6 +579,36 @@ describe( 'BarChart', () => {
562
579
  expect( width ).toBeGreaterThan( 0 );
563
580
  } );
564
581
  } );
582
+
583
+ test( 'ensures minimum pixel height for zero values in small charts', () => {
584
+ // With a small chart height (100px) and large data range, zero-value bars
585
+ // should still be visible (at least 3px based on MIN_PIXEL_HEIGHT)
586
+ renderWithTheme( {
587
+ showZeroValues: true,
588
+ height: 100,
589
+ data: [
590
+ {
591
+ label: 'Test Series',
592
+ data: [
593
+ { label: 'Zero', value: 0 },
594
+ { label: 'Large', value: 10000 },
595
+ ],
596
+ options: {},
597
+ },
598
+ ],
599
+ } );
600
+
601
+ const svgElement = screen.getByRole( 'grid', { name: /bar chart/i } ).querySelector( 'svg' );
602
+ const bars = svgElement?.querySelectorAll( '.visx-bar-group rect' );
603
+
604
+ expect( bars?.length ).toBe( 2 );
605
+
606
+ // The zero-value bar (first bar) should have a minimum visible height.
607
+ // We check for >= 2px to allow for rounding in the pixel calculation.
608
+ const zeroBar = bars?.[ 0 ];
609
+ const zeroBarHeight = parseFloat( zeroBar?.getAttribute( 'height' ) || '0' );
610
+ expect( zeroBarHeight ).toBeGreaterThanOrEqual( 2 );
611
+ } );
565
612
  } );
566
613
 
567
614
  /* eslint-enable testing-library/no-node-access */
@@ -713,7 +760,7 @@ describe( 'BarChart', () => {
713
760
 
714
761
  renderWithTheme( {
715
762
  showLegend: true,
716
- legendInteractive: true,
763
+ legend: { interactive: true },
717
764
  chartId: 'test-interactive-bar-chart',
718
765
  data: [
719
766
  {
@@ -741,7 +788,7 @@ describe( 'BarChart', () => {
741
788
  it( 'does not filter series when legendInteractive is false', () => {
742
789
  renderWithTheme( {
743
790
  showLegend: true,
744
- legendInteractive: false,
791
+ legend: { interactive: false },
745
792
  chartId: 'test-non-interactive-bar-chart',
746
793
  data: [
747
794
  {
@@ -765,7 +812,7 @@ describe( 'BarChart', () => {
765
812
  it( 'shows all series when chartId is missing even if legendInteractive is true', () => {
766
813
  renderWithTheme( {
767
814
  showLegend: true,
768
- legendInteractive: true,
815
+ legend: { interactive: true },
769
816
  // No chartId provided
770
817
  data: [
771
818
  {
@@ -793,7 +840,7 @@ describe( 'BarChart', () => {
793
840
 
794
841
  renderWithTheme( {
795
842
  showLegend: true,
796
- legendInteractive: true,
843
+ legend: { interactive: true },
797
844
  chartId: 'test-all-hidden-bar-chart',
798
845
  data: [
799
846
  {
@@ -372,7 +372,7 @@ describe( 'ConversionFunnelChart', () => {
372
372
  expect( customRenderMainMetric ).toHaveBeenCalledWith( {
373
373
  mainRate: 10.3,
374
374
  changeIndicator: undefined,
375
- className: undefined,
375
+ className: 'main-metric',
376
376
  changeColor: expect.any( String ),
377
377
  } );
378
378
  } );
@@ -427,7 +427,7 @@ describe( 'ConversionFunnelChart', () => {
427
427
  index: 1,
428
428
  top: expect.any( Number ),
429
429
  left: expect.any( Number ),
430
- className: undefined,
430
+ className: 'tooltip-wrapper',
431
431
  } );
432
432
  } );
433
433
 
@@ -53,7 +53,6 @@ export function useLeaderboardLegendItems( {
53
53
 
54
54
  items.push( {
55
55
  label: legendLabels?.primary || __( 'Current period', 'jetpack-charts' ),
56
- value: '',
57
56
  color: resolvedPrimaryColor,
58
57
  } );
59
58
 
@@ -66,7 +65,6 @@ export function useLeaderboardLegendItems( {
66
65
 
67
66
  items.push( {
68
67
  label: legendLabels?.comparison || __( 'Previous period', 'jetpack-charts' ),
69
- value: '',
70
68
  color: resolvedSecondaryColor,
71
69
  } );
72
70
  }
@@ -1,19 +1,20 @@
1
1
  .leaderboardChart {
2
- display: flex;
3
- flex-direction: column;
4
2
  transition: opacity 0.3s ease-in-out;
5
3
 
6
- &--legend-top {
7
- flex-direction: column-reverse;
8
- }
9
-
10
- &--with-legend {
11
- gap: 16px;
4
+ &--responsive {
5
+ height: 100%;
6
+ width: 100%;
12
7
  }
13
8
 
14
9
  &--loading {
15
10
  opacity: 0.5;
16
11
  }
12
+
13
+ &__content {
14
+ flex: 1;
15
+ min-height: 0;
16
+ overflow: auto;
17
+ }
17
18
  }
18
19
 
19
20
  .barWithLabelContainer {
@@ -61,8 +62,6 @@
61
62
  }
62
63
 
63
64
  .valueContainer {
64
- display: flex;
65
- gap: 4px;
66
65
  justify-content: flex-end;
67
66
  }
68
67