@automattic/charts 3.1.1 → 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 +12 -0
- package/TOKENS.md +51 -12
- package/dist/index.cjs +292 -200
- 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 +291 -199
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/charts/bar-chart/bar-chart.tsx +36 -10
- package/src/charts/bar-chart/test/bar-chart-pointer-events.test.tsx +67 -0
- package/src/charts/bar-chart/test/bar-chart.test.tsx +79 -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 +16 -1
- package/src/charts/line-chart/test/line-chart.test.tsx +47 -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
|
@@ -29,6 +29,9 @@ describe( 'themeOverrideVars', () => {
|
|
|
29
29
|
xAxisLineStyles: { stroke: '#333' },
|
|
30
30
|
xTickLineStyles: { stroke: '#444' },
|
|
31
31
|
svgLabelSmall: { fill: '#555' },
|
|
32
|
+
labelBackgroundColor: '#556',
|
|
33
|
+
labelTextColor: '#557',
|
|
34
|
+
colors: [ '#661', '#662', '#663', '#664', '#665' ],
|
|
32
35
|
} )
|
|
33
36
|
).toEqual( {
|
|
34
37
|
vars: {
|
|
@@ -37,6 +40,13 @@ describe( 'themeOverrideVars', () => {
|
|
|
37
40
|
'--a8c-charts-color-axis-theme': '#333',
|
|
38
41
|
'--a8c-charts-color-tick-theme': '#444',
|
|
39
42
|
'--a8c-charts-color-label-axis-theme': '#555',
|
|
43
|
+
'--a8c-charts-color-label-background-theme': '#556',
|
|
44
|
+
'--a8c-charts-color-label-on-fill-theme': '#557',
|
|
45
|
+
'--a8c-charts-color-series-1-theme': '#661',
|
|
46
|
+
'--a8c-charts-color-series-2-theme': '#662',
|
|
47
|
+
'--a8c-charts-color-series-3-theme': '#663',
|
|
48
|
+
'--a8c-charts-color-series-4-theme': '#664',
|
|
49
|
+
'--a8c-charts-color-series-5-theme': '#665',
|
|
40
50
|
},
|
|
41
51
|
roles: [
|
|
42
52
|
'--a8c-charts-color-background',
|
|
@@ -44,6 +54,13 @@ describe( 'themeOverrideVars', () => {
|
|
|
44
54
|
'--a8c-charts-color-axis',
|
|
45
55
|
'--a8c-charts-color-tick',
|
|
46
56
|
'--a8c-charts-color-label-axis',
|
|
57
|
+
'--a8c-charts-color-label-background',
|
|
58
|
+
'--a8c-charts-color-label-on-fill',
|
|
59
|
+
'--a8c-charts-color-series-1',
|
|
60
|
+
'--a8c-charts-color-series-2',
|
|
61
|
+
'--a8c-charts-color-series-3',
|
|
62
|
+
'--a8c-charts-color-series-4',
|
|
63
|
+
'--a8c-charts-color-series-5',
|
|
47
64
|
],
|
|
48
65
|
} );
|
|
49
66
|
} );
|
|
@@ -55,6 +72,9 @@ describe( 'themeOverrideVars', () => {
|
|
|
55
72
|
xAxisLineStyles: { stroke: '#333' },
|
|
56
73
|
xTickLineStyles: { stroke: '#444' },
|
|
57
74
|
svgLabelSmall: { fill: '#555' },
|
|
75
|
+
labelBackgroundColor: '#556',
|
|
76
|
+
labelTextColor: '#557',
|
|
77
|
+
colors: [ '#661', '#662', '#663', '#664', '#665' ],
|
|
58
78
|
} );
|
|
59
79
|
|
|
60
80
|
expect( Object.keys( vars ) ).toEqual( THEME_LAYERED_ROLES.map( themeLayerVar ) );
|
|
@@ -68,6 +88,51 @@ describe( 'themeOverrideVars', () => {
|
|
|
68
88
|
} );
|
|
69
89
|
} );
|
|
70
90
|
|
|
91
|
+
// A short array is not padded: the later slots stay unset, so the palette compacts rather than repeating a color the consumer never chose.
|
|
92
|
+
it( 'publishes one palette slot per color and leaves the rest unset', () => {
|
|
93
|
+
expect( themeOverrideVars( { colors: [ 'red', 'blue' ] } ) ).toEqual( {
|
|
94
|
+
vars: {
|
|
95
|
+
'--a8c-charts-color-series-1-theme': 'red',
|
|
96
|
+
'--a8c-charts-color-series-2-theme': 'blue',
|
|
97
|
+
},
|
|
98
|
+
roles: [ '--a8c-charts-color-series-1', '--a8c-charts-color-series-2' ],
|
|
99
|
+
} );
|
|
100
|
+
} );
|
|
101
|
+
|
|
102
|
+
it( 'drops palette entries past the last slot', () => {
|
|
103
|
+
// Spied rather than asserted on: an over-long palette warns, and `@wordpress/jest-console` fails any test that leaves a console call unclaimed. The warning itself is covered below.
|
|
104
|
+
const warn = jest.spyOn( console, 'warn' ).mockImplementation( () => {} );
|
|
105
|
+
const { vars } = themeOverrideVars( {
|
|
106
|
+
colors: [ 'a', 'b', 'c', 'd', 'e', 'f', 'g' ],
|
|
107
|
+
} );
|
|
108
|
+
|
|
109
|
+
expect( vars[ '--a8c-charts-color-series-5-theme' ] ).toBe( 'e' );
|
|
110
|
+
expect( vars[ '--a8c-charts-color-series-6-theme' ] ).toBeUndefined();
|
|
111
|
+
|
|
112
|
+
warn.mockRestore();
|
|
113
|
+
} );
|
|
114
|
+
|
|
115
|
+
// Isolated so the warning's module-level latch starts unset — the assertion is that it warns once per module instance, not once per call.
|
|
116
|
+
it( 'warns once about the dropped entries, not once per render', () => {
|
|
117
|
+
jest.isolateModules( () => {
|
|
118
|
+
const warn = jest.spyOn( console, 'warn' ).mockImplementation( () => {} );
|
|
119
|
+
const {
|
|
120
|
+
themeOverrideVars: freshThemeOverrideVars,
|
|
121
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- isolateModules needs a synchronous require to get a module instance whose latch is unset.
|
|
122
|
+
} = require( '../private/theme-override-vars' ) as {
|
|
123
|
+
themeOverrideVars: typeof themeOverrideVars;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
freshThemeOverrideVars( { colors: [ 'a', 'b', 'c', 'd', 'e', 'f' ] } );
|
|
127
|
+
freshThemeOverrideVars( { colors: [ 'a', 'b', 'c', 'd', 'e', 'f' ] } );
|
|
128
|
+
|
|
129
|
+
expect( warn ).toHaveBeenCalledTimes( 1 );
|
|
130
|
+
expect( warn ).toHaveBeenCalledWith( expect.stringContaining( 'holds 6 colors' ) );
|
|
131
|
+
|
|
132
|
+
warn.mockRestore();
|
|
133
|
+
} );
|
|
134
|
+
} );
|
|
135
|
+
|
|
71
136
|
it( 'ignores a value that is itself a pointer at the role it would override', () => {
|
|
72
137
|
expect(
|
|
73
138
|
themeOverrideVars( { gridStyles: { stroke: 'var(--a8c-charts-color-grid, #dbdbdb)' } } ).vars
|
|
@@ -27,7 +27,14 @@ describe( 'useGlobalChartsTheme', () => {
|
|
|
27
27
|
|
|
28
28
|
const { result } = renderHook( () => useGlobalChartsTheme(), { wrapper } );
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
// `theme.colors` publishes the palette's theme layers, so the merged theme holds catalog pointers rather than the consumer's literals. Each keeps its consumer color as the pointer's terminal literal, for SSR and jsdom.
|
|
31
|
+
expect( result.current.colors ).toEqual( [
|
|
32
|
+
'var(--a8c-charts-color-series-1, #FF0000)',
|
|
33
|
+
'var(--a8c-charts-color-series-2, #00FF00)',
|
|
34
|
+
'var(--a8c-charts-color-series-3, #0000FF)',
|
|
35
|
+
'var(--a8c-charts-color-series-4)',
|
|
36
|
+
'var(--a8c-charts-color-series-5)',
|
|
37
|
+
] );
|
|
31
38
|
// Other properties should still come from default theme
|
|
32
39
|
expect( result.current.backgroundColor ).toBe( defaultTheme.backgroundColor );
|
|
33
40
|
expect( result.current.gridStyles ).toEqual( defaultTheme.gridStyles );
|
|
@@ -11,6 +11,8 @@ describe( 'withCatalogPointers', () => {
|
|
|
11
11
|
xAxisLineStyles: { stroke: '#333' },
|
|
12
12
|
xTickLineStyles: { stroke: '#444' },
|
|
13
13
|
svgLabelSmall: { fill: '#555' },
|
|
14
|
+
labelBackgroundColor: '#556',
|
|
15
|
+
labelTextColor: '#557',
|
|
14
16
|
} as Partial< ChartTheme > );
|
|
15
17
|
|
|
16
18
|
const result = withCatalogPointers( merged, [
|
|
@@ -19,6 +21,8 @@ describe( 'withCatalogPointers', () => {
|
|
|
19
21
|
'--a8c-charts-color-axis',
|
|
20
22
|
'--a8c-charts-color-tick',
|
|
21
23
|
'--a8c-charts-color-label-axis',
|
|
24
|
+
'--a8c-charts-color-label-background',
|
|
25
|
+
'--a8c-charts-color-label-on-fill',
|
|
22
26
|
] );
|
|
23
27
|
|
|
24
28
|
expect( result.backgroundColor ).toBe( defaultTheme.backgroundColor );
|
|
@@ -26,6 +30,8 @@ describe( 'withCatalogPointers', () => {
|
|
|
26
30
|
expect( result.xAxisLineStyles.stroke ).toBe( defaultTheme.xAxisLineStyles.stroke );
|
|
27
31
|
expect( result.xTickLineStyles.stroke ).toBe( defaultTheme.xTickLineStyles.stroke );
|
|
28
32
|
expect( result.svgLabelSmall.fill ).toBe( defaultTheme.svgLabelSmall.fill );
|
|
33
|
+
expect( result.labelBackgroundColor ).toBe( defaultTheme.labelBackgroundColor );
|
|
34
|
+
expect( result.labelTextColor ).toBe( defaultTheme.labelTextColor );
|
|
29
35
|
|
|
30
36
|
expect( merged.backgroundColor ).toBe( '#111' );
|
|
31
37
|
expect( merged.gridStyles.stroke ).toBe( '#222' );
|
|
@@ -44,4 +50,55 @@ describe( 'withCatalogPointers', () => {
|
|
|
44
50
|
// Not a mapped role, so its literal survives even when other roles are being restored.
|
|
45
51
|
expect( result.leaderboardChart.deltaColors ).toEqual( [ 'red', 'grey', 'green' ] );
|
|
46
52
|
} );
|
|
53
|
+
|
|
54
|
+
// The palette is restored as a whole, so a consumer's short array cannot shorten it. `mergeThemes` replaces arrays outright, and a two-entry palette would leave slots 3 to 5 unreadable — a CSS declaration of one of them would have no entry to resolve through.
|
|
55
|
+
it( 'restores the full five-slot palette from a shorter consumer array', () => {
|
|
56
|
+
const merged = mergeThemes( defaultTheme, {
|
|
57
|
+
colors: [ '#111', '#222' ],
|
|
58
|
+
} as Partial< ChartTheme > );
|
|
59
|
+
|
|
60
|
+
const result = withCatalogPointers( merged, [
|
|
61
|
+
'--a8c-charts-color-series-1',
|
|
62
|
+
'--a8c-charts-color-series-2',
|
|
63
|
+
] );
|
|
64
|
+
|
|
65
|
+
expect( result.colors ).toEqual( [
|
|
66
|
+
'var(--a8c-charts-color-series-1, #111)',
|
|
67
|
+
'var(--a8c-charts-color-series-2, #222)',
|
|
68
|
+
'var(--a8c-charts-color-series-3)',
|
|
69
|
+
'var(--a8c-charts-color-series-4)',
|
|
70
|
+
'var(--a8c-charts-color-series-5)',
|
|
71
|
+
] );
|
|
72
|
+
} );
|
|
73
|
+
|
|
74
|
+
// Each slot's restore rewrites the whole array, so restoring five of them must not wrap the pointers five times over.
|
|
75
|
+
it( 'restores the palette idempotently across every overridden slot', () => {
|
|
76
|
+
const merged = mergeThemes( defaultTheme, {
|
|
77
|
+
colors: [ '#111', '#222', '#333', '#444', '#555' ],
|
|
78
|
+
} as Partial< ChartTheme > );
|
|
79
|
+
|
|
80
|
+
const result = withCatalogPointers( merged, [
|
|
81
|
+
'--a8c-charts-color-series-1',
|
|
82
|
+
'--a8c-charts-color-series-2',
|
|
83
|
+
'--a8c-charts-color-series-3',
|
|
84
|
+
'--a8c-charts-color-series-4',
|
|
85
|
+
'--a8c-charts-color-series-5',
|
|
86
|
+
] );
|
|
87
|
+
|
|
88
|
+
expect( result.colors ).toEqual( [
|
|
89
|
+
'var(--a8c-charts-color-series-1, #111)',
|
|
90
|
+
'var(--a8c-charts-color-series-2, #222)',
|
|
91
|
+
'var(--a8c-charts-color-series-3, #333)',
|
|
92
|
+
'var(--a8c-charts-color-series-4, #444)',
|
|
93
|
+
'var(--a8c-charts-color-series-5, #555)',
|
|
94
|
+
] );
|
|
95
|
+
} );
|
|
96
|
+
|
|
97
|
+
// The literal is only reached where getComputedStyle resolves nothing, and the palette is the one field where falling back to the catalog default would be visible: every series would paint the same seeded blue.
|
|
98
|
+
it( 'keeps the consumer color as each pointer’s terminal literal, for SSR and jsdom', () => {
|
|
99
|
+
const merged = mergeThemes( defaultTheme, { colors: [ 'red' ] } as Partial< ChartTheme > );
|
|
100
|
+
const result = withCatalogPointers( merged, [ '--a8c-charts-color-series-1' ] );
|
|
101
|
+
|
|
102
|
+
expect( result.colors[ 0 ] ).toBe( 'var(--a8c-charts-color-series-1, red)' );
|
|
103
|
+
} );
|
|
47
104
|
} );
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SERIES_PALETTE_POINTERS } from './private/series-palette';
|
|
1
2
|
import type { CompleteChartTheme } from '../../types';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -5,10 +6,14 @@ import type { CompleteChartTheme } from '../../types';
|
|
|
5
6
|
*/
|
|
6
7
|
const defaultTheme: CompleteChartTheme = {
|
|
7
8
|
backgroundColor: 'var(--a8c-charts-color-background, #fff)',
|
|
8
|
-
labelBackgroundColor: '
|
|
9
|
-
// White label text sits on top of arbitrary series colors, so it has no WPDS content-foreground equivalent. Every other
|
|
9
|
+
labelBackgroundColor: 'var(--a8c-charts-color-label-background, transparent)',
|
|
10
|
+
// White label text sits on top of arbitrary series colors, so it has no WPDS content-foreground equivalent. Every other color here is a bare pointer at the catalog emitted by `chart-scope.scss`; the terminal literal is the last resort for the SSR and jsdom paths, where getComputedStyle resolves nothing.
|
|
10
11
|
labelTextColor: 'var(--a8c-charts-color-label-on-fill, #FFFFFF)',
|
|
11
|
-
|
|
12
|
+
// Derived, not authored: the slot manifest lives in `private/series-palette.ts` because which
|
|
13
|
+
// slots exist describes the catalog, not the theme. The field itself is still load-bearing —
|
|
14
|
+
// see that file for why the provider reads the palette through the theme and what has to move
|
|
15
|
+
// before this can be deleted.
|
|
16
|
+
colors: [ ...SERIES_PALETTE_POINTERS ],
|
|
12
17
|
gridStyles: {
|
|
13
18
|
stroke: 'var(--a8c-charts-color-grid, #dbdbdb)',
|
|
14
19
|
strokeWidth: 1,
|
|
@@ -1,41 +1,69 @@
|
|
|
1
1
|
// The single mapping point between the --a8c-charts-* catalog and WordPress
|
|
2
|
-
// design-system tokens.
|
|
2
|
+
// design-system tokens. Declares custom properties only — this stylesheet must
|
|
3
|
+
// never change layout.
|
|
3
4
|
|
|
4
|
-
// Declared on the GlobalChartsProvider wrapper
|
|
5
|
+
// Declared on the GlobalChartsProvider wrapper, not at :root, because
|
|
5
6
|
// @wordpress/theme's ThemeProvider emits its generated --wpds-* ramp as inline
|
|
6
|
-
// styles on its own wrapper div
|
|
7
|
-
// provider means a ThemeProvider above it is picked up; substituting at :root
|
|
8
|
-
// would miss it entirely.
|
|
7
|
+
// styles on its own wrapper div. Substituting at :root would miss it entirely.
|
|
9
8
|
|
|
10
|
-
// :where() keeps the rule at zero specificity so any consumer rule
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// the provider tree.
|
|
9
|
+
// :where() keeps the rule at zero specificity so any consumer rule targeting
|
|
10
|
+
// the same element wins. Chart roots deliberately do NOT re-declare these: an
|
|
11
|
+
// element's own declaration beats an inherited one, so re-declaring lower down
|
|
12
|
+
// would shadow a consumer override set inside the provider tree.
|
|
15
13
|
|
|
16
|
-
// The
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// guaranteed-invalid and took every bare `var(--a8c-charts-color-grid)` read
|
|
25
|
-
// site with it — gridlines painted `unset` instead of the spec grey.
|
|
14
|
+
// The roles a `theme` prop field can override read a `*-theme` variable first,
|
|
15
|
+
// which GlobalChartsProvider writes inline from that field. Publishing the
|
|
16
|
+
// consumer's value one layer out keeps the catalog default reachable: a value
|
|
17
|
+
// that is invalid at computed-value time (a fallback-less `var()` naming a
|
|
18
|
+
// token nothing set, which is how premium-analytics passes its grid stroke)
|
|
19
|
+
// invalidates only the `*-theme` variable, leaving the role's own fallback to
|
|
20
|
+
// resolve. Written as the role directly, it made the role guaranteed-invalid
|
|
21
|
+
// and took every bare read site with it.
|
|
26
22
|
// `src/styles/test/chart-scope.test.ts` pins which roles carry the layer.
|
|
27
|
-
|
|
28
|
-
// Declares custom properties only. This stylesheet must never change layout.
|
|
29
23
|
:where(.a8c-charts-scope) {
|
|
24
|
+
// The series palette. GlobalChartsProvider resolves these five slots at its
|
|
25
|
+
// wrapper and seeds ColorCache with whatever resolves; a slot that resolves
|
|
26
|
+
// to nothing is skipped, so setting only slots 1 and 3 gives a two-color
|
|
27
|
+
// palette, and charts generate accessible colors beyond the seeds. Only
|
|
28
|
+
// slot 1 carries a default.
|
|
29
|
+
|
|
30
|
+
// Slot 1 names --wp-admin-theme-color first, because that is the only leg
|
|
31
|
+
// that does not depend on someone else's runtime. The design system's brand
|
|
32
|
+
// token tracks the admin color scheme only where a WPDS root provider
|
|
33
|
+
// boots and emits its generated ramp inline; without one the token falls to
|
|
34
|
+
// the plain stylesheet rule, a static #3858e9 with no reference to the
|
|
35
|
+
// admin color. Leading with the admin color costs nothing:
|
|
36
|
+
// @wordpress/theme writes --wp-admin-theme-color from a provider's own
|
|
37
|
+
// accent as a legacy wp-admin override, so a provider accent still wins.
|
|
38
|
+
|
|
39
|
+
// DO NOT SIMPLIFY the chain below. The innermost
|
|
40
|
+
// var(--wp-admin-theme-color, #3858e9) is unreachable — the outer leg
|
|
41
|
+
// already tried that variable — and reads like a copy-paste mistake. It is
|
|
42
|
+
// the design system's own spec value for the WPDS token, which
|
|
43
|
+
// `src/styles/test/wpds-fallbacks.test.ts` compares against literally, so
|
|
44
|
+
// collapsing it to a bare hex fails that test. Reordering to put the WPDS
|
|
45
|
+
// token first passes every test and breaks only on a host with no root
|
|
46
|
+
// provider.
|
|
47
|
+
|
|
48
|
+
// That test scans this file as text, comments included, so do not write an
|
|
49
|
+
// example --wpds-* reference in a comment here — it is read as a real one.
|
|
50
|
+
--a8c-charts-color-series-1: var(--a8c-charts-color-series-1-theme, var(--wp-admin-theme-color, var(--wpds-color-foreground-interactive-brand, var(--wp-admin-theme-color, #3858e9))));
|
|
51
|
+
--a8c-charts-color-series-2: var(--a8c-charts-color-series-2-theme);
|
|
52
|
+
--a8c-charts-color-series-3: var(--a8c-charts-color-series-3-theme);
|
|
53
|
+
--a8c-charts-color-series-4: var(--a8c-charts-color-series-4-theme);
|
|
54
|
+
--a8c-charts-color-series-5: var(--a8c-charts-color-series-5-theme);
|
|
30
55
|
--a8c-charts-color-grid: var(--a8c-charts-color-grid-theme, var(--wpds-color-stroke-surface-neutral, #dbdbdb));
|
|
31
56
|
--a8c-charts-color-axis: var(--a8c-charts-color-axis-theme, var(--wpds-color-stroke-surface-neutral, #dbdbdb));
|
|
32
57
|
--a8c-charts-color-tick: var(--a8c-charts-color-tick-theme, var(--wpds-color-stroke-surface-neutral, #dbdbdb));
|
|
33
58
|
--a8c-charts-color-label: var(--wpds-color-foreground-content-neutral, #1e1e1e);
|
|
34
59
|
--a8c-charts-color-label-secondary: var(--wpds-color-foreground-content-neutral-weak, #707070);
|
|
35
60
|
--a8c-charts-color-label-inverse: var(--wpds-color-foreground-interactive-neutral-strong, #f0f0f0);
|
|
36
|
-
// White label text sits on arbitrary series
|
|
61
|
+
// White label text sits on arbitrary series colors, so it has no WPDS
|
|
37
62
|
// content-foreground equivalent.
|
|
38
|
-
--a8c-charts-color-label-on-fill: #fff;
|
|
63
|
+
--a8c-charts-color-label-on-fill: var(--a8c-charts-color-label-on-fill-theme, #fff);
|
|
64
|
+
// The plate behind a pie-slice label. Transparent by default, so a label
|
|
65
|
+
// reads straight off the slice; there is no WPDS token for "no surface".
|
|
66
|
+
--a8c-charts-color-label-background: var(--a8c-charts-color-label-background-theme, transparent);
|
|
39
67
|
// The SVG axis and tick labels. `svgLabelSmall.fill` publishes THIS role, so
|
|
40
68
|
// deriving from --a8c-charts-color-label is safe and wanted: the theme field
|
|
41
69
|
// moves only these labels, while setting the broad role in CSS still moves
|
|
@@ -20,16 +20,19 @@ const normalize = ( value: string ): string => value.replace( /\s+/g, ' ' ).trim
|
|
|
20
20
|
/**
|
|
21
21
|
* Unwraps the theme layer a `theme`-prop-overridable role carries, so the tables in `TOKENS.md` keep documenting what a role ultimately resolves to — its `--wpds-*` token and spec fallback — rather than restating the override plumbing in every row. Which roles carry the layer is pinned separately below.
|
|
22
22
|
*
|
|
23
|
+
* A role with no catalog default reads its layer with no fallback at all — the empty series-palette slots — and unwraps to nothing, which is what it resolves to until a consumer sets it.
|
|
24
|
+
*
|
|
23
25
|
* @param name - The declared property name.
|
|
24
26
|
* @param value - Its normalized value.
|
|
25
|
-
* @return The value with a leading `var(<name>-theme, … )` wrapper removed.
|
|
27
|
+
* @return The value with a leading `var(<name>-theme, … )` wrapper removed, or the empty string where that wrapper carried no fallback.
|
|
26
28
|
*/
|
|
27
29
|
function stripThemeLayer( name: string, value: string ): string {
|
|
28
|
-
const layered = new RegExp(
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
const layered = new RegExp(
|
|
31
|
+
`^var\\(\\s*${ themeLayerVar( name ) }\\s*(?:,\\s*(.*))?\\)$`,
|
|
32
|
+
's'
|
|
33
|
+
).exec( value );
|
|
31
34
|
|
|
32
|
-
return layered ? layered[ 1 ].trim() : value;
|
|
35
|
+
return layered ? ( layered[ 1 ] ?? '' ).trim() : value;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
/**
|
|
@@ -55,6 +58,13 @@ function parseStylesheet(): Map< string, Entry > {
|
|
|
55
58
|
|
|
56
59
|
const name = declaration.slice( 0, separator ).trim();
|
|
57
60
|
const value = stripThemeLayer( name, normalize( declaration.slice( separator + 1 ) ) );
|
|
61
|
+
|
|
62
|
+
// A role that unwrapped to nothing maps to nothing and falls back to nothing.
|
|
63
|
+
if ( value === '' ) {
|
|
64
|
+
entries.set( name, { reads: null, fallback: null } );
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
58
68
|
const wrapped = /^var\(\s*(.*)\)$/s.exec( value );
|
|
59
69
|
|
|
60
70
|
if ( ! wrapped ) {
|
|
@@ -112,10 +122,13 @@ function parseTokensDoc(): Map< string, Entry > {
|
|
|
112
122
|
// "no mapping" before looking for a token name inside it.
|
|
113
123
|
const unmapped = mapping.startsWith( '_(none' );
|
|
114
124
|
const derives = /derives from (--[\w-]+)/.exec( mapping );
|
|
115
|
-
|
|
125
|
+
// `--wp-*` rather than `--wpds-*`: the series palette maps to WordPress's own
|
|
126
|
+
// `--wp-admin-theme-color`, since the design system's brand token is a static
|
|
127
|
+
// hex on every admin screen and cannot carry the admin color scheme.
|
|
128
|
+
const token = /(--wp[\w-]+)/.exec( mapping );
|
|
116
129
|
|
|
117
130
|
entries.set( role, {
|
|
118
|
-
reads: unmapped ? null : derives?.[ 1 ] ??
|
|
131
|
+
reads: unmapped ? null : derives?.[ 1 ] ?? token?.[ 1 ] ?? null,
|
|
119
132
|
fallback: fallback === '—' ? null : normalize( fallback ),
|
|
120
133
|
} );
|
|
121
134
|
}
|
|
@@ -140,13 +153,13 @@ describe( 'chart scope catalog', () => {
|
|
|
140
153
|
// The layer is what keeps a `theme` prop override from being able to take its role down with it: an override that is invalid at computed-value time only invalidates `<role>-theme`, and the role's own fallback still resolves the mapped token. Drop the layer from a role and that role's overrides go back to blanking every read site.
|
|
141
154
|
it.each( THEME_LAYERED_ROLES )( 'declares %s reading its theme layer first', role => {
|
|
142
155
|
expect( stylesheet ).toMatch(
|
|
143
|
-
new RegExp( `${ role }:\\s*var\\(\\s*${ themeLayerVar( role ) }\\s
|
|
156
|
+
new RegExp( `${ role }:\\s*var\\(\\s*${ themeLayerVar( role ) }\\s*[,)]` )
|
|
144
157
|
);
|
|
145
158
|
} );
|
|
146
159
|
|
|
147
160
|
it( 'gives a theme layer to the overridable roles and to nothing else', () => {
|
|
148
161
|
const layered = [ ...declared.keys() ].filter( role =>
|
|
149
|
-
new RegExp( `${ role }:\\s*var\\(\\s*${ themeLayerVar( role ) }\\s
|
|
162
|
+
new RegExp( `${ role }:\\s*var\\(\\s*${ themeLayerVar( role ) }\\s*[,)]` ).test( stylesheet )
|
|
150
163
|
);
|
|
151
164
|
|
|
152
165
|
expect( layered.sort() ).toEqual( [ ...THEME_LAYERED_ROLES ].sort() );
|
package/src/types.ts
CHANGED
|
@@ -108,13 +108,31 @@ export type ChartType =
|
|
|
108
108
|
|
|
109
109
|
export type OrientationType = ValueOf< typeof Orientation >;
|
|
110
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Annotation styling.
|
|
113
|
+
*
|
|
114
|
+
* Each color member is deprecated on its own rather than the field it sits in: `radius`, `stroke` widths and the label geometry alongside them have no catalog role behind them and still apply.
|
|
115
|
+
*/
|
|
111
116
|
export type AnnotationStyles = {
|
|
112
|
-
circleSubject?: Omit< CircleSubjectProps, 'x' | 'y' > & {
|
|
117
|
+
circleSubject?: Omit< CircleSubjectProps, 'x' | 'y' | 'fill' > & {
|
|
118
|
+
/** @deprecated Set the `--a8c-charts-color-annotation` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
119
|
+
fill?: string;
|
|
120
|
+
};
|
|
113
121
|
lineSubject?: Omit< LineSubjectProps, 'x' | 'y' >;
|
|
114
|
-
connector?: Omit< ConnectorProps, 'x' | 'y' | 'dx' | 'dy'
|
|
115
|
-
|
|
122
|
+
connector?: Omit< ConnectorProps, 'x' | 'y' | 'dx' | 'dy' | 'stroke' > & {
|
|
123
|
+
/** @deprecated Set the `--a8c-charts-color-annotation` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
124
|
+
stroke?: ConnectorProps[ 'stroke' ];
|
|
125
|
+
};
|
|
126
|
+
label?: Omit<
|
|
127
|
+
LabelProps,
|
|
128
|
+
'title' | 'subtitle' | 'x' | 'y' | 'anchorLineStroke' | 'backgroundFill'
|
|
129
|
+
> & {
|
|
116
130
|
x?: number | 'start' | 'end';
|
|
117
131
|
y?: number | 'start' | 'end';
|
|
132
|
+
/** @deprecated Set the `--a8c-charts-color-annotation` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
133
|
+
anchorLineStroke?: LabelProps[ 'anchorLineStroke' ];
|
|
134
|
+
/** @deprecated Set the `--a8c-charts-color-surface` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
135
|
+
backgroundFill?: LabelProps[ 'backgroundFill' ];
|
|
118
136
|
};
|
|
119
137
|
};
|
|
120
138
|
|
|
@@ -305,7 +323,7 @@ export type DataPointPercentage = {
|
|
|
305
323
|
*/
|
|
306
324
|
valueDisplay?: string;
|
|
307
325
|
/**
|
|
308
|
-
* Color code for the segment, by default
|
|
326
|
+
* Color code for the segment, by default colors are taken from the theme but this property can overrides it
|
|
309
327
|
*/
|
|
310
328
|
color?: string;
|
|
311
329
|
/**
|
|
@@ -329,26 +347,67 @@ export type DataPointPercentageCalculated = DataPointPercentage & {
|
|
|
329
347
|
* Base theme configuration for chart components with optional properties
|
|
330
348
|
*/
|
|
331
349
|
export type ChartTheme = {
|
|
332
|
-
/**
|
|
333
|
-
|
|
334
|
-
|
|
350
|
+
/**
|
|
351
|
+
* Background color for chart components.
|
|
352
|
+
*
|
|
353
|
+
* Still resolved in JS — gradient stops, the glyph stroke and `GeoChart`'s Google Charts config each need a concrete string — but that is about where the value is *consumed*, not where it is *set*. `withCatalogPointers` parks a consumer's value in the catalog role and restores the pointer, so the field is only ever a carrier for `--a8c-charts-color-background`, and setting the role directly does the same job.
|
|
354
|
+
*
|
|
355
|
+
* Optional so the deprecation is actionable: a consumer writing a full theme literal can now stop setting it. `CompleteChartTheme` is `Required< ChartTheme >`, so `defaultTheme` must still carry one.
|
|
356
|
+
*
|
|
357
|
+
* @deprecated Set the `--a8c-charts-color-background` custom property inside the provider tree instead. See `TOKENS.md`.
|
|
358
|
+
*/
|
|
359
|
+
backgroundColor?: string;
|
|
360
|
+
/**
|
|
361
|
+
* Background color for labels.
|
|
362
|
+
*
|
|
363
|
+
* @deprecated Set the `--a8c-charts-color-label-background` custom property inside the provider tree instead. See `TOKENS.md`.
|
|
364
|
+
*/
|
|
335
365
|
labelBackgroundColor?: string;
|
|
336
|
-
/**
|
|
366
|
+
/**
|
|
367
|
+
* Text color for labels.
|
|
368
|
+
*
|
|
369
|
+
* @deprecated Set the `--a8c-charts-color-label-on-fill` custom property inside the provider tree instead. See `TOKENS.md`.
|
|
370
|
+
*/
|
|
337
371
|
labelTextColor?: string;
|
|
338
|
-
/**
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
372
|
+
/**
|
|
373
|
+
* Series palette seeds. Entry N publishes `--a8c-charts-color-series-{N+1}`; entries past the fifth are ignored.
|
|
374
|
+
*
|
|
375
|
+
* Optional so the deprecation is actionable: a consumer writing a full theme literal can now stop setting it. `CompleteChartTheme` is `Required< ChartTheme >`, so `defaultTheme` must still carry one.
|
|
376
|
+
*
|
|
377
|
+
* @deprecated Set the `--a8c-charts-color-series-1` … `-5` custom properties inside the provider tree instead, or `options.stroke` on a series for a single one. See `TOKENS.md`.
|
|
378
|
+
*/
|
|
379
|
+
colors?: string[];
|
|
380
|
+
/**
|
|
381
|
+
* Optional CSS styles for grid lines.
|
|
382
|
+
*
|
|
383
|
+
* `stroke` is deprecated on its own, not the whole field: `strokeWidth` has no CSS role behind it and still applies. The same shape is used for the other fields whose color moved to CSS — annotating the field itself would strike through the half that stays.
|
|
384
|
+
*/
|
|
385
|
+
gridStyles?: Omit< GridStyles, 'stroke' > & {
|
|
386
|
+
/** @deprecated Set the `--a8c-charts-color-grid` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
387
|
+
stroke?: GridStyles[ 'stroke' ];
|
|
388
|
+
};
|
|
342
389
|
/** Length of axis ticks in pixels */
|
|
343
390
|
tickLength: number;
|
|
344
|
-
/**
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
391
|
+
/**
|
|
392
|
+
* Set `--a8c-charts-color-grid` for the gridlines.
|
|
393
|
+
*
|
|
394
|
+
* @deprecated Do not drop this field without replacing it. Nothing in this package consults it, but `buildChartTheme` seeds `y.left/right.axisLine.stroke` and `y.*.tickLine.stroke` from it, and `defaultTheme`'s empty string is the only thing leaving the y axis unpainted — deleting the field hands those a black `#222` instead. CHARTS-263 replaces it with visx's own `yAxisLineStyles`/`yTickLineStyles` and a pair of catalog roles.
|
|
395
|
+
*/
|
|
396
|
+
gridColor?: string;
|
|
397
|
+
/**
|
|
398
|
+
* @deprecated Paints nothing, and unlike `gridColor` is safe to delete: `buildChartTheme` seeds `x.*.axisLine.stroke` from it, but spreads `xAxisLineStyles` over the top and `defaultTheme` always carries that stroke. Charts follow the host's theme through the catalog rather than a dark-mode field of their own.
|
|
399
|
+
*/
|
|
400
|
+
gridColorDark?: string;
|
|
348
401
|
/** Styles for x-axis tick lines */
|
|
349
|
-
xTickLineStyles?: LineStyles
|
|
402
|
+
xTickLineStyles?: Omit< LineStyles, 'stroke' > & {
|
|
403
|
+
/** @deprecated Set the `--a8c-charts-color-tick` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
404
|
+
stroke?: LineStyles[ 'stroke' ];
|
|
405
|
+
};
|
|
350
406
|
/** Styles for x-axis line */
|
|
351
|
-
xAxisLineStyles?: LineStyles
|
|
407
|
+
xAxisLineStyles?: Omit< LineStyles, 'stroke' > & {
|
|
408
|
+
/** @deprecated Set the `--a8c-charts-color-axis` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
409
|
+
stroke?: LineStyles[ 'stroke' ];
|
|
410
|
+
};
|
|
352
411
|
/** Styles for series lines */
|
|
353
412
|
seriesLineStyles?: LineStyles[];
|
|
354
413
|
/** Array of render functions for glyphs */
|
|
@@ -357,19 +416,37 @@ export type ChartTheme = {
|
|
|
357
416
|
legend?: {
|
|
358
417
|
/** Styles for legend shapes */
|
|
359
418
|
shapeStyles?: Record< string, unknown >[];
|
|
360
|
-
/**
|
|
361
|
-
|
|
419
|
+
/**
|
|
420
|
+
* Styles for legend labels.
|
|
421
|
+
*
|
|
422
|
+
* `color` is deprecated on its own, not the whole field: everything else a consumer sets here — font size, weight, spacing — has no catalog role behind it and still applies.
|
|
423
|
+
*/
|
|
424
|
+
labelStyles?: Omit< CSSProperties, 'color' > & {
|
|
425
|
+
/** @deprecated Set the `--a8c-charts-color-label` custom property inside the provider tree instead. See `TOKENS.md`. */
|
|
426
|
+
color?: CSSProperties[ 'color' ];
|
|
427
|
+
};
|
|
362
428
|
/** Styles for legend container */
|
|
363
429
|
containerStyles?: CSSProperties;
|
|
364
430
|
};
|
|
365
|
-
/**
|
|
366
|
-
|
|
431
|
+
/**
|
|
432
|
+
* Styles for small SVG text (eg. axis tick labels), passed through to the XYChart theme.
|
|
433
|
+
*
|
|
434
|
+
* `fontFamily: 'inherit'` is load-bearing here — it overrides the font stack `buildChartTheme` injects inline on SVG `<text>` — so only `fill` is deprecated.
|
|
435
|
+
*/
|
|
436
|
+
svgLabelSmall?: Omit< TextProps, 'fill' > & {
|
|
437
|
+
/** @deprecated Set the `--a8c-charts-color-label-axis` custom property inside the provider tree instead, or `--a8c-charts-color-label` to move every label at once. See `TOKENS.md`. */
|
|
438
|
+
fill?: TextProps[ 'fill' ];
|
|
439
|
+
};
|
|
367
440
|
/** Styles for large SVG text (eg. axis titles), passed through to the XYChart theme. */
|
|
368
441
|
svgLabelBig?: TextProps;
|
|
369
442
|
annotationStyles?: AnnotationStyles;
|
|
370
443
|
/** GeoChart specific settings */
|
|
371
444
|
geoChart?: {
|
|
372
|
-
/**
|
|
445
|
+
/**
|
|
446
|
+
* Default fill color for a geo chart feature (e.g. country) with no data.
|
|
447
|
+
*
|
|
448
|
+
* @deprecated Set the `--a8c-charts-color-surface-secondary` custom property inside the provider tree instead. Google Charts still takes a resolved hex, but the value is read from the role. See `TOKENS.md`.
|
|
449
|
+
*/
|
|
373
450
|
featureFillColor?: string;
|
|
374
451
|
};
|
|
375
452
|
/** LeaderboardChart specific settings */
|
|
@@ -380,22 +457,50 @@ export type ChartTheme = {
|
|
|
380
457
|
columnGap?: number;
|
|
381
458
|
/** Spacing between label and progress bars */
|
|
382
459
|
labelSpacing?: GapSize;
|
|
383
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Primary color for current period bars.
|
|
462
|
+
*
|
|
463
|
+
* @deprecated Use the `primaryColor` prop on `LeaderboardChart` for one chart, or set `--a8c-charts-color-series-1` to move the palette this falls back to. See `TOKENS.md`.
|
|
464
|
+
*/
|
|
384
465
|
primaryColor?: string;
|
|
385
|
-
/**
|
|
466
|
+
/**
|
|
467
|
+
* Secondary color for comparison period bars.
|
|
468
|
+
*
|
|
469
|
+
* @deprecated Use the `secondaryColor` prop on `LeaderboardChart` for one chart, or set `--a8c-charts-color-series-2` to move the palette this falls back to. See `TOKENS.md`.
|
|
470
|
+
*/
|
|
386
471
|
secondaryColor?: string;
|
|
387
|
-
/**
|
|
472
|
+
/**
|
|
473
|
+
* Delta colors: [negative, neutral, positive].
|
|
474
|
+
*
|
|
475
|
+
* @deprecated Set the `--a8c-charts-color-trend-down`, `-trend-neutral` and `-trend-up` custom properties inside the provider tree instead. See `TOKENS.md`.
|
|
476
|
+
*/
|
|
388
477
|
deltaColors?: [ string, string, string ];
|
|
389
478
|
};
|
|
390
479
|
/** ConversionFunnelChart specific settings */
|
|
391
480
|
conversionFunnelChart?: {
|
|
392
|
-
/**
|
|
481
|
+
/**
|
|
482
|
+
* Primary color for funnel bars.
|
|
483
|
+
*
|
|
484
|
+
* @deprecated Set `--a8c-charts-color-series-1` to move the palette this falls back to. See `TOKENS.md`.
|
|
485
|
+
*/
|
|
393
486
|
primaryColor?: string;
|
|
394
|
-
/**
|
|
487
|
+
/**
|
|
488
|
+
* Background color for chart container.
|
|
489
|
+
*
|
|
490
|
+
* @deprecated Set the `--a8c-charts-color-surface-secondary` custom property inside the provider tree instead. See `TOKENS.md`.
|
|
491
|
+
*/
|
|
395
492
|
backgroundColor?: string;
|
|
396
|
-
/**
|
|
493
|
+
/**
|
|
494
|
+
* Color for positive change indicators.
|
|
495
|
+
*
|
|
496
|
+
* @deprecated Set the `--a8c-charts-color-trend-up` custom property inside the provider tree instead. See `TOKENS.md`.
|
|
497
|
+
*/
|
|
397
498
|
positiveChangeColor?: string;
|
|
398
|
-
/**
|
|
499
|
+
/**
|
|
500
|
+
* Color for negative change indicators.
|
|
501
|
+
*
|
|
502
|
+
* @deprecated Set the `--a8c-charts-color-trend-down` custom property inside the provider tree instead. See `TOKENS.md`.
|
|
503
|
+
*/
|
|
399
504
|
negativeChangeColor?: string;
|
|
400
505
|
};
|
|
401
506
|
lineChart?: {
|
|
@@ -424,6 +529,8 @@ export type ChartTheme = {
|
|
|
424
529
|
/**
|
|
425
530
|
* Color the cell scale interpolates toward at the highest value (prop > this >
|
|
426
531
|
* palette `colors[0]`), fed to CSS `color-mix`. Omit to use the palette color.
|
|
532
|
+
*
|
|
533
|
+
* @deprecated Use the `primaryColor` prop on `HeatmapChart` for one chart, or set `--a8c-charts-color-series-1` to move the palette this falls back to. See `TOKENS.md`.
|
|
427
534
|
*/
|
|
428
535
|
primaryColor?: string;
|
|
429
536
|
/** Gap in px between cells in compact mode */
|
|
@@ -626,7 +733,7 @@ export type ChartLegendConfig< T = DataPoint | DataPointDate | LeaderboardEntry
|
|
|
626
733
|
/**
|
|
627
734
|
* Legend config for charts built from `SeriesData` (line, bar, area). Adds `collapseGroups` on top
|
|
628
735
|
* of the shared config. It is intentionally absent from the base `ChartLegendConfig` so point-based
|
|
629
|
-
* charts (pie, semi-circle pie) — whose data points carry `group` only to coordinate
|
|
736
|
+
* charts (pie, semi-circle pie) — whose data points carry `group` only to coordinate colors — can't
|
|
630
737
|
* set it.
|
|
631
738
|
*/
|
|
632
739
|
export type SeriesChartLegendConfig = ChartLegendConfig< SeriesData[] > & {
|
|
@@ -706,6 +813,16 @@ export type BaseChartProps< T = DataPoint | DataPointDate | LeaderboardEntry > =
|
|
|
706
813
|
* Callback function for pointer out event
|
|
707
814
|
*/
|
|
708
815
|
onPointerOut?: ( event: PointerEvent< Element > ) => void;
|
|
816
|
+
/**
|
|
817
|
+
* Callback for Enter or Space on the point keyboard navigation has selected:
|
|
818
|
+
* the keyboard counterpart of a click. `index` is the point's position in its
|
|
819
|
+
* series and `key` the series label.
|
|
820
|
+
*/
|
|
821
|
+
onDatumActivate?: ( params: {
|
|
822
|
+
datum: DataPoint | DataPointDate;
|
|
823
|
+
index: number;
|
|
824
|
+
key: string;
|
|
825
|
+
} ) => void;
|
|
709
826
|
/**
|
|
710
827
|
* Whether to show tooltips on hover. False by default.
|
|
711
828
|
*/
|