@automattic/charts 3.2.0 → 4.0.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 +29 -0
- package/TOKENS.md +53 -58
- package/dist/index.cjs +1012 -542
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +72 -29
- package/dist/index.d.cts +151 -179
- package/dist/index.d.ts +151 -179
- package/dist/index.js +1013 -544
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/charts/area-chart/area-chart.tsx +39 -25
- package/src/charts/area-chart/test/area-chart.test.tsx +4 -33
- package/src/charts/area-chart/test/tick-placement.test.tsx +55 -0
- package/src/charts/area-chart/test/tooltip-resolution-branches.test.tsx +86 -0
- package/src/charts/area-chart/test/tooltip-resolution.test.tsx +69 -0
- package/src/charts/area-chart/types.ts +4 -7
- package/src/charts/bar-chart/bar-chart.tsx +2 -1
- package/src/charts/bar-chart/private/test/use-bar-chart-options-formatting.test.tsx +69 -0
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +27 -15
- package/src/charts/bar-list-chart/bar-list-chart.tsx +5 -0
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +33 -23
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +138 -182
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +46 -0
- package/src/charts/geo-chart/geo-chart.module.scss +1 -0
- package/src/charts/geo-chart/geo-chart.tsx +5 -10
- package/src/charts/geo-chart/test/geo-chart.test.tsx +2 -2
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +21 -16
- package/src/charts/heatmap-chart/heatmap-chart.tsx +45 -28
- package/src/charts/heatmap-chart/private/build-calendar-data.ts +3 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +11 -4
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +51 -12
- package/src/charts/heatmap-chart/types.ts +2 -2
- package/src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts +2 -2
- package/src/charts/leaderboard-chart/hooks/use-leaderboard-legend-items.ts +3 -5
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +31 -19
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +27 -17
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +14 -0
- package/src/charts/leaderboard-chart/test/use-leaderboard-legend-items.test.tsx +2 -9
- package/src/charts/line-chart/line-chart.module.scss +10 -18
- package/src/charts/line-chart/line-chart.tsx +93 -24
- package/src/charts/line-chart/private/line-chart-annotation.tsx +18 -19
- package/src/charts/line-chart/test/default-tooltip-formatting.test.tsx +74 -0
- package/src/charts/line-chart/test/line-chart.test.tsx +27 -3
- package/src/charts/line-chart/test/tick-placement.test.tsx +84 -0
- package/src/charts/line-chart/test/tooltip-resolution.test.tsx +140 -0
- package/src/charts/line-chart/types.ts +4 -1
- package/src/charts/pie-chart/pie-chart.module.scss +13 -1
- package/src/charts/pie-chart/pie-chart.tsx +30 -40
- package/src/charts/pie-chart/test/pie-chart.test.tsx +56 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +8 -3
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +23 -37
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +50 -0
- package/src/charts/private/chart-layout/chart-layout.module.scss +3 -2
- package/src/charts/private/svg-empty-state/svg-empty-state.module.scss +1 -1
- package/src/charts/private/test/axis-formatting.test.tsx +85 -0
- package/src/charts/private/test/time-axis-formatting.test.ts +109 -0
- package/src/charts/private/test/time-axis-options.test.ts +267 -0
- package/src/charts/private/test/time-axis-tick-invariants.test.ts +153 -0
- package/src/charts/private/test/time-axis-tick-values.test.ts +280 -0
- package/src/charts/private/test/time-axis.test.ts +9 -69
- package/src/charts/private/time-axis-options.ts +106 -0
- package/src/charts/private/time-axis.ts +318 -136
- package/src/charts/private/x-zoom/x-zoom.module.scss +3 -3
- package/src/charts/private/xy-plot/xy-plot.module.scss +8 -0
- package/src/charts/sparkline/test/sparkline.test.tsx +29 -56
- package/src/charts/sparkline/types.ts +1 -1
- package/src/components/legend/private/base-legend.module.scss +9 -5
- package/src/components/tooltip/accessible-tooltip.tsx +13 -15
- package/src/components/tooltip/base-tooltip.module.scss +3 -3
- package/src/components/tooltip/private/bounded-tooltip.tsx +172 -0
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +2 -3
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +129 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +279 -0
- package/src/components/tooltip/xy-chart-tooltip.tsx +288 -0
- package/src/components/trend-indicator/trend-indicator.module.scss +2 -2
- package/src/hooks/test/use-xychart-theme.test.tsx +16 -3
- package/src/hooks/use-xychart-theme.ts +25 -9
- package/src/index.ts +4 -0
- package/src/providers/chart-context/global-charts-provider.tsx +37 -38
- package/src/providers/chart-context/hooks/use-chart-formatting.ts +22 -0
- package/src/providers/chart-context/index.ts +1 -0
- package/src/providers/chart-context/private/catalog-pointers.ts +42 -0
- package/src/providers/chart-context/private/series-palette.ts +3 -13
- package/src/providers/chart-context/test/{sparse-theme.test.ts → catalog-pointers.test.ts} +22 -10
- package/src/providers/chart-context/test/chart-context.test.tsx +177 -792
- package/src/providers/chart-context/test/use-global-charts-theme.test.tsx +7 -25
- package/src/providers/chart-context/themes.ts +7 -52
- package/src/providers/chart-context/types.ts +3 -0
- package/src/styles/chart-scope.scss +39 -62
- package/src/styles/test/chart-scope.test.ts +19 -47
- package/src/test-utils/series-fixtures.ts +31 -0
- package/src/types.ts +79 -166
- package/src/utils/bucket-info.ts +87 -0
- package/src/utils/color-utils.ts +0 -27
- package/src/utils/date-formatting.ts +174 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/test/bucket-info.test.ts +185 -0
- package/src/utils/test/color-utils.test.ts +1 -48
- package/src/utils/test/date-formatting.test.ts +89 -0
- package/src/utils/test/get-styles.test.ts +10 -7
- package/src/utils/test/merge-themes.test.ts +18 -46
- package/src/visx/types.ts +29 -2
- package/src/hooks/test/use-xychart-theme-provider-override.test.tsx +0 -28
- package/src/providers/chart-context/private/theme-override-vars.ts +0 -131
- package/src/providers/chart-context/private/with-catalog-pointers.ts +0 -93
- package/src/providers/chart-context/test/theme-override-vars-guard.test.tsx +0 -29
- package/src/providers/chart-context/test/theme-override-vars.test.ts +0 -183
- package/src/providers/chart-context/test/with-catalog-pointers.test.ts +0 -104
- package/src/styles/test/wpds-fallbacks.test.ts +0 -131
|
@@ -22,21 +22,12 @@ describe( 'useGlobalChartsTheme', () => {
|
|
|
22
22
|
|
|
23
23
|
describe( 'with GlobalChartsProvider', () => {
|
|
24
24
|
it( 'should return merged theme when provider has custom theme', () => {
|
|
25
|
-
const
|
|
26
|
-
const wrapper = createWrapper( customTheme );
|
|
25
|
+
const wrapper = createWrapper( { tickLength: 9 } );
|
|
27
26
|
|
|
28
27
|
const { result } = renderHook( () => useGlobalChartsTheme(), { wrapper } );
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
] );
|
|
38
|
-
// Other properties should still come from default theme
|
|
39
|
-
expect( result.current.backgroundColor ).toBe( defaultTheme.backgroundColor );
|
|
29
|
+
expect( result.current.tickLength ).toBe( 9 );
|
|
30
|
+
// Everything the consumer did not set still comes from the default theme.
|
|
40
31
|
expect( result.current.gridStyles ).toEqual( defaultTheme.gridStyles );
|
|
41
32
|
} );
|
|
42
33
|
|
|
@@ -46,13 +37,12 @@ describe( 'useGlobalChartsTheme', () => {
|
|
|
46
37
|
const { result } = renderHook( () => useGlobalChartsTheme(), { wrapper } );
|
|
47
38
|
|
|
48
39
|
expect( result.current ).toEqual( defaultTheme );
|
|
49
|
-
expect( result.current.colors ).toBe( defaultTheme.colors );
|
|
50
40
|
} );
|
|
51
41
|
} );
|
|
52
42
|
|
|
53
43
|
describe( 'theme stability', () => {
|
|
54
44
|
it( 'should return the same theme object when provider theme does not change', () => {
|
|
55
|
-
const customTheme = {
|
|
45
|
+
const customTheme = { tickLength: 9 };
|
|
56
46
|
const wrapper = createWrapper( customTheme );
|
|
57
47
|
|
|
58
48
|
const { result, rerender } = renderHook( () => useGlobalChartsTheme(), { wrapper } );
|
|
@@ -68,20 +58,12 @@ describe( 'useGlobalChartsTheme', () => {
|
|
|
68
58
|
|
|
69
59
|
describe( 'edge cases', () => {
|
|
70
60
|
it( 'should handle null/undefined theme values gracefully', () => {
|
|
71
|
-
const customTheme = {
|
|
72
|
-
const wrapper = createWrapper( customTheme );
|
|
61
|
+
const customTheme = { tickLength: undefined };
|
|
62
|
+
const wrapper = createWrapper( customTheme as unknown as Partial< ChartTheme > );
|
|
73
63
|
|
|
74
64
|
const { result } = renderHook( () => useGlobalChartsTheme(), { wrapper } );
|
|
75
65
|
|
|
76
|
-
|
|
77
|
-
expect( result.current.backgroundColor ).toBe( defaultTheme.backgroundColor );
|
|
78
|
-
expect( result.current.colors ).toBeUndefined();
|
|
79
|
-
} );
|
|
80
|
-
|
|
81
|
-
it( 'should not throw when GlobalChartsContext is not available', () => {
|
|
82
|
-
expect( () => {
|
|
83
|
-
renderHook( () => useGlobalChartsTheme() );
|
|
84
|
-
} ).not.toThrow();
|
|
66
|
+
expect( result.current.gridStyles ).toEqual( defaultTheme.gridStyles );
|
|
85
67
|
} );
|
|
86
68
|
} );
|
|
87
69
|
} );
|
|
@@ -1,38 +1,24 @@
|
|
|
1
|
-
import { SERIES_PALETTE_POINTERS } from './private/series-palette';
|
|
2
1
|
import type { CompleteChartTheme } from '../../types';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
|
-
* Default theme configuration
|
|
4
|
+
* Default theme configuration: the shape and spacing a consumer can override.
|
|
5
|
+
*
|
|
6
|
+
* For a color, set the matching `--a8c-charts-color-*` role in CSS instead; the `var()`
|
|
7
|
+
* chains that deliver those live in `private/catalog-pointers.ts`.
|
|
6
8
|
*/
|
|
7
9
|
const defaultTheme: CompleteChartTheme = {
|
|
8
|
-
backgroundColor: 'var(--a8c-charts-color-background, #fff)',
|
|
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.
|
|
11
|
-
labelTextColor: 'var(--a8c-charts-color-label-on-fill, #FFFFFF)',
|
|
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 ],
|
|
17
10
|
gridStyles: {
|
|
18
|
-
stroke: 'var(--a8c-charts-color-grid, #dbdbdb)',
|
|
19
11
|
strokeWidth: 1,
|
|
20
12
|
},
|
|
21
13
|
tickLength: 4,
|
|
22
|
-
gridColor: '',
|
|
23
|
-
gridColorDark: '',
|
|
24
14
|
xTickLineStyles: {
|
|
25
|
-
stroke: 'var(--a8c-charts-color-tick, #dbdbdb)',
|
|
26
15
|
strokeWidth: 1,
|
|
27
16
|
},
|
|
28
17
|
xAxisLineStyles: {
|
|
29
|
-
stroke: 'var(--a8c-charts-color-axis, #dbdbdb)',
|
|
30
18
|
strokeWidth: 1,
|
|
31
19
|
},
|
|
32
20
|
legend: {
|
|
33
|
-
labelStyles: {
|
|
34
|
-
color: 'var(--a8c-charts-color-label, #1e1e1e)',
|
|
35
|
-
},
|
|
21
|
+
labelStyles: {},
|
|
36
22
|
containerStyles: {},
|
|
37
23
|
shapeStyles: [],
|
|
38
24
|
},
|
|
@@ -44,42 +30,12 @@ const defaultTheme: CompleteChartTheme = {
|
|
|
44
30
|
// elements for axis labels and ticks. Setting `inherit` lets SVG text
|
|
45
31
|
// pick up the host application's font-family via normal CSS inheritance.
|
|
46
32
|
svgLabelSmall: {
|
|
47
|
-
fill: 'var(--a8c-charts-color-label-axis, #1e1e1e)',
|
|
48
33
|
fontFamily: 'inherit',
|
|
49
34
|
},
|
|
50
35
|
svgLabelBig: { fontFamily: 'inherit' },
|
|
51
|
-
annotationStyles: {
|
|
52
|
-
label: {
|
|
53
|
-
anchorLineStroke: 'var(--a8c-charts-color-annotation, #1e1e1e)',
|
|
54
|
-
backgroundFill: 'var(--a8c-charts-color-surface, #fff)',
|
|
55
|
-
},
|
|
56
|
-
connector: {
|
|
57
|
-
stroke: 'var(--a8c-charts-color-annotation, #1e1e1e)',
|
|
58
|
-
},
|
|
59
|
-
circleSubject: {
|
|
60
|
-
stroke: 'transparent',
|
|
61
|
-
fill: 'var(--a8c-charts-color-annotation, #1e1e1e)',
|
|
62
|
-
radius: 5,
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
geoChart: {
|
|
66
|
-
featureFillColor: 'var(--a8c-charts-color-surface-secondary, #f4f4f4)',
|
|
67
|
-
},
|
|
36
|
+
annotationStyles: {},
|
|
68
37
|
leaderboardChart: {
|
|
69
|
-
rowGap: 12,
|
|
70
|
-
columnGap: 4,
|
|
71
38
|
labelSpacing: 'xs',
|
|
72
|
-
// [negative, neutral, positive]
|
|
73
|
-
deltaColors: [
|
|
74
|
-
'var(--a8c-charts-color-trend-down, #cc1818)',
|
|
75
|
-
'var(--a8c-charts-color-trend-neutral, #707070)',
|
|
76
|
-
'var(--a8c-charts-color-trend-up, #008030)',
|
|
77
|
-
],
|
|
78
|
-
},
|
|
79
|
-
conversionFunnelChart: {
|
|
80
|
-
backgroundColor: 'var(--a8c-charts-color-surface-secondary, #f4f4f4)',
|
|
81
|
-
positiveChangeColor: 'var(--a8c-charts-color-trend-up, #008030)',
|
|
82
|
-
negativeChangeColor: 'var(--a8c-charts-color-trend-down, #cc1818)',
|
|
83
39
|
},
|
|
84
40
|
lineChart: {
|
|
85
41
|
lineStyles: {
|
|
@@ -101,8 +57,7 @@ const defaultTheme: CompleteChartTheme = {
|
|
|
101
57
|
margin: { top: 2, right: 2, bottom: 2, left: 2 },
|
|
102
58
|
strokeWidth: 1.5,
|
|
103
59
|
},
|
|
104
|
-
//
|
|
105
|
-
// 11px square / 2px gap is the contribution-graph rhythm, which has no WPDS dimension.
|
|
60
|
+
// The compact 11px square / 2px gap is the contribution-graph rhythm, which has no WPDS dimension.
|
|
106
61
|
heatmapChart: {
|
|
107
62
|
compactCellGap: 2,
|
|
108
63
|
compactCellSize: 11,
|
|
@@ -2,6 +2,7 @@ import { CSSProperties, ReactNode } from 'react';
|
|
|
2
2
|
import type { BaseLegendItem } from '../../components/legend';
|
|
3
3
|
import type {
|
|
4
4
|
BarStyles,
|
|
5
|
+
ChartFormatting,
|
|
5
6
|
ChartType,
|
|
6
7
|
CompleteChartTheme,
|
|
7
8
|
DataPointPercentage,
|
|
@@ -37,6 +38,8 @@ export interface GlobalChartsContextValue {
|
|
|
37
38
|
unregisterChart: ( id: string ) => void;
|
|
38
39
|
getChartData: ( id: string ) => ChartRegistration | undefined;
|
|
39
40
|
theme: CompleteChartTheme;
|
|
41
|
+
/** Locale and time zone every date the charts print is rendered in. */
|
|
42
|
+
formatting: ChartFormatting;
|
|
40
43
|
getElementStyles: ( params: GetElementStylesParams ) => ElementStyles;
|
|
41
44
|
// Series visibility management shared by charts, legends, and programmatic controls.
|
|
42
45
|
toggleSeriesVisibility: ( chartId: string, seriesLabel: string ) => void;
|
|
@@ -10,16 +10,6 @@
|
|
|
10
10
|
// the same element wins. Chart roots deliberately do NOT re-declare these: an
|
|
11
11
|
// element's own declaration beats an inherited one, so re-declaring lower down
|
|
12
12
|
// would shadow a consumer override set inside the provider tree.
|
|
13
|
-
|
|
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.
|
|
22
|
-
// `src/styles/test/chart-scope.test.ts` pins which roles carry the layer.
|
|
23
13
|
:where(.a8c-charts-scope) {
|
|
24
14
|
// The series palette. GlobalChartsProvider resolves these five slots at its
|
|
25
15
|
// wrapper and seeds ColorCache with whatever resolves; a slot that resolves
|
|
@@ -35,58 +25,42 @@
|
|
|
35
25
|
// admin color. Leading with the admin color costs nothing:
|
|
36
26
|
// @wordpress/theme writes --wp-admin-theme-color from a provider's own
|
|
37
27
|
// accent as a legacy wp-admin override, so a provider accent still wins.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
// `
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
//
|
|
49
|
-
|
|
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);
|
|
55
|
-
--a8c-charts-color-grid: var(--a8c-charts-color-grid-theme, var(--wpds-color-stroke-surface-neutral, #dbdbdb));
|
|
56
|
-
--a8c-charts-color-axis: var(--a8c-charts-color-axis-theme, var(--wpds-color-stroke-surface-neutral, #dbdbdb));
|
|
57
|
-
--a8c-charts-color-tick: var(--a8c-charts-color-tick-theme, var(--wpds-color-stroke-surface-neutral, #dbdbdb));
|
|
58
|
-
--a8c-charts-color-label: var(--wpds-color-foreground-content-neutral, #1e1e1e);
|
|
59
|
-
--a8c-charts-color-label-secondary: var(--wpds-color-foreground-content-neutral-weak, #707070);
|
|
60
|
-
--a8c-charts-color-label-inverse: var(--wpds-color-foreground-interactive-neutral-strong, #f0f0f0);
|
|
61
|
-
// White label text sits on arbitrary series colors, so it has no WPDS
|
|
62
|
-
// content-foreground equivalent.
|
|
63
|
-
--a8c-charts-color-label-on-fill: var(--a8c-charts-color-label-on-fill-theme, #fff);
|
|
28
|
+
--a8c-charts-color-series-1: var(--wp-admin-theme-color, var(--wpds-color-foreground-interactive-brand));
|
|
29
|
+
--a8c-charts-color-grid: var(--wpds-color-stroke-surface-neutral);
|
|
30
|
+
--a8c-charts-color-axis-x: var(--wpds-color-stroke-surface-neutral);
|
|
31
|
+
--a8c-charts-color-tick-x: var(--wpds-color-stroke-surface-neutral);
|
|
32
|
+
// The y axis carries labels only until one of these is declared. `none`
|
|
33
|
+
// rather than `transparent` keeps the line out of hit-testing too.
|
|
34
|
+
--a8c-charts-color-axis-y: none;
|
|
35
|
+
--a8c-charts-color-tick-y: none;
|
|
36
|
+
--a8c-charts-color-label: var(--wpds-color-foreground-content-neutral);
|
|
37
|
+
--a8c-charts-color-label-secondary: var(--wpds-color-foreground-content-neutral-weak);
|
|
38
|
+
// Label text on a filled surface — a pie segment, a heatmap cell.
|
|
39
|
+
--a8c-charts-color-label-inverse: var(--wpds-color-foreground-interactive-neutral-strong);
|
|
64
40
|
// The plate behind a pie-slice label. Transparent by default, so a label
|
|
65
41
|
// reads straight off the slice; there is no WPDS token for "no surface".
|
|
66
|
-
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
// every label at once
|
|
71
|
-
//
|
|
72
|
-
--a8c-charts-color-label-axis: var(--a8c-charts-color-label
|
|
73
|
-
--a8c-charts-color-annotation: var(--wpds-color-foreground-content-neutral
|
|
74
|
-
--a8c-charts-color-trend-up: var(--wpds-color-foreground-content-success-weak
|
|
75
|
-
--a8c-charts-color-trend-down: var(--wpds-color-foreground-content-error-weak
|
|
76
|
-
--a8c-charts-color-trend-neutral: var(--wpds-color-foreground-content-neutral-weak
|
|
77
|
-
--a8c-charts-color-background: var(--
|
|
78
|
-
// Surfaces
|
|
79
|
-
// zoom-reset control. Same WPDS token as --a8c-charts-color-background
|
|
80
|
-
// deliberately
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
--a8c-charts-color-
|
|
84
|
-
--a8c-charts-color-surface-secondary: var(--wpds-color-background-surface-neutral-weak, #f4f4f4);
|
|
85
|
-
--a8c-charts-color-track: var(--wpds-color-background-track-neutral-weak, #f0f0f0);
|
|
42
|
+
// The literal is load-bearing: a `fill` reading a fallback-less var() on an
|
|
43
|
+
// undeclared property drops the declaration and paints black instead.
|
|
44
|
+
--a8c-charts-color-label-background: transparent;
|
|
45
|
+
// The SVG axis and tick labels. Narrower than --a8c-charts-color-label and
|
|
46
|
+
// derived from it, so setting the broad role moves every label at once while
|
|
47
|
+
// setting this one moves only the axis.
|
|
48
|
+
--a8c-charts-color-label-axis: var(--a8c-charts-color-label);
|
|
49
|
+
--a8c-charts-color-annotation: var(--wpds-color-foreground-content-neutral);
|
|
50
|
+
--a8c-charts-color-trend-up: var(--wpds-color-foreground-content-success-weak);
|
|
51
|
+
--a8c-charts-color-trend-down: var(--wpds-color-foreground-content-error-weak);
|
|
52
|
+
--a8c-charts-color-trend-neutral: var(--wpds-color-foreground-content-neutral-weak);
|
|
53
|
+
--a8c-charts-color-background: var(--wpds-color-background-surface-neutral-strong);
|
|
54
|
+
// Surfaces floating over the chart — tooltips, the annotation label, the
|
|
55
|
+
// zoom-reset control. Same WPDS token as --a8c-charts-color-background but
|
|
56
|
+
// deliberately not derived from it, so either can move without the other.
|
|
57
|
+
--a8c-charts-color-surface: var(--wpds-color-background-surface-neutral-strong);
|
|
58
|
+
--a8c-charts-color-surface-secondary: var(--wpds-color-background-surface-neutral-weak);
|
|
59
|
+
--a8c-charts-color-track: var(--wpds-color-background-track-neutral-weak);
|
|
86
60
|
// Translucent dark surface; no WPDS token carries this.
|
|
87
61
|
--a8c-charts-color-tooltip-surface: rgb(0 0 0 / 85%);
|
|
88
|
-
--a8c-charts-color-zoom-selection: var(--wpds-color-background-interactive-brand-strong
|
|
89
|
-
--a8c-charts-color-zoom-selection-stroke: var(--wpds-color-stroke-interactive-brand
|
|
62
|
+
--a8c-charts-color-zoom-selection: var(--wpds-color-background-interactive-brand-strong);
|
|
63
|
+
--a8c-charts-color-zoom-selection-stroke: var(--wpds-color-stroke-interactive-brand);
|
|
90
64
|
|
|
91
65
|
// @wordpress/theme 1.0.0 removed the whole --wpds-elevation-* group while the
|
|
92
66
|
// elevation model is redefined (gutenberg#80099). These carry the removed spec
|
|
@@ -102,10 +76,13 @@
|
|
|
102
76
|
0 6px 6px 0 #00000008,
|
|
103
77
|
0 8px 8px 0 #00000005;
|
|
104
78
|
|
|
105
|
-
--a8c-charts-motion-duration-entrance: var(--wpds-motion-duration-xl
|
|
106
|
-
--a8c-charts-motion-easing-entrance: var(--wpds-motion-easing-expressive
|
|
107
|
-
--a8c-charts-border-radius-bar: var(--wpds-border-radius-md
|
|
108
|
-
--a8c-charts-border-radius-cell: var(--wpds-border-radius-sm
|
|
79
|
+
--a8c-charts-motion-duration-entrance: var(--wpds-motion-duration-xl);
|
|
80
|
+
--a8c-charts-motion-easing-entrance: var(--wpds-motion-easing-expressive);
|
|
81
|
+
--a8c-charts-border-radius-bar: var(--wpds-border-radius-md);
|
|
82
|
+
--a8c-charts-border-radius-cell: var(--wpds-border-radius-sm);
|
|
109
83
|
// Pill shape; no WPDS radius reaches it.
|
|
110
84
|
--a8c-charts-border-radius-leaderboard-bar: 9999px;
|
|
85
|
+
|
|
86
|
+
--a8c-charts-dimension-leaderboard-row-gap: var(--wpds-dimension-gap-md);
|
|
87
|
+
--a8c-charts-dimension-leaderboard-column-gap: var(--wpds-dimension-gap-xs);
|
|
111
88
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
THEME_LAYERED_ROLES,
|
|
5
|
-
themeLayerVar,
|
|
6
|
-
} from '../../providers/chart-context/private/theme-override-vars';
|
|
7
3
|
|
|
8
4
|
const stylesheet = readFileSync( join( __dirname, '..', 'chart-scope.scss' ), 'utf8' );
|
|
9
5
|
const tokensDoc = readFileSync( join( __dirname, '..', '..', '..', 'TOKENS.md' ), 'utf8' );
|
|
10
6
|
|
|
7
|
+
const normalize = ( value: string ): string => value.replace( /\s+/g, ' ' ).trim();
|
|
8
|
+
|
|
11
9
|
type Entry = {
|
|
12
10
|
/** The custom property this one reads, or null when the value is a literal. */
|
|
13
11
|
reads: string | null;
|
|
@@ -15,26 +13,6 @@ type Entry = {
|
|
|
15
13
|
fallback: string | null;
|
|
16
14
|
};
|
|
17
15
|
|
|
18
|
-
const normalize = ( value: string ): string => value.replace( /\s+/g, ' ' ).trim();
|
|
19
|
-
|
|
20
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
*
|
|
25
|
-
* @param name - The declared property name.
|
|
26
|
-
* @param value - Its normalized value.
|
|
27
|
-
* @return The value with a leading `var(<name>-theme, … )` wrapper removed, or the empty string where that wrapper carried no fallback.
|
|
28
|
-
*/
|
|
29
|
-
function stripThemeLayer( name: string, value: string ): string {
|
|
30
|
-
const layered = new RegExp(
|
|
31
|
-
`^var\\(\\s*${ themeLayerVar( name ) }\\s*(?:,\\s*(.*))?\\)$`,
|
|
32
|
-
's'
|
|
33
|
-
).exec( value );
|
|
34
|
-
|
|
35
|
-
return layered ? ( layered[ 1 ] ?? '' ).trim() : value;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
16
|
/**
|
|
39
17
|
* Parses each catalog declaration in the stylesheet into the property it reads and the fallback it carries. Splitting the `var()` arguments at the *first* comma keeps a fallback that is itself a function call intact — `cubic-bezier(0.25, 0, 0, 1)` would otherwise be truncated at its first argument.
|
|
40
18
|
*
|
|
@@ -57,13 +35,7 @@ function parseStylesheet(): Map< string, Entry > {
|
|
|
57
35
|
}
|
|
58
36
|
|
|
59
37
|
const name = declaration.slice( 0, separator ).trim();
|
|
60
|
-
const value =
|
|
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
|
-
}
|
|
38
|
+
const value = normalize( declaration.slice( separator + 1 ) );
|
|
67
39
|
|
|
68
40
|
const wrapped = /^var\(\s*(.*)\)$/s.exec( value );
|
|
69
41
|
|
|
@@ -145,24 +117,24 @@ describe( 'chart scope catalog', () => {
|
|
|
145
117
|
} );
|
|
146
118
|
|
|
147
119
|
// The tables in TOKENS.md restate the stylesheet for consumers who only have the
|
|
148
|
-
// published package.
|
|
149
|
-
|
|
150
|
-
|
|
120
|
+
// published package. Mapping (what a role reads) must match the source. The
|
|
121
|
+
// Fallback column for `--wpds-*` mappings is injected at build time, so only
|
|
122
|
+
// literals and `--a8c-charts-*` derivations are compared as fallbacks.
|
|
123
|
+
it.each( [ ...declared.keys() ] )( 'documents %s with the mapping it is declared with', token => {
|
|
124
|
+
expect( documented.get( token )?.reads ).toEqual( declared.get( token )?.reads );
|
|
151
125
|
} );
|
|
152
126
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
expect( layered.sort() ).toEqual( [ ...THEME_LAYERED_ROLES ].sort() );
|
|
127
|
+
it.each(
|
|
128
|
+
[ ...declared.keys() ].filter( token => {
|
|
129
|
+
const entry = declared.get( token );
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
entry?.reads?.startsWith( '--wpds-' ) !== true &&
|
|
133
|
+
entry?.fallback?.includes( '--wpds-' ) !== true
|
|
134
|
+
);
|
|
135
|
+
} )
|
|
136
|
+
)( 'documents %s with the fallback it is declared with', token => {
|
|
137
|
+
expect( documented.get( token )?.fallback ).toEqual( declared.get( token )?.fallback );
|
|
166
138
|
} );
|
|
167
139
|
|
|
168
140
|
it( 'scopes the catalog to :where(.a8c-charts-scope) rather than :root', () => {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SeriesData } from '../types';
|
|
2
|
+
|
|
3
|
+
const series = ( start: string, count: number, stepInHours: number ): SeriesData[] => [
|
|
4
|
+
{
|
|
5
|
+
label: 'views',
|
|
6
|
+
data: Array.from( { length: count }, ( _, index ) => ( {
|
|
7
|
+
date: new Date( new Date( start ).getTime() + index * stepInHours * 60 * 60 * 1000 ),
|
|
8
|
+
value: index,
|
|
9
|
+
} ) ),
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* One series of hourly points starting at `start`, `count` long.
|
|
15
|
+
*
|
|
16
|
+
* @param start - ISO instant of the first point.
|
|
17
|
+
* @param count - Number of points.
|
|
18
|
+
* @return A single-series fixture.
|
|
19
|
+
*/
|
|
20
|
+
export const hourlySeries = ( start: string, count: number ): SeriesData[] =>
|
|
21
|
+
series( start, count, 1 );
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* One series of daily points starting at `start`, `count` long.
|
|
25
|
+
*
|
|
26
|
+
* @param start - ISO instant of the first point.
|
|
27
|
+
* @param count - Number of points.
|
|
28
|
+
* @return A single-series fixture.
|
|
29
|
+
*/
|
|
30
|
+
export const dailySeries = ( start: string, count: number ): SeriesData[] =>
|
|
31
|
+
series( start, count, 24 );
|