@automattic/charts 1.8.1 → 1.9.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 +16 -0
- package/dist/index.cjs +530 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +122 -34
- package/dist/index.d.cts +97 -7
- package/dist/index.d.ts +97 -7
- package/dist/index.js +527 -54
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/charts/area-chart/area-chart.module.scss +3 -1
- package/src/charts/area-chart/area-chart.tsx +5 -2
- package/src/charts/bar-chart/bar-chart.module.scss +6 -2
- package/src/charts/bar-chart/private/comparison-bars.tsx +6 -0
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +15 -12
- package/src/charts/geo-chart/geo-chart.tsx +6 -1
- package/src/charts/geo-chart/test/geo-chart.test.tsx +11 -1
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +103 -0
- package/src/charts/heatmap-chart/heatmap-chart.tsx +422 -0
- package/src/charts/heatmap-chart/index.ts +4 -0
- package/src/charts/heatmap-chart/private/build-calendar-data.ts +81 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +53 -0
- package/src/charts/heatmap-chart/private/index.ts +5 -0
- package/src/charts/heatmap-chart/private/use-heatmap-colors.ts +45 -0
- package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +88 -0
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +301 -0
- package/src/charts/heatmap-chart/test/use-heatmap-colors.test.ts +34 -0
- package/src/charts/heatmap-chart/types.ts +42 -0
- package/src/charts/index.ts +1 -0
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +18 -6
- package/src/charts/line-chart/line-chart.module.scss +6 -4
- package/src/charts/line-chart/line-chart.tsx +6 -2
- package/src/charts/line-chart/private/line-chart-annotation.tsx +16 -3
- package/src/charts/private/grid-control/grid-control.module.scss +1 -4
- package/src/charts/private/svg-empty-state/svg-empty-state.module.scss +1 -1
- package/src/charts/private/with-responsive/test/with-responsive.test.tsx +14 -0
- package/src/charts/private/with-responsive/with-responsive.tsx +12 -0
- package/src/charts/private/x-zoom.module.scss +6 -3
- package/src/components/legend/private/base-legend.module.scss +3 -1
- package/src/components/tooltip/base-tooltip.module.scss +4 -1
- package/src/components/trend-indicator/trend-indicator.module.scss +5 -3
- package/src/hooks/use-xychart-theme.ts +24 -0
- package/src/index.ts +12 -0
- package/src/providers/chart-context/themes.ts +29 -16
- package/src/types.ts +19 -2
- package/src/utils/color-utils.ts +36 -0
- package/src/utils/test/color-utils.test.ts +33 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/charts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Display charts within Automattic products.",
|
|
5
5
|
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/charts/#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -97,8 +97,8 @@
|
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@automattic/jetpack-webpack-config": "workspace:*",
|
|
99
99
|
"@babel/core": "^7.29.7",
|
|
100
|
-
"@storybook/addon-docs": "10.
|
|
101
|
-
"@storybook/react": "10.
|
|
100
|
+
"@storybook/addon-docs": "10.4.6",
|
|
101
|
+
"@storybook/react": "10.4.6",
|
|
102
102
|
"@testing-library/dom": "^10.0.0",
|
|
103
103
|
"@testing-library/jest-dom": "^6.0.0",
|
|
104
104
|
"@testing-library/react": "^16.0.0",
|
|
@@ -109,9 +109,9 @@
|
|
|
109
109
|
"@types/react-dom": "18.3.7",
|
|
110
110
|
"@typescript/native-preview": "7.0.0-dev.20260225.1",
|
|
111
111
|
"@visx/glyph": "4.0.0",
|
|
112
|
-
"@wordpress/components": "
|
|
113
|
-
"@wordpress/element": "8.0
|
|
114
|
-
"@wordpress/private-apis": "1.
|
|
112
|
+
"@wordpress/components": "36.1.0",
|
|
113
|
+
"@wordpress/element": "8.2.0",
|
|
114
|
+
"@wordpress/private-apis": "1.50.0",
|
|
115
115
|
"babel-jest": "30.4.1",
|
|
116
116
|
"identity-obj-proxy": "^3.0.0",
|
|
117
117
|
"jest": "30.4.2",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"react": "18.3.1",
|
|
121
121
|
"react-dom": "18.3.1",
|
|
122
122
|
"sass-embedded": "1.97.3",
|
|
123
|
-
"storybook": "10.
|
|
123
|
+
"storybook": "10.4.6",
|
|
124
124
|
"tsdown": "0.22.2",
|
|
125
125
|
"typescript": "5.9.3"
|
|
126
126
|
},
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
useGlobalChartsContext,
|
|
28
28
|
useGlobalChartsTheme,
|
|
29
29
|
} from '../../providers';
|
|
30
|
-
import { attachSubComponents } from '../../utils';
|
|
30
|
+
import { attachSubComponents, resolveCssVariable } from '../../utils';
|
|
31
31
|
import { renderDefaultTooltip } from '../line-chart';
|
|
32
32
|
import { useChartChildren } from '../private/chart-composition';
|
|
33
33
|
import { ChartLayout } from '../private/chart-layout';
|
|
@@ -461,7 +461,10 @@ const AreaChartInternal = forwardRef< SingleChartRef, AreaChartProps >(
|
|
|
461
461
|
stacked={ stacked }
|
|
462
462
|
stackOffset={ stackOffset }
|
|
463
463
|
getElementStyles={ getElementStyles }
|
|
464
|
-
strokeColor={
|
|
464
|
+
strokeColor={
|
|
465
|
+
resolveCssVariable( providerTheme.backgroundColor ) ??
|
|
466
|
+
providerTheme.backgroundColor
|
|
467
|
+
}
|
|
465
468
|
/>
|
|
466
469
|
</>
|
|
467
470
|
) }
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
transform-origin: bottom;
|
|
9
9
|
transform-box: fill-box;
|
|
10
10
|
transform: scaleY(0);
|
|
11
|
-
animation:
|
|
11
|
+
animation:
|
|
12
|
+
rise var(--wpds-motion-duration-xl, 400ms)
|
|
13
|
+
var(--wpds-motion-easing-expressive, cubic-bezier(0.25, 0, 0, 1)) forwards;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
@keyframes rise {
|
|
@@ -22,7 +24,9 @@
|
|
|
22
24
|
transform-origin: left;
|
|
23
25
|
transform-box: fill-box;
|
|
24
26
|
transform: scaleX(0);
|
|
25
|
-
animation:
|
|
27
|
+
animation:
|
|
28
|
+
stretch var(--wpds-motion-duration-xl, 400ms)
|
|
29
|
+
var(--wpds-motion-easing-expressive, cubic-bezier(0.25, 0, 0, 1)) forwards;
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
@keyframes stretch {
|
|
@@ -10,6 +10,12 @@ import type { ElementStyles, GetElementStylesParams } from '../../../providers';
|
|
|
10
10
|
import type { DataPointDate, SeriesData } from '../../../types';
|
|
11
11
|
import type { FC, ReactNode } from 'react';
|
|
12
12
|
|
|
13
|
+
/*
|
|
14
|
+
* `process.env.NODE_ENV` is replaced by the bundler at build time. Declare a
|
|
15
|
+
* minimal `process` locally so this file type-checks as source under `jetpack:src`.
|
|
16
|
+
*/
|
|
17
|
+
declare const process: { env: Record< string, string | undefined > };
|
|
18
|
+
|
|
13
19
|
export type ComparisonSeriesEntry = {
|
|
14
20
|
series: SeriesData;
|
|
15
21
|
index: number;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
.main-rate {
|
|
14
14
|
overflow: hidden;
|
|
15
|
-
color: #1e1e1e;
|
|
15
|
+
color: var(--wpds-color-fg-content-neutral, #1e1e1e);
|
|
16
16
|
text-overflow: ellipsis;
|
|
17
17
|
font-size: var(--wpds-typography-font-size-xl, 18px);
|
|
18
18
|
font-style: normal;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
.funnel-container {
|
|
35
35
|
flex: 1;
|
|
36
|
-
min-height:
|
|
36
|
+
min-height: 0;
|
|
37
37
|
width: 100%;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -43,7 +43,9 @@
|
|
|
43
43
|
height: 100%;
|
|
44
44
|
|
|
45
45
|
&--animated {
|
|
46
|
-
transition:
|
|
46
|
+
transition:
|
|
47
|
+
opacity var(--wpds-motion-duration-lg, 300ms)
|
|
48
|
+
var(--wpds-motion-easing-subtle, cubic-bezier(0.15, 0, 0.15, 1));
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
&--blurred {
|
|
@@ -52,7 +54,7 @@
|
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
.step-label {
|
|
55
|
-
color: #
|
|
57
|
+
color: var(--wpds-color-fg-content-neutral-weak, #707070);
|
|
56
58
|
font-size: var(--wpds-typography-font-size-sm, 12px);
|
|
57
59
|
font-weight: var(--wpds-typography-font-weight-regular, 400);
|
|
58
60
|
line-height: var(--wpds-typography-line-height-xs, 16px);
|
|
@@ -62,7 +64,7 @@
|
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
.step-rate {
|
|
65
|
-
color: #1e1e1e;
|
|
67
|
+
color: var(--wpds-color-fg-content-neutral, #1e1e1e);
|
|
66
68
|
font-size: var(--wpds-typography-font-size-md, 13px);
|
|
67
69
|
font-weight: var(--wpds-typography-font-weight-medium, 499);
|
|
68
70
|
line-height: var(--wpds-typography-line-height-xs, 16px);
|
|
@@ -84,7 +86,9 @@
|
|
|
84
86
|
transform-origin: bottom;
|
|
85
87
|
transform-box: fill-box;
|
|
86
88
|
transform: scaleY(0);
|
|
87
|
-
animation:
|
|
89
|
+
animation:
|
|
90
|
+
stretch var(--wpds-motion-duration-xl, 400ms)
|
|
91
|
+
var(--wpds-motion-easing-expressive, cubic-bezier(0.25, 0, 0, 1)) forwards;
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
@keyframes stretch {
|
|
@@ -96,18 +100,17 @@
|
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
.tooltip-wrapper {
|
|
99
|
-
|
|
100
|
-
background: var(--black-white-white, #fff);
|
|
103
|
+
background: var(--wpds-color-bg-surface-neutral-strong, #fff);
|
|
101
104
|
|
|
102
105
|
// Override .visx-tooltip inline styles.
|
|
103
106
|
border-radius: var(--wpds-border-radius-md, 4px) !important;
|
|
104
107
|
padding: var(--wpds-dimension-padding-md, 12px) !important;
|
|
105
|
-
box-shadow: 0 1px
|
|
108
|
+
box-shadow: var(--wpds-elevation-sm, 0 1px 2px 0 #0000000d, 0 2px 3px 0 #0000000a, 0 6px 6px 0 #00000008, 0 8px 8px 0 #00000005) !important;
|
|
106
109
|
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
.tooltip-title {
|
|
110
|
-
color: #1e1e1e;
|
|
113
|
+
color: var(--wpds-color-fg-content-neutral, #1e1e1e);
|
|
111
114
|
font-size: var(--wpds-typography-font-size-sm, 12px);
|
|
112
115
|
font-style: normal;
|
|
113
116
|
font-weight: var(--wpds-typography-font-weight-regular, 400);
|
|
@@ -115,7 +118,7 @@
|
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
.tooltip-content {
|
|
118
|
-
color: #1e1e1e;
|
|
121
|
+
color: var(--wpds-color-fg-content-neutral, #1e1e1e);
|
|
119
122
|
font-size: var(--wpds-typography-font-size-md, 13px);
|
|
120
123
|
font-style: normal;
|
|
121
124
|
font-weight: var(--wpds-typography-font-weight-medium, 499);
|
|
@@ -124,6 +127,6 @@
|
|
|
124
127
|
|
|
125
128
|
.empty-state {
|
|
126
129
|
text-align: center;
|
|
127
|
-
color: #
|
|
130
|
+
color: var(--wpds-color-fg-content-neutral-weak, #707070);
|
|
128
131
|
font-size: var(--wpds-typography-font-size-lg, 16px);
|
|
129
132
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
import clsx from 'clsx';
|
|
6
6
|
import { FC, useContext, useMemo } from 'react';
|
|
7
|
-
import { Chart } from 'react-google-charts';
|
|
7
|
+
import { Chart, type GoogleChartPackages } from 'react-google-charts';
|
|
8
8
|
/**
|
|
9
9
|
* Internal dependencies
|
|
10
10
|
*/
|
|
@@ -19,6 +19,10 @@ import { GeoChartProps } from './types';
|
|
|
19
19
|
|
|
20
20
|
const DEFAULT_FEATURE_FILL_COLOR = '#ffffff';
|
|
21
21
|
const DEFAULT_BACKGROUND_COLOR = '#ffffff';
|
|
22
|
+
// `chartPackages` replaces (not extends) react-google-charts' default `[ 'corechart', 'controls' ]`,
|
|
23
|
+
// so we restate the defaults and add `geochart`. Without it the loader backfills the geochart package
|
|
24
|
+
// late, which can clash with another Google Charts version already loaded on the page.
|
|
25
|
+
const GEO_CHART_PACKAGES: GoogleChartPackages[] = [ 'corechart', 'controls', 'geochart' ];
|
|
22
26
|
|
|
23
27
|
type GoogleChartOptions = Record< string, unknown >;
|
|
24
28
|
|
|
@@ -154,6 +158,7 @@ const GeoChartInternal: FC< GeoChartProps > = ( {
|
|
|
154
158
|
>
|
|
155
159
|
<Chart
|
|
156
160
|
chartType="GeoChart"
|
|
161
|
+
chartPackages={ GEO_CHART_PACKAGES }
|
|
157
162
|
width={ width }
|
|
158
163
|
height={ height }
|
|
159
164
|
data={ sanitizedData.data }
|
|
@@ -4,9 +4,10 @@ import GeoChart, { GeoChartUnresponsive } from '../geo-chart';
|
|
|
4
4
|
|
|
5
5
|
// Mock react-google-charts
|
|
6
6
|
jest.mock( 'react-google-charts', () => ( {
|
|
7
|
-
Chart: jest.fn( ( { data, options, width, height } ) => {
|
|
7
|
+
Chart: jest.fn( ( { chartPackages, data, options, width, height } ) => {
|
|
8
8
|
return (
|
|
9
9
|
<div data-testid="google-chart-mock" data-width={ width } data-height={ height }>
|
|
10
|
+
<div data-testid="chart-packages">{ JSON.stringify( chartPackages ) }</div>
|
|
10
11
|
<div data-testid="chart-data">{ JSON.stringify( data ) }</div>
|
|
11
12
|
<div data-testid="chart-options">{ JSON.stringify( options ) }</div>
|
|
12
13
|
</div>
|
|
@@ -64,6 +65,15 @@ describe( 'GeoChart', () => {
|
|
|
64
65
|
expect( chart ).toHaveAttribute( 'data-width', '1200' );
|
|
65
66
|
expect( chart ).toHaveAttribute( 'data-height', '600' );
|
|
66
67
|
} );
|
|
68
|
+
|
|
69
|
+
test( 'loads the GeoChart package explicitly', () => {
|
|
70
|
+
renderWithTheme();
|
|
71
|
+
|
|
72
|
+
const chartPackages = screen.getByTestId( 'chart-packages' );
|
|
73
|
+
const packages = JSON.parse( chartPackages.textContent || '[]' );
|
|
74
|
+
|
|
75
|
+
expect( packages ).toEqual( [ 'corechart', 'controls', 'geochart' ] );
|
|
76
|
+
} );
|
|
67
77
|
} );
|
|
68
78
|
|
|
69
79
|
describe( 'Data Handling', () => {
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
.heatmap-chart {
|
|
2
|
+
width: 100%;
|
|
3
|
+
height: 100%;
|
|
4
|
+
min-height: 0;
|
|
5
|
+
font-size: var(--wpds-typography-font-size-sm, 12px);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.heatmap-chart__empty {
|
|
9
|
+
padding: var(--wpds-dimension-padding-lg, 16px);
|
|
10
|
+
color: var(--wpds-color-fg-content-neutral-weak, #707070);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Track template is set inline because CSS `repeat()` won't take a `var()`
|
|
14
|
+
// count. ARIA rows are `display: contents` so their cells join this grid.
|
|
15
|
+
.heatmap-chart__grid {
|
|
16
|
+
display: grid;
|
|
17
|
+
gap: var(--heatmap-cell-gap, var(--wpds-dimension-gap-xs, 4px));
|
|
18
|
+
flex: 1 1 0;
|
|
19
|
+
width: 100%;
|
|
20
|
+
// Floor so the grid stays usable when the parent has no explicit height.
|
|
21
|
+
min-height: 200px;
|
|
22
|
+
|
|
23
|
+
&:focus-visible {
|
|
24
|
+
outline:
|
|
25
|
+
var(--wpds-border-width-focus, var(--wp-admin-border-width-focus, 2px)) solid
|
|
26
|
+
var(--wpds-color-stroke-focus-brand, var(--wp-admin-theme-color, #3858e9));
|
|
27
|
+
outline-offset: 2px;
|
|
28
|
+
border-radius: var(--wpds-border-radius-sm, 2px);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.heatmap-chart__grid--compact {
|
|
33
|
+
flex: 0 0 auto;
|
|
34
|
+
width: max-content;
|
|
35
|
+
height: max-content;
|
|
36
|
+
min-height: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.heatmap-chart__row {
|
|
40
|
+
display: contents;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.heatmap-chart__col-label,
|
|
44
|
+
.heatmap-chart__row-label {
|
|
45
|
+
color: var(--wpds-color-fg-content-neutral-weak, #707070);
|
|
46
|
+
font-size: var(--wpds-typography-font-size-xs, 11px);
|
|
47
|
+
white-space: nowrap;
|
|
48
|
+
overflow: visible;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.heatmap-chart__col-label {
|
|
52
|
+
align-self: end;
|
|
53
|
+
text-align: left;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.heatmap-chart__row-label {
|
|
57
|
+
align-self: center;
|
|
58
|
+
justify-self: end;
|
|
59
|
+
text-align: right;
|
|
60
|
+
padding-inline-end: var(--wpds-dimension-padding-xs, 4px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.heatmap-chart__cell {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
min-width: 0;
|
|
68
|
+
min-height: 0;
|
|
69
|
+
border-radius: var(--wpds-border-radius-sm, 2px);
|
|
70
|
+
// Empty (no-data) default; cells with a value override it below.
|
|
71
|
+
background: var(--wpds-color-bg-track-neutral-weak, #f0f0f0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Floor the mix at 15% so the lowest value stays visibly tinted, distinct from
|
|
75
|
+
// an empty cell.
|
|
76
|
+
.heatmap-chart__cell--filled {
|
|
77
|
+
background: color-mix(in sRGB, var(--heatmap-primary) calc((0.15 + 0.85 * var(--intensity)) * 100%), transparent);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.heatmap-chart__cell--selected {
|
|
81
|
+
outline:
|
|
82
|
+
var(--wpds-border-width-focus, var(--wp-admin-border-width-focus, 2px)) solid
|
|
83
|
+
var(--wpds-color-stroke-focus-brand, var(--wp-admin-theme-color, #3858e9));
|
|
84
|
+
outline-offset: calc(-1 * var(--wpds-border-width-focus, var(--wp-admin-border-width-focus, 2px)));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.heatmap-chart__cell-value {
|
|
88
|
+
color: var(--wpds-color-fg-content-neutral, #1e1e1e);
|
|
89
|
+
font-size: var(--wpds-typography-font-size-md, 13px);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Light text on fills dark enough to out-contrast dark text (decided in JS from
|
|
93
|
+
// the blended fill luminance).
|
|
94
|
+
.heatmap-chart__cell--strong .heatmap-chart__cell-value {
|
|
95
|
+
color: var(--wpds-color-fg-interactive-neutral-strong, #f0f0f0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.heatmap-chart__legend-swatch {
|
|
99
|
+
width: var(--wpds-dimension-size-3xs, 12px);
|
|
100
|
+
height: var(--wpds-dimension-size-3xs, 12px);
|
|
101
|
+
border-radius: var(--wpds-border-radius-sm, 2px);
|
|
102
|
+
background: color-mix(in sRGB, var(--heatmap-primary) calc((0.15 + 0.85 * var(--intensity)) * 100%), transparent);
|
|
103
|
+
}
|