@automattic/charts 0.57.0 → 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 (210) hide show
  1. package/CHANGELOG.md +16 -2
  2. package/dist/charts/bar-chart/index.cjs +7 -5
  3. package/dist/charts/bar-chart/index.cjs.map +1 -1
  4. package/dist/charts/bar-chart/index.css +12 -24
  5. package/dist/charts/bar-chart/index.css.map +1 -1
  6. package/dist/charts/bar-chart/index.d.cts +3 -4
  7. package/dist/charts/bar-chart/index.d.ts +3 -4
  8. package/dist/charts/bar-chart/index.js +6 -4
  9. package/dist/charts/bar-list-chart/index.cjs +8 -6
  10. package/dist/charts/bar-list-chart/index.cjs.map +1 -1
  11. package/dist/charts/bar-list-chart/index.css +12 -24
  12. package/dist/charts/bar-list-chart/index.css.map +1 -1
  13. package/dist/charts/bar-list-chart/index.d.cts +3 -3
  14. package/dist/charts/bar-list-chart/index.d.ts +3 -3
  15. package/dist/charts/bar-list-chart/index.js +7 -5
  16. package/dist/charts/conversion-funnel-chart/index.cjs +5 -5
  17. package/dist/charts/conversion-funnel-chart/index.css +0 -94
  18. package/dist/charts/conversion-funnel-chart/index.css.map +1 -1
  19. package/dist/charts/conversion-funnel-chart/index.d.cts +1 -1
  20. package/dist/charts/conversion-funnel-chart/index.d.ts +1 -1
  21. package/dist/charts/conversion-funnel-chart/index.js +4 -4
  22. package/dist/charts/geo-chart/index.cjs +4 -4
  23. package/dist/charts/geo-chart/index.css +0 -94
  24. package/dist/charts/geo-chart/index.css.map +1 -1
  25. package/dist/charts/geo-chart/index.d.cts +1 -1
  26. package/dist/charts/geo-chart/index.d.ts +1 -1
  27. package/dist/charts/geo-chart/index.js +3 -3
  28. package/dist/charts/leaderboard-chart/index.cjs +7 -6
  29. package/dist/charts/leaderboard-chart/index.cjs.map +1 -1
  30. package/dist/charts/leaderboard-chart/index.css +12 -24
  31. package/dist/charts/leaderboard-chart/index.css.map +1 -1
  32. package/dist/charts/leaderboard-chart/index.d.cts +3 -3
  33. package/dist/charts/leaderboard-chart/index.d.ts +3 -3
  34. package/dist/charts/leaderboard-chart/index.js +6 -5
  35. package/dist/charts/line-chart/index.cjs +7 -5
  36. package/dist/charts/line-chart/index.cjs.map +1 -1
  37. package/dist/charts/line-chart/index.css +12 -24
  38. package/dist/charts/line-chart/index.css.map +1 -1
  39. package/dist/charts/line-chart/index.d.cts +3 -4
  40. package/dist/charts/line-chart/index.d.ts +3 -4
  41. package/dist/charts/line-chart/index.js +6 -4
  42. package/dist/charts/pie-chart/index.cjs +7 -6
  43. package/dist/charts/pie-chart/index.cjs.map +1 -1
  44. package/dist/charts/pie-chart/index.css +12 -24
  45. package/dist/charts/pie-chart/index.css.map +1 -1
  46. package/dist/charts/pie-chart/index.d.cts +7 -13
  47. package/dist/charts/pie-chart/index.d.ts +7 -13
  48. package/dist/charts/pie-chart/index.js +6 -5
  49. package/dist/charts/pie-semi-circle-chart/index.cjs +7 -6
  50. package/dist/charts/pie-semi-circle-chart/index.cjs.map +1 -1
  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 -5
  56. package/dist/charts/sparkline/index.cjs +8 -6
  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 -5
  61. package/dist/{chunk-32DH6JDF.js → chunk-2I67QUIV.js} +52 -420
  62. package/dist/chunk-2I67QUIV.js.map +1 -0
  63. package/dist/{chunk-WLODYNLB.js → chunk-2ICEEQOC.js} +31 -27
  64. package/dist/chunk-2ICEEQOC.js.map +1 -0
  65. package/dist/{chunk-IU4DYUAV.js → chunk-4B7BL2DD.js} +3 -3
  66. package/dist/{chunk-BCX5THDQ.js → chunk-4OXMTKAL.js} +24 -26
  67. package/dist/chunk-4OXMTKAL.js.map +1 -0
  68. package/dist/{chunk-4OPFE4RM.js → chunk-B6NLZFRW.js} +30 -27
  69. package/dist/chunk-B6NLZFRW.js.map +1 -0
  70. package/dist/{chunk-D2UH4CFE.cjs → chunk-BBAUQOW6.cjs} +9 -9
  71. package/dist/{chunk-D2UH4CFE.cjs.map → chunk-BBAUQOW6.cjs.map} +1 -1
  72. package/dist/{chunk-XKRJL2QT.cjs → chunk-CMMHCTBX.cjs} +45 -47
  73. package/dist/chunk-CMMHCTBX.cjs.map +1 -0
  74. package/dist/{chunk-YE2T52VZ.cjs → chunk-CPPXJATQ.cjs} +51 -47
  75. package/dist/chunk-CPPXJATQ.cjs.map +1 -0
  76. package/dist/{chunk-H2V4JMSA.js → chunk-DKU775VC.js} +3 -3
  77. package/dist/{chunk-ZH4F5RMG.cjs → chunk-GRA7Y2ZG.cjs} +46 -48
  78. package/dist/chunk-GRA7Y2ZG.cjs.map +1 -0
  79. package/dist/{chunk-DAU3HNEG.js → chunk-JJIMABHT.js} +9 -2
  80. package/dist/chunk-JJIMABHT.js.map +1 -0
  81. package/dist/{chunk-CZGYJKG6.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-V36ERY7Y.js → chunk-LTFH7SEG.js} +24 -26
  85. package/dist/chunk-LTFH7SEG.js.map +1 -0
  86. package/dist/{chunk-PXLEMUGJ.js → chunk-MUNOKLLE.js} +3 -3
  87. package/dist/{chunk-VTS3PNMS.cjs → chunk-MXGLYWVP.cjs} +9 -2
  88. package/dist/chunk-MXGLYWVP.cjs.map +1 -0
  89. package/dist/{chunk-Z45KX47P.cjs → chunk-OYC34VTO.cjs} +154 -94
  90. package/dist/chunk-OYC34VTO.cjs.map +1 -0
  91. package/dist/{chunk-77OKCVQN.cjs → chunk-PQL5I3F6.cjs} +17 -17
  92. package/dist/{chunk-77OKCVQN.cjs.map → chunk-PQL5I3F6.cjs.map} +1 -1
  93. package/dist/{chunk-I35UYJJR.cjs → chunk-REZTQ4PH.cjs} +41 -21
  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-2NCY7R4G.js → chunk-UTYVIOWZ.js} +111 -51
  98. package/dist/chunk-UTYVIOWZ.js.map +1 -0
  99. package/dist/{chunk-TO3OQBXG.cjs → chunk-W2LDIX26.cjs} +5 -5
  100. package/dist/{chunk-TO3OQBXG.cjs.map → chunk-W2LDIX26.cjs.map} +1 -1
  101. package/dist/{chunk-7FQX4ALL.cjs → chunk-WSG64BVN.cjs} +6 -6
  102. package/dist/{chunk-7FQX4ALL.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-RHHVEJHJ.cjs → chunk-WYK7EL5R.cjs} +68 -436
  106. package/dist/chunk-WYK7EL5R.cjs.map +1 -0
  107. package/dist/{chunk-VJM5XCB4.cjs → chunk-XC4KHJYX.cjs} +49 -46
  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-Z26M4V2M.js → chunk-YAFQVVDI.js} +41 -21
  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 +3 -11
  127. package/dist/hooks/index.d.ts +3 -11
  128. package/dist/hooks/index.js +2 -4
  129. package/dist/index.cjs +18 -16
  130. package/dist/index.cjs.map +1 -1
  131. package/dist/index.css +12 -24
  132. package/dist/index.css.map +1 -1
  133. package/dist/index.d.cts +7 -7
  134. package/dist/index.d.ts +7 -7
  135. package/dist/index.js +17 -15
  136. package/dist/{leaderboard-chart-DR7CGb0L.d.cts → leaderboard-chart-BSbg0ufV.d.cts} +3 -7
  137. package/dist/{leaderboard-chart-BKYYXcg2.d.ts → leaderboard-chart-odEYxxEC.d.ts} +3 -7
  138. package/dist/{legend-C2grwnWk.d.cts → legend-DFkosEvC.d.cts} +1 -1
  139. package/dist/{legend-Cj0xM5dU.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-CyjKm-P_.d.cts → themes-D0qc5JaW.d.cts} +2 -2
  147. package/dist/{themes-BmVGrYnF.d.ts → themes-itO4Ht5g.d.ts} +2 -2
  148. package/dist/{types-KtOPPzPX.d.cts → types-B5f6XQ7Q.d.cts} +1 -1
  149. package/dist/{types-CuUEszrM.d.ts → types-BsHooDbM.d.ts} +1 -1
  150. package/dist/{types-I67mddpr.d.cts → types-BuSrRM4p.d.ts} +3 -32
  151. package/dist/{types-DZordNiO.d.cts → types-ChOUI9-N.d.cts} +80 -40
  152. package/dist/{types-DZordNiO.d.ts → types-ChOUI9-N.d.ts} +80 -40
  153. package/dist/{types-I67mddpr.d.ts → types-Dfw9VOKI.d.cts} +3 -32
  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 +6 -6
  159. package/src/charts/bar-chart/bar-chart.tsx +17 -18
  160. package/src/charts/bar-chart/test/bar-chart.test.tsx +48 -31
  161. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +38 -41
  162. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +4 -5
  163. package/src/charts/leaderboard-chart/types.ts +1 -11
  164. package/src/charts/line-chart/line-chart.tsx +18 -16
  165. package/src/charts/line-chart/test/line-chart.test.tsx +49 -27
  166. package/src/charts/line-chart/types.ts +0 -1
  167. package/src/charts/pie-chart/pie-chart.tsx +23 -22
  168. package/src/charts/pie-chart/test/composition-api.test.tsx +41 -0
  169. package/src/charts/pie-chart/test/pie-chart.test.tsx +9 -9
  170. package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +21 -23
  171. package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +33 -5
  172. package/src/charts/private/chart-composition/index.ts +2 -0
  173. package/src/charts/private/chart-composition/render-legend-slot.ts +22 -0
  174. package/src/charts/private/chart-composition/test/render-legend-slot.test.tsx +60 -0
  175. package/src/charts/private/chart-composition/test/use-chart-children.test.tsx +91 -0
  176. package/src/charts/private/chart-composition/use-chart-children.ts +34 -2
  177. package/src/components/legend/index.ts +1 -8
  178. package/src/components/legend/private/base-legend.module.scss +19 -37
  179. package/src/components/legend/private/base-legend.tsx +0 -2
  180. package/src/components/legend/types.ts +7 -34
  181. package/src/hooks/index.ts +0 -1
  182. package/src/index.ts +1 -7
  183. package/src/types.ts +83 -38
  184. package/src/utils/date-parsing.ts +10 -1
  185. package/src/utils/test/date-parsing.test.ts +12 -0
  186. package/src/utils/test/resolve-css-var.test.ts +2 -2
  187. package/tsup.config.ts +1 -1
  188. package/dist/chunk-2NCY7R4G.js.map +0 -1
  189. package/dist/chunk-32DH6JDF.js.map +0 -1
  190. package/dist/chunk-4OPFE4RM.js.map +0 -1
  191. package/dist/chunk-6CCZL2JJ.js.map +0 -1
  192. package/dist/chunk-BCX5THDQ.js.map +0 -1
  193. package/dist/chunk-DAU3HNEG.js.map +0 -1
  194. package/dist/chunk-I35UYJJR.cjs.map +0 -1
  195. package/dist/chunk-RCY6XLGU.cjs.map +0 -1
  196. package/dist/chunk-RHHVEJHJ.cjs.map +0 -1
  197. package/dist/chunk-V36ERY7Y.js.map +0 -1
  198. package/dist/chunk-VJM5XCB4.cjs.map +0 -1
  199. package/dist/chunk-VTS3PNMS.cjs.map +0 -1
  200. package/dist/chunk-WLODYNLB.js.map +0 -1
  201. package/dist/chunk-XKRJL2QT.cjs.map +0 -1
  202. package/dist/chunk-YE2T52VZ.cjs.map +0 -1
  203. package/dist/chunk-Z26M4V2M.js.map +0 -1
  204. package/dist/chunk-Z45KX47P.cjs.map +0 -1
  205. package/dist/chunk-ZH4F5RMG.cjs.map +0 -1
  206. package/src/hooks/use-has-legend-child.ts +0 -22
  207. /package/dist/{chunk-IU4DYUAV.js.map → chunk-4B7BL2DD.js.map} +0 -0
  208. /package/dist/{chunk-H2V4JMSA.js.map → chunk-DKU775VC.js.map} +0 -0
  209. /package/dist/{chunk-CZGYJKG6.js.map → chunk-KJHWXOCZ.js.map} +0 -0
  210. /package/dist/{chunk-PXLEMUGJ.js.map → chunk-MUNOKLLE.js.map} +0 -0
@@ -1,4 +1,10 @@
1
1
  import { LegendOrdinal } from '@visx/legend';
2
+ import type {
3
+ LegendItemStyles,
4
+ LegendLabelStyles,
5
+ LegendPosition,
6
+ LegendShapeStyles,
7
+ } from '../../types';
2
8
  import type { GlyphProps, LineStyles } from '@visx/xychart';
3
9
  import type { ComponentProps, CSSProperties, ReactNode } from 'react';
4
10
 
@@ -7,43 +13,10 @@ type VisxLegendProps = Pick<
7
13
  'className' | 'shape' | 'fill' | 'size' | 'labelFormat' | 'labelTransform'
8
14
  >;
9
15
 
10
- export type LegendItemStyles = {
11
- /** Margin around each legend item. */
12
- margin?: CSSProperties[ 'margin' ];
13
- /** Flex direction for items within each legend entry. */
14
- flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
15
- };
16
-
17
- export type LegendLabelStyles = Pick< CSSProperties, 'justifyContent' | 'flex' | 'margin' > & {
18
- /**
19
- * Maximum width for legend label text as a CSS value (e.g. '200px', '50%', '10rem').
20
- * When set, text overflow behavior is controlled by textOverflow.
21
- */
22
- maxWidth?: string;
23
- /**
24
- * Controls how text behaves when it exceeds maxWidth.
25
- * - 'ellipsis': Truncate with ellipsis (ideal for widgets/small devices)
26
- * - 'wrap': Wrap text to multiple lines (default, ideal for larger displays)
27
- */
28
- textOverflow?: 'ellipsis' | 'wrap';
29
- };
30
-
31
- export type LegendShapeStyles = {
32
- /** Width of the legend shape in pixels. */
33
- width?: number;
34
- /** Height of the legend shape in pixels. */
35
- height?: number;
36
- /** Margin around the legend shape. */
37
- margin?: CSSProperties[ 'margin' ];
38
- };
39
-
40
16
  export type BaseLegendProps = VisxLegendProps & {
41
17
  items: BaseLegendItem[];
42
18
  orientation?: 'horizontal' | 'vertical';
43
- /**
44
- * TODO: Add 'left' | 'right' positioning support in future implementation
45
- */
46
- position?: 'top' | 'bottom';
19
+ position?: LegendPosition;
47
20
  alignment?: 'start' | 'center' | 'end';
48
21
  /** Additional CSS class name for legend items. */
49
22
  itemClassName?: string;
@@ -4,7 +4,6 @@ export { useXYChartTheme } from './use-xychart-theme';
4
4
  export { useChartDataTransform } from './use-chart-data-transform';
5
5
  export { useChartMargin } from './use-chart-margin';
6
6
  export { useElementSize } from './use-element-size';
7
- export { useHasLegendChild } from './use-has-legend-child';
8
7
  export { useTextTruncation } from './use-text-truncation';
9
8
  export { useZeroValueDisplay } from './use-zero-value-display';
10
9
  export { useInteractiveLegendData } from './use-interactive-legend-data';
package/src/index.ts CHANGED
@@ -37,13 +37,7 @@ export type {
37
37
  PieSemiCircleChartRenderTooltipParams,
38
38
  } from './charts/pie-semi-circle-chart';
39
39
  export type { GeoChartProps, GeoRegion, GeoResolution } from './charts/geo-chart';
40
- export type {
41
- LegendValueDisplay,
42
- BaseLegendItem,
43
- LegendItemStyles,
44
- LegendLabelStyles,
45
- LegendShapeStyles,
46
- } from './components/legend';
40
+ export type { LegendValueDisplay, BaseLegendItem } from './components/legend';
47
41
  export type { TrendIndicatorProps, TrendDirection } from './components/trend-indicator';
48
42
  export type { LineStyles, GridStyles, EventHandlerParams } from '@visx/xychart';
49
43
  export type {
package/src/types.ts CHANGED
@@ -352,6 +352,86 @@ export type ScaleOptions = {
352
352
  paddingOuter?: number;
353
353
  };
354
354
 
355
+ export type LegendItemStyles = {
356
+ /** Margin around each legend item. */
357
+ margin?: CSSProperties[ 'margin' ];
358
+ /** Flex direction for items within each legend entry. */
359
+ flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
360
+ };
361
+
362
+ export type LegendLabelStyles = Pick< CSSProperties, 'justifyContent' | 'flex' | 'margin' > & {
363
+ /**
364
+ * Maximum width for legend label text as a CSS value (e.g. '200px', '50%', '10rem').
365
+ * When set, text overflow behavior is controlled by textOverflow.
366
+ */
367
+ maxWidth?: string;
368
+ /**
369
+ * Controls how text behaves when it exceeds maxWidth.
370
+ * - 'ellipsis': Truncate with ellipsis (ideal for widgets/small devices)
371
+ * - 'wrap': Wrap text to multiple lines (default, ideal for larger displays)
372
+ */
373
+ textOverflow?: 'ellipsis' | 'wrap';
374
+ };
375
+
376
+ export type LegendShapeStyles = {
377
+ /** Width of the legend shape in pixels. */
378
+ width?: number;
379
+ /** Height of the legend shape in pixels. */
380
+ height?: number;
381
+ /** Margin around the legend shape. */
382
+ margin?: CSSProperties[ 'margin' ];
383
+ };
384
+
385
+ /** Position of the legend relative to chart content. */
386
+ export type LegendPosition = 'top' | 'bottom';
387
+
388
+ /**
389
+ * Configuration object for chart legend appearance and behavior.
390
+ * Consolidates all legend styling and layout props into a single structured object.
391
+ */
392
+ export type ChartLegendConfig< T = DataPoint | DataPointDate | LeaderboardEntry > = {
393
+ /**
394
+ * Layout direction of legend items.
395
+ */
396
+ orientation?: 'horizontal' | 'vertical';
397
+ /**
398
+ * Position of the legend relative to the chart.
399
+ * TODO: Add 'left' | 'right' positioning support in future implementation
400
+ */
401
+ position?: LegendPosition;
402
+ /**
403
+ * Alignment of the legend within its position.
404
+ */
405
+ alignment?: 'start' | 'center' | 'end';
406
+ /**
407
+ * Shape of the legend marker icon.
408
+ */
409
+ shape?: LegendShape< T, number >;
410
+ /**
411
+ * Enable interactive legend items that can toggle series visibility.
412
+ * Supported for all chart types that render series.
413
+ * Requires chartId and GlobalChartsProvider.
414
+ * For pie charts, percentages are recalculated so visible segments total 100%.
415
+ */
416
+ interactive?: boolean;
417
+ /**
418
+ * Additional CSS class name for individual legend items.
419
+ */
420
+ itemClassName?: string;
421
+ /**
422
+ * CSS styles for each legend item (margin, flexDirection).
423
+ */
424
+ itemStyles?: LegendItemStyles;
425
+ /**
426
+ * CSS styles for legend labels (maxWidth, textOverflow, justifyContent, flex, margin).
427
+ */
428
+ labelStyles?: LegendLabelStyles;
429
+ /**
430
+ * Styles for legend shapes (width, height, margin).
431
+ */
432
+ shapeStyles?: LegendShapeStyles;
433
+ };
434
+
355
435
  /**
356
436
  * Base properties shared across all chart components
357
437
  */
@@ -416,45 +496,10 @@ export type BaseChartProps< T = DataPoint | DataPointDate | LeaderboardEntry > =
416
496
  */
417
497
  showLegend?: boolean;
418
498
  /**
419
- * Legend orientation
420
- */
421
- legendOrientation?: 'horizontal' | 'vertical';
422
- /**
423
- * Legend shape
424
- */
425
- legendShape?: LegendShape< T, number >;
426
- /**
427
- * Legend position (where the legend appears)
428
- * TODO: Add 'left' | 'right' positioning support in future implementation
429
- */
430
- legendPosition?: 'top' | 'bottom';
431
- /**
432
- * Legend alignment within its position
433
- */
434
- legendAlignment?: 'start' | 'center' | 'end';
435
- /**
436
- * Maximum width for legend items. When set, text overflow behavior is controlled by legendTextOverflow.
437
- * Should be a CSS value string (e.g. '200px', '50%', '10rem')
438
- */
439
- legendMaxWidth?: string;
440
- /**
441
- * Controls how text behaves when it exceeds legendMaxWidth.
442
- * - 'ellipsis': Truncate with ellipsis (ideal for widgets/small devices)
443
- * - 'wrap': Wrap text to multiple lines (default, ideal for larger displays)
444
- */
445
- legendTextOverflow?: 'ellipsis' | 'wrap';
446
- /**
447
- * Additional CSS class name for legend items.
448
- * This allows consumers to customize individual legend item styling.
449
- */
450
- legendItemClassName?: string;
451
- /**
452
- * Enable interactive legend items that can toggle series visibility.
453
- * Supported for all chart types that render series.
454
- * Requires chartId and GlobalChartsProvider.
455
- * For pie charts, percentages are recalculated so visible segments total 100%.
499
+ * Legend configuration object for controlling legend appearance and behavior.
500
+ * Includes orientation, position, alignment, shape, styling, and interactivity options.
456
501
  */
457
- legendInteractive?: boolean;
502
+ legend?: ChartLegendConfig< T >;
458
503
  /**
459
504
  * Grid visibility. x is default when orientation is vertical. y is default when orientation is horizontal.
460
505
  */
@@ -44,7 +44,16 @@ import { parse, parseISO, isValid } from 'date-fns';
44
44
  * @return {boolean} True if the date string contains timezone information, false otherwise
45
45
  */
46
46
  const hasTimezone = ( dateString: string ): boolean => {
47
- return /T.*[Z]$|T.*[+-]\d{2}:?\d{2}$/.test( dateString );
47
+ const tIndex = dateString.indexOf( 'T' );
48
+ if ( tIndex === -1 ) {
49
+ return false;
50
+ }
51
+
52
+ if ( dateString.endsWith( 'Z' ) ) {
53
+ return true;
54
+ }
55
+
56
+ return /[+-]\d{2}:?\d{2}$/.test( dateString.slice( tIndex + 1 ) );
48
57
  };
49
58
 
50
59
  /**
@@ -268,6 +268,18 @@ describe( 'parseAsLocalDate', () => {
268
268
  } );
269
269
  } );
270
270
 
271
+ describe( 'ReDoS resilience', () => {
272
+ test( 'should handle adversarial input without catastrophic backtracking', () => {
273
+ const malicious = 'T' + 'a'.repeat( 8000000 ) + 'X';
274
+ const start = performance.now();
275
+ const result = parseAsLocalDate( malicious );
276
+ const elapsed = performance.now() - start;
277
+
278
+ expect( isNaN( result.getTime() ) ).toBe( true );
279
+ expect( elapsed ).toBeLessThan( 50 );
280
+ } );
281
+ } );
282
+
271
283
  describe( 'Performance and consistency', () => {
272
284
  test( 'should consistently parse the same input', () => {
273
285
  const dateString = '2025-01-15T14:30:45Z';
@@ -414,7 +414,7 @@ describe( 'resolveCssVariable', () => {
414
414
  if ( element === themedElement ) {
415
415
  return {
416
416
  getPropertyValue: ( prop: string ) => {
417
- if ( prop === '--wpds-color-bg-interactive-brand' ) {
417
+ if ( prop === '--wpds-color-bg-interactive-brand-weak' ) {
418
418
  return '#c029dc'; // User's custom accent color
419
419
  }
420
420
  return '';
@@ -427,7 +427,7 @@ describe( 'resolveCssVariable', () => {
427
427
  } );
428
428
  window.getComputedStyle = mockGetComputedStyle as unknown as typeof window.getComputedStyle;
429
429
 
430
- const result = resolveCssVariable( '--wpds-color-bg-interactive-brand', themedElement );
430
+ const result = resolveCssVariable( '--wpds-color-bg-interactive-brand-weak', themedElement );
431
431
  expect( result ).toBe( '#c029dc' );
432
432
  } );
433
433
  } );
package/tsup.config.ts CHANGED
@@ -16,7 +16,7 @@ export default defineConfig( {
16
16
  dts: true,
17
17
  format: [ 'esm', 'cjs' ],
18
18
  outDir: 'dist',
19
- noExternal: [ '@wordpress/ui' ],
19
+ noExternal: [ '@wordpress/ui', 'fast-deep-equal' ],
20
20
  loader: {
21
21
  '.jpg': 'file',
22
22
  '.gif': 'file',