@automattic/charts 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/TOKENS.md +51 -12
- package/dist/index.cjs +307 -213
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +7 -1
- package/dist/index.d.cts +223 -127
- package/dist/index.d.ts +223 -127
- package/dist/index.js +306 -212
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/charts/area-chart/area-chart.tsx +2 -2
- package/src/charts/area-chart/test/area-chart.test.tsx +45 -0
- package/src/charts/bar-chart/bar-chart.tsx +36 -10
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +19 -12
- package/src/charts/bar-chart/test/bar-chart-pointer-events.test.tsx +67 -0
- package/src/charts/bar-chart/test/bar-chart.test.tsx +101 -0
- package/src/charts/bar-list-chart/bar-list-chart.tsx +40 -2
- package/src/charts/bar-list-chart/test/bar-list-chart.test.tsx +38 -0
- package/src/charts/line-chart/line-chart.tsx +18 -3
- package/src/charts/line-chart/test/line-chart.test.tsx +98 -0
- package/src/charts/sparkline/sparkline.tsx +9 -3
- package/src/charts/sparkline/types.ts +1 -1
- package/src/components/tooltip/accessible-tooltip.tsx +32 -2
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +68 -0
- package/src/hooks/test/use-xychart-theme-provider-override.test.tsx +4 -4
- package/src/hooks/test/use-xychart-theme-style-reads.test.tsx +17 -10
- package/src/hooks/test/use-xychart-theme.test.tsx +50 -5
- package/src/hooks/use-xychart-theme.ts +14 -20
- package/src/providers/chart-context/global-charts-provider.tsx +44 -33
- package/src/providers/chart-context/private/series-palette.ts +45 -0
- package/src/providers/chart-context/private/theme-override-vars.ts +46 -2
- package/src/providers/chart-context/private/with-catalog-pointers.ts +45 -2
- package/src/providers/chart-context/test/sparse-theme.test.ts +16 -2
- package/src/providers/chart-context/test/theme-override-vars.test.ts +65 -0
- package/src/providers/chart-context/test/use-global-charts-theme.test.tsx +8 -1
- package/src/providers/chart-context/test/with-catalog-pointers.test.ts +57 -0
- package/src/providers/chart-context/themes.ts +8 -3
- package/src/styles/chart-scope.scss +52 -24
- package/src/styles/test/chart-scope.test.ts +22 -9
- package/src/types.ts +148 -31
- package/src/utils/get-styles.ts +7 -1
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
|
+
## [3.2.0] - 2026-09-01
|
|
9
|
+
### Added
|
|
10
|
+
- Bar and line charts: Report a click through the pointer event handlers and Enter or Space through an activation callback, so a chart can open the point under the pointer or the keyboard selection. [#51544]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Follow the WordPress admin color scheme for series colors, and move the palette to five --a8c-charts-color-series-* custom properties. theme.colors is deprecated. [#51535]
|
|
14
|
+
- Stop resolving the grid, axis, tick and label colors in JavaScript and let their `--a8c-charts-color-*` chain reach the element instead, so an override set on a chart's own element applies to it and a theme change repaints with no re-render. Add `--a8c-charts-color-label-background` for the plate behind a pie-slice label.
|
|
15
|
+
|
|
16
|
+
Deprecate every color field on the chart theme — each one now has a `--a8c-charts-color-*` role, a component prop, or both. They all still work. Where a field mixes a color with something else, only the color member is deprecated: `gridStyles.strokeWidth`, `svgLabelSmall.fontFamily` and the annotation geometry are unaffected. [#51687]
|
|
17
|
+
- Update package dependencies. [#51303] [#51665] [#51802]
|
|
18
|
+
|
|
19
|
+
## [3.1.1] - 2026-08-26
|
|
20
|
+
### Fixed
|
|
21
|
+
- LineChart, AreaChart, BarChart: Keep the derived date tick labels when a consumer passes an undefined tickFormat. [#51531]
|
|
22
|
+
|
|
8
23
|
## [3.1.0] - 2026-08-25
|
|
9
24
|
### Added
|
|
10
25
|
- Add `defaultHiddenSeries` to seed a series hidden on load, plus absolute visibility setters. Keep the keyboard tooltip open when the chart re-renders under it. [#51458]
|
|
@@ -1003,6 +1018,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1003
1018
|
- Fixed lints following ESLint rule changes for TS [#40584]
|
|
1004
1019
|
- Fixing a bug in Chart storybook data. [#40640]
|
|
1005
1020
|
|
|
1021
|
+
[3.2.0]: https://github.com/Automattic/charts/compare/v3.1.1...v3.2.0
|
|
1022
|
+
[3.1.1]: https://github.com/Automattic/charts/compare/v3.1.0...v3.1.1
|
|
1006
1023
|
[3.1.0]: https://github.com/Automattic/charts/compare/v3.0.0...v3.1.0
|
|
1007
1024
|
[3.0.0]: https://github.com/Automattic/charts/compare/v2.0.1...v3.0.0
|
|
1008
1025
|
[2.0.1]: https://github.com/Automattic/charts/compare/v2.0.0...v2.0.1
|
package/TOKENS.md
CHANGED
|
@@ -34,11 +34,11 @@ Highest first:
|
|
|
34
34
|
|
|
35
35
|
A CSS declaration of a role therefore beats a `theme` prop override *anywhere* it is set, the wrapper included — the prop writes a variable the role reads, not the role itself, and a role declared in CSS never reads it.
|
|
36
36
|
|
|
37
|
-
An override set **above** `GlobalChartsProvider` does not apply: the provider's own declaration on its wrapper beats a value merely inherited from an ancestor. Set overrides inside the provider tree, or target the scope class itself — `.a8c-charts-scope { --a8c-charts-color-grid: #e0e0e0; }` matches every provider wrapper on the page, including the one a bare chart mounts for itself and the one a portal tooltip carries, and outranks the zero-specificity catalog default. That rule is the replacement for a page-level `:root` override. The same rule limits `@wordpress/theme`'s `ThemeProvider` to *above* the charts provider: the catalog substitutes its `--wpds-*` tokens at the wrapper, so a `ThemeProvider` mounted between the wrapper and a chart is never consulted and CSS-painted
|
|
37
|
+
An override set **above** `GlobalChartsProvider` does not apply: the provider's own declaration on its wrapper beats a value merely inherited from an ancestor. Set overrides inside the provider tree, or target the scope class itself — `.a8c-charts-scope { --a8c-charts-color-grid: #e0e0e0; }` matches every provider wrapper on the page, including the one a bare chart mounts for itself and the one a portal tooltip carries, and outranks the zero-specificity catalog default. That rule is the replacement for a page-level `:root` override. The same rule limits `@wordpress/theme`'s `ThemeProvider` to *above* the charts provider: the catalog substitutes its `--wpds-*` tokens at the wrapper, so a `ThemeProvider` mounted between the wrapper and a chart is never consulted and CSS-painted colors keep their light-mode spec fallbacks. The JS-consumed ones do not — `getElementStyles` resolves at the chart element — so that nesting shows up as a chart whose series marks retint while its gridlines, axis and surfaces do not.
|
|
38
38
|
|
|
39
39
|
#### The theme layer
|
|
40
40
|
|
|
41
|
-
Each
|
|
41
|
+
Each role a `theme` prop field can override is declared reading a `*-theme` variable first:
|
|
42
42
|
|
|
43
43
|
```scss
|
|
44
44
|
:where(.a8c-charts-scope) {
|
|
@@ -54,7 +54,7 @@ A value that reads the role it would override is not published at all. The role
|
|
|
54
54
|
|
|
55
55
|
#### A `theme`-prop override keeps the reach of the field it was set from
|
|
56
56
|
|
|
57
|
-
A role is a shared name, so publishing an override as a custom property could widen it — `theme={ { svgLabelSmall: { fill: 'purple' } } }`
|
|
57
|
+
A role is a shared name, so publishing an override as a custom property could widen it — `theme={ { svgLabelSmall: { fill: 'purple' } } }` recoloring legend labels, heatmap cell values, funnel labels and the line-chart tooltip along with the SVG axis labels it names.
|
|
58
58
|
|
|
59
59
|
It doesn't, because a mapped field publishes a role read by exactly the elements that field already controlled. Where the obvious role has wider readership, one side or the other gets a role of its own:
|
|
60
60
|
|
|
@@ -67,13 +67,25 @@ It doesn't, because a mapped field publishes a role read by exactly the elements
|
|
|
67
67
|
|
|
68
68
|
The consequence: `--a8c-charts-color-label` moves every label, but no single role repaints the chart background and the floating surfaces together.
|
|
69
69
|
|
|
70
|
-
`gridStyles.stroke`, `xAxisLineStyles.stroke
|
|
70
|
+
`gridStyles.stroke`, `xAxisLineStyles.stroke`, `xTickLineStyles.stroke`, `labelBackgroundColor` and `labelTextColor` need no narrow role — nothing outside the element each names reads their role.
|
|
71
71
|
|
|
72
72
|
### The SVG bridge
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
**A color that is only painted is not resolved at all.** The grid, axis line, tick marks and tick labels keep their `var(--a8c-charts-color-*, …)` chain the whole way: `useXYChartTheme` spreads them through untouched, `buildChartTheme` passes them on, and visx writes the chain onto the element it paints — an inline style for the grid, a presentation attribute elsewhere. A presentation attribute is mapped to a CSS declaration, so the chain resolves there natively, in Blink, WebKit and Gecko alike.
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
That is what makes the role read **at the painted element** rather than snapshot at the provider wrapper: an override on a chart's own class reaches it, a theme change repaints with no re-render, and SSR emits the chain for the client to resolve on paint. Resolving such a color in JS would freeze it and undo all three, which is why nothing does.
|
|
77
|
+
|
|
78
|
+
There is no stylesheet and no class involved. In particular the axes need neither: `xAxisLineStyles` and `xTickLineStyles` are x-axis-only fields, so visx paints the x axis and leaves the y axis unstroked without anything having to distinguish them.
|
|
79
|
+
|
|
80
|
+
What else crosses in JS is what something reads as a *value*: the series palette, which visx turns into its `colorScale`, and 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.
|
|
81
|
+
|
|
82
|
+
**The tooltip is the one painted exception, because visx paints 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 reaches only its own hardcoded fallback — never the role, never a consumer's override. Two colors take that route and are therefore resolved before visx sees them: `htmlLabel.color`, in `useXYChartTheme`, and the crosshair stroke, in `AccessibleTooltip`. `htmlLabel.color` has a second reason: 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. Giving the portal the scope class instead would fix neither: visx hardcodes the crosshair portals' `className`.
|
|
83
|
+
|
|
84
|
+
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.
|
|
85
|
+
|
|
86
|
+
Being JS-consumed is not a reason for a field to survive, though — where a value is *consumed* and where it is *set* are separate questions. `withCatalogPointers` parks a consumer's `theme` value in the catalog role and restores the pointer, so `theme.backgroundColor` and `theme.colors` are only ever carriers for their roles. Both are deprecated; set `--a8c-charts-color-background` and `--a8c-charts-color-series-*` instead. Those resolve through `getComputedStyle` against the chart's own scope element — never `document.documentElement` — so both delivery paths obey the same cascade. The JS theme in `themes.ts` holds a bare catalog pointer with a terminal literal (`var(--a8c-charts-color-background, #fff)`); the literal is the last resort for SSR and jsdom, where `getComputedStyle` resolves nothing.
|
|
87
|
+
|
|
88
|
+
The scope element is the wrapper a chart is rendered into, which sits **above** the element the chart's own `className` lands on, so a role declared on that inner element is invisible to the JS bridge. `.line-chart { --a8c-charts-color-background: red }` therefore does not reach the glyph strokes, while `.line-chart { --a8c-charts-color-grid: red }` does reach the gridlines — the CSS-painted roles read at the painted element, so any ancestor of it will do. Scope a rule for a JS-resolved role to a wrapper around the chart rather than to the chart itself. CHARTS-255 tracks closing the remainder.
|
|
77
89
|
|
|
78
90
|
`GeoChart` (Google Charts) takes a resolved-hex snapshot at render, so it does not live-update on a theme change without a re-render.
|
|
79
91
|
|
|
@@ -81,8 +93,13 @@ The scope element is the wrapper a chart is rendered into, which sits **above**
|
|
|
81
93
|
|
|
82
94
|
> These tables are checked against `src/styles/chart-scope.scss` by `src/styles/test/chart-scope.test.ts`. Update the stylesheet and the table together.
|
|
83
95
|
|
|
84
|
-
| Role | Maps to
|
|
96
|
+
| Role | Maps to | Fallback |
|
|
85
97
|
|---|---|---|
|
|
98
|
+
| `--a8c-charts-color-series-1` | `--wp-admin-theme-color` | `var(--wpds-color-foreground-interactive-brand, var(--wp-admin-theme-color, #3858e9))` |
|
|
99
|
+
| `--a8c-charts-color-series-2` | _(none — unset until a consumer sets it)_ | — |
|
|
100
|
+
| `--a8c-charts-color-series-3` | _(none — unset until a consumer sets it)_ | — |
|
|
101
|
+
| `--a8c-charts-color-series-4` | _(none — unset until a consumer sets it)_ | — |
|
|
102
|
+
| `--a8c-charts-color-series-5` | _(none — unset until a consumer sets it)_ | — |
|
|
86
103
|
| `--a8c-charts-color-grid` | `--wpds-color-stroke-surface-neutral` | `#dbdbdb` |
|
|
87
104
|
| `--a8c-charts-color-axis` | `--wpds-color-stroke-surface-neutral` | `#dbdbdb` |
|
|
88
105
|
| `--a8c-charts-color-tick` | `--wpds-color-stroke-surface-neutral` | `#dbdbdb` |
|
|
@@ -90,6 +107,7 @@ The scope element is the wrapper a chart is rendered into, which sits **above**
|
|
|
90
107
|
| `--a8c-charts-color-label-secondary` | `--wpds-color-foreground-content-neutral-weak` | `#707070` |
|
|
91
108
|
| `--a8c-charts-color-label-inverse` | `--wpds-color-foreground-interactive-neutral-strong` | `#f0f0f0` |
|
|
92
109
|
| `--a8c-charts-color-label-on-fill` | _(none — white-on-series-fill, no WPDS fit)_ | `#fff` |
|
|
110
|
+
| `--a8c-charts-color-label-background` | _(none — transparent by default, no WPDS fit)_ | `transparent` |
|
|
93
111
|
| `--a8c-charts-color-label-axis` | _(derives from `--a8c-charts-color-label`)_ | — |
|
|
94
112
|
| `--a8c-charts-color-annotation` | `--wpds-color-foreground-content-neutral` | `#1e1e1e` |
|
|
95
113
|
| `--a8c-charts-color-trend-up` | `--wpds-color-foreground-content-success-weak` | `#008030` |
|
|
@@ -103,9 +121,30 @@ The scope element is the wrapper a chart is rendered into, which sits **above**
|
|
|
103
121
|
|
|
104
122
|
Axis and tick share grid's WPDS token but stay distinct roles, so the three can be themed independently.
|
|
105
123
|
|
|
106
|
-
|
|
124
|
+
### The series palette
|
|
125
|
+
|
|
126
|
+
The five `--a8c-charts-color-series-*` slots are the palette. `GlobalChartsProvider` resolves them once, at its wrapper, and seeds its color cache with whatever resolves; charts generate accessible colors beyond the seeds, so five slots is a cap on *seeds*, not on series. A slot that resolves to nothing is skipped and the palette compacts — set only slots 1 and 3 and the palette is two colors, in that order.
|
|
127
|
+
|
|
128
|
+
Only slot 1 has a default, and it names `--wp-admin-theme-color` first, so series colors follow the WordPress admin color scheme with no host configuration.
|
|
129
|
+
|
|
130
|
+
The design system's brand token is the next leg rather than the first, because it only reaches the admin color scheme when a WPDS **root provider** is on the page. Measured on a live WordPress 7.1 wp-admin dashboard, `<html data-wpds-root-provider>` carries the whole generated ramp inline, derived from `--wp-admin-theme-color`. Where no root provider boots, the token falls back to the plain stylesheet rule — a static `#3858e9` with no reference to the admin color. So on WP 7.1 either order happens to work; everywhere else (WP 7.0.x, a page without a root provider, Calypso, SSR) only this one does.
|
|
131
|
+
|
|
132
|
+
Leading with the admin color costs nothing, because `@wordpress/theme` writes `--wp-admin-theme-color` from a provider's own accent — its legacy wp-admin override — alongside the `--wpds-*` ramp. A provider accent therefore still wins.
|
|
133
|
+
|
|
134
|
+
Precedence for a series color, highest first:
|
|
135
|
+
|
|
136
|
+
1. `options.stroke` on that series, resolved at the chart element. This is the per-series override.
|
|
137
|
+
2. A CSS declaration of `--a8c-charts-color-series-N`, on the usual catalog rules above.
|
|
138
|
+
3. `theme.colors[ N - 1 ]`, which publishes slot N's theme layer. Deprecated — see below.
|
|
139
|
+
4. The catalog default, which exists only for slot 1.
|
|
140
|
+
|
|
141
|
+
The palette is resolved per provider, so one `ColorCache` and one group-to-color map serve every chart under it and siblings agree on what a group is colored. The consequence is that a slot set on a *chart's own* element does not apply — the palette was resolved at the provider wrapper before that element existed. Use `options.stroke` for a per-chart color.
|
|
142
|
+
|
|
143
|
+
`theme.colors` is deprecated sugar over the slots: entry N publishes slot N's theme layer through the same mechanism as every other mapped field, so a CSS declaration still outranks it and a short array leaves the later slots unset rather than blank. Entries past the fifth are ignored, with a one-time console warning. It is removed in CHARTS-263.
|
|
144
|
+
|
|
145
|
+
## Non-color roles
|
|
107
146
|
|
|
108
|
-
| Role | Maps to
|
|
147
|
+
| Role | Maps to | Fallback |
|
|
109
148
|
|---|---|---|
|
|
110
149
|
| `--a8c-charts-motion-duration-entrance` | `--wpds-motion-duration-xl` | `400ms` |
|
|
111
150
|
| `--a8c-charts-motion-easing-entrance` | `--wpds-motion-easing-expressive` | `cubic-bezier(0.25, 0, 0, 1)` |
|
|
@@ -123,14 +162,14 @@ The elevation fallbacks hold the values their removed `--wpds-elevation-*` token
|
|
|
123
162
|
|
|
124
163
|
Instance styling knobs, on the same convention but not shared semantic roles: `--a8c-charts-dimension-leaderboard-bar-hover-inset`, `--a8c-charts-color-heatmap-*`, `--a8c-charts-dimension-heatmap-*`, `--a8c-charts-heatmap-cell-intensity`, `--a8c-charts-color-zoom-selection`, `--a8c-charts-color-zoom-selection-stroke`.
|
|
125
164
|
|
|
126
|
-
| Role | Maps to
|
|
165
|
+
| Role | Maps to | Fallback |
|
|
127
166
|
|---|---|---|
|
|
128
167
|
| `--a8c-charts-color-zoom-selection` | `--wpds-color-background-interactive-brand-strong` | `var(--wp-admin-theme-color, #3858e9)` |
|
|
129
168
|
| `--a8c-charts-color-zoom-selection-stroke` | `--wpds-color-stroke-interactive-brand` | `var(--wp-admin-theme-color, #3858e9)` |
|
|
130
169
|
|
|
131
|
-
The zoom selection roles' translucency is not part of the role — it lives in `fill-opacity` / `stroke-opacity`, so an override sets an opaque
|
|
170
|
+
The zoom selection roles' translucency is not part of the role — it lives in `fill-opacity` / `stroke-opacity`, so an override sets an opaque color and keeps the intended transparency.
|
|
132
171
|
|
|
133
|
-
`--a8c-charts-heatmap-cell-intensity` is the one variable without a `{category}` segment: it holds a unitless 0–1 scalar consumed inside `color-mix()`, not a
|
|
172
|
+
`--a8c-charts-heatmap-cell-intensity` is the one variable without a `{category}` segment: it holds a unitless 0–1 scalar consumed inside `color-mix()`, not a color.
|
|
134
173
|
|
|
135
174
|
The heatmap Tier-2 variables and `--a8c-charts-dimension-leaderboard-bar-hover-inset` are **component-emitted** — set from JS per render, or in the component's own stylesheet — rather than on the provider wrapper. They are deliberately absent from `chart-scope.scss` and are not consumer override points in the same sense as the catalog above.
|
|
136
175
|
|