@automattic/charts 4.6.0 → 4.7.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 (57) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/TOKENS.md +12 -10
  3. package/dist/index.cjs +244 -145
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.css +33 -20
  6. package/dist/index.d.cts +10 -10
  7. package/dist/index.d.ts +10 -10
  8. package/dist/index.js +245 -146
  9. package/dist/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +0 -10
  12. package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +4 -2
  13. package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +11 -1
  14. package/src/charts/conversion-funnel-chart/types.ts +3 -0
  15. package/src/charts/heatmap-chart/heatmap-chart.module.scss +10 -3
  16. package/src/charts/heatmap-chart/heatmap-chart.tsx +54 -37
  17. package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +129 -25
  18. package/src/charts/heatmap-chart/types.ts +2 -6
  19. package/src/charts/line-chart/crosshair-style-types.fixture.ts +23 -0
  20. package/src/charts/line-chart/line-chart.module.scss +0 -5
  21. package/src/charts/line-chart/line-chart.tsx +8 -40
  22. package/src/charts/line-chart/test/line-chart.test.tsx +19 -47
  23. package/src/charts/pie-chart/pie-chart.module.scss +9 -0
  24. package/src/charts/pie-chart/pie-chart.tsx +22 -76
  25. package/src/charts/pie-chart/test/pie-chart.test.tsx +21 -8
  26. package/src/charts/private/chart-composition/chart-html.tsx +1 -1
  27. package/src/charts/private/chart-composition/chart-svg.tsx +1 -1
  28. package/src/charts/private/label-text-color.ts +116 -0
  29. package/src/charts/private/radial-wipe-animation/radial-wipe-animation.tsx +2 -0
  30. package/src/charts/private/svg-empty-state/svg-empty-state.tsx +1 -1
  31. package/src/charts/private/test/label-text-color.test.ts +191 -0
  32. package/src/charts/private/with-responsive/test/with-responsive.test.tsx +1 -0
  33. package/src/charts/private/with-responsive/with-responsive.tsx +2 -5
  34. package/src/components/tooltip/accessible-tooltip.tsx +1 -1
  35. package/src/components/tooltip/base-tooltip.module.scss +12 -8
  36. package/src/components/tooltip/base-tooltip.tsx +11 -9
  37. package/src/components/tooltip/private/bounded-tooltip.tsx +27 -8
  38. package/src/components/tooltip/private/tooltip-theme.tsx +37 -0
  39. package/src/components/tooltip/test/bounded-tooltip.test.tsx +82 -1
  40. package/src/components/tooltip/test/tool-tip.test.tsx +5 -0
  41. package/src/components/tooltip/test/tooltip-theme.test.tsx +61 -0
  42. package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +41 -28
  43. package/src/components/tooltip/xy-chart-tooltip.tsx +29 -29
  44. package/src/components/trend-indicator/trend-indicator.tsx +1 -0
  45. package/src/hooks/index.ts +1 -0
  46. package/src/hooks/test/use-xychart-theme.test.tsx +3 -3
  47. package/src/hooks/use-isomorphic-layout-effect.ts +5 -0
  48. package/src/hooks/use-xychart-theme.ts +4 -12
  49. package/src/providers/chart-context/hooks/use-default-hidden-series.ts +2 -4
  50. package/src/providers/chart-context/private/perceptual-color.ts +45 -4
  51. package/src/providers/chart-context/test/perceptual-color.test.ts +31 -0
  52. package/src/styles/chart-scope-class.ts +5 -0
  53. package/src/styles/chart-scope.scss +9 -6
  54. package/src/styles/test/chart-scope.test.ts +3 -3
  55. package/src/utils/color-utils.ts +2 -1
  56. package/src/visx/types.ts +1 -1
  57. package/src/charts/line-chart/test/crosshair-style-types.test.ts +0 -31
package/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@ 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
+ ## [4.7.0] - 2026-10-05
9
+ ### Added
10
+ - Conversion funnel chart: Add `tooltipStyle` to restyle the tooltip box. [#52850]
11
+
12
+ ### Changed
13
+ - Tooltips: Draw every chart tooltip on one dark surface that matches the WordPress design system; set `--a8c-charts-color-tooltip-surface` for a light tooltip. [#52850]
14
+
15
+ ### Deprecated
16
+ - Conversion funnel chart: Deprecate `className` in the custom `renderTooltip` props, which is no longer set. [#52850]
17
+ - Deprecate the `prefersLightText` color utility. [#52968]
18
+ - Heatmap chart: Deprecate `tooltipVariant`, which no longer has an effect. [#52850]
19
+
20
+ ### Fixed
21
+ - Keep values drawn on heatmap and pie chart fills at WCAG AA contrast. [#52968]
22
+
8
23
  ## [4.6.0] - 2026-09-29
9
24
  ### Added
10
25
  - Geo Chart: Add a displayMode prop to draw rows as markers. [#52859]
@@ -1131,6 +1146,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1131
1146
  - Fixed lints following ESLint rule changes for TS [#40584]
1132
1147
  - Fixing a bug in Chart storybook data. [#40640]
1133
1148
 
1149
+ [4.7.0]: https://github.com/Automattic/charts/compare/v4.6.0...v4.7.0
1134
1150
  [4.6.0]: https://github.com/Automattic/charts/compare/v4.5.0...v4.6.0
1135
1151
  [4.5.0]: https://github.com/Automattic/charts/compare/v4.4.0...v4.5.0
1136
1152
  [4.4.0]: https://github.com/Automattic/charts/compare/v4.3.0...v4.4.0
package/TOKENS.md CHANGED
@@ -4,18 +4,18 @@
4
4
 
5
5
  ## How it resolves
6
6
 
7
- `src/styles/chart-scope.scss` declares the whole catalog once, on the `GlobalChartsProvider` wrapper, via `:where(.a8c-charts-scope)`. `:where()` keeps the rule at zero specificity, so a consumer rule targeting that same element wins without `!important`. It is declared on the wrapper rather than `:root` because `@wordpress/theme`'s `ThemeProvider` emits its generated `--wpds-*` ramp as inline styles on its own wrapper div — a `:root` declaration would miss a `ThemeProvider` entirely.
7
+ `src/styles/chart-scope.scss` declares the whole catalog once, on the `GlobalChartsProvider` wrapper, via `:where(.a8c-charts-scope, .a8c-charts-tooltip-scope)`. `:where()` keeps the rule at zero specificity, so a consumer rule targeting that same element wins without `!important`. It is declared on the wrapper rather than `:root` because `@wordpress/theme`'s `ThemeProvider` emits its generated `--wpds-*` ramp as inline styles on its own wrapper div — a `:root` declaration would miss a `ThemeProvider` entirely.
8
8
 
9
9
  Chart roots deliberately do *not* carry the `a8c-charts-scope` class. Custom properties inherit down the tree, and an element only shadows an inherited value by re-declaring it, so a chart root that re-declared the catalog would beat an override set between it and the provider — closing off the one place consumers are meant to set overrides. This inheritance rule drives every precedence question below.
10
10
 
11
- Tooltips render inside the chart, so they carry the class only when no provider is above them, the same as `TrendIndicator`, `BaseTooltip` and `BaseLegend` (`useStandaloneScopeClass()`).
11
+ The tooltip box is the exception, and on purpose. Like the `@wordpress/ui` Tooltip popup, it renders inside its own `ThemeProvider`, seeded with `--a8c-charts-color-tooltip-surface`, and carries its own `a8c-charts-tooltip-scope` class, so it re-declares the catalog under that dark theme. Every role read inside the box resolves for the dark surface, whatever theme the chart is in, and neither an override set on the chart nor a rule on `.a8c-charts-scope` reaches the box. To override a role inside every tooltip, target `.a8c-charts-tooltip-scope`. An `unstyled` box gets neither the theme nor the class.
12
12
 
13
- Inside a provider a tooltip therefore inherits the provider's inline `theme` var and any consumer rule scoped to the provider wrapper, the same as the chart it belongs to.
13
+ `TrendIndicator` and `BaseLegend` carry the class only when no provider is above them (`useStandaloneScopeClass()`), so inside a provider they inherit its overrides like the chart they belong to.
14
14
 
15
15
  Catalog entries normally map to WPDS tokens. Source writes these mappings bare; the LightningCSS plugin in `tsdown.config.ts` injects the WPDS spec value as a fallback into `dist/`:
16
16
 
17
17
  ```scss
18
- :where(.a8c-charts-scope) {
18
+ :where(.a8c-charts-scope, .a8c-charts-tooltip-scope) {
19
19
  --a8c-charts-color-grid: var(--wpds-color-stroke-surface-neutral);
20
20
  }
21
21
  ```
@@ -41,12 +41,12 @@ Some roles are deliberately narrower than the obvious name, so that moving one t
41
41
 
42
42
  | Narrow role | Broad role | What the broad one also reaches |
43
43
  |---|---|---|
44
- | `--a8c-charts-color-label-axis` | `--a8c-charts-color-label` | legend labels, `.heatmap-chart__cell-value`, funnel labels, the line-chart tooltip, pie labels on light slices |
44
+ | `--a8c-charts-color-label-axis` | `--a8c-charts-color-label` | legend labels, `.heatmap-chart__cell-value`, funnel labels, pie labels on light slices |
45
45
  | `--a8c-charts-color-background` | — | — |
46
46
 
47
47
  Outside forced-colors mode, `--a8c-charts-color-label-axis` derives from `--a8c-charts-color-label`, so setting the broad role moves every label at once and setting the narrow one moves only the SVG axis labels. See [One pair of roles per axis](#one-pair-of-roles-per-axis) for forced-colors defaults.
48
48
 
49
- `--a8c-charts-color-surface` — the annotation label, `.x-zoom__reset`, tooltips — is a **sibling** of `--a8c-charts-color-background`, not a child. The chart's own background and the surfaces floating over it are set apart from each other often enough that one has to be able to move without the other. The consequence: no single role repaints both.
49
+ `--a8c-charts-color-surface` (the annotation label, `.x-zoom__reset`) is a **sibling** of `--a8c-charts-color-background`, not a child. The chart's own background and the surfaces floating over it are set apart from each other often enough that one has to be able to move without the other. The consequence: no single role repaints both.
50
50
 
51
51
  ### The SVG bridge
52
52
 
@@ -56,13 +56,13 @@ That is what makes the role read **at the painted element** rather than snapshot
56
56
 
57
57
  There is no stylesheet and no class involved. In particular the axes need neither: visx takes a separate style object per axis, so each one is handed its own roles and nothing has to distinguish them after the fact.
58
58
 
59
- What else crosses in JS is what something reads as a *value*: the series palette, which visx turns into its `colorScale`; the background, which the default glyph, the area-chart band, the line-chart gradient stops, the heatmap's contrast math and `GeoChart` each consume as a concrete string; and, for the pie chart, `label` and `label-inverse` against the resolved slice fill, to pick which one contrasts more before painting the label.
59
+ What else crosses in JS is what something reads as a *value*: the series palette, which visx turns into its `colorScale`; the background, which the default glyph, the area-chart band, the line-chart gradient stops, the heatmap's contrast math and `GeoChart` each consume as a concrete string; and, for the pie chart and the heatmap, `label` and `label-inverse` against the resolved fill, to pick which one contrasts more (or black or white, when neither reaches AA) before painting the label.
60
60
 
61
61
  **The tooltip used to be the one painted exception, because visx painted it outside the scope.** `@visx/tooltip` appends each portal container straight to `document.body`, where the catalog is not declared, so a chain handed to one reached only its own hardcoded fallback — never the role, never a consumer's override. Charts no longer take that route: the box renders into the chart's own wrapper and the crosshairs and glyphs are drawn into the chart SVG, both inside the scope, so a chain handed to either resolves there natively.
62
62
 
63
- Two colors are still resolved before visx sees them. `htmlLabel.color`, in `useXYChartTheme`, for a reason the move does not touch: visx builds the tooltip's shadow as `` `0 1px 2px ${color}55` ``, and a `var()` chain cannot take a suffix — token streams do not merge across a substitution boundary, so the whole declaration is invalid and the tooltip renders flat. The crosshair stroke, in `AccessibleTooltip`, only still matters where a consumer supplies a `ChartScopeContext` element that is not one of the chart's own ancestors; in the ordinary tree the CSS path now reaches it.
63
+ One tooltip color is still resolved before visx sees it: the crosshair stroke, in `AccessibleTooltip`, which only still matters where a consumer supplies a `ChartScopeContext` element that is not one of the chart's own ancestors; in the ordinary tree the CSS path now reaches it.
64
64
 
65
- Being resolved in JS, both then carry the bridge's limitations rather than the CSS path's: they read at the scope element, so a role declared on the chart's own class moves the gridlines but leaves the crosshair at the catalog value, and neither repaints on a theme change until something re-renders.
65
+ Being resolved in JS, it then carries the bridge's limitations rather than the CSS path's: it reads at the scope element, so a role declared on the chart's own class moves the gridlines but leaves the crosshair at the catalog value, and it does not repaint on a theme change until something re-renders.
66
66
 
67
67
  Where a value is *consumed* says nothing about where it is *set*. These are set the same way as every other catalog color — `--a8c-charts-color-background`, `--a8c-charts-color-series-*` — and resolved through `getComputedStyle` against the chart's own scope element, never `document.documentElement`, so both delivery paths obey the same cascade. Each pointer carries a terminal literal (`var(--a8c-charts-color-background, #fff)`) as the last resort for SSR and jsdom, where `getComputedStyle` resolves nothing.
68
68
 
@@ -95,10 +95,12 @@ The scope element is the wrapper a chart is rendered into, which sits **above**
95
95
  | `--a8c-charts-color-surface` | `--wpds-color-background-surface-neutral-strong` | `#fff` |
96
96
  | `--a8c-charts-color-surface-secondary` | `--wpds-color-background-surface-neutral-weak` | `#f4f4f4` |
97
97
  | `--a8c-charts-color-track` | `--wpds-color-background-track-neutral-weak` | `#f0f0f0` |
98
- | `--a8c-charts-color-tooltip-surface` | _(none — translucent dark surface, no WPDS fit)_ | `rgb(0 0 0 / 85%)` |
98
+ | `--a8c-charts-color-tooltip-surface` | _(none: WPDS has no inverted surface token yet)_ | `#1e1e1e` |
99
99
 
100
100
  The x axis and tick roles share grid's WPDS token but stay distinct roles, so the three can be themed independently.
101
101
 
102
+ `--a8c-charts-color-tooltip-surface` is the color the tooltip theme is generated from, as `@wordpress/ui` seeds its Tooltip popup with `#1e1e1e`. Set it on the provider wrapper to retheme every tooltip, light or dark: the box surface, its text, every catalog role and every `--wpds-*` token inside follow. It must be an opaque sRGB color; anything else falls back to `#1e1e1e`. To recolor one chart's tooltip, repoint `--a8c-charts-color-surface` and `--a8c-charts-color-label` in that chart's `tooltipStyle`. That moves only those two roles: content that reads a `--wpds-*` token keeps the dark theme's value.
103
+
102
104
  ### One pair of roles per axis
103
105
 
104
106
  Each axis names itself: `--a8c-charts-color-axis-x` / `-tick-x` paint the x axis, `--a8c-charts-color-axis-y` / `-tick-y` the y. The y pair resolves to `none`, so by default that axis carries tick labels and nothing else. Declare either to paint it: