@automattic/charts 4.8.0 → 4.10.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 +28 -0
- package/dist/index.cjs +766 -277
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +72 -8
- package/dist/index.d.cts +54 -15
- package/dist/index.d.ts +54 -15
- package/dist/index.js +770 -281
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/charts/area-chart/area-chart.tsx +7 -3
- package/src/charts/area-chart/test/area-chart.test.tsx +15 -14
- package/src/charts/area-chart/test/tooltip-resolution.test.tsx +2 -2
- package/src/charts/bar-chart/bar-chart.tsx +12 -4
- package/src/charts/bar-chart/test/bar-chart.test.tsx +74 -63
- package/src/charts/bar-list-chart/bar-list-chart.tsx +3 -0
- package/src/charts/bar-list-chart/test/bar-list-chart.test.tsx +3 -1
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +23 -7
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +22 -0
- package/src/charts/conversion-funnel-chart/types.ts +1 -1
- package/src/charts/geo-chart/geo-chart.tsx +17 -2
- package/src/charts/geo-chart/test/geo-chart.test.tsx +9 -4
- package/src/charts/geo-chart/types.ts +1 -1
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +10 -4
- package/src/charts/heatmap-chart/heatmap-chart.tsx +144 -37
- package/src/charts/heatmap-chart/private/column-groups.ts +79 -8
- package/src/charts/heatmap-chart/private/fit-compact-cells.ts +72 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +14 -2
- package/src/charts/heatmap-chart/private/index.ts +4 -2
- package/src/charts/heatmap-chart/test/column-groups.test.ts +41 -4
- package/src/charts/heatmap-chart/test/fit-compact-cells.test.ts +59 -0
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +132 -7
- 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/leaderboard-chart.module.scss +52 -4
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +60 -9
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +80 -1
- package/src/charts/leaderboard-chart/types.ts +7 -1
- package/src/charts/line-chart/line-chart.tsx +8 -2
- package/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx +19 -9
- package/src/charts/line-chart/test/default-tooltip-formatting.test.tsx +1 -1
- package/src/charts/line-chart/test/line-chart.test.tsx +37 -35
- package/src/charts/line-chart/test/tooltip-resolution.test.tsx +2 -2
- package/src/charts/line-chart/types.ts +3 -3
- package/src/charts/pie-chart/pie-chart.module.scss +3 -0
- package/src/charts/pie-chart/pie-chart.tsx +144 -139
- package/src/charts/pie-chart/test/pie-chart.test.tsx +167 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +3 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +117 -120
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +54 -0
- package/src/charts/private/chart-composition/use-chart-children.ts +11 -6
- package/src/charts/private/pie-keyboard-navigation/index.ts +4 -0
- package/src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts +10 -0
- package/src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss +16 -0
- package/src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx +14 -0
- package/src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx +82 -0
- package/src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx +49 -0
- package/src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx +47 -0
- package/src/charts/private/pie-keyboard-navigation/test/order-arcs-for-navigation.test.ts +34 -0
- package/src/charts/private/pie-keyboard-navigation/test/selected-segment-ring.test.ts +14 -0
- package/src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts +139 -0
- package/src/charts/private/x-zoom/test/x-zoom.test.tsx +3 -2
- package/src/charts/test/accessible-name.test.tsx +181 -0
- package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +63 -3
- package/src/components/legend/hooks/use-chart-legend-items.ts +63 -1
- package/src/components/legend/private/base-legend.tsx +27 -15
- package/src/components/legend/test/legend.test.tsx +42 -0
- package/src/components/legend/types.ts +2 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +20 -19
- package/src/components/tooltip/xy-chart-tooltip.tsx +3 -3
- package/src/hooks/test/use-xychart-theme.test.tsx +22 -0
- package/src/hooks/use-xychart-theme.ts +33 -2
- package/src/index.ts +1 -0
- package/src/types.ts +37 -3
- package/src/utils/resolve-font-size.ts +9 -10
- package/src/utils/test/resolve-font-size.test.ts +11 -2
|
@@ -42,12 +42,12 @@ describe( 'BarChart', () => {
|
|
|
42
42
|
// visx renders bars and grid lines without accessible roles or configurable test IDs.
|
|
43
43
|
const getBarRects = () => {
|
|
44
44
|
// eslint-disable-next-line testing-library/no-node-access -- See the visx node constraint above.
|
|
45
|
-
return screen.getByRole( '
|
|
45
|
+
return screen.getByRole( 'application' ).querySelectorAll( '.visx-bar-group rect' );
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
const getGridLines = () => {
|
|
49
49
|
// eslint-disable-next-line testing-library/no-node-access -- visx grid lines cannot receive test IDs.
|
|
50
|
-
return screen.getByRole( '
|
|
50
|
+
return screen.getByRole( 'application' ).querySelectorAll( '.visx-rows line' );
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
const renderWithTheme = ( props = {}, children = undefined ) => {
|
|
@@ -151,20 +151,21 @@ describe( 'BarChart', () => {
|
|
|
151
151
|
|
|
152
152
|
const pointer = ( type: string, clientX: number, clientY: number ) => {
|
|
153
153
|
// visx owns the pointer capture rect and does not expose an attribute prop for it.
|
|
154
|
+
const chart = screen.getByRole( 'application' );
|
|
154
155
|
// eslint-disable-next-line testing-library/no-node-access
|
|
155
|
-
const target =
|
|
156
|
+
const target = chart.querySelector( 'svg > rect[fill="transparent"]' );
|
|
156
157
|
fireEvent( target, new MouseEvent( type, { bubbles: true, clientX, clientY } ) );
|
|
157
158
|
};
|
|
158
159
|
|
|
159
160
|
const hover = ( clientX: number, clientY: number ) =>
|
|
160
161
|
pointer( 'pointermove', clientX, clientY );
|
|
161
162
|
|
|
162
|
-
test( 'Escape returns focus to the
|
|
163
|
+
test( 'Escape returns focus to the chart without reopening either tooltip', async () => {
|
|
163
164
|
jest.useFakeTimers();
|
|
164
165
|
try {
|
|
165
166
|
const user = userEvent.setup( { advanceTimers: jest.advanceTimersByTime } );
|
|
166
167
|
renderWithTheme( { withTooltips: true } );
|
|
167
|
-
const chart = screen.getByRole( '
|
|
168
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
168
169
|
await user.tab();
|
|
169
170
|
await user.keyboard( '{ArrowRight}' );
|
|
170
171
|
expect( screen.getByTestId( 'chart-tooltip-0' ) ).toHaveFocus();
|
|
@@ -369,7 +370,7 @@ describe( 'BarChart', () => {
|
|
|
369
370
|
unmount();
|
|
370
371
|
renderWithTheme( { withBandHighlight: true, onBandHighlightChange } );
|
|
371
372
|
expect( warn ).toHaveBeenCalledTimes( 1 );
|
|
372
|
-
expect( screen.getByRole( '
|
|
373
|
+
expect( screen.getByRole( 'application' ) ).toBeInTheDocument();
|
|
373
374
|
expect( warn ).toHaveBeenCalledWith(
|
|
374
375
|
'[Charts] BarChart: withBandHighlight and onBandHighlightChange require withTooltips.'
|
|
375
376
|
);
|
|
@@ -473,7 +474,7 @@ describe( 'BarChart', () => {
|
|
|
473
474
|
|
|
474
475
|
test( 'labels a whole-number range smaller than the tick count once per whole number', () => {
|
|
475
476
|
renderWithTheme( { data: wholeNumberData } );
|
|
476
|
-
const chart = screen.getByRole( '
|
|
477
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
477
478
|
const ticks = within( chart )
|
|
478
479
|
.getAllByText( /^-?[\d.,]+$/ )
|
|
479
480
|
.map( el => el.textContent );
|
|
@@ -482,7 +483,7 @@ describe( 'BarChart', () => {
|
|
|
482
483
|
|
|
483
484
|
test( 'labels a horizontal whole-number range once per whole number', () => {
|
|
484
485
|
renderWithTheme( { data: wholeNumberData, orientation: 'horizontal' } );
|
|
485
|
-
const chart = screen.getByRole( '
|
|
486
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
486
487
|
const ticks = within( chart )
|
|
487
488
|
.getAllByText( /^-?[\d.,]+$/ )
|
|
488
489
|
.map( el => el.textContent );
|
|
@@ -501,7 +502,7 @@ describe( 'BarChart', () => {
|
|
|
501
502
|
},
|
|
502
503
|
],
|
|
503
504
|
} );
|
|
504
|
-
const chart = screen.getByRole( '
|
|
505
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
505
506
|
const ticks = within( chart )
|
|
506
507
|
.getAllByText( /^-?[\d.,]+$/ )
|
|
507
508
|
.map( el => el.textContent );
|
|
@@ -530,7 +531,7 @@ describe( 'BarChart', () => {
|
|
|
530
531
|
},
|
|
531
532
|
},
|
|
532
533
|
} );
|
|
533
|
-
const chart = screen.getByRole( '
|
|
534
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
534
535
|
expect( within( chart ).getAllByText( /^\d+%$/ ) ).toHaveLength( 6 );
|
|
535
536
|
}
|
|
536
537
|
);
|
|
@@ -540,7 +541,7 @@ describe( 'BarChart', () => {
|
|
|
540
541
|
data: wholeNumberData,
|
|
541
542
|
options: { axis: { y: { tickValues: [ 0, 0.5, 1 ] } } },
|
|
542
543
|
} );
|
|
543
|
-
const chart = screen.getByRole( '
|
|
544
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
544
545
|
expect( within( chart ).getAllByText( /^-?[\d.,]+$/ ) ).toHaveLength( 3 );
|
|
545
546
|
} );
|
|
546
547
|
} );
|
|
@@ -584,7 +585,7 @@ describe( 'BarChart', () => {
|
|
|
584
585
|
},
|
|
585
586
|
],
|
|
586
587
|
} );
|
|
587
|
-
expect( screen.getByRole( '
|
|
588
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
588
589
|
} );
|
|
589
590
|
|
|
590
591
|
test( 'handles negative values', () => {
|
|
@@ -600,7 +601,7 @@ describe( 'BarChart', () => {
|
|
|
600
601
|
},
|
|
601
602
|
],
|
|
602
603
|
} );
|
|
603
|
-
expect( screen.getByRole( '
|
|
604
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
604
605
|
} );
|
|
605
606
|
|
|
606
607
|
test( 'renders a bucket with no reading instead of failing the whole chart', () => {
|
|
@@ -617,7 +618,7 @@ describe( 'BarChart', () => {
|
|
|
617
618
|
],
|
|
618
619
|
} );
|
|
619
620
|
expect( screen.queryByText( /invalid data/i ) ).not.toBeInTheDocument();
|
|
620
|
-
expect( screen.getByRole( '
|
|
621
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
621
622
|
} );
|
|
622
623
|
|
|
623
624
|
test( 'draws no bar for a bucket with no reading', () => {
|
|
@@ -736,7 +737,7 @@ describe( 'BarChart', () => {
|
|
|
736
737
|
expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength( 2 );
|
|
737
738
|
const html = document.body.innerHTML;
|
|
738
739
|
expect( html.indexOf( 'data-testid="legend-horizontal"' ) ).toBeLessThan(
|
|
739
|
-
html.indexOf( 'role="
|
|
740
|
+
html.indexOf( 'role="application"' )
|
|
740
741
|
);
|
|
741
742
|
} );
|
|
742
743
|
} );
|
|
@@ -744,7 +745,7 @@ describe( 'BarChart', () => {
|
|
|
744
745
|
describe( 'Grid tick counts', () => {
|
|
745
746
|
const getPositions = ( selector: string, coordinate: string ) => {
|
|
746
747
|
// eslint-disable-next-line testing-library/no-node-access -- See the visx node constraint above.
|
|
747
|
-
const lines = screen.getByRole( '
|
|
748
|
+
const lines = screen.getByRole( 'application' ).querySelectorAll( selector );
|
|
748
749
|
return Array.from( lines, line => Number( line.getAttribute( coordinate ) ) );
|
|
749
750
|
};
|
|
750
751
|
|
|
@@ -822,7 +823,7 @@ describe( 'BarChart', () => {
|
|
|
822
823
|
},
|
|
823
824
|
},
|
|
824
825
|
} );
|
|
825
|
-
const chart = screen.getByRole( '
|
|
826
|
+
const chart = screen.getByRole( 'application' );
|
|
826
827
|
|
|
827
828
|
// eslint-disable-next-line testing-library/no-node-access -- See the visx node constraint above.
|
|
828
829
|
expect( chart.querySelector( '.test-hidden-axis' ) ).toBeNull();
|
|
@@ -834,21 +835,21 @@ describe( 'BarChart', () => {
|
|
|
834
835
|
describe( 'Grid Visibility', () => {
|
|
835
836
|
test( 'renders with different grid visibility options', () => {
|
|
836
837
|
const { rerender } = renderWithTheme( { gridVisibility: 'x' } );
|
|
837
|
-
expect( screen.getByRole( '
|
|
838
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
838
839
|
|
|
839
840
|
rerender(
|
|
840
841
|
<GlobalChartsProvider>
|
|
841
842
|
<BarChart { ...defaultProps } gridVisibility="y" />
|
|
842
843
|
</GlobalChartsProvider>
|
|
843
844
|
);
|
|
844
|
-
expect( screen.getByRole( '
|
|
845
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
845
846
|
|
|
846
847
|
rerender(
|
|
847
848
|
<GlobalChartsProvider>
|
|
848
849
|
<BarChart { ...defaultProps } gridVisibility="xy" />
|
|
849
850
|
</GlobalChartsProvider>
|
|
850
851
|
);
|
|
851
|
-
expect( screen.getByRole( '
|
|
852
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
852
853
|
} );
|
|
853
854
|
} );
|
|
854
855
|
|
|
@@ -930,7 +931,7 @@ describe( 'BarChart', () => {
|
|
|
930
931
|
|
|
931
932
|
// Scoped to the chart: @visx/text parks a measuring node on document.body,
|
|
932
933
|
// which a negative assertion would otherwise match.
|
|
933
|
-
const inChart = () => within( screen.getByRole( '
|
|
934
|
+
const inChart = () => within( screen.getByRole( 'application', { name: /bar chart/i } ) );
|
|
934
935
|
|
|
935
936
|
test( 'leaves tick values alone when a bucket is labelled rather than dated', () => {
|
|
936
937
|
// visx builds the band domain from `label || date`, so a labelled bucket
|
|
@@ -1134,7 +1135,7 @@ describe( 'BarChart', () => {
|
|
|
1134
1135
|
// on document.body, which outlives RTL's cleanup still holding the last
|
|
1135
1136
|
// string measured. Query inside the chart so a previous test's measurement
|
|
1136
1137
|
// can't answer for this one's axis.
|
|
1137
|
-
const inChart = () => within( screen.getByRole( '
|
|
1138
|
+
const inChart = () => within( screen.getByRole( 'application', { name: /bar chart/i } ) );
|
|
1138
1139
|
|
|
1139
1140
|
test( 'renders distinct date ticks for daily buckets within a year', () => {
|
|
1140
1141
|
renderWithTheme( {
|
|
@@ -1570,7 +1571,7 @@ describe( 'BarChart', () => {
|
|
|
1570
1571
|
],
|
|
1571
1572
|
} );
|
|
1572
1573
|
|
|
1573
|
-
screen.getByRole( '
|
|
1574
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
1574
1575
|
await user.keyboard( '{ArrowRight}' );
|
|
1575
1576
|
|
|
1576
1577
|
// The month tick reads "2024" here; the tooltip names the bucket itself.
|
|
@@ -1629,7 +1630,7 @@ describe( 'BarChart', () => {
|
|
|
1629
1630
|
|
|
1630
1631
|
test( 'renders with patterns', () => {
|
|
1631
1632
|
renderWithTheme( { withPatterns: true } );
|
|
1632
|
-
expect( screen.getByRole( '
|
|
1633
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
1633
1634
|
|
|
1634
1635
|
// Check that pattern definitions container is present
|
|
1635
1636
|
expect( screen.getByTestId( 'bar-chart-patterns' ) ).toBeInTheDocument();
|
|
@@ -1637,7 +1638,7 @@ describe( 'BarChart', () => {
|
|
|
1637
1638
|
|
|
1638
1639
|
test( 'renders without patterns by default', () => {
|
|
1639
1640
|
renderWithTheme( { withPatterns: false } );
|
|
1640
|
-
expect( screen.getByRole( '
|
|
1641
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
1641
1642
|
|
|
1642
1643
|
// Check that no pattern definitions container is present
|
|
1643
1644
|
expect( screen.queryByTestId( 'bar-chart-patterns' ) ).not.toBeInTheDocument();
|
|
@@ -1679,17 +1680,18 @@ describe( 'BarChart', () => {
|
|
|
1679
1680
|
describe( 'Chart Focus and Accessibility Attributes', () => {
|
|
1680
1681
|
test( 'chart container has proper accessibility attributes', () => {
|
|
1681
1682
|
renderWithTheme();
|
|
1682
|
-
const chart = screen.getByRole( '
|
|
1683
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
1683
1684
|
|
|
1684
1685
|
expect( chart ).toHaveAttribute( 'tabIndex', '0' );
|
|
1685
|
-
expect( chart ).toHaveAttribute( 'role', '
|
|
1686
|
+
expect( chart ).toHaveAttribute( 'role', 'application' );
|
|
1686
1687
|
expect( chart ).toHaveAttribute( 'aria-label', 'Bar chart' );
|
|
1688
|
+
expect( screen.queryByLabelText( 'XYChart' ) ).not.toBeInTheDocument();
|
|
1687
1689
|
} );
|
|
1688
1690
|
|
|
1689
1691
|
test( 'chart container can receive focus', async () => {
|
|
1690
1692
|
const user = userEvent.setup();
|
|
1691
1693
|
renderWithTheme();
|
|
1692
|
-
const chart = screen.getByRole( '
|
|
1694
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
1693
1695
|
|
|
1694
1696
|
await user.tab();
|
|
1695
1697
|
expect( chart ).toHaveFocus();
|
|
@@ -1719,7 +1721,7 @@ describe( 'BarChart', () => {
|
|
|
1719
1721
|
const onDatumActivate = jest.fn();
|
|
1720
1722
|
renderWithTheme( { withTooltips: true, data: [ SERIES_A ], onDatumActivate } );
|
|
1721
1723
|
|
|
1722
|
-
screen.getByRole( '
|
|
1724
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
1723
1725
|
await user.keyboard( '{ArrowRight}{ArrowRight}{Enter}' );
|
|
1724
1726
|
|
|
1725
1727
|
expect( onDatumActivate ).toHaveBeenCalledTimes( 1 );
|
|
@@ -1735,7 +1737,7 @@ describe( 'BarChart', () => {
|
|
|
1735
1737
|
const onDatumActivate = jest.fn();
|
|
1736
1738
|
renderWithTheme( { withTooltips: true, data: [ SERIES_A ], onDatumActivate } );
|
|
1737
1739
|
|
|
1738
|
-
screen.getByRole( '
|
|
1740
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
1739
1741
|
await user.keyboard( '{ArrowRight}[Space]' );
|
|
1740
1742
|
|
|
1741
1743
|
expect( onDatumActivate ).toHaveBeenCalledWith( {
|
|
@@ -1753,7 +1755,7 @@ describe( 'BarChart', () => {
|
|
|
1753
1755
|
const onDatumActivate = jest.fn();
|
|
1754
1756
|
renderWithTheme( { withTooltips: true, data: [ SERIES_A, SERIES_B ], onDatumActivate } );
|
|
1755
1757
|
|
|
1756
|
-
screen.getByRole( '
|
|
1758
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
1757
1759
|
await user.keyboard( '{ArrowRight}{ArrowRight}{Enter}' );
|
|
1758
1760
|
|
|
1759
1761
|
expect( onDatumActivate ).toHaveBeenCalledWith( {
|
|
@@ -1768,7 +1770,7 @@ describe( 'BarChart', () => {
|
|
|
1768
1770
|
const onDatumActivate = jest.fn();
|
|
1769
1771
|
renderWithTheme( { withTooltips: true, data: [ SERIES_A ], onDatumActivate } );
|
|
1770
1772
|
|
|
1771
|
-
screen.getByRole( '
|
|
1773
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
1772
1774
|
await user.keyboard( '{Enter}' );
|
|
1773
1775
|
|
|
1774
1776
|
expect( onDatumActivate ).not.toHaveBeenCalled();
|
|
@@ -1802,7 +1804,7 @@ describe( 'BarChart', () => {
|
|
|
1802
1804
|
],
|
|
1803
1805
|
} );
|
|
1804
1806
|
|
|
1805
|
-
const chart = screen.getByRole( '
|
|
1807
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
1806
1808
|
chart.focus();
|
|
1807
1809
|
|
|
1808
1810
|
// Single tab should focus on the first tooltip.
|
|
@@ -1853,7 +1855,7 @@ describe( 'BarChart', () => {
|
|
|
1853
1855
|
],
|
|
1854
1856
|
} );
|
|
1855
1857
|
|
|
1856
|
-
const chart = screen.getByRole( '
|
|
1858
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
1857
1859
|
chart.focus();
|
|
1858
1860
|
|
|
1859
1861
|
await user.keyboard( '{ArrowRight}' );
|
|
@@ -1902,7 +1904,7 @@ describe( 'BarChart', () => {
|
|
|
1902
1904
|
],
|
|
1903
1905
|
} );
|
|
1904
1906
|
|
|
1905
|
-
const chart = screen.getByRole( '
|
|
1907
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
1906
1908
|
chart.focus();
|
|
1907
1909
|
|
|
1908
1910
|
// Right arrow key should focus on the first tooltip.
|
|
@@ -1925,7 +1927,7 @@ describe( 'BarChart', () => {
|
|
|
1925
1927
|
} );
|
|
1926
1928
|
} );
|
|
1927
1929
|
|
|
1928
|
-
describe( '
|
|
1930
|
+
describe( 'Keyboard navigation boundaries', () => {
|
|
1929
1931
|
// Three points, so a clamp at a boundary lands on a different index than a wrap would.
|
|
1930
1932
|
const threePointData = [
|
|
1931
1933
|
{
|
|
@@ -1943,7 +1945,7 @@ describe( 'BarChart', () => {
|
|
|
1943
1945
|
const user = userEvent.setup();
|
|
1944
1946
|
renderWithTheme( { withTooltips: true, data: threePointData } );
|
|
1945
1947
|
|
|
1946
|
-
const chart = screen.getByRole( '
|
|
1948
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
1947
1949
|
chart.focus();
|
|
1948
1950
|
|
|
1949
1951
|
// Move to the first, then on to the last (third) point.
|
|
@@ -1953,7 +1955,7 @@ describe( 'BarChart', () => {
|
|
|
1953
1955
|
expect( screen.getByTestId( 'chart-tooltip-2' ) ).toHaveFocus();
|
|
1954
1956
|
|
|
1955
1957
|
// Right arrow at the last point must not move focus: the highlighted
|
|
1956
|
-
// bar/tooltip stays visible and focused (
|
|
1958
|
+
// bar/tooltip stays visible and focused (focus does not move).
|
|
1957
1959
|
await user.keyboard( '{ArrowRight}' );
|
|
1958
1960
|
expect( screen.getByTestId( 'chart-tooltip-2' ) ).toBeInTheDocument();
|
|
1959
1961
|
expect( screen.getByTestId( 'chart-tooltip-2' ) ).toHaveFocus();
|
|
@@ -1968,7 +1970,7 @@ describe( 'BarChart', () => {
|
|
|
1968
1970
|
const user = userEvent.setup();
|
|
1969
1971
|
renderWithTheme( { withTooltips: true, data: threePointData } );
|
|
1970
1972
|
|
|
1971
|
-
screen.getByRole( '
|
|
1973
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
1972
1974
|
await user.keyboard( '{ArrowLeft}' );
|
|
1973
1975
|
|
|
1974
1976
|
expect( screen.getByTestId( 'chart-tooltip-0' ) ).toHaveFocus();
|
|
@@ -2002,7 +2004,7 @@ describe( 'BarChart', () => {
|
|
|
2002
2004
|
],
|
|
2003
2005
|
} );
|
|
2004
2006
|
|
|
2005
|
-
const chart = screen.getByRole( '
|
|
2007
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
2006
2008
|
chart.focus();
|
|
2007
2009
|
|
|
2008
2010
|
await user.keyboard( '{ArrowRight}' );
|
|
@@ -2037,7 +2039,7 @@ describe( 'BarChart', () => {
|
|
|
2037
2039
|
],
|
|
2038
2040
|
} );
|
|
2039
2041
|
|
|
2040
|
-
const chart = screen.getByRole( '
|
|
2042
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
2041
2043
|
chart.focus();
|
|
2042
2044
|
|
|
2043
2045
|
// Slot 0 is the first primary bar (Mon); slot 1 must be the SECOND primary
|
|
@@ -2069,7 +2071,7 @@ describe( 'BarChart', () => {
|
|
|
2069
2071
|
],
|
|
2070
2072
|
} );
|
|
2071
2073
|
|
|
2072
|
-
screen.getByRole( '
|
|
2074
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
2073
2075
|
await user.keyboard( '{ArrowRight}' );
|
|
2074
2076
|
|
|
2075
2077
|
const tooltip = screen.getByTestId( 'chart-tooltip-0' );
|
|
@@ -2102,7 +2104,7 @@ describe( 'BarChart', () => {
|
|
|
2102
2104
|
],
|
|
2103
2105
|
} );
|
|
2104
2106
|
|
|
2105
|
-
screen.getByRole( '
|
|
2107
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
2106
2108
|
await user.keyboard( '{ArrowRight}' );
|
|
2107
2109
|
|
|
2108
2110
|
const tooltip = screen.getByTestId( 'chart-tooltip-0' );
|
|
@@ -2162,7 +2164,7 @@ describe( 'BarChart', () => {
|
|
|
2162
2164
|
],
|
|
2163
2165
|
} );
|
|
2164
2166
|
|
|
2165
|
-
const chart = screen.getByRole( '
|
|
2167
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
2166
2168
|
chart.focus();
|
|
2167
2169
|
|
|
2168
2170
|
// Chart should be in focus.
|
|
@@ -2202,7 +2204,7 @@ describe( 'BarChart', () => {
|
|
|
2202
2204
|
],
|
|
2203
2205
|
} );
|
|
2204
2206
|
|
|
2205
|
-
const chart = screen.getByRole( '
|
|
2207
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
2206
2208
|
chart.focus();
|
|
2207
2209
|
|
|
2208
2210
|
// Navigate to the first bar
|
|
@@ -2237,7 +2239,7 @@ describe( 'BarChart', () => {
|
|
|
2237
2239
|
],
|
|
2238
2240
|
} );
|
|
2239
2241
|
|
|
2240
|
-
const chart = screen.getByRole( '
|
|
2242
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
2241
2243
|
chart.focus();
|
|
2242
2244
|
|
|
2243
2245
|
// Navigate to the first bar (Series A, Jan 1)
|
|
@@ -2269,7 +2271,7 @@ describe( 'BarChart', () => {
|
|
|
2269
2271
|
const user = userEvent.setup();
|
|
2270
2272
|
renderWithTheme( { withTooltips: true, data } );
|
|
2271
2273
|
|
|
2272
|
-
screen.getByRole( '
|
|
2274
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
2273
2275
|
await user.keyboard( '{ArrowRight}' );
|
|
2274
2276
|
|
|
2275
2277
|
expect( screen.getByTestId( 'chart-tooltip-0' ) ).toHaveTextContent( 'No data' );
|
|
@@ -2280,7 +2282,7 @@ describe( 'BarChart', () => {
|
|
|
2280
2282
|
const user = userEvent.setup();
|
|
2281
2283
|
renderWithTheme( { withTooltips: true, data } );
|
|
2282
2284
|
|
|
2283
|
-
screen.getByRole( '
|
|
2285
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
2284
2286
|
await user.keyboard( '{ArrowRight}{ArrowRight}' );
|
|
2285
2287
|
|
|
2286
2288
|
expect( screen.getByTestId( 'chart-tooltip-1' ) ).toHaveTextContent( '20' );
|
|
@@ -2313,7 +2315,7 @@ describe( 'BarChart', () => {
|
|
|
2313
2315
|
];
|
|
2314
2316
|
renderWithTheme( { withTooltips: true, data: twoSeries } );
|
|
2315
2317
|
|
|
2316
|
-
screen.getByRole( '
|
|
2318
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
2317
2319
|
await user.keyboard( '{ArrowRight}{ArrowRight}{ArrowRight}{ArrowRight}' );
|
|
2318
2320
|
|
|
2319
2321
|
expect( screen.getByTestId( 'chart-tooltip-3' ) ).toHaveTextContent( '15' );
|
|
@@ -2340,7 +2342,7 @@ describe( 'BarChart', () => {
|
|
|
2340
2342
|
|
|
2341
2343
|
renderWithTheme( { withTooltips: true, renderTooltip: customTooltipRenderer } );
|
|
2342
2344
|
|
|
2343
|
-
const chart = screen.getByRole( '
|
|
2345
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
2344
2346
|
chart.focus();
|
|
2345
2347
|
|
|
2346
2348
|
// Click on right arrow key to focus on the first tooltip.
|
|
@@ -2372,7 +2374,9 @@ describe( 'BarChart', () => {
|
|
|
2372
2374
|
],
|
|
2373
2375
|
} );
|
|
2374
2376
|
|
|
2375
|
-
const svgElement = screen
|
|
2377
|
+
const svgElement = screen
|
|
2378
|
+
.getByRole( 'application', { name: /bar chart/i } )
|
|
2379
|
+
.querySelector( 'svg' );
|
|
2376
2380
|
const bars = svgElement?.querySelectorAll( '.visx-bar-group rect' );
|
|
2377
2381
|
|
|
2378
2382
|
// Should have 2 bars
|
|
@@ -2399,7 +2403,9 @@ describe( 'BarChart', () => {
|
|
|
2399
2403
|
],
|
|
2400
2404
|
} );
|
|
2401
2405
|
|
|
2402
|
-
const svgElement = screen
|
|
2406
|
+
const svgElement = screen
|
|
2407
|
+
.getByRole( 'application', { name: /bar chart/i } )
|
|
2408
|
+
.querySelector( 'svg' );
|
|
2403
2409
|
const bars = svgElement?.querySelectorAll( '.visx-bar-group rect' );
|
|
2404
2410
|
|
|
2405
2411
|
// Should have 2 bars
|
|
@@ -2432,7 +2438,9 @@ describe( 'BarChart', () => {
|
|
|
2432
2438
|
orientation: 'horizontal',
|
|
2433
2439
|
} );
|
|
2434
2440
|
|
|
2435
|
-
const svgElement = screen
|
|
2441
|
+
const svgElement = screen
|
|
2442
|
+
.getByRole( 'application', { name: /bar chart/i } )
|
|
2443
|
+
.querySelector( 'svg' );
|
|
2436
2444
|
const bars = svgElement?.querySelectorAll( '.visx-bar-group rect' );
|
|
2437
2445
|
|
|
2438
2446
|
// Both bars should be visible in horizontal mode
|
|
@@ -2461,7 +2469,9 @@ describe( 'BarChart', () => {
|
|
|
2461
2469
|
],
|
|
2462
2470
|
} );
|
|
2463
2471
|
|
|
2464
|
-
const svgElement = screen
|
|
2472
|
+
const svgElement = screen
|
|
2473
|
+
.getByRole( 'application', { name: /bar chart/i } )
|
|
2474
|
+
.querySelector( 'svg' );
|
|
2465
2475
|
const bars = svgElement?.querySelectorAll( '.visx-bar-group rect' );
|
|
2466
2476
|
|
|
2467
2477
|
expect( bars?.length ).toBe( 2 );
|
|
@@ -2501,7 +2511,7 @@ describe( 'BarChart', () => {
|
|
|
2501
2511
|
},
|
|
2502
2512
|
} );
|
|
2503
2513
|
|
|
2504
|
-
expect( screen.getByRole( '
|
|
2514
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
2505
2515
|
} );
|
|
2506
2516
|
|
|
2507
2517
|
test( 'truncates labels with CSS text-overflow ellipsis', () => {
|
|
@@ -2594,7 +2604,7 @@ describe( 'BarChart', () => {
|
|
|
2594
2604
|
} );
|
|
2595
2605
|
|
|
2596
2606
|
// Chart should still render without errors
|
|
2597
|
-
expect( screen.getByRole( '
|
|
2607
|
+
expect( screen.getByRole( 'application', { name: /bar chart/i } ) ).toBeInTheDocument();
|
|
2598
2608
|
|
|
2599
2609
|
// Labels should still be present and have minimum width applied
|
|
2600
2610
|
const label = screen.getByText( /Very Long Category Label One/i );
|
|
@@ -2890,7 +2900,7 @@ describe( 'BarChart', () => {
|
|
|
2890
2900
|
</GlobalChartsProvider>
|
|
2891
2901
|
);
|
|
2892
2902
|
|
|
2893
|
-
const chart = screen.getByRole( '
|
|
2903
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
2894
2904
|
chart.focus();
|
|
2895
2905
|
|
|
2896
2906
|
// Navigate through all 4 primary slots (2 series × 2 data points)
|
|
@@ -3176,8 +3186,9 @@ describe( 'BarChart', () => {
|
|
|
3176
3186
|
</GlobalChartsProvider>
|
|
3177
3187
|
);
|
|
3178
3188
|
|
|
3189
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
3179
3190
|
// eslint-disable-next-line testing-library/no-node-access
|
|
3180
|
-
const svgElement =
|
|
3191
|
+
const svgElement = chart.querySelector( 'svg' );
|
|
3181
3192
|
// eslint-disable-next-line testing-library/no-node-access
|
|
3182
3193
|
expect( svgElement?.querySelectorAll( '.visx-bar-group rect' ) ).toHaveLength( 2 );
|
|
3183
3194
|
|
|
@@ -3382,7 +3393,7 @@ describe( 'BarChart', () => {
|
|
|
3382
3393
|
const user = userEvent.setup();
|
|
3383
3394
|
const toggle = mountWithVisibilityToggle();
|
|
3384
3395
|
|
|
3385
|
-
screen.getByRole( '
|
|
3396
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
3386
3397
|
for ( let i = 0; i < 6; i++ ) {
|
|
3387
3398
|
await user.keyboard( '{ArrowRight}' );
|
|
3388
3399
|
}
|
|
@@ -3427,7 +3438,7 @@ describe( 'BarChart', () => {
|
|
|
3427
3438
|
],
|
|
3428
3439
|
} );
|
|
3429
3440
|
|
|
3430
|
-
screen.getByRole( '
|
|
3441
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
3431
3442
|
for ( let i = 0; i < 6; i++ ) {
|
|
3432
3443
|
await user.keyboard( '{ArrowRight}' );
|
|
3433
3444
|
}
|
|
@@ -3484,12 +3495,12 @@ describe( 'BarChart', () => {
|
|
|
3484
3495
|
</GlobalChartsProvider>
|
|
3485
3496
|
);
|
|
3486
3497
|
|
|
3487
|
-
screen.getByRole( '
|
|
3498
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).focus();
|
|
3488
3499
|
await user.keyboard( '{ArrowRight}{ArrowRight}' );
|
|
3489
3500
|
expect( screen.getByTestId( 'chart-tooltip-1' ) ).toHaveTextContent( 'Series A' );
|
|
3490
3501
|
|
|
3491
3502
|
// Move focus out of the chart, then swap which series is hidden without changing the count.
|
|
3492
|
-
screen.getByRole( '
|
|
3503
|
+
screen.getByRole( 'application', { name: /bar chart/i } ).blur();
|
|
3493
3504
|
act( () => context.setChartHiddenSeries( 'test-equal-count-swap', [ 'Series A' ] ) );
|
|
3494
3505
|
|
|
3495
3506
|
expect( screen.queryAllByTestId( /^chart-tooltip-/ ) ).toHaveLength( 0 );
|
|
@@ -3528,7 +3539,7 @@ describe( 'BarChart', () => {
|
|
|
3528
3539
|
|
|
3529
3540
|
await user.click( screen.getByRole( 'button', { name: /Series B: visible/i } ) );
|
|
3530
3541
|
|
|
3531
|
-
const chart = screen.getByRole( '
|
|
3542
|
+
const chart = screen.getByRole( 'application', { name: /bar chart/i } );
|
|
3532
3543
|
chart.focus();
|
|
3533
3544
|
|
|
3534
3545
|
for ( let i = 0; i < 5; i++ ) {
|
|
@@ -2,6 +2,7 @@ import { formatNumberCompact } from '@automattic/number-formatters';
|
|
|
2
2
|
import { Group } from '@visx/group';
|
|
3
3
|
import { createScale, scaleBand } from '@visx/scale';
|
|
4
4
|
import { Text, type TextProps } from '@visx/text';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
5
6
|
import clsx from 'clsx';
|
|
6
7
|
import { useContext, useMemo } from 'react';
|
|
7
8
|
import { GlobalChartsContext, GlobalChartsProvider, useGlobalChartsContext } from '../../providers';
|
|
@@ -235,6 +236,7 @@ const BarListChartInternal: FC< BarListChartProps > = ( {
|
|
|
235
236
|
top: 0,
|
|
236
237
|
},
|
|
237
238
|
className,
|
|
239
|
+
ariaLabel,
|
|
238
240
|
...rest
|
|
239
241
|
} ) => {
|
|
240
242
|
const { getElementStyles } = useGlobalChartsContext();
|
|
@@ -333,6 +335,7 @@ const BarListChartInternal: FC< BarListChartProps > = ( {
|
|
|
333
335
|
xScale: chartOptions.xScale,
|
|
334
336
|
yScale: chartOptions.yScale,
|
|
335
337
|
} }
|
|
338
|
+
ariaLabel={ ariaLabel ?? __( 'Bar list chart', 'jetpack-charts' ) }
|
|
336
339
|
{ ...rest }
|
|
337
340
|
/>
|
|
338
341
|
);
|
|
@@ -72,7 +72,9 @@ describe( 'BarListChart', () => {
|
|
|
72
72
|
/* eslint-disable testing-library/no-node-access */
|
|
73
73
|
const barFills = () =>
|
|
74
74
|
Array.from(
|
|
75
|
-
screen
|
|
75
|
+
screen
|
|
76
|
+
.getByRole( 'application' )
|
|
77
|
+
.querySelectorAll< SVGRectElement >( '.visx-bar-group rect' )
|
|
76
78
|
).map( bar => bar.getAttribute( 'fill' ) );
|
|
77
79
|
/* eslint-enable testing-library/no-node-access */
|
|
78
80
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useTooltip } from '@visx/tooltip';
|
|
2
|
+
import { __ } from '@wordpress/i18n';
|
|
2
3
|
import { Stack } from '@wordpress/ui';
|
|
3
4
|
import clsx from 'clsx';
|
|
4
5
|
import { type FC, useRef, useMemo, useEffect, useState, useCallback, useContext } from 'react';
|
|
5
6
|
import { BoundedTooltip } from '../../components/tooltip/private/bounded-tooltip';
|
|
6
|
-
import { usePrefersReducedMotion } from '../../hooks';
|
|
7
|
+
import { useElementSize, usePrefersReducedMotion } from '../../hooks';
|
|
7
8
|
import {
|
|
8
9
|
GlobalChartsProvider,
|
|
9
10
|
GlobalChartsContext,
|
|
@@ -19,6 +20,9 @@ import styles from './conversion-funnel-chart.module.scss';
|
|
|
19
20
|
import { useFunnelSelection } from './private';
|
|
20
21
|
import type { FunnelStep, ConversionFunnelChartProps } from './types';
|
|
21
22
|
|
|
23
|
+
/** Chart height (px) below which the funnel tightens its gaps so the bars keep their room. */
|
|
24
|
+
const SHORT_CHART_HEIGHT = 180;
|
|
25
|
+
|
|
22
26
|
/**
|
|
23
27
|
* Internal ConversionFunnelChart component with chart registration
|
|
24
28
|
*
|
|
@@ -30,6 +34,7 @@ import type { FunnelStep, ConversionFunnelChartProps } from './types';
|
|
|
30
34
|
* @param props.loading - Whether the chart is in loading state
|
|
31
35
|
* @param props.animation - Whether to show chart animation on initial render or not
|
|
32
36
|
* @param props.className - Additional CSS class name
|
|
37
|
+
* @param props.ariaLabel - Accessible name for the chart group
|
|
33
38
|
* @param props.height - Height of the chart container. Falls back to style.height if set, otherwise defaults to "100%".
|
|
34
39
|
* @param props.style - Custom styling
|
|
35
40
|
* @param props.renderStepLabel - Custom render function for step labels
|
|
@@ -46,6 +51,7 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
46
51
|
loading = false,
|
|
47
52
|
animation,
|
|
48
53
|
className,
|
|
54
|
+
ariaLabel,
|
|
49
55
|
chartId: providedChartId,
|
|
50
56
|
height,
|
|
51
57
|
style,
|
|
@@ -69,11 +75,19 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
69
75
|
const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } =
|
|
70
76
|
useFunnelSelection( hideTooltip );
|
|
71
77
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
78
|
+
const [ measureChartRef, , chartHeight ] = useElementSize< HTMLDivElement >();
|
|
79
|
+
// A zero height is an unmeasured or hidden chart, not a short one.
|
|
80
|
+
const isShort = chartHeight > 0 && chartHeight < SHORT_CHART_HEIGHT;
|
|
81
|
+
const gap = isShort ? 'sm' : 'xl';
|
|
72
82
|
// Stable identity so React doesn't detach/reattach (and re-render the scope context) on every commit. Keep it firing on unmount (node === null).
|
|
73
|
-
const setChartRef = useCallback(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
83
|
+
const setChartRef = useCallback(
|
|
84
|
+
( node: HTMLDivElement | null ) => {
|
|
85
|
+
chartRef.current = node;
|
|
86
|
+
setScopeNode( node );
|
|
87
|
+
measureChartRef( node );
|
|
88
|
+
},
|
|
89
|
+
[ measureChartRef ]
|
|
90
|
+
);
|
|
77
91
|
|
|
78
92
|
// Wrapper to clear selectedBarRef after clearing selection
|
|
79
93
|
const clearSelectionAndRef = useCallback( () => {
|
|
@@ -309,8 +323,10 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
309
323
|
return (
|
|
310
324
|
<Stack
|
|
311
325
|
direction="column"
|
|
312
|
-
gap=
|
|
326
|
+
gap={ gap }
|
|
313
327
|
data-testid="conversion-funnel-chart"
|
|
328
|
+
role="group"
|
|
329
|
+
aria-label={ ariaLabel ?? __( 'Conversion funnel chart', 'jetpack-charts' ) }
|
|
314
330
|
ref={ setChartRef }
|
|
315
331
|
className={ clsx(
|
|
316
332
|
'conversion-funnel-chart',
|
|
@@ -351,7 +367,7 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
|
|
|
351
367
|
isColorPaletteResolved && styles[ 'funnel-step--animated' ],
|
|
352
368
|
isBlurred && styles[ 'funnel-step--blurred' ]
|
|
353
369
|
) }
|
|
354
|
-
gap=
|
|
370
|
+
gap={ gap }
|
|
355
371
|
>
|
|
356
372
|
{ /* Step Label and Rate */ }
|
|
357
373
|
<Stack direction="column" gap="xs">
|