@automattic/charts 4.14.0 → 4.15.1

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 (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/TOKENS.md +1 -1
  3. package/dist/index.cjs +649 -882
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +58 -1
  6. package/dist/index.d.cts +41 -7
  7. package/dist/index.d.ts +41 -7
  8. package/dist/index.js +650 -883
  9. package/dist/index.js.map +1 -1
  10. package/package.json +8 -8
  11. package/src/charts/area-chart/area-chart.tsx +29 -20
  12. package/src/charts/area-chart/types.ts +3 -1
  13. package/src/charts/bar-chart/bar-chart.module.scss +38 -0
  14. package/src/charts/bar-chart/bar-chart.tsx +159 -56
  15. package/src/charts/bar-chart/private/band-tooltip.tsx +40 -5
  16. package/src/charts/bar-chart/private/bar-layer.tsx +66 -13
  17. package/src/charts/bar-chart/private/category.ts +25 -0
  18. package/src/charts/bar-chart/private/comparison-bars-geometry.ts +13 -1
  19. package/src/charts/bar-chart/private/index.ts +3 -1
  20. package/src/charts/bar-chart/private/selected-bar-ring.tsx +17 -6
  21. package/src/charts/bar-chart/private/stack-layout.ts +99 -0
  22. package/src/charts/bar-chart/private/stacked-bar-series.tsx +145 -0
  23. package/src/charts/bar-chart/private/test/stack-layout.test.ts +81 -0
  24. package/src/charts/bar-chart/private/test/value-domain.test.ts +10 -0
  25. package/src/charts/bar-chart/private/use-bar-chart-options.ts +35 -11
  26. package/src/charts/bar-chart/private/{use-overlap-slots.ts → use-bar-slots.ts} +36 -38
  27. package/src/charts/bar-chart/private/use-bar-stops.ts +19 -19
  28. package/src/charts/bar-chart/private/value-domain.ts +10 -8
  29. package/src/charts/bar-chart/test/bar-chart-stacked.test.tsx +546 -0
  30. package/src/charts/bar-chart/test/bar-chart.test.tsx +75 -0
  31. package/src/charts/bar-chart/test/use-bar-legend-items.test.tsx +18 -0
  32. package/src/charts/bar-chart/types.ts +3 -1
  33. package/src/charts/bar-chart/use-bar-colors.ts +12 -0
  34. package/src/charts/bar-chart/use-bar-legend-items.ts +4 -2
  35. package/src/charts/bar-list-chart/bar-list-chart.tsx +2 -0
  36. package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +43 -1
  37. package/src/charts/leaderboard-chart/leaderboard-chart.tsx +25 -20
  38. package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +15 -20
  39. package/src/charts/line-chart/line-chart.tsx +55 -26
  40. package/src/charts/line-chart/test/line-chart.test.tsx +86 -0
  41. package/src/charts/line-chart/types.ts +3 -1
  42. package/src/charts/private/test/compact-when-short.test.tsx +170 -0
  43. package/src/charts/private/test/tick-decimals.test.tsx +95 -0
  44. package/src/charts/private/tick-decimals.tsx +132 -0
  45. package/src/charts/private/use-compact-when-short.ts +18 -0
  46. package/src/providers/chart-context/themes.ts +4 -0
  47. package/src/types.ts +35 -2
  48. package/src/charts/private/test/whole-number-ticks.test.tsx +0 -57
  49. package/src/charts/private/whole-number-ticks.tsx +0 -79
package/dist/index.css CHANGED
@@ -349,6 +349,37 @@
349
349
  transform: scaleX(1);
350
350
  }
351
351
  }
352
+
353
+ .a8ccharts-97yN9W-bar-chart--stacked .visx-bar-group rect {
354
+ rx: 0;
355
+ animation: none;
356
+ }
357
+
358
+ .a8ccharts-97yN9W-bar-chart--stacked .visx-bar-group rect[data-stack-end="top"] {
359
+ clip-path: inset(0 round var(--a8c-charts-border-radius-bar-chart) var(--a8c-charts-border-radius-bar-chart) 0 0);
360
+ }
361
+
362
+ .a8ccharts-97yN9W-bar-chart--stacked .visx-bar-group rect[data-stack-end="right"] {
363
+ clip-path: inset(0 round 0 var(--a8c-charts-border-radius-bar-chart) var(--a8c-charts-border-radius-bar-chart) 0);
364
+ }
365
+
366
+ .a8ccharts-97yN9W-bar-chart--stacked .visx-bar-group rect[data-stack-end="bottom"] {
367
+ clip-path: inset(0 round 0 0 var(--a8c-charts-border-radius-bar-chart) var(--a8c-charts-border-radius-bar-chart));
368
+ }
369
+
370
+ .a8ccharts-97yN9W-bar-chart--stacked .visx-bar-group rect[data-stack-end="left"] {
371
+ clip-path: inset(0 round var(--a8c-charts-border-radius-bar-chart) 0 0 var(--a8c-charts-border-radius-bar-chart));
372
+ }
373
+
374
+ .a8ccharts-97yN9W-bar-chart--stacked.a8ccharts-97yN9W-bar-chart--animated .visx-bar-group {
375
+ transform-box: view-box;
376
+ animation: a8ccharts-97yN9W-rise var(--a8c-charts-motion-duration-entrance) var(--a8c-charts-motion-easing-entrance) both;
377
+ }
378
+
379
+ .a8ccharts-97yN9W-bar-chart--stacked.a8ccharts-97yN9W-bar-chart--animated-horizontal .visx-bar-group {
380
+ transform-box: view-box;
381
+ animation: a8ccharts-97yN9W-stretch var(--a8c-charts-motion-duration-entrance) var(--a8c-charts-motion-easing-entrance) both;
382
+ }
352
383
  .a8ccharts-gx1_AW-selected-ring__far, .a8ccharts-gx1_AW-selected-ring__edge {
353
384
  fill: none;
354
385
  }
@@ -745,6 +776,17 @@
745
776
  overflow: hidden;
746
777
  }
747
778
 
779
+ .a8ccharts-GovfoW-grid {
780
+ row-gap: var(--a8c-charts-dimension-leaderboard-row-gap);
781
+ column-gap: var(--a8c-charts-dimension-leaderboard-column-gap);
782
+ grid-template-columns: minmax(0, 1fr) auto;
783
+ display: grid;
784
+ }
785
+
786
+ .a8ccharts-GovfoW-grid--comparison {
787
+ grid-template-columns: minmax(0, 1fr) auto auto;
788
+ }
789
+
748
790
  .a8ccharts-GovfoW-barWithLabelContainer {
749
791
  isolation: isolate;
750
792
  grid-template-columns: 1fr;
@@ -896,6 +938,21 @@
896
938
  transition: opacity var(--wpds-motion-duration-sm, .1s) var(--wpds-motion-easing-subtle, cubic-bezier(.15, 0, .15, 1)), width var(--wpds-motion-duration-sm, .1s) var(--wpds-motion-easing-subtle, cubic-bezier(.15, 0, .15, 1));
897
939
  }
898
940
 
941
+ .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-barWithLabelContainer > :not(.a8ccharts-GovfoW-bar, .a8ccharts-GovfoW-barTrack) {
942
+ max-inline-size: 100%;
943
+ transition: max-inline-size var(--wpds-motion-duration-sm, .1s) var(--wpds-motion-easing-subtle, cubic-bezier(.15, 0, .15, 1));
944
+ }
945
+
946
+ .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-label {
947
+ text-overflow: ellipsis;
948
+ white-space: nowrap;
949
+ overflow: hidden;
950
+ }
951
+
952
+ .a8ccharts-GovfoW-interactiveRow:hover .a8ccharts-GovfoW-barWithLabelContainer > :not(.a8ccharts-GovfoW-bar, .a8ccharts-GovfoW-barTrack), .a8ccharts-GovfoW-interactiveRow:focus-visible .a8ccharts-GovfoW-barWithLabelContainer > :not(.a8ccharts-GovfoW-bar, .a8ccharts-GovfoW-barTrack), .a8ccharts-GovfoW-interactiveRow:has(:focus-visible) .a8ccharts-GovfoW-barWithLabelContainer > :not(.a8ccharts-GovfoW-bar, .a8ccharts-GovfoW-barTrack) {
953
+ max-inline-size: calc(100% - var(--wpds-dimension-gap-2xl, 32px));
954
+ }
955
+
899
956
  .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-valueContainer {
900
957
  transition: transform var(--wpds-motion-duration-sm, .1s) var(--wpds-motion-easing-subtle, cubic-bezier(.15, 0, .15, 1));
901
958
  }
@@ -976,7 +1033,7 @@
976
1033
  }
977
1034
 
978
1035
  @media (prefers-reduced-motion: reduce) {
979
- .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-bar, .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-valueContainer, .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-chevron {
1036
+ .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-bar, .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-barWithLabelContainer > :not(.a8ccharts-GovfoW-bar, .a8ccharts-GovfoW-barTrack), .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-valueContainer, .a8ccharts-GovfoW-interactiveRow .a8ccharts-GovfoW-chevron {
980
1037
  transition: none;
981
1038
  }
982
1039
  }
package/dist/index.d.cts CHANGED
@@ -253,9 +253,9 @@ type BarStyles = {
253
253
  opacity?: number;
254
254
  };
255
255
  /**
256
- * How a bar chart places its series in a category. `grouped` puts each primary series in a slot of its own; `overlap` puts every primary in one slot and every comparison in a second, and overlaps the `group`s within each slot.
256
+ * How a bar chart places its series in a category. `grouped` puts each primary series in a slot of its own; `overlap` puts every primary in one slot and every comparison in a second, and overlaps the `group`s within each slot; `stacked` stacks every primary in one bar, the first series at the bottom.
257
257
  */
258
- type BarChartLayout = 'grouped' | 'overlap';
258
+ type BarChartLayout = 'grouped' | 'overlap' | 'stacked';
259
259
  type MultipleDataPointsDate = {
260
260
  label: string;
261
261
  data: DataPointDate[];
@@ -367,6 +367,18 @@ type ChartTheme = {
367
367
  /** Stroke width for the sparkline line */
368
368
  strokeWidth?: number;
369
369
  };
370
+ /** Compact mode for `compactWhenShort` line, area and bar charts */
371
+ compactWhenShort?: {
372
+ /** Height (px) below which the chart turns compact */
373
+ below?: number;
374
+ /** Margin the chart defaults to while compact */
375
+ margin?: {
376
+ top?: number;
377
+ right?: number;
378
+ bottom?: number;
379
+ left?: number;
380
+ };
381
+ };
370
382
  /**
371
383
  * HeatmapChart settings. Cell gap, radius, value size and the selection ring come from
372
384
  * WPDS tokens in CSS, so only the compact sizing lives here.
@@ -396,6 +408,9 @@ type CompleteChartTheme = Required<ChartTheme> & {
396
408
  sparkline: Required<NonNullable<ChartTheme['sparkline']>> & {
397
409
  margin: Required<NonNullable<ChartTheme['sparkline']>['margin']>;
398
410
  };
411
+ compactWhenShort: Required<NonNullable<ChartTheme['compactWhenShort']>> & {
412
+ margin: Required<NonNullable<ChartTheme['compactWhenShort']>['margin']>;
413
+ };
399
414
  heatmapChart: Required<NonNullable<ChartTheme['heatmapChart']>>;
400
415
  };
401
416
  /**
@@ -445,6 +460,12 @@ type AxisOptions = {
445
460
  * so callers can force a specific axis (e.g. integer-only steps on a sparse chart).
446
461
  */
447
462
  tickValues?: ScaleInput<AxisScale>[];
463
+ /**
464
+ * Most decimal places a value-axis tick may carry, so labels rounded to that precision never repeat;
465
+ * an axis holding fewer than two steps widens to the nearest ones. Whole-number data always uses 0.
466
+ * Ignored on a log scale, or when `tickValues` or the value scale's `domain` is set. Line and bar charts only.
467
+ */
468
+ tickDecimals?: number;
448
469
  axisClassName?: string;
449
470
  axisLineClassName?: string;
450
471
  labelClassName?: string;
@@ -624,6 +645,17 @@ interface SeriesVisibilityProps {
624
645
  */
625
646
  defaultHiddenSeries?: readonly string[];
626
647
  }
648
+ /**
649
+ * Compact mode for cartesian charts placed in short containers.
650
+ */
651
+ interface CompactWhenShortProps {
652
+ /**
653
+ * Drop the axes, grid and legend, and default to `theme.compactWhenShort.margin`, while the
654
+ * chart is shorter than `theme.compactWhenShort.below`. Series hidden through the legend stay
655
+ * hidden until the chart is tall again. Horizontal bar charts ignore it.
656
+ */
657
+ compactWhenShort?: boolean;
658
+ }
627
659
  /**
628
660
  * Base properties shared across all chart components
629
661
  */
@@ -931,7 +963,7 @@ type RenderLineGlyphProps<Datum extends object> = GlyphProps<Datum> & {
931
963
  glyphStyle?: SVGProps<SVGCircleElement>;
932
964
  position?: 'start' | 'end';
933
965
  };
934
- interface LineChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps {
966
+ interface LineChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps, CompactWhenShortProps {
935
967
  /**
936
968
  * Legend configuration. Supports `collapseGroups` on top of the shared options.
937
969
  */
@@ -984,7 +1016,7 @@ type TooltipDatum = {
984
1016
  /** The series' reading, or null when the bucket has none. */
985
1017
  value: number | null;
986
1018
  };
987
- interface AreaChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps {
1019
+ interface AreaChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps, CompactWhenShortProps {
988
1020
  /**
989
1021
  * Legend configuration. Supports `collapseGroups` on top of the shared options.
990
1022
  */
@@ -1087,7 +1119,7 @@ type BandHighlightSelection = {
1087
1119
  width: number;
1088
1120
  height: number;
1089
1121
  };
1090
- interface BarChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps {
1122
+ interface BarChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps, CompactWhenShortProps {
1091
1123
  /**
1092
1124
  * Legend configuration. Supports `collapseGroups` on top of the shared options.
1093
1125
  */
@@ -1136,13 +1168,15 @@ type BarLegendOptions = Omit<ChartLegendOptions, 'seriesColors'> & {
1136
1168
  /**
1137
1169
  * Builds legend items that match `BarChart`'s bars in a layout, for a custom legend or a chart's own.
1138
1170
  *
1139
- * @param data - The series the chart draws.
1171
+ * @param allData - The chart's series; those the layout does not draw get no item.
1140
1172
  * @param options - The legend options, and the layout the bars are drawn in.
1141
1173
  * @param legendShape - The shape of the legend swatches.
1142
1174
  * @return The legend items.
1143
1175
  */
1144
- export declare function useBarLegendItems(data: SeriesData[], options?: BarLegendOptions, legendShape?: LegendShape<SeriesData[], number>): BaseLegendItem[];
1176
+ export declare function useBarLegendItems(allData: SeriesData[], options?: BarLegendOptions, legendShape?: LegendShape<SeriesData[], number>): BaseLegendItem[];
1145
1177
  interface BarListChartProps extends Exclude<BarChartProps, 'orientation' | 'size' | 'gridVisibility'> {
1178
+ /** Bar lists are always horizontal, and horizontal bars ignore `compactWhenShort`. */
1179
+ compactWhenShort?: never;
1146
1180
  options?: {
1147
1181
  /**
1148
1182
  * Scale for the y axis. Exclude the type property.
package/dist/index.d.ts CHANGED
@@ -253,9 +253,9 @@ type BarStyles = {
253
253
  opacity?: number;
254
254
  };
255
255
  /**
256
- * How a bar chart places its series in a category. `grouped` puts each primary series in a slot of its own; `overlap` puts every primary in one slot and every comparison in a second, and overlaps the `group`s within each slot.
256
+ * How a bar chart places its series in a category. `grouped` puts each primary series in a slot of its own; `overlap` puts every primary in one slot and every comparison in a second, and overlaps the `group`s within each slot; `stacked` stacks every primary in one bar, the first series at the bottom.
257
257
  */
258
- type BarChartLayout = 'grouped' | 'overlap';
258
+ type BarChartLayout = 'grouped' | 'overlap' | 'stacked';
259
259
  type MultipleDataPointsDate = {
260
260
  label: string;
261
261
  data: DataPointDate[];
@@ -367,6 +367,18 @@ type ChartTheme = {
367
367
  /** Stroke width for the sparkline line */
368
368
  strokeWidth?: number;
369
369
  };
370
+ /** Compact mode for `compactWhenShort` line, area and bar charts */
371
+ compactWhenShort?: {
372
+ /** Height (px) below which the chart turns compact */
373
+ below?: number;
374
+ /** Margin the chart defaults to while compact */
375
+ margin?: {
376
+ top?: number;
377
+ right?: number;
378
+ bottom?: number;
379
+ left?: number;
380
+ };
381
+ };
370
382
  /**
371
383
  * HeatmapChart settings. Cell gap, radius, value size and the selection ring come from
372
384
  * WPDS tokens in CSS, so only the compact sizing lives here.
@@ -396,6 +408,9 @@ type CompleteChartTheme = Required<ChartTheme> & {
396
408
  sparkline: Required<NonNullable<ChartTheme['sparkline']>> & {
397
409
  margin: Required<NonNullable<ChartTheme['sparkline']>['margin']>;
398
410
  };
411
+ compactWhenShort: Required<NonNullable<ChartTheme['compactWhenShort']>> & {
412
+ margin: Required<NonNullable<ChartTheme['compactWhenShort']>['margin']>;
413
+ };
399
414
  heatmapChart: Required<NonNullable<ChartTheme['heatmapChart']>>;
400
415
  };
401
416
  /**
@@ -445,6 +460,12 @@ type AxisOptions = {
445
460
  * so callers can force a specific axis (e.g. integer-only steps on a sparse chart).
446
461
  */
447
462
  tickValues?: ScaleInput<AxisScale>[];
463
+ /**
464
+ * Most decimal places a value-axis tick may carry, so labels rounded to that precision never repeat;
465
+ * an axis holding fewer than two steps widens to the nearest ones. Whole-number data always uses 0.
466
+ * Ignored on a log scale, or when `tickValues` or the value scale's `domain` is set. Line and bar charts only.
467
+ */
468
+ tickDecimals?: number;
448
469
  axisClassName?: string;
449
470
  axisLineClassName?: string;
450
471
  labelClassName?: string;
@@ -624,6 +645,17 @@ interface SeriesVisibilityProps {
624
645
  */
625
646
  defaultHiddenSeries?: readonly string[];
626
647
  }
648
+ /**
649
+ * Compact mode for cartesian charts placed in short containers.
650
+ */
651
+ interface CompactWhenShortProps {
652
+ /**
653
+ * Drop the axes, grid and legend, and default to `theme.compactWhenShort.margin`, while the
654
+ * chart is shorter than `theme.compactWhenShort.below`. Series hidden through the legend stay
655
+ * hidden until the chart is tall again. Horizontal bar charts ignore it.
656
+ */
657
+ compactWhenShort?: boolean;
658
+ }
627
659
  /**
628
660
  * Base properties shared across all chart components
629
661
  */
@@ -931,7 +963,7 @@ type RenderLineGlyphProps<Datum extends object> = GlyphProps<Datum> & {
931
963
  glyphStyle?: SVGProps<SVGCircleElement>;
932
964
  position?: 'start' | 'end';
933
965
  };
934
- interface LineChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps {
966
+ interface LineChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps, CompactWhenShortProps {
935
967
  /**
936
968
  * Legend configuration. Supports `collapseGroups` on top of the shared options.
937
969
  */
@@ -984,7 +1016,7 @@ type TooltipDatum = {
984
1016
  /** The series' reading, or null when the bucket has none. */
985
1017
  value: number | null;
986
1018
  };
987
- interface AreaChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps {
1019
+ interface AreaChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps, CompactWhenShortProps {
988
1020
  /**
989
1021
  * Legend configuration. Supports `collapseGroups` on top of the shared options.
990
1022
  */
@@ -1087,7 +1119,7 @@ type BandHighlightSelection = {
1087
1119
  width: number;
1088
1120
  height: number;
1089
1121
  };
1090
- interface BarChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps {
1122
+ interface BarChartProps extends BaseChartProps<SeriesData[]>, SeriesVisibilityProps, CompactWhenShortProps {
1091
1123
  /**
1092
1124
  * Legend configuration. Supports `collapseGroups` on top of the shared options.
1093
1125
  */
@@ -1136,13 +1168,15 @@ type BarLegendOptions = Omit<ChartLegendOptions, 'seriesColors'> & {
1136
1168
  /**
1137
1169
  * Builds legend items that match `BarChart`'s bars in a layout, for a custom legend or a chart's own.
1138
1170
  *
1139
- * @param data - The series the chart draws.
1171
+ * @param allData - The chart's series; those the layout does not draw get no item.
1140
1172
  * @param options - The legend options, and the layout the bars are drawn in.
1141
1173
  * @param legendShape - The shape of the legend swatches.
1142
1174
  * @return The legend items.
1143
1175
  */
1144
- export declare function useBarLegendItems(data: SeriesData[], options?: BarLegendOptions, legendShape?: LegendShape<SeriesData[], number>): BaseLegendItem[];
1176
+ export declare function useBarLegendItems(allData: SeriesData[], options?: BarLegendOptions, legendShape?: LegendShape<SeriesData[], number>): BaseLegendItem[];
1145
1177
  interface BarListChartProps extends Exclude<BarChartProps, 'orientation' | 'size' | 'gridVisibility'> {
1178
+ /** Bar lists are always horizontal, and horizontal bars ignore `compactWhenShort`. */
1179
+ compactWhenShort?: never;
1146
1180
  options?: {
1147
1181
  /**
1148
1182
  * Scale for the y axis. Exclude the type property.