@automattic/charts 2.0.1 → 3.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 +29 -0
- package/TOKENS.md +109 -50
- package/dist/index.cjs +529 -233
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +118 -55
- package/dist/index.d.cts +90 -48
- package/dist/index.d.ts +90 -48
- package/dist/index.js +527 -235
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/charts/area-chart/area-chart.module.scss +8 -3
- package/src/charts/area-chart/area-chart.tsx +25 -25
- package/src/charts/area-chart/private/overlays.tsx +3 -3
- package/src/charts/area-chart/test/area-chart.test.tsx +301 -11
- package/src/charts/area-chart/types.ts +4 -3
- package/src/charts/bar-chart/bar-chart.module.scss +14 -6
- package/src/charts/bar-chart/bar-chart.tsx +21 -15
- package/src/charts/bar-chart/test/bar-chart.test.tsx +255 -2
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +23 -18
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +107 -86
- package/src/charts/conversion-funnel-chart/test/chart-scope.test.tsx +36 -0
- package/src/charts/geo-chart/geo-chart.module.scss +8 -0
- package/src/charts/geo-chart/geo-chart.tsx +12 -4
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +22 -9
- package/src/charts/heatmap-chart/heatmap-chart.tsx +43 -13
- package/src/charts/heatmap-chart/private/build-calendar-data.ts +65 -5
- package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +125 -0
- package/src/charts/heatmap-chart/types.ts +8 -0
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +13 -7
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +17 -22
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +107 -1
- package/src/charts/leaderboard-chart/types.ts +0 -2
- package/src/charts/line-chart/line-chart.module.scss +12 -7
- package/src/charts/line-chart/line-chart.tsx +32 -28
- package/src/charts/line-chart/private/line-chart-annotation.tsx +4 -4
- package/src/charts/line-chart/private/line-chart-annotations-overlay.tsx +2 -2
- package/src/charts/line-chart/test/line-chart.test.tsx +262 -5
- package/src/charts/line-chart/types.ts +4 -3
- package/src/charts/pie-chart/pie-chart.tsx +12 -14
- package/src/charts/pie-chart/test/pie-chart.test.tsx +73 -1
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +2 -2
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +12 -14
- package/src/charts/private/{single-chart-context/single-chart-context.tsx → chart-instance-context/chart-instance-context.ts} +1 -5
- package/src/charts/private/chart-instance-context/index.ts +3 -0
- package/src/charts/private/{single-chart-context/use-single-chart-context.ts → chart-instance-context/use-chart-instance-context.ts} +1 -3
- package/src/charts/private/svg-empty-state/get-all-hidden-message.ts +41 -0
- package/src/charts/private/svg-empty-state/index.ts +1 -0
- package/src/charts/private/svg-empty-state/svg-empty-state.module.scss +1 -1
- package/src/charts/private/svg-empty-state/test/get-all-hidden-message.test.ts +15 -0
- package/src/charts/private/with-responsive/test/with-responsive.test.tsx +16 -0
- package/src/charts/private/with-responsive/with-responsive.tsx +18 -11
- package/src/charts/private/x-zoom/test/x-zoom.test.tsx +2 -2
- package/src/charts/private/x-zoom/x-zoom.module.scss +3 -3
- package/src/charts/private/x-zoom/x-zoom.tsx +2 -2
- package/src/components/legend/legend.tsx +4 -4
- package/src/components/legend/private/base-legend.module.scss +1 -1
- package/src/components/legend/private/base-legend.tsx +70 -19
- package/src/components/legend/test/legend.test.tsx +100 -4
- package/src/components/tooltip/accessible-tooltip.tsx +17 -4
- package/src/components/tooltip/base-tooltip.tsx +8 -1
- package/src/components/trend-indicator/test/trend-indicator.test.tsx +20 -0
- package/src/components/trend-indicator/trend-indicator.module.scss +4 -7
- package/src/components/trend-indicator/trend-indicator.tsx +3 -0
- package/src/hooks/index.ts +1 -1
- package/src/hooks/test/use-xychart-theme-provider-override.test.tsx +28 -0
- package/src/hooks/test/use-xychart-theme-style-reads.test.tsx +19 -13
- package/src/hooks/test/use-xychart-theme.test.tsx +25 -0
- package/src/hooks/{use-interactive-legend-data.ts → use-legend-visibility-data.ts} +29 -30
- package/src/hooks/use-xychart-theme.ts +6 -4
- package/src/index.ts +12 -3
- package/src/providers/chart-context/global-charts-provider.tsx +127 -30
- package/src/providers/chart-context/hooks/use-default-hidden-series.ts +47 -0
- package/src/providers/chart-context/private/theme-override-vars.ts +87 -0
- package/src/providers/chart-context/private/with-catalog-pointers.ts +50 -0
- package/src/providers/chart-context/test/chart-context.test.tsx +142 -40
- package/src/providers/chart-context/test/chart-scope-class.test.tsx +19 -0
- package/src/providers/chart-context/test/sparse-theme.test.ts +35 -0
- package/src/providers/chart-context/test/theme-override-vars-guard.test.tsx +29 -0
- package/src/providers/chart-context/test/theme-override-vars.test.ts +118 -0
- package/src/providers/chart-context/test/use-default-hidden-series-paint.test.tsx +56 -0
- package/src/providers/chart-context/test/use-default-hidden-series.ssr.test.tsx +39 -0
- package/src/providers/chart-context/test/use-default-hidden-series.test.tsx +222 -0
- package/src/providers/chart-context/test/with-catalog-pointers.test.ts +47 -0
- package/src/providers/chart-context/themes.ts +18 -27
- package/src/providers/chart-context/types.ts +7 -4
- package/src/providers/chart-scope/chart-scope-context.ts +8 -0
- package/src/providers/chart-scope/index.ts +3 -0
- package/src/providers/chart-scope/test/chart-scope.test.tsx +24 -0
- package/src/providers/chart-scope/test/use-standalone-scope-class.test.tsx +20 -0
- package/src/providers/chart-scope/use-chart-scope-element.ts +9 -0
- package/src/providers/chart-scope/use-standalone-scope-class.ts +13 -0
- package/src/providers/index.ts +1 -0
- package/src/styles/chart-scope-class.ts +6 -0
- package/src/styles/chart-scope.scss +83 -0
- package/src/styles/test/chart-scope.test.ts +165 -0
- package/src/styles/test/wpds-fallbacks.test.ts +131 -0
- package/src/types.ts +12 -34
- package/src/charts/private/grid-control/grid-control.module.scss +0 -8
- package/src/charts/private/grid-control/grid-control.tsx +0 -26
- package/src/charts/private/grid-control/index.ts +0 -1
- package/src/charts/private/grid-control/test/grid-control.test.tsx +0 -56
- package/src/charts/private/single-chart-context/index.ts +0 -8
|
@@ -4,17 +4,22 @@
|
|
|
4
4
|
overflow: visible;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
// Keep the collapsed state in `from` and never on the element: a dropped
|
|
8
|
+
// animation then fails visible. `both`, not `forwards`, for backwards fill.
|
|
7
9
|
&--animated rect {
|
|
8
10
|
transform-origin: bottom;
|
|
9
11
|
transform-box: fill-box;
|
|
10
|
-
transform: scaleY(0);
|
|
11
12
|
animation:
|
|
12
|
-
rise var(--
|
|
13
|
-
var(--
|
|
13
|
+
rise var(--a8c-charts-motion-duration-entrance)
|
|
14
|
+
var(--a8c-charts-motion-easing-entrance) both;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
@keyframes rise {
|
|
17
18
|
|
|
19
|
+
from {
|
|
20
|
+
transform: scaleY(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
to {
|
|
19
24
|
transform: scaleY(1);
|
|
20
25
|
}
|
|
@@ -23,14 +28,17 @@
|
|
|
23
28
|
&--animated-horizontal rect {
|
|
24
29
|
transform-origin: left;
|
|
25
30
|
transform-box: fill-box;
|
|
26
|
-
transform: scaleX(0);
|
|
27
31
|
animation:
|
|
28
|
-
stretch var(--
|
|
29
|
-
var(--
|
|
32
|
+
stretch var(--a8c-charts-motion-duration-entrance)
|
|
33
|
+
var(--a8c-charts-motion-easing-entrance) both;
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
@keyframes stretch {
|
|
33
37
|
|
|
38
|
+
from {
|
|
39
|
+
transform: scaleX(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
to {
|
|
35
43
|
transform: scaleX(1);
|
|
36
44
|
}
|
|
@@ -20,11 +20,12 @@ import {
|
|
|
20
20
|
useGlobalChartsContext,
|
|
21
21
|
GlobalChartsContext,
|
|
22
22
|
} from '../../providers';
|
|
23
|
+
import { useDefaultHiddenSeries } from '../../providers/chart-context/hooks/use-default-hidden-series';
|
|
23
24
|
import { attachSubComponents } from '../../utils';
|
|
24
25
|
import { useChartChildren } from '../private/chart-composition';
|
|
26
|
+
import { ChartInstanceContext } from '../private/chart-instance-context';
|
|
25
27
|
import { ChartLayout } from '../private/chart-layout';
|
|
26
|
-
import {
|
|
27
|
-
import { SvgEmptyState } from '../private/svg-empty-state';
|
|
28
|
+
import { getAllHiddenMessage, SvgEmptyState } from '../private/svg-empty-state';
|
|
28
29
|
import { withResponsive } from '../private/with-responsive';
|
|
29
30
|
import styles from './bar-chart.module.scss';
|
|
30
31
|
import {
|
|
@@ -42,13 +43,14 @@ import type {
|
|
|
42
43
|
DataPointDate,
|
|
43
44
|
SeriesData,
|
|
44
45
|
SeriesChartLegendConfig,
|
|
46
|
+
SeriesVisibilityProps,
|
|
45
47
|
Optional,
|
|
46
48
|
} from '../../types';
|
|
47
49
|
import type { RenderTooltipParams } from '../../visx/types';
|
|
48
50
|
import type { ResponsiveConfig } from '../private/with-responsive';
|
|
49
51
|
import type { FC, ReactNode, ComponentType } from 'react';
|
|
50
52
|
|
|
51
|
-
export interface BarChartProps extends BaseChartProps< SeriesData[]
|
|
53
|
+
export interface BarChartProps extends BaseChartProps< SeriesData[] >, SeriesVisibilityProps {
|
|
52
54
|
/**
|
|
53
55
|
* Legend configuration. Supports `collapseGroups` on top of the shared options.
|
|
54
56
|
*/
|
|
@@ -122,6 +124,7 @@ const BarChartInternal: FC< BarChartProps > = ( {
|
|
|
122
124
|
orientation = 'vertical',
|
|
123
125
|
withPatterns = false,
|
|
124
126
|
showZeroValues = false,
|
|
127
|
+
defaultHiddenSeries,
|
|
125
128
|
animation,
|
|
126
129
|
children,
|
|
127
130
|
gap = 'md',
|
|
@@ -130,6 +133,11 @@ const BarChartInternal: FC< BarChartProps > = ( {
|
|
|
130
133
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
131
134
|
const horizontal = orientation === 'horizontal';
|
|
132
135
|
const chartId = useChartId( providedChartId );
|
|
136
|
+
const hiddenSeries = useDefaultHiddenSeries( chartId, defaultHiddenSeries );
|
|
137
|
+
const isSeriesVisible = useCallback(
|
|
138
|
+
( seriesLabel: string ) => ! hiddenSeries.has( seriesLabel ),
|
|
139
|
+
[ hiddenSeries ]
|
|
140
|
+
);
|
|
133
141
|
const theme = useXYChartTheme( data );
|
|
134
142
|
|
|
135
143
|
const dataSorted = useChartDataTransform( data );
|
|
@@ -148,14 +156,14 @@ const BarChartInternal: FC< BarChartProps > = ( {
|
|
|
148
156
|
);
|
|
149
157
|
const legendItems = useChartLegendItems( dataSorted, legendOptions );
|
|
150
158
|
|
|
151
|
-
const { getElementStyles
|
|
159
|
+
const { getElementStyles } = useGlobalChartsContext();
|
|
152
160
|
|
|
153
161
|
// A hidden series is unmounted, so it is not on the band scale either — the
|
|
154
|
-
// axis has to choose its tick values from what is left.
|
|
162
|
+
// axis has to choose its tick values from what is left. Visibility is owned by
|
|
163
|
+
// the provider, whether it changed through the legend or programmatically.
|
|
155
164
|
const isSeriesRendered = useCallback(
|
|
156
|
-
( series: SeriesData ) =>
|
|
157
|
-
|
|
158
|
-
[ chartId, legendInteractive, isSeriesVisible ]
|
|
165
|
+
( series: SeriesData ) => isSeriesVisible( series.label ),
|
|
166
|
+
[ isSeriesVisible ]
|
|
159
167
|
);
|
|
160
168
|
|
|
161
169
|
const chartOptions = useBarChartOptions(
|
|
@@ -198,7 +206,7 @@ const BarChartInternal: FC< BarChartProps > = ( {
|
|
|
198
206
|
totalPoints,
|
|
199
207
|
} );
|
|
200
208
|
|
|
201
|
-
// Add visibility information
|
|
209
|
+
// Add visibility information from the shared legend state.
|
|
202
210
|
const seriesWithVisibility = useMemo(
|
|
203
211
|
() =>
|
|
204
212
|
dataWithVisibleZeros.map( ( series, index ) => ( {
|
|
@@ -514,9 +522,10 @@ const BarChartInternal: FC< BarChartProps > = ( {
|
|
|
514
522
|
);
|
|
515
523
|
|
|
516
524
|
return (
|
|
517
|
-
<
|
|
525
|
+
<ChartInstanceContext.Provider
|
|
518
526
|
value={ {
|
|
519
527
|
chartId,
|
|
528
|
+
isSeriesVisible,
|
|
520
529
|
chartWidth: width,
|
|
521
530
|
chartHeight: measuredChartHeight || 0,
|
|
522
531
|
} }
|
|
@@ -606,10 +615,7 @@ const BarChartInternal: FC< BarChartProps > = ( {
|
|
|
606
615
|
width={ width }
|
|
607
616
|
height={ chartHeight }
|
|
608
617
|
>
|
|
609
|
-
{
|
|
610
|
-
'All series are hidden. Click legend items to show data.',
|
|
611
|
-
'jetpack-charts'
|
|
612
|
-
) }
|
|
618
|
+
{ getAllHiddenMessage( legendInteractive, 'series' ) }
|
|
613
619
|
</SvgEmptyState>
|
|
614
620
|
) : null }
|
|
615
621
|
|
|
@@ -673,7 +679,7 @@ const BarChartInternal: FC< BarChartProps > = ( {
|
|
|
673
679
|
);
|
|
674
680
|
} }
|
|
675
681
|
</ChartLayout>
|
|
676
|
-
</
|
|
682
|
+
</ChartInstanceContext.Provider>
|
|
677
683
|
);
|
|
678
684
|
};
|
|
679
685
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { render, renderHook, screen, within } from '@testing-library/react';
|
|
1
|
+
import { render, renderHook, screen, within, act } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { GlobalChartsProvider } from '../../../providers';
|
|
4
|
-
import
|
|
4
|
+
import { useGlobalChartsContext } from '../../../providers/chart-context/hooks/use-global-charts-context';
|
|
5
|
+
import BarChart, { BarChartUnresponsive } from '../bar-chart';
|
|
5
6
|
import { useBarChartOptions } from '../private';
|
|
7
|
+
import type { GlobalChartsContextValue } from '../../../providers/chart-context/types';
|
|
6
8
|
import type { SeriesData } from '../../../types';
|
|
7
9
|
|
|
8
10
|
// Mock useElementSize to return non-zero dimensions in jsdom so charts render
|
|
@@ -1017,6 +1019,64 @@ describe( 'BarChart', () => {
|
|
|
1017
1019
|
expect( screen.queryByTestId( 'chart-tooltip-0' ) ).not.toBeInTheDocument();
|
|
1018
1020
|
} );
|
|
1019
1021
|
|
|
1022
|
+
test( 'keeps the tooltip open once the chart re-renders under it', async () => {
|
|
1023
|
+
// visx hides its tooltip on a debounce and cancels only the most recently
|
|
1024
|
+
// scheduled hide, so anything that re-runs the tooltip effect while nothing
|
|
1025
|
+
// is shown leaves a hide pending that lands on the next tooltip. Seeding a
|
|
1026
|
+
// hidden series re-renders the chart right after mount, which is exactly
|
|
1027
|
+
// that shape.
|
|
1028
|
+
jest.useFakeTimers();
|
|
1029
|
+
|
|
1030
|
+
try {
|
|
1031
|
+
const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime } );
|
|
1032
|
+
renderWithTheme( {
|
|
1033
|
+
withTooltips: true,
|
|
1034
|
+
defaultHiddenSeries: [ 'Series B' ],
|
|
1035
|
+
data: [
|
|
1036
|
+
{
|
|
1037
|
+
label: 'Series A',
|
|
1038
|
+
data: [
|
|
1039
|
+
{ date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' },
|
|
1040
|
+
{ date: new Date( '2024-01-02' ), value: 20, label: 'Jan 2' },
|
|
1041
|
+
],
|
|
1042
|
+
options: {},
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
label: 'Series B',
|
|
1046
|
+
data: [
|
|
1047
|
+
{ date: new Date( '2024-01-01' ), value: 15, label: 'Jan 1' },
|
|
1048
|
+
{ date: new Date( '2024-01-02' ), value: 25, label: 'Jan 2' },
|
|
1049
|
+
],
|
|
1050
|
+
options: {},
|
|
1051
|
+
},
|
|
1052
|
+
],
|
|
1053
|
+
} );
|
|
1054
|
+
|
|
1055
|
+
const chart = screen.getByRole( 'grid', { name: /bar chart/i } );
|
|
1056
|
+
chart.focus();
|
|
1057
|
+
|
|
1058
|
+
await user.keyboard( '{ArrowRight}' );
|
|
1059
|
+
expect( screen.getByTestId( 'chart-tooltip-0' ) ).toHaveTextContent( 'Series A' );
|
|
1060
|
+
|
|
1061
|
+
// Well past any pending hide.
|
|
1062
|
+
await act( async () => {
|
|
1063
|
+
jest.advanceTimersByTime( 5000 );
|
|
1064
|
+
} );
|
|
1065
|
+
|
|
1066
|
+
expect( screen.getByTestId( 'chart-tooltip-0' ) ).toBeInTheDocument();
|
|
1067
|
+
|
|
1068
|
+
// Leaving navigation still closes it.
|
|
1069
|
+
await user.keyboard( '{Escape}' );
|
|
1070
|
+
await act( async () => {
|
|
1071
|
+
jest.advanceTimersByTime( 5000 );
|
|
1072
|
+
} );
|
|
1073
|
+
|
|
1074
|
+
expect( screen.queryByTestId( 'chart-tooltip-0' ) ).not.toBeInTheDocument();
|
|
1075
|
+
} finally {
|
|
1076
|
+
jest.useRealTimers();
|
|
1077
|
+
}
|
|
1078
|
+
} );
|
|
1079
|
+
|
|
1020
1080
|
test( 'left arrow key navigates to previous data point', async () => {
|
|
1021
1081
|
const user = userEvent.setup();
|
|
1022
1082
|
renderWithTheme( {
|
|
@@ -1918,6 +1978,133 @@ describe( 'BarChart', () => {
|
|
|
1918
1978
|
screen.getByText( /all series are hidden.*click legend items to show data/i )
|
|
1919
1979
|
).toBeInTheDocument();
|
|
1920
1980
|
} );
|
|
1981
|
+
|
|
1982
|
+
it( 'hides a series programmatically when the legend is not interactive', () => {
|
|
1983
|
+
let context: GlobalChartsContextValue;
|
|
1984
|
+
const Grab = () => {
|
|
1985
|
+
context = useGlobalChartsContext();
|
|
1986
|
+
return null;
|
|
1987
|
+
};
|
|
1988
|
+
|
|
1989
|
+
render(
|
|
1990
|
+
<GlobalChartsProvider>
|
|
1991
|
+
<Grab />
|
|
1992
|
+
<BarChartUnresponsive
|
|
1993
|
+
width={ 500 }
|
|
1994
|
+
height={ 300 }
|
|
1995
|
+
showLegend={ true }
|
|
1996
|
+
legend={ { interactive: false } }
|
|
1997
|
+
chartId="test-programmatic-bar"
|
|
1998
|
+
data={ [
|
|
1999
|
+
{
|
|
2000
|
+
label: 'Series A',
|
|
2001
|
+
data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
|
|
2002
|
+
options: {},
|
|
2003
|
+
},
|
|
2004
|
+
{
|
|
2005
|
+
label: 'Series B',
|
|
2006
|
+
data: [ { date: new Date( '2024-01-01' ), value: 20, label: 'Jan 1' } ],
|
|
2007
|
+
options: {},
|
|
2008
|
+
},
|
|
2009
|
+
] }
|
|
2010
|
+
/>
|
|
2011
|
+
</GlobalChartsProvider>
|
|
2012
|
+
);
|
|
2013
|
+
|
|
2014
|
+
act( () => {
|
|
2015
|
+
context.toggleSeriesVisibility( 'test-programmatic-bar', 'Series A' );
|
|
2016
|
+
context.toggleSeriesVisibility( 'test-programmatic-bar', 'Series B' );
|
|
2017
|
+
} );
|
|
2018
|
+
|
|
2019
|
+
expect( screen.getByText( /all series are hidden/i ) ).toBeInTheDocument();
|
|
2020
|
+
} );
|
|
2021
|
+
|
|
2022
|
+
it( 'omits the click instruction when the legend cannot be clicked', () => {
|
|
2023
|
+
let context: GlobalChartsContextValue;
|
|
2024
|
+
const Grab = () => {
|
|
2025
|
+
context = useGlobalChartsContext();
|
|
2026
|
+
return null;
|
|
2027
|
+
};
|
|
2028
|
+
|
|
2029
|
+
render(
|
|
2030
|
+
<GlobalChartsProvider>
|
|
2031
|
+
<Grab />
|
|
2032
|
+
<BarChartUnresponsive
|
|
2033
|
+
width={ 500 }
|
|
2034
|
+
height={ 300 }
|
|
2035
|
+
showLegend={ true }
|
|
2036
|
+
legend={ { interactive: false } }
|
|
2037
|
+
chartId="test-empty-copy-bar"
|
|
2038
|
+
data={ [
|
|
2039
|
+
{
|
|
2040
|
+
label: 'Series A',
|
|
2041
|
+
data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
|
|
2042
|
+
options: {},
|
|
2043
|
+
},
|
|
2044
|
+
] }
|
|
2045
|
+
/>
|
|
2046
|
+
</GlobalChartsProvider>
|
|
2047
|
+
);
|
|
2048
|
+
|
|
2049
|
+
act( () => {
|
|
2050
|
+
context.toggleSeriesVisibility( 'test-empty-copy-bar', 'Series A' );
|
|
2051
|
+
} );
|
|
2052
|
+
|
|
2053
|
+
expect( screen.getByText( 'All series are hidden.' ) ).toBeInTheDocument();
|
|
2054
|
+
expect( screen.queryByText( /click legend items/i ) ).not.toBeInTheDocument();
|
|
2055
|
+
} );
|
|
2056
|
+
|
|
2057
|
+
it( 'still renders the other series when only one is hidden programmatically', () => {
|
|
2058
|
+
// A test that hides every series would pass even if the chart still forced
|
|
2059
|
+
// all series visible right up until `allSeriesHidden` short-circuited it —
|
|
2060
|
+
// that shape of test masked a real bug in a sibling chart. Hiding exactly
|
|
2061
|
+
// one of two series exercises the partial-hide render path: the bar count
|
|
2062
|
+
// only drops to one if the hidden series' `BarSeries` is actually excluded
|
|
2063
|
+
// from the `BarGroup`, not merely rendered with zero opacity.
|
|
2064
|
+
let context: GlobalChartsContextValue;
|
|
2065
|
+
const Grab = () => {
|
|
2066
|
+
context = useGlobalChartsContext();
|
|
2067
|
+
return null;
|
|
2068
|
+
};
|
|
2069
|
+
|
|
2070
|
+
render(
|
|
2071
|
+
<GlobalChartsProvider>
|
|
2072
|
+
<Grab />
|
|
2073
|
+
<BarChartUnresponsive
|
|
2074
|
+
width={ 500 }
|
|
2075
|
+
height={ 300 }
|
|
2076
|
+
showLegend={ true }
|
|
2077
|
+
legend={ { interactive: false } }
|
|
2078
|
+
chartId="test-programmatic-partial-bar"
|
|
2079
|
+
data={ [
|
|
2080
|
+
{
|
|
2081
|
+
label: 'Series A',
|
|
2082
|
+
data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
|
|
2083
|
+
options: {},
|
|
2084
|
+
},
|
|
2085
|
+
{
|
|
2086
|
+
label: 'Series B',
|
|
2087
|
+
data: [ { date: new Date( '2024-01-01' ), value: 20, label: 'Jan 1' } ],
|
|
2088
|
+
options: {},
|
|
2089
|
+
},
|
|
2090
|
+
] }
|
|
2091
|
+
/>
|
|
2092
|
+
</GlobalChartsProvider>
|
|
2093
|
+
);
|
|
2094
|
+
|
|
2095
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
2096
|
+
const svgElement = screen.getByRole( 'grid', { name: /bar chart/i } ).querySelector( 'svg' );
|
|
2097
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
2098
|
+
expect( svgElement?.querySelectorAll( '.visx-bar-group rect' ) ).toHaveLength( 2 );
|
|
2099
|
+
|
|
2100
|
+
act( () => {
|
|
2101
|
+
context.toggleSeriesVisibility( 'test-programmatic-partial-bar', 'Series B' );
|
|
2102
|
+
} );
|
|
2103
|
+
|
|
2104
|
+
expect( screen.queryByText( /all series are hidden/i ) ).not.toBeInTheDocument();
|
|
2105
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
2106
|
+
expect( svgElement?.querySelectorAll( '.visx-bar-group rect' ) ).toHaveLength( 1 );
|
|
2107
|
+
} );
|
|
1921
2108
|
} );
|
|
1922
2109
|
|
|
1923
2110
|
describe( 'Legend group collapsing', () => {
|
|
@@ -1996,4 +2183,70 @@ describe( 'BarChart', () => {
|
|
|
1996
2183
|
).toBeInTheDocument();
|
|
1997
2184
|
} );
|
|
1998
2185
|
} );
|
|
2186
|
+
|
|
2187
|
+
describe( 'defaultHiddenSeries', () => {
|
|
2188
|
+
it( 'renders a series hidden when named in defaultHiddenSeries', () => {
|
|
2189
|
+
render(
|
|
2190
|
+
<GlobalChartsProvider>
|
|
2191
|
+
<BarChartUnresponsive
|
|
2192
|
+
width={ 500 }
|
|
2193
|
+
height={ 300 }
|
|
2194
|
+
showLegend={ true }
|
|
2195
|
+
legend={ { interactive: true } }
|
|
2196
|
+
chartId="test-default-hidden-bar"
|
|
2197
|
+
defaultHiddenSeries={ [ 'Series B' ] }
|
|
2198
|
+
data={ [
|
|
2199
|
+
{
|
|
2200
|
+
label: 'Series A',
|
|
2201
|
+
data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
|
|
2202
|
+
options: {},
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
label: 'Series B',
|
|
2206
|
+
data: [ { date: new Date( '2024-01-01' ), value: 20, label: 'Jan 1' } ],
|
|
2207
|
+
options: {},
|
|
2208
|
+
},
|
|
2209
|
+
] }
|
|
2210
|
+
/>
|
|
2211
|
+
</GlobalChartsProvider>
|
|
2212
|
+
);
|
|
2213
|
+
|
|
2214
|
+
const items = screen.getAllByRole( 'button' );
|
|
2215
|
+
expect( items[ 0 ] ).toHaveAttribute( 'aria-pressed', 'true' );
|
|
2216
|
+
expect( items[ 1 ] ).toHaveAttribute( 'aria-pressed', 'false' );
|
|
2217
|
+
} );
|
|
2218
|
+
|
|
2219
|
+
it( 'lets the user reveal a series seeded hidden', async () => {
|
|
2220
|
+
const user = userEvent.setup();
|
|
2221
|
+
|
|
2222
|
+
render(
|
|
2223
|
+
<GlobalChartsProvider>
|
|
2224
|
+
<BarChartUnresponsive
|
|
2225
|
+
width={ 500 }
|
|
2226
|
+
height={ 300 }
|
|
2227
|
+
showLegend={ true }
|
|
2228
|
+
legend={ { interactive: true } }
|
|
2229
|
+
chartId="test-default-hidden-reveal-bar"
|
|
2230
|
+
defaultHiddenSeries={ [ 'Series B' ] }
|
|
2231
|
+
data={ [
|
|
2232
|
+
{
|
|
2233
|
+
label: 'Series A',
|
|
2234
|
+
data: [ { date: new Date( '2024-01-01' ), value: 10, label: 'Jan 1' } ],
|
|
2235
|
+
options: {},
|
|
2236
|
+
},
|
|
2237
|
+
{
|
|
2238
|
+
label: 'Series B',
|
|
2239
|
+
data: [ { date: new Date( '2024-01-01' ), value: 20, label: 'Jan 1' } ],
|
|
2240
|
+
options: {},
|
|
2241
|
+
},
|
|
2242
|
+
] }
|
|
2243
|
+
/>
|
|
2244
|
+
</GlobalChartsProvider>
|
|
2245
|
+
);
|
|
2246
|
+
|
|
2247
|
+
await user.click( screen.getAllByRole( 'button' )[ 1 ] );
|
|
2248
|
+
|
|
2249
|
+
expect( screen.getAllByRole( 'button' )[ 1 ] ).toHaveAttribute( 'aria-pressed', 'true' );
|
|
2250
|
+
} );
|
|
2251
|
+
} );
|
|
1999
2252
|
} );
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
|
|
13
13
|
.main-rate {
|
|
14
14
|
overflow: hidden;
|
|
15
|
-
color: var(--a8c-charts-color-label
|
|
15
|
+
color: var(--a8c-charts-color-label);
|
|
16
16
|
text-overflow: ellipsis;
|
|
17
|
-
font-size: var(--wpds-typography-font-size-xl,
|
|
17
|
+
font-size: var(--wpds-typography-font-size-xl, 20px);
|
|
18
18
|
font-style: normal;
|
|
19
|
-
font-weight: var(--wpds-typography-font-weight-emphasis,
|
|
19
|
+
font-weight: var(--wpds-typography-font-weight-emphasis, 600);
|
|
20
20
|
line-height: var(--wpds-typography-line-height-sm, 20px);
|
|
21
21
|
margin: 0;
|
|
22
22
|
}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
text-overflow: ellipsis;
|
|
27
27
|
font-size: var(--wpds-typography-font-size-md, 13px);
|
|
28
28
|
font-style: normal;
|
|
29
|
-
font-weight: var(--wpds-typography-font-weight-emphasis,
|
|
29
|
+
font-weight: var(--wpds-typography-font-weight-emphasis, 600);
|
|
30
30
|
line-height: var(--wpds-typography-line-height-sm, 20px);
|
|
31
31
|
margin: 0;
|
|
32
32
|
}
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
.step-label {
|
|
57
|
-
color: var(--a8c-charts-color-label-secondary
|
|
57
|
+
color: var(--a8c-charts-color-label-secondary);
|
|
58
58
|
font-size: var(--wpds-typography-font-size-sm, 12px);
|
|
59
59
|
font-weight: var(--wpds-typography-font-weight-default, 400);
|
|
60
60
|
line-height: var(--wpds-typography-line-height-xs, 16px);
|
|
@@ -64,15 +64,15 @@
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
.step-rate {
|
|
67
|
-
color: var(--a8c-charts-color-label
|
|
67
|
+
color: var(--a8c-charts-color-label);
|
|
68
68
|
font-size: var(--wpds-typography-font-size-md, 13px);
|
|
69
|
-
font-weight: var(--wpds-typography-font-weight-emphasis,
|
|
69
|
+
font-weight: var(--wpds-typography-font-weight-emphasis, 600);
|
|
70
70
|
line-height: var(--wpds-typography-line-height-xs, 16px);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
.bar-container {
|
|
74
74
|
flex: 1;
|
|
75
|
-
border-radius: var(--
|
|
75
|
+
border-radius: var(--a8c-charts-border-radius-bar);
|
|
76
76
|
position: relative;
|
|
77
77
|
cursor: pointer;
|
|
78
78
|
}
|
|
@@ -80,19 +80,24 @@
|
|
|
80
80
|
.funnel-bar {
|
|
81
81
|
width: 100%;
|
|
82
82
|
min-height: 4px;
|
|
83
|
-
border-radius: var(--
|
|
83
|
+
border-radius: var(--a8c-charts-border-radius-bar) var(--a8c-charts-border-radius-bar) 0 0;
|
|
84
84
|
|
|
85
|
+
// Keep the collapsed state in `from` and never on the element: a dropped
|
|
86
|
+
// animation then fails visible. `both`, not `forwards`, for backwards fill.
|
|
85
87
|
&--animated {
|
|
86
88
|
transform-origin: bottom;
|
|
87
89
|
transform-box: fill-box;
|
|
88
|
-
transform: scaleY(0);
|
|
89
90
|
animation:
|
|
90
|
-
stretch var(--
|
|
91
|
-
var(--
|
|
91
|
+
stretch var(--a8c-charts-motion-duration-entrance)
|
|
92
|
+
var(--a8c-charts-motion-easing-entrance) both;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
@keyframes stretch {
|
|
95
96
|
|
|
97
|
+
from {
|
|
98
|
+
transform: scaleY(0);
|
|
99
|
+
}
|
|
100
|
+
|
|
96
101
|
to {
|
|
97
102
|
transform: scaleY(1);
|
|
98
103
|
}
|
|
@@ -100,7 +105,7 @@
|
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
.tooltip-wrapper {
|
|
103
|
-
background: var(--a8c-charts-color-
|
|
108
|
+
background: var(--a8c-charts-color-surface);
|
|
104
109
|
|
|
105
110
|
// Override .visx-tooltip inline styles.
|
|
106
111
|
border-radius: var(--wpds-border-radius-md, 4px) !important;
|
|
@@ -110,7 +115,7 @@
|
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
.tooltip-title {
|
|
113
|
-
color: var(--a8c-charts-color-label
|
|
118
|
+
color: var(--a8c-charts-color-label);
|
|
114
119
|
font-size: var(--wpds-typography-font-size-sm, 12px);
|
|
115
120
|
font-style: normal;
|
|
116
121
|
font-weight: var(--wpds-typography-font-weight-default, 400);
|
|
@@ -118,15 +123,15 @@
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
.tooltip-content {
|
|
121
|
-
color: var(--a8c-charts-color-label
|
|
126
|
+
color: var(--a8c-charts-color-label);
|
|
122
127
|
font-size: var(--wpds-typography-font-size-md, 13px);
|
|
123
128
|
font-style: normal;
|
|
124
|
-
font-weight: var(--wpds-typography-font-weight-emphasis,
|
|
129
|
+
font-weight: var(--wpds-typography-font-weight-emphasis, 600);
|
|
125
130
|
line-height: var(--wpds-typography-line-height-sm, 20px);
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
.empty-state {
|
|
129
134
|
text-align: center;
|
|
130
|
-
color: var(--a8c-charts-color-label-secondary
|
|
131
|
-
font-size: var(--wpds-typography-font-size-lg,
|
|
135
|
+
color: var(--a8c-charts-color-label-secondary);
|
|
136
|
+
font-size: var(--wpds-typography-font-size-lg, 15px);
|
|
132
137
|
}
|