@automattic/charts 1.0.1 → 1.1.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 +20 -0
- package/dist/{chunk-G3PMV62Z.js → chunk-5WRI5ZAA.js} +1 -6
- package/dist/{chunk-EMMSS5I5.cjs → chunk-DZUJEN5N.cjs} +2 -7
- package/dist/chunk-DZUJEN5N.cjs.map +1 -0
- package/dist/index.cjs +602 -1386
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +36 -52
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +699 -1483
- package/dist/index.js.map +1 -1
- package/dist/visx/group/index.cjs +1 -1
- package/dist/visx/group/index.js +1 -1
- package/dist/visx/legend/index.cjs +1 -1
- package/dist/visx/legend/index.js +1 -1
- package/dist/visx/text/index.cjs +1 -1
- package/dist/visx/text/index.js +1 -1
- package/package.json +12 -11
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +26 -42
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +18 -5
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +11 -0
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +1 -1
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +2 -2
- package/src/charts/line-chart/line-chart.module.scss +3 -3
- package/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx +2 -2
- package/src/charts/pie-chart/pie-chart.tsx +5 -3
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +3 -3
- package/src/components/legend/private/base-legend.module.scss +2 -2
- package/src/components/tooltip/base-tooltip.module.scss +1 -1
- package/src/components/trend-indicator/trend-indicator.module.scss +2 -2
- package/src/hooks/use-chart-margin.tsx +1 -14
- package/src/providers/chart-context/global-charts-provider.tsx +13 -0
- package/src/providers/chart-context/test/chart-context.test.tsx +51 -0
- package/src/providers/chart-context/themes.ts +7 -1
- package/src/providers/chart-context/types.ts +1 -0
- package/src/types.ts +2 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/resolve-font-size.ts +37 -0
- package/src/utils/test/resolve-css-var.test.ts +3 -5
- package/src/utils/test/resolve-font-size.test.ts +66 -0
- package/dist/chunk-EMMSS5I5.cjs.map +0 -1
- /package/dist/{chunk-G3PMV62Z.js.map → chunk-5WRI5ZAA.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../../chunk-
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../../chunk-DZUJEN5N.cjs');
|
|
2
2
|
|
|
3
3
|
// src/visx/group/index.ts
|
|
4
4
|
var _group = require('@visx/group');
|
package/dist/visx/group/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../../chunk-
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../../chunk-DZUJEN5N.cjs');
|
|
2
2
|
|
|
3
3
|
// src/visx/legend/index.ts
|
|
4
4
|
var _legend = require('@visx/legend');
|
package/dist/visx/text/index.cjs
CHANGED
package/dist/visx/text/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/charts",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.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": {
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
"typecheck": "tsgo --noEmit"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@automattic/number-formatters": "^1.1.
|
|
67
|
-
"@babel/runtime": "7.
|
|
66
|
+
"@automattic/number-formatters": "^1.1.5",
|
|
67
|
+
"@babel/runtime": "7.29.2",
|
|
68
68
|
"@react-spring/web": "9.7.5",
|
|
69
69
|
"@visx/annotation": "^3.12.0",
|
|
70
70
|
"@visx/axis": "^3.12.0",
|
|
@@ -83,14 +83,14 @@
|
|
|
83
83
|
"@visx/vendor": "^3.12.0",
|
|
84
84
|
"@visx/xychart": "^3.12.0",
|
|
85
85
|
"@wordpress/i18n": "^6.0.0",
|
|
86
|
-
"@wordpress/
|
|
86
|
+
"@wordpress/icons": "^12.0.0",
|
|
87
|
+
"@wordpress/theme": "0.10.0",
|
|
87
88
|
"@wordpress/ui": "0.9.0",
|
|
88
89
|
"clsx": "2.1.1",
|
|
89
90
|
"date-fns": "^4.1.0",
|
|
90
91
|
"deepmerge": "4.3.1",
|
|
91
92
|
"dompurify": "^3.3.3",
|
|
92
93
|
"fast-deep-equal": "3.1.3",
|
|
93
|
-
"gridicons": "3.4.2",
|
|
94
94
|
"react-google-charts": "^5.2.1",
|
|
95
95
|
"tslib": "2.8.1"
|
|
96
96
|
},
|
|
@@ -99,8 +99,8 @@
|
|
|
99
99
|
"@babel/core": "7.29.0",
|
|
100
100
|
"@babel/preset-react": "7.28.5",
|
|
101
101
|
"@babel/preset-typescript": "7.28.5",
|
|
102
|
-
"@storybook/addon-docs": "10.3.
|
|
103
|
-
"@storybook/react": "10.3.
|
|
102
|
+
"@storybook/addon-docs": "10.3.3",
|
|
103
|
+
"@storybook/react": "10.3.3",
|
|
104
104
|
"@testing-library/dom": "^10.0.0",
|
|
105
105
|
"@testing-library/jest-dom": "^6.0.0",
|
|
106
106
|
"@testing-library/react": "^16.0.0",
|
|
@@ -110,11 +110,12 @@
|
|
|
110
110
|
"@types/react-dom": "18.3.7",
|
|
111
111
|
"@typescript/native-preview": "7.0.0-dev.20260225.1",
|
|
112
112
|
"@visx/glyph": "3.12.0",
|
|
113
|
-
"@wordpress/components": "32.
|
|
114
|
-
"@wordpress/element": "6.
|
|
113
|
+
"@wordpress/components": "32.5.0",
|
|
114
|
+
"@wordpress/element": "6.43.0",
|
|
115
|
+
"@wordpress/private-apis": "1.43.0",
|
|
115
116
|
"babel-jest": "30.3.0",
|
|
116
117
|
"babel-plugin-react-remove-properties": "^0.3.1",
|
|
117
|
-
"esbuild": "0.
|
|
118
|
+
"esbuild": "0.27.4",
|
|
118
119
|
"esbuild-plugin-babel": "^0.2.3",
|
|
119
120
|
"esbuild-sass-plugin": "^3.1.0",
|
|
120
121
|
"identity-obj-proxy": "^3.0.0",
|
|
@@ -125,7 +126,7 @@
|
|
|
125
126
|
"react": "18.3.1",
|
|
126
127
|
"react-dom": "18.3.1",
|
|
127
128
|
"sass-embedded": "1.97.3",
|
|
128
|
-
"storybook": "10.3.
|
|
129
|
+
"storybook": "10.3.3",
|
|
129
130
|
"tsup": "8.5.1",
|
|
130
131
|
"typescript": "5.9.3"
|
|
131
132
|
},
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
.
|
|
2
|
-
font-family: var(--funnel-font-family, "SF Pro Text");
|
|
1
|
+
.conversion-funnel-chart {
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
&--loading {
|
|
5
4
|
opacity: 0.6;
|
|
6
5
|
pointer-events: none;
|
|
7
6
|
}
|
|
@@ -19,22 +18,20 @@
|
|
|
19
18
|
overflow: hidden;
|
|
20
19
|
color: #1e1e1e;
|
|
21
20
|
text-overflow: ellipsis;
|
|
22
|
-
font-
|
|
23
|
-
font-size: 18px;
|
|
21
|
+
font-size: var(--wpds-font-size-xl, 18px);
|
|
24
22
|
font-style: normal;
|
|
25
|
-
font-weight:
|
|
26
|
-
line-height: 20px;
|
|
23
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
24
|
+
line-height: var(--wpds-font-line-height-sm, 20px);
|
|
27
25
|
margin: 0;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
.change-indicator {
|
|
31
29
|
overflow: hidden;
|
|
32
30
|
text-overflow: ellipsis;
|
|
33
|
-
font-
|
|
34
|
-
font-size: 13px;
|
|
31
|
+
font-size: var(--wpds-font-size-md, 13px);
|
|
35
32
|
font-style: normal;
|
|
36
|
-
font-weight:
|
|
37
|
-
line-height: 20px;
|
|
33
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
34
|
+
line-height: var(--wpds-font-line-height-sm, 20px);
|
|
38
35
|
margin: 0;
|
|
39
36
|
}
|
|
40
37
|
|
|
@@ -53,9 +50,12 @@
|
|
|
53
50
|
display: flex;
|
|
54
51
|
flex-direction: column;
|
|
55
52
|
height: 100%;
|
|
56
|
-
transition: all 0.3s ease;
|
|
57
53
|
|
|
58
|
-
|
|
54
|
+
&--animated {
|
|
55
|
+
transition: opacity 0.3s ease;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&--blurred {
|
|
59
59
|
opacity: 0.3;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -66,11 +66,10 @@
|
|
|
66
66
|
|
|
67
67
|
.step-label {
|
|
68
68
|
color: #757575;
|
|
69
|
-
font-
|
|
70
|
-
font-size: 12px;
|
|
69
|
+
font-size: var(--wpds-font-size-sm, 12px);
|
|
71
70
|
font-style: normal;
|
|
72
|
-
font-weight: 400;
|
|
73
|
-
line-height: 16px;
|
|
71
|
+
font-weight: var(--wpds-font-weight-regular, 400);
|
|
72
|
+
line-height: var(--wpds-font-line-height-xs, 16px);
|
|
74
73
|
margin: 0 0 2px 0;
|
|
75
74
|
display: block;
|
|
76
75
|
overflow: hidden;
|
|
@@ -79,11 +78,10 @@
|
|
|
79
78
|
|
|
80
79
|
.step-rate {
|
|
81
80
|
color: #1e1e1e;
|
|
82
|
-
font-
|
|
83
|
-
font-size: 13px;
|
|
81
|
+
font-size: var(--wpds-font-size-md, 13px);
|
|
84
82
|
font-style: normal;
|
|
85
|
-
font-weight:
|
|
86
|
-
line-height: 20px;
|
|
83
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
84
|
+
line-height: var(--wpds-font-line-height-sm, 20px);
|
|
87
85
|
margin: 0;
|
|
88
86
|
display: block;
|
|
89
87
|
}
|
|
@@ -95,24 +93,12 @@
|
|
|
95
93
|
border-radius: 4px;
|
|
96
94
|
position: relative;
|
|
97
95
|
cursor: pointer;
|
|
98
|
-
transition: all 0.2s ease;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
&.disabled {
|
|
102
|
-
cursor: pointer;
|
|
103
|
-
}
|
|
104
96
|
}
|
|
105
97
|
|
|
106
98
|
.funnel-bar {
|
|
107
99
|
width: 100%;
|
|
108
100
|
min-height: 4px;
|
|
109
101
|
border-radius: 4px 4px 0 0;
|
|
110
|
-
transition: all 0.3s ease;
|
|
111
|
-
|
|
112
|
-
&.selected {
|
|
113
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
|
114
|
-
filter: brightness(1.1);
|
|
115
|
-
}
|
|
116
102
|
|
|
117
103
|
&--animated {
|
|
118
104
|
transform-origin: bottom;
|
|
@@ -148,25 +134,23 @@
|
|
|
148
134
|
|
|
149
135
|
.tooltip-title {
|
|
150
136
|
color: #1e1e1e;
|
|
151
|
-
font-
|
|
152
|
-
font-size: 12px;
|
|
137
|
+
font-size: var(--wpds-font-size-sm, 12px);
|
|
153
138
|
font-style: normal;
|
|
154
|
-
font-weight: 400;
|
|
155
|
-
line-height: 16px;
|
|
139
|
+
font-weight: var(--wpds-font-weight-regular, 400);
|
|
140
|
+
line-height: var(--wpds-font-line-height-xs, 16px);
|
|
156
141
|
}
|
|
157
142
|
|
|
158
143
|
.tooltip-content {
|
|
159
144
|
color: #1e1e1e;
|
|
160
|
-
font-
|
|
161
|
-
font-size: 13px;
|
|
145
|
+
font-size: var(--wpds-font-size-md, 13px);
|
|
162
146
|
font-style: normal;
|
|
163
|
-
font-weight:
|
|
164
|
-
line-height: 20px;
|
|
147
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
148
|
+
line-height: var(--wpds-font-line-height-sm, 20px);
|
|
165
149
|
}
|
|
166
150
|
|
|
167
151
|
.empty-state {
|
|
168
152
|
text-align: center;
|
|
169
153
|
padding: 48px 24px;
|
|
170
154
|
color: #6b7280;
|
|
171
|
-
font-size: 16px;
|
|
155
|
+
font-size: var(--wpds-font-size-lg, 16px);
|
|
172
156
|
}
|
|
@@ -52,7 +52,7 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
52
52
|
} ) => {
|
|
53
53
|
const chartId = useChartId( providedChartId );
|
|
54
54
|
const { conversionFunnelChart: conversionFunnelChartSettings } = useGlobalChartsTheme();
|
|
55
|
-
const { getElementStyles } = useGlobalChartsContext();
|
|
55
|
+
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
56
56
|
const chartRef = useRef< HTMLDivElement >( null );
|
|
57
57
|
const selectedBarRef = useRef< HTMLDivElement | null >( null );
|
|
58
58
|
|
|
@@ -301,7 +301,11 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
301
301
|
<Stack
|
|
302
302
|
direction="column"
|
|
303
303
|
data-testid="conversion-funnel-chart"
|
|
304
|
-
className={ clsx(
|
|
304
|
+
className={ clsx(
|
|
305
|
+
styles[ 'conversion-funnel-chart' ],
|
|
306
|
+
loading && styles[ 'conversion-funnel-chart--loading' ],
|
|
307
|
+
className
|
|
308
|
+
) }
|
|
305
309
|
style={ { ...style, height: resolvedHeight } }
|
|
306
310
|
>
|
|
307
311
|
<div className={ styles[ 'empty-state' ] }>
|
|
@@ -324,7 +328,11 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
324
328
|
portalContainerRef( node );
|
|
325
329
|
chartRef.current = node;
|
|
326
330
|
} }
|
|
327
|
-
className={ clsx(
|
|
331
|
+
className={ clsx(
|
|
332
|
+
styles[ 'conversion-funnel-chart' ],
|
|
333
|
+
loading && styles[ 'conversion-funnel-chart--loading' ],
|
|
334
|
+
className
|
|
335
|
+
) }
|
|
328
336
|
style={ { ...style, height: resolvedHeight } }
|
|
329
337
|
>
|
|
330
338
|
{ /* Main Metric */ }
|
|
@@ -348,7 +356,12 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
348
356
|
return (
|
|
349
357
|
<div
|
|
350
358
|
key={ step.id }
|
|
351
|
-
|
|
359
|
+
data-testid="funnel-step"
|
|
360
|
+
className={ clsx(
|
|
361
|
+
styles[ 'funnel-step' ],
|
|
362
|
+
isColorPaletteResolved && styles[ 'funnel-step--animated' ],
|
|
363
|
+
isBlurred && styles[ 'funnel-step--blurred' ]
|
|
364
|
+
) }
|
|
352
365
|
>
|
|
353
366
|
{ /* Step Label and Rate */ }
|
|
354
367
|
<div className={ styles[ 'step-header' ] }>
|
|
@@ -376,7 +389,7 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
376
389
|
|
|
377
390
|
{ /* Funnel Bar */ }
|
|
378
391
|
<div
|
|
379
|
-
className={
|
|
392
|
+
className={ styles[ 'bar-container' ] }
|
|
380
393
|
onClick={ stepHandlers.get( step.id )?.onClick }
|
|
381
394
|
onKeyDown={ stepHandlers.get( step.id )?.onKeyDown }
|
|
382
395
|
role="button"
|
|
@@ -461,4 +461,15 @@ describe( 'ConversionFunnelChart', () => {
|
|
|
461
461
|
expect( customRenderMainMetric ).toHaveBeenCalled();
|
|
462
462
|
} );
|
|
463
463
|
} );
|
|
464
|
+
|
|
465
|
+
describe( 'Color palette readiness', () => {
|
|
466
|
+
it( 'enables transitions once color palette is resolved', () => {
|
|
467
|
+
render( <ConversionFunnelChart { ...defaultProps } /> );
|
|
468
|
+
|
|
469
|
+
// After render, effects have run (via useEffect in GlobalChartsProvider),
|
|
470
|
+
// so the palette is resolved and the animated class is applied to funnel steps
|
|
471
|
+
const funnelStep = screen.getAllByTestId( 'funnel-step' )[ 0 ];
|
|
472
|
+
expect( funnelStep ).toHaveClass( 'funnel-step--animated' );
|
|
473
|
+
} );
|
|
474
|
+
} );
|
|
464
475
|
} );
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* eslint-disable @wordpress/no-unsafe-wp-apis */
|
|
2
|
-
import { __experimentalGrid as Grid
|
|
2
|
+
import { __experimentalGrid as Grid } from '@wordpress/components';
|
|
3
3
|
import { Fragment } from '@wordpress/element';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
|
-
import { Stack } from '@wordpress/ui';
|
|
5
|
+
import { Stack, Text } from '@wordpress/ui';
|
|
6
6
|
import clsx from 'clsx';
|
|
7
7
|
import { useContext, useMemo, type FC } from 'react';
|
|
8
8
|
import { Legend } from '../../components/legend';
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
&__tooltip-date {
|
|
24
|
-
font-weight:
|
|
24
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
25
25
|
padding-bottom: 10px;
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
&__tooltip-label {
|
|
36
|
-
font-weight:
|
|
36
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
37
37
|
padding-right: 1rem;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
background: #fff;
|
|
66
66
|
border: none;
|
|
67
67
|
border-radius: 4px;
|
|
68
|
-
font-size:
|
|
68
|
+
font-size: var(--wpds-font-size-md, 13px);
|
|
69
69
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
70
70
|
position: fixed;
|
|
71
71
|
margin: 0.5rem;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import { Icon, close } from '@wordpress/icons';
|
|
2
3
|
import clsx from 'clsx';
|
|
3
|
-
import Gridicon from 'gridicons';
|
|
4
4
|
import { useEffect, useId, useRef, useState } from 'react';
|
|
5
5
|
import { isSafari } from '../../../utils';
|
|
6
6
|
import styles from '../line-chart.module.scss';
|
|
@@ -100,7 +100,7 @@ const LineChartAnnotationLabelWithPopover: FC< LineChartAnnotationLabelWithPopov
|
|
|
100
100
|
className={ styles[ 'line-chart__annotation-label-popover-close-button' ] }
|
|
101
101
|
aria-label={ __( 'Close', 'jetpack-charts' ) }
|
|
102
102
|
>
|
|
103
|
-
<
|
|
103
|
+
<Icon icon={ close } size={ 16 } />
|
|
104
104
|
</button>
|
|
105
105
|
</div>
|
|
106
106
|
</div>
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
useGlobalChartsTheme,
|
|
21
21
|
GlobalChartsContext,
|
|
22
22
|
} from '../../providers';
|
|
23
|
-
import { attachSubComponents } from '../../utils';
|
|
23
|
+
import { attachSubComponents, resolveFontSize } from '../../utils';
|
|
24
24
|
import { getStringWidth } from '../../visx/text';
|
|
25
25
|
import { ChartSVG, ChartHTML, useChartChildren } from '../private/chart-composition';
|
|
26
26
|
import { ChartLayout } from '../private/chart-layout';
|
|
@@ -441,10 +441,12 @@ const PieChartInternal = ( {
|
|
|
441
441
|
groupProps.onMouseLeave = onMouseLeave;
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
-
|
|
445
|
-
const fontSize = 12;
|
|
444
|
+
const svgLabelSmall = providerTheme.svgLabelSmall;
|
|
445
|
+
const fontSize = resolveFontSize( svgLabelSmall?.fontSize ) ?? 12;
|
|
446
446
|
const estimatedTextWidth = getStringWidth( arc.data.label, {
|
|
447
447
|
fontSize,
|
|
448
|
+
fontFamily: svgLabelSmall?.fontFamily,
|
|
449
|
+
fontWeight: svgLabelSmall?.fontWeight,
|
|
448
450
|
} );
|
|
449
451
|
const labelPadding = 6;
|
|
450
452
|
const backgroundWidth = estimatedTextWidth + labelPadding * 2;
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
.label {
|
|
14
|
-
font-weight:
|
|
15
|
-
font-size: 16px;
|
|
14
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
15
|
+
font-size: var(--wpds-font-size-lg, 16px);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
.note {
|
|
19
|
-
font-size:
|
|
19
|
+
font-size: var(--wpds-font-size-md, 13px);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
.legend-item {
|
|
45
45
|
display: flex;
|
|
46
46
|
align-items: center;
|
|
47
|
-
font-size:
|
|
47
|
+
font-size: var(--wpds-font-size-md, 13px);
|
|
48
48
|
|
|
49
49
|
&--interactive {
|
|
50
50
|
cursor: pointer;
|
|
@@ -101,6 +101,6 @@
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
.legend-item-value {
|
|
104
|
-
font-weight:
|
|
104
|
+
font-weight: var(--wpds-font-weight-medium, 499);
|
|
105
105
|
flex-shrink: 0; // Prevent value from shrinking when text is ellipsized
|
|
106
106
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createScale, getTicks } from '@visx/scale';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
|
-
import { getLongestTickWidth } from '../utils';
|
|
3
|
+
import { getLongestTickWidth, resolveFontSize } from '../utils';
|
|
4
4
|
import type { BaseChartProps, DataPointDate, SeriesData } from '../types';
|
|
5
5
|
import type { XYChartTheme } from '@visx/xychart';
|
|
6
6
|
|
|
@@ -50,19 +50,6 @@ const DEFAULT_TICK_LENGTH = 8;
|
|
|
50
50
|
*/
|
|
51
51
|
const DEFAULT_Y_TICK_WIDTH = 40;
|
|
52
52
|
|
|
53
|
-
const resolveFontSize = ( val?: number | string ): number | undefined => {
|
|
54
|
-
if ( typeof val === 'number' && ! isNaN( val ) ) {
|
|
55
|
-
return val;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if ( typeof val === 'string' ) {
|
|
59
|
-
const parsed = parseFloat( val );
|
|
60
|
-
return isNaN( parsed ) ? undefined : parsed;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return undefined;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
53
|
const getXAxisLabelMetrics = ( theme: XYChartTheme, orientation: 'top' | 'bottom' ) => {
|
|
67
54
|
const xAxisStyles =
|
|
68
55
|
orientation === 'top' ? theme.axisStyles?.x?.top : theme.axisStyles?.x?.bottom;
|
|
@@ -70,11 +70,16 @@ export const GlobalChartsProvider: FC< GlobalChartsProviderProps > = ( {
|
|
|
70
70
|
maxHue: 0,
|
|
71
71
|
} ) );
|
|
72
72
|
|
|
73
|
+
// Track if the color palette has been resolved from the DOM
|
|
74
|
+
// Useful for animations that should only run after the color palette is resolved
|
|
75
|
+
const [ isColorPaletteResolved, setIsColorPaletteResolved ] = useState( false );
|
|
76
|
+
|
|
73
77
|
// Compute color cache after DOM is updated (so CSS variables are available)
|
|
74
78
|
// Resolves CSS variables from the wrapper element's scope to handle scoped variables
|
|
75
79
|
// Note: Only re-runs when providerTheme changes, not when wrapper element changes.
|
|
76
80
|
// This is intentional, as wrapperRef is expected to be stable for the lifetime of the provider.
|
|
77
81
|
useLayoutEffect( () => {
|
|
82
|
+
setIsColorPaletteResolved( false );
|
|
78
83
|
const { colors } = providerTheme;
|
|
79
84
|
const resolvedColors: string[] = [];
|
|
80
85
|
const hues: number[] = [];
|
|
@@ -125,6 +130,12 @@ export const GlobalChartsProvider: FC< GlobalChartsProviderProps > = ( {
|
|
|
125
130
|
} );
|
|
126
131
|
}, [ providerTheme ] );
|
|
127
132
|
|
|
133
|
+
useEffect( () => {
|
|
134
|
+
if ( colorCache.colors.length > 0 ) {
|
|
135
|
+
setIsColorPaletteResolved( true );
|
|
136
|
+
}
|
|
137
|
+
}, [ colorCache ] );
|
|
138
|
+
|
|
128
139
|
const [ groupToColorMap, setGroupToColorMap ] = useState< Map< string, string > >(
|
|
129
140
|
() => new Map()
|
|
130
141
|
);
|
|
@@ -271,6 +282,7 @@ export const GlobalChartsProvider: FC< GlobalChartsProviderProps > = ( {
|
|
|
271
282
|
toggleSeriesVisibility,
|
|
272
283
|
isSeriesVisible,
|
|
273
284
|
getHiddenSeries,
|
|
285
|
+
isColorPaletteResolved,
|
|
274
286
|
} ),
|
|
275
287
|
[
|
|
276
288
|
charts,
|
|
@@ -282,6 +294,7 @@ export const GlobalChartsProvider: FC< GlobalChartsProviderProps > = ( {
|
|
|
282
294
|
toggleSeriesVisibility,
|
|
283
295
|
isSeriesVisible,
|
|
284
296
|
getHiddenSeries,
|
|
297
|
+
isColorPaletteResolved,
|
|
285
298
|
]
|
|
286
299
|
);
|
|
287
300
|
|
|
@@ -47,6 +47,57 @@ describe( 'ChartContext', () => {
|
|
|
47
47
|
expect( contextValue.charts ).toBeInstanceOf( Map );
|
|
48
48
|
} );
|
|
49
49
|
|
|
50
|
+
it( 'exposes isColorPaletteResolved as true after render', () => {
|
|
51
|
+
let contextValue: GlobalChartsContextValue;
|
|
52
|
+
|
|
53
|
+
const TestComponent = () => {
|
|
54
|
+
contextValue = useGlobalChartsContext();
|
|
55
|
+
return <div>Test</div>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
render(
|
|
59
|
+
<GlobalChartsProvider>
|
|
60
|
+
<TestComponent />
|
|
61
|
+
</GlobalChartsProvider>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// After render and effects, isColorPaletteResolved should be true
|
|
65
|
+
expect( contextValue.isColorPaletteResolved ).toBe( true );
|
|
66
|
+
} );
|
|
67
|
+
|
|
68
|
+
it( 'resolves palette again after theme change', () => {
|
|
69
|
+
let contextValue: GlobalChartsContextValue;
|
|
70
|
+
|
|
71
|
+
const TestComponent = () => {
|
|
72
|
+
contextValue = useGlobalChartsContext();
|
|
73
|
+
return <div>Test</div>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const theme1: Partial< ChartTheme > = {
|
|
77
|
+
colors: [ '#006DAB', '#1F9828' ],
|
|
78
|
+
};
|
|
79
|
+
const theme2: Partial< ChartTheme > = {
|
|
80
|
+
colors: [ '#FF0000', '#00FF00' ],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const { rerender } = render(
|
|
84
|
+
<GlobalChartsProvider theme={ theme1 }>
|
|
85
|
+
<TestComponent />
|
|
86
|
+
</GlobalChartsProvider>
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect( contextValue.isColorPaletteResolved ).toBe( true );
|
|
90
|
+
|
|
91
|
+
rerender(
|
|
92
|
+
<GlobalChartsProvider theme={ theme2 }>
|
|
93
|
+
<TestComponent />
|
|
94
|
+
</GlobalChartsProvider>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// After theme change, palette should re-resolve to true
|
|
98
|
+
expect( contextValue.isColorPaletteResolved ).toBe( true );
|
|
99
|
+
} );
|
|
100
|
+
|
|
50
101
|
it( 'throws error when useGlobalChartsContext is used outside provider', () => {
|
|
51
102
|
const TestComponent = () => {
|
|
52
103
|
useGlobalChartsContext();
|
|
@@ -26,7 +26,13 @@ const defaultTheme: CompleteChartTheme = {
|
|
|
26
26
|
},
|
|
27
27
|
seriesLineStyles: [],
|
|
28
28
|
glyphs: [],
|
|
29
|
-
|
|
29
|
+
// `fontFamily: 'inherit'` overrides visx's hardcoded default font stack
|
|
30
|
+
// (`-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,sans-serif`)
|
|
31
|
+
// that `buildChartTheme` injects as an inline style on SVG `<text>`
|
|
32
|
+
// elements for axis labels and ticks. Setting `inherit` lets SVG text
|
|
33
|
+
// pick up the host application's font-family via normal CSS inheritance.
|
|
34
|
+
svgLabelSmall: { fill: 'var(--jp-gray-80, #2c3338)', fontFamily: 'inherit' },
|
|
35
|
+
svgLabelBig: { fontFamily: 'inherit' },
|
|
30
36
|
annotationStyles: {
|
|
31
37
|
label: {
|
|
32
38
|
anchorLineStroke: 'var(--jp-gray-80, #2c3338)',
|
|
@@ -35,4 +35,5 @@ export interface GlobalChartsContextValue {
|
|
|
35
35
|
toggleSeriesVisibility: ( chartId: string, seriesLabel: string ) => void;
|
|
36
36
|
isSeriesVisible: ( chartId: string, seriesLabel: string ) => boolean;
|
|
37
37
|
getHiddenSeries: ( chartId: string ) => Set< string >;
|
|
38
|
+
isColorPaletteResolved: boolean;
|
|
38
39
|
}
|
package/src/types.ts
CHANGED
|
@@ -243,6 +243,8 @@ export type ChartTheme = {
|
|
|
243
243
|
};
|
|
244
244
|
/** Styles for small SVG text (eg. axis tick labels), passed through to the XYChart theme. */
|
|
245
245
|
svgLabelSmall?: TextProps;
|
|
246
|
+
/** Styles for large SVG text (eg. axis titles), passed through to the XYChart theme. */
|
|
247
|
+
svgLabelBig?: TextProps;
|
|
246
248
|
annotationStyles?: AnnotationStyles;
|
|
247
249
|
/** GeoChart specific settings */
|
|
248
250
|
geoChart?: {
|