@automattic/charts 0.56.7 → 0.58.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/AGENTS.md +28 -98
- package/CHANGELOG.md +30 -0
- package/dist/charts/bar-chart/index.cjs +7 -6
- package/dist/charts/bar-chart/index.cjs.map +1 -1
- package/dist/charts/bar-chart/index.css +12 -24
- package/dist/charts/bar-chart/index.css.map +1 -1
- package/dist/charts/bar-chart/index.d.cts +3 -4
- package/dist/charts/bar-chart/index.d.ts +3 -4
- package/dist/charts/bar-chart/index.js +6 -5
- package/dist/charts/bar-list-chart/index.cjs +8 -7
- package/dist/charts/bar-list-chart/index.cjs.map +1 -1
- package/dist/charts/bar-list-chart/index.css +12 -24
- package/dist/charts/bar-list-chart/index.css.map +1 -1
- package/dist/charts/bar-list-chart/index.d.cts +3 -3
- package/dist/charts/bar-list-chart/index.d.ts +3 -3
- package/dist/charts/bar-list-chart/index.js +7 -6
- package/dist/charts/conversion-funnel-chart/index.cjs +5 -6
- package/dist/charts/conversion-funnel-chart/index.cjs.map +1 -1
- package/dist/charts/conversion-funnel-chart/index.css +0 -94
- package/dist/charts/conversion-funnel-chart/index.css.map +1 -1
- package/dist/charts/conversion-funnel-chart/index.d.cts +1 -1
- package/dist/charts/conversion-funnel-chart/index.d.ts +1 -1
- package/dist/charts/conversion-funnel-chart/index.js +4 -5
- package/dist/charts/geo-chart/index.cjs +4 -4
- package/dist/charts/geo-chart/index.css +0 -94
- package/dist/charts/geo-chart/index.css.map +1 -1
- package/dist/charts/geo-chart/index.d.cts +1 -1
- package/dist/charts/geo-chart/index.d.ts +1 -1
- package/dist/charts/geo-chart/index.js +3 -3
- package/dist/charts/leaderboard-chart/index.cjs +7 -6
- package/dist/charts/leaderboard-chart/index.cjs.map +1 -1
- package/dist/charts/leaderboard-chart/index.css +20 -33
- package/dist/charts/leaderboard-chart/index.css.map +1 -1
- package/dist/charts/leaderboard-chart/index.d.cts +3 -3
- package/dist/charts/leaderboard-chart/index.d.ts +3 -3
- package/dist/charts/leaderboard-chart/index.js +6 -5
- package/dist/charts/line-chart/index.cjs +7 -6
- package/dist/charts/line-chart/index.cjs.map +1 -1
- package/dist/charts/line-chart/index.css +12 -24
- package/dist/charts/line-chart/index.css.map +1 -1
- package/dist/charts/line-chart/index.d.cts +3 -4
- package/dist/charts/line-chart/index.d.ts +3 -4
- package/dist/charts/line-chart/index.js +6 -5
- package/dist/charts/pie-chart/index.cjs +7 -7
- package/dist/charts/pie-chart/index.css +12 -24
- package/dist/charts/pie-chart/index.css.map +1 -1
- package/dist/charts/pie-chart/index.d.cts +7 -13
- package/dist/charts/pie-chart/index.d.ts +7 -13
- package/dist/charts/pie-chart/index.js +6 -6
- package/dist/charts/pie-semi-circle-chart/index.cjs +7 -7
- package/dist/charts/pie-semi-circle-chart/index.css +12 -24
- package/dist/charts/pie-semi-circle-chart/index.css.map +1 -1
- package/dist/charts/pie-semi-circle-chart/index.d.cts +7 -13
- package/dist/charts/pie-semi-circle-chart/index.d.ts +7 -13
- package/dist/charts/pie-semi-circle-chart/index.js +6 -6
- package/dist/charts/sparkline/index.cjs +8 -7
- package/dist/charts/sparkline/index.cjs.map +1 -1
- package/dist/charts/sparkline/index.css +12 -24
- package/dist/charts/sparkline/index.css.map +1 -1
- package/dist/charts/sparkline/index.js +7 -6
- package/dist/{chunk-RFSHE3HL.js → chunk-2I67QUIV.js} +84 -431
- package/dist/chunk-2I67QUIV.js.map +1 -0
- package/dist/{chunk-OMS5QIJN.js → chunk-2ICEEQOC.js} +31 -25
- package/dist/chunk-2ICEEQOC.js.map +1 -0
- package/dist/{chunk-GWBS65VC.js → chunk-4B7BL2DD.js} +3 -3
- package/dist/{chunk-7FDQGBY7.js → chunk-4OXMTKAL.js} +24 -24
- package/dist/chunk-4OXMTKAL.js.map +1 -0
- package/dist/{chunk-SSFFCBCF.js → chunk-B6NLZFRW.js} +32 -26
- package/dist/chunk-B6NLZFRW.js.map +1 -0
- package/dist/{chunk-3EXJP67N.cjs → chunk-BBAUQOW6.cjs} +9 -9
- package/dist/{chunk-3EXJP67N.cjs.map → chunk-BBAUQOW6.cjs.map} +1 -1
- package/dist/{chunk-NQJE2CC7.cjs → chunk-CMMHCTBX.cjs} +45 -45
- package/dist/chunk-CMMHCTBX.cjs.map +1 -0
- package/dist/{chunk-O2JIANHK.cjs → chunk-CPPXJATQ.cjs} +51 -45
- package/dist/chunk-CPPXJATQ.cjs.map +1 -0
- package/dist/{chunk-MDRCAGKZ.js → chunk-DKU775VC.js} +3 -3
- package/dist/{chunk-BXFD7JIG.cjs → chunk-GRA7Y2ZG.cjs} +46 -46
- package/dist/chunk-GRA7Y2ZG.cjs.map +1 -0
- package/dist/{chunk-TE63Y5PX.js → chunk-JJIMABHT.js} +10 -3
- package/dist/chunk-JJIMABHT.js.map +1 -0
- package/dist/{chunk-KHQPN77E.js → chunk-KJHWXOCZ.js} +4 -4
- package/dist/{chunk-6CCZL2JJ.js → chunk-KRWGSOJ2.js} +30 -2
- package/dist/chunk-KRWGSOJ2.js.map +1 -0
- package/dist/{chunk-VPAEBI2F.js → chunk-LTFH7SEG.js} +24 -24
- package/dist/chunk-LTFH7SEG.js.map +1 -0
- package/dist/{chunk-E62LCBGD.js → chunk-MUNOKLLE.js} +3 -3
- package/dist/{chunk-ZVGEDXDP.cjs → chunk-MXGLYWVP.cjs} +10 -3
- package/dist/chunk-MXGLYWVP.cjs.map +1 -0
- package/dist/{chunk-55ZCOYDF.cjs → chunk-OYC34VTO.cjs} +252 -827
- package/dist/chunk-OYC34VTO.cjs.map +1 -0
- package/dist/{chunk-CAFJRZPZ.cjs → chunk-PQL5I3F6.cjs} +17 -17
- package/dist/{chunk-CAFJRZPZ.cjs.map → chunk-PQL5I3F6.cjs.map} +1 -1
- package/dist/{chunk-UFRBUT2D.cjs → chunk-REZTQ4PH.cjs} +87 -24
- package/dist/chunk-REZTQ4PH.cjs.map +1 -0
- package/dist/{chunk-RCY6XLGU.cjs → chunk-TZRUHQOH.cjs} +36 -8
- package/dist/chunk-TZRUHQOH.cjs.map +1 -0
- package/dist/{chunk-XD2HV7M5.js → chunk-UTYVIOWZ.js} +226 -801
- package/dist/chunk-UTYVIOWZ.js.map +1 -0
- package/dist/{chunk-YAXY5L7I.cjs → chunk-W2LDIX26.cjs} +5 -5
- package/dist/{chunk-YAXY5L7I.cjs.map → chunk-W2LDIX26.cjs.map} +1 -1
- package/dist/{chunk-K6TGILHX.cjs → chunk-WSG64BVN.cjs} +6 -6
- package/dist/{chunk-K6TGILHX.cjs.map → chunk-WSG64BVN.cjs.map} +1 -1
- package/dist/chunk-WTQYGUNF.js +400 -0
- package/dist/chunk-WTQYGUNF.js.map +1 -0
- package/dist/{chunk-YDVHT7GS.cjs → chunk-WYK7EL5R.cjs} +100 -447
- package/dist/chunk-WYK7EL5R.cjs.map +1 -0
- package/dist/{chunk-X7JL2NYJ.cjs → chunk-XC4KHJYX.cjs} +51 -45
- package/dist/chunk-XC4KHJYX.cjs.map +1 -0
- package/dist/chunk-XVBH5XHE.cjs +400 -0
- package/dist/chunk-XVBH5XHE.cjs.map +1 -0
- package/dist/{chunk-IS5YYLTV.js → chunk-YAFQVVDI.js} +85 -22
- package/dist/chunk-YAFQVVDI.js.map +1 -0
- package/dist/components/legend/index.cjs +4 -3
- package/dist/components/legend/index.cjs.map +1 -1
- package/dist/components/legend/index.css +12 -24
- package/dist/components/legend/index.css.map +1 -1
- package/dist/components/legend/index.d.cts +4 -4
- package/dist/components/legend/index.d.ts +4 -4
- package/dist/components/legend/index.js +3 -2
- package/dist/components/tooltip/index.d.cts +1 -1
- package/dist/components/tooltip/index.d.ts +1 -1
- package/dist/hooks/index.cjs +3 -5
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.css +0 -94
- package/dist/hooks/index.css.map +1 -1
- package/dist/hooks/index.d.cts +9 -13
- package/dist/hooks/index.d.ts +9 -13
- package/dist/hooks/index.js +2 -4
- package/dist/index.cjs +18 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +20 -33
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +17 -16
- package/dist/{leaderboard-chart-COtgamhe.d.cts → leaderboard-chart-BSbg0ufV.d.cts} +3 -11
- package/dist/{leaderboard-chart-BSgEw_Um.d.ts → leaderboard-chart-odEYxxEC.d.ts} +3 -11
- package/dist/{legend-C9ahiwOt.d.cts → legend-DFkosEvC.d.cts} +1 -1
- package/dist/{legend-jjMmhSg3.d.ts → legend-DLswHhOk.d.ts} +1 -1
- package/dist/providers/index.cjs +3 -3
- package/dist/providers/index.css +0 -94
- package/dist/providers/index.css.map +1 -1
- package/dist/providers/index.d.cts +3 -3
- package/dist/providers/index.d.ts +3 -3
- package/dist/providers/index.js +2 -2
- package/dist/{themes-CVR5rmIs.d.cts → themes-D0qc5JaW.d.cts} +2 -2
- package/dist/{themes-DQzmaSze.d.ts → themes-itO4Ht5g.d.ts} +2 -2
- package/dist/{types-BBwg4Evw.d.cts → types-B5f6XQ7Q.d.cts} +1 -1
- package/dist/{types-DQNnq5Fr.d.ts → types-BsHooDbM.d.ts} +1 -1
- package/dist/{types-C05PdDJa.d.cts → types-BuSrRM4p.d.ts} +15 -23
- package/dist/{types-CzdN7rUe.d.cts → types-ChOUI9-N.d.cts} +90 -46
- package/dist/{types-CzdN7rUe.d.ts → types-ChOUI9-N.d.ts} +90 -46
- package/dist/{types-C05PdDJa.d.ts → types-Dfw9VOKI.d.cts} +15 -23
- package/dist/utils/index.cjs +2 -2
- package/dist/utils/index.d.cts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/package.json +10 -8
- package/src/charts/bar-chart/bar-chart.tsx +19 -19
- package/src/charts/bar-chart/test/bar-chart.test.tsx +78 -31
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +2 -2
- package/src/charts/leaderboard-chart/hooks/use-leaderboard-legend-items.ts +0 -2
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +9 -10
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +124 -102
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +61 -33
- package/src/charts/leaderboard-chart/test/use-leaderboard-legend-items.test.tsx +2 -5
- package/src/charts/leaderboard-chart/types.ts +2 -15
- package/src/charts/line-chart/line-chart.tsx +18 -17
- package/src/charts/line-chart/test/line-chart.test.tsx +49 -27
- package/src/charts/line-chart/types.ts +0 -1
- package/src/charts/pie-chart/pie-chart.tsx +23 -23
- package/src/charts/pie-chart/test/composition-api.test.tsx +41 -0
- package/src/charts/pie-chart/test/pie-chart.test.tsx +9 -9
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +21 -24
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +33 -5
- package/src/charts/private/chart-composition/index.ts +2 -0
- package/src/charts/private/chart-composition/render-legend-slot.ts +22 -0
- package/src/charts/private/chart-composition/test/render-legend-slot.test.tsx +60 -0
- package/src/charts/private/chart-composition/test/use-chart-children.test.tsx +91 -0
- package/src/charts/private/chart-composition/use-chart-children.ts +34 -2
- package/src/components/legend/private/base-legend.module.scss +19 -37
- package/src/components/legend/private/base-legend.tsx +32 -24
- package/src/components/legend/test/legend.test.tsx +148 -52
- package/src/components/legend/types.ts +23 -24
- package/src/hooks/index.ts +0 -1
- package/src/hooks/test/use-zero-value-display.test.tsx +206 -0
- package/src/hooks/use-zero-value-display.ts +52 -23
- package/src/providers/chart-context/test/chart-context.test.tsx +12 -6
- package/src/providers/chart-context/themes.ts +6 -4
- package/src/types.ts +93 -44
- package/src/utils/date-parsing.ts +10 -1
- package/src/utils/get-styles.ts +1 -1
- package/src/utils/test/date-parsing.test.ts +12 -0
- package/src/utils/test/get-styles.test.ts +12 -10
- package/src/utils/test/resolve-css-var.test.ts +2 -2
- package/tsup.config.ts +1 -1
- package/dist/chunk-55ZCOYDF.cjs.map +0 -1
- package/dist/chunk-6CCZL2JJ.js.map +0 -1
- package/dist/chunk-7FDQGBY7.js.map +0 -1
- package/dist/chunk-BXFD7JIG.cjs.map +0 -1
- package/dist/chunk-IS5YYLTV.js.map +0 -1
- package/dist/chunk-KNIMXN6Z.js +0 -51
- package/dist/chunk-KNIMXN6Z.js.map +0 -1
- package/dist/chunk-NQJE2CC7.cjs.map +0 -1
- package/dist/chunk-O2JIANHK.cjs.map +0 -1
- package/dist/chunk-OMS5QIJN.js.map +0 -1
- package/dist/chunk-RCY6XLGU.cjs.map +0 -1
- package/dist/chunk-RFSHE3HL.js.map +0 -1
- package/dist/chunk-SSFFCBCF.js.map +0 -1
- package/dist/chunk-SUDERBUA.cjs +0 -51
- package/dist/chunk-SUDERBUA.cjs.map +0 -1
- package/dist/chunk-TE63Y5PX.js.map +0 -1
- package/dist/chunk-UFRBUT2D.cjs.map +0 -1
- package/dist/chunk-VPAEBI2F.js.map +0 -1
- package/dist/chunk-X7JL2NYJ.cjs.map +0 -1
- package/dist/chunk-XD2HV7M5.js.map +0 -1
- package/dist/chunk-YDVHT7GS.cjs.map +0 -1
- package/dist/chunk-ZVGEDXDP.cjs.map +0 -1
- package/src/hooks/use-has-legend-child.ts +0 -22
- /package/dist/{chunk-GWBS65VC.js.map → chunk-4B7BL2DD.js.map} +0 -0
- /package/dist/{chunk-MDRCAGKZ.js.map → chunk-DKU775VC.js.map} +0 -0
- /package/dist/{chunk-KHQPN77E.js.map → chunk-KJHWXOCZ.js.map} +0 -0
- /package/dist/{chunk-E62LCBGD.js.map → chunk-MUNOKLLE.js.map} +0 -0
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/* eslint-disable @wordpress/no-unsafe-wp-apis */
|
|
2
|
-
import {
|
|
3
|
-
__experimentalVStack as VStack,
|
|
4
|
-
__experimentalGrid as Grid,
|
|
5
|
-
__experimentalText as Text,
|
|
6
|
-
} from '@wordpress/components';
|
|
2
|
+
import { __experimentalGrid as Grid, __experimentalText as Text } from '@wordpress/components';
|
|
7
3
|
import { Fragment } from '@wordpress/element';
|
|
8
4
|
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { Stack } from '@wordpress/ui';
|
|
9
6
|
import clsx from 'clsx';
|
|
10
7
|
import { useContext, useMemo, type FC } from 'react';
|
|
11
8
|
import { Legend } from '../../components/legend';
|
|
@@ -19,7 +16,7 @@ import {
|
|
|
19
16
|
useGlobalChartsTheme,
|
|
20
17
|
} from '../../providers';
|
|
21
18
|
import { formatMetricValue, attachSubComponents } from '../../utils';
|
|
22
|
-
import { useChartChildren } from '../private/chart-composition';
|
|
19
|
+
import { useChartChildren, renderLegendSlot } from '../private/chart-composition';
|
|
23
20
|
import { SingleChartContext } from '../private/single-chart-context';
|
|
24
21
|
import { withResponsive } from '../private/with-responsive';
|
|
25
22
|
import { useLeaderboardLegendItems } from './hooks';
|
|
@@ -113,34 +110,33 @@ const BarWithLabel = ( {
|
|
|
113
110
|
* LeaderboardChart component displays a ranked list of data with progress bars
|
|
114
111
|
* and optional comparison values.
|
|
115
112
|
*
|
|
116
|
-
* @param props
|
|
117
|
-
* @param props.data
|
|
118
|
-
* @param props.chartId
|
|
119
|
-
* @param props.
|
|
120
|
-
* @param props.
|
|
121
|
-
* @param props.
|
|
122
|
-
* @param props.
|
|
123
|
-
* @param props.
|
|
124
|
-
* @param props.
|
|
125
|
-
* @param props.
|
|
126
|
-
* @param props.
|
|
127
|
-
* @param props.
|
|
128
|
-
* @param props.
|
|
129
|
-
* @param props.
|
|
130
|
-
* @param props.
|
|
131
|
-
* @param props.
|
|
132
|
-
* @param props.
|
|
133
|
-
* @param props.
|
|
134
|
-
* @param props.
|
|
135
|
-
* @param props.
|
|
136
|
-
* @param props.children - Child components for composition API
|
|
137
|
-
* @param props.className - Additional CSS class name
|
|
138
|
-
* @param props.style - Custom styling for the chart container
|
|
113
|
+
* @param props - Component props
|
|
114
|
+
* @param props.data - Array of leaderboard entries to display
|
|
115
|
+
* @param props.chartId - Optional unique identifier for the chart
|
|
116
|
+
* @param props.width - Optional width of the chart container in pixels
|
|
117
|
+
* @param props.height - Optional height of the chart container in pixels
|
|
118
|
+
* @param props.withComparison - Whether to show comparison data
|
|
119
|
+
* @param props.withOverlayLabel - Whether to overlay the label on top of the bar
|
|
120
|
+
* @param props.primaryColor - Primary color for current period bars
|
|
121
|
+
* @param props.secondaryColor - Secondary color for comparison period bars
|
|
122
|
+
* @param props.valueFormatter - Custom formatter for values
|
|
123
|
+
* @param props.deltaFormatter - Custom formatter for delta values
|
|
124
|
+
* @param props.loading - Whether the chart is in loading state
|
|
125
|
+
* @param props.animation - Whether the chart should animate on load
|
|
126
|
+
* @param props.showLegend - Whether to show legend
|
|
127
|
+
* @param props.legend - Legend configuration (orientation, position, alignment, shape, shapeStyles, interactive)
|
|
128
|
+
* @param props.legendLabels - Custom labels for legend items
|
|
129
|
+
* @param props.gap - Spacing between legend and chart content
|
|
130
|
+
* @param props.children - Child components for composition API
|
|
131
|
+
* @param props.className - Additional CSS class name
|
|
132
|
+
* @param props.style - Custom styling for the chart container
|
|
139
133
|
* @return JSX element representing the leaderboard chart
|
|
140
134
|
*/
|
|
141
135
|
const LeaderboardChartInternal: FC< LeaderboardChartProps > = ( {
|
|
142
136
|
data,
|
|
143
137
|
chartId: providedChartId,
|
|
138
|
+
width: propWidth,
|
|
139
|
+
height: propHeight,
|
|
144
140
|
withComparison = false,
|
|
145
141
|
withOverlayLabel = false,
|
|
146
142
|
primaryColor,
|
|
@@ -150,23 +146,22 @@ const LeaderboardChartInternal: FC< LeaderboardChartProps > = ( {
|
|
|
150
146
|
animation,
|
|
151
147
|
loading = false,
|
|
152
148
|
showLegend = false,
|
|
153
|
-
|
|
154
|
-
legendPosition = 'bottom',
|
|
155
|
-
legendAlignment = 'center',
|
|
156
|
-
legendShape = 'circle',
|
|
157
|
-
legendShapeWidth = 8,
|
|
158
|
-
legendShapeHeight = 8,
|
|
149
|
+
legend = {},
|
|
159
150
|
legendLabels,
|
|
160
|
-
|
|
151
|
+
gap = 'md',
|
|
161
152
|
className,
|
|
162
153
|
style,
|
|
163
154
|
children,
|
|
164
155
|
} ) => {
|
|
156
|
+
const legendInteractive = legend.interactive ?? false;
|
|
157
|
+
const legendPosition = legend.position ?? 'bottom';
|
|
158
|
+
|
|
165
159
|
const chartId = useChartId( providedChartId );
|
|
166
160
|
const { leaderboardChart: leaderboardChartSettings } = useGlobalChartsTheme();
|
|
161
|
+
const legendShapeStyles = { width: 8, height: 8, ...legend.shapeStyles };
|
|
167
162
|
|
|
168
163
|
// Process children to extract compound components
|
|
169
|
-
const {
|
|
164
|
+
const { legendChildren, nonLegendChildren } = useChartChildren( children, 'LeaderboardChart' );
|
|
170
165
|
const {
|
|
171
166
|
labelSpacing,
|
|
172
167
|
rowGap,
|
|
@@ -258,26 +253,49 @@ const LeaderboardChartInternal: FC< LeaderboardChartProps > = ( {
|
|
|
258
253
|
chartHeight: 0,
|
|
259
254
|
} }
|
|
260
255
|
>
|
|
261
|
-
<
|
|
256
|
+
<Stack
|
|
257
|
+
direction="column"
|
|
258
|
+
data-testid="leaderboard-chart-container"
|
|
262
259
|
className={ clsx(
|
|
263
260
|
styles.leaderboardChart,
|
|
261
|
+
{ [ styles[ 'leaderboardChart--responsive' ] ]: ! propWidth && ! propHeight },
|
|
264
262
|
{ [ styles[ 'leaderboardChart--loading' ] ]: loading },
|
|
265
263
|
className
|
|
266
264
|
) }
|
|
267
|
-
|
|
265
|
+
gap={ gap }
|
|
266
|
+
style={ {
|
|
267
|
+
...style,
|
|
268
|
+
width: propWidth || undefined,
|
|
269
|
+
height: propHeight || undefined,
|
|
270
|
+
} }
|
|
268
271
|
>
|
|
269
272
|
<div className={ styles.emptyState }>
|
|
270
273
|
{ loading
|
|
271
274
|
? __( 'Loading…', 'jetpack-charts' )
|
|
272
275
|
: __( 'No data available', 'jetpack-charts' ) }
|
|
273
276
|
</div>
|
|
274
|
-
|
|
275
|
-
{
|
|
276
|
-
</
|
|
277
|
+
|
|
278
|
+
{ nonLegendChildren }
|
|
279
|
+
</Stack>
|
|
277
280
|
</SingleChartContext.Provider>
|
|
278
281
|
);
|
|
279
282
|
}
|
|
280
283
|
|
|
284
|
+
const legendElement = showLegend && (
|
|
285
|
+
<Legend
|
|
286
|
+
orientation={ legend.orientation ?? 'horizontal' }
|
|
287
|
+
position={ legendPosition }
|
|
288
|
+
alignment={ legend.alignment ?? 'center' }
|
|
289
|
+
labelStyles={ legend.labelStyles }
|
|
290
|
+
itemClassName={ legend.itemClassName }
|
|
291
|
+
itemStyles={ legend.itemStyles }
|
|
292
|
+
shape={ legend.shape ?? 'circle' }
|
|
293
|
+
shapeStyles={ legendShapeStyles }
|
|
294
|
+
chartId={ chartId }
|
|
295
|
+
interactive={ legendInteractive }
|
|
296
|
+
/>
|
|
297
|
+
);
|
|
298
|
+
|
|
281
299
|
return (
|
|
282
300
|
<SingleChartContext.Provider
|
|
283
301
|
value={ {
|
|
@@ -286,76 +304,80 @@ const LeaderboardChartInternal: FC< LeaderboardChartProps > = ( {
|
|
|
286
304
|
chartHeight: 0,
|
|
287
305
|
} }
|
|
288
306
|
>
|
|
289
|
-
<
|
|
307
|
+
<Stack
|
|
308
|
+
direction="column"
|
|
309
|
+
data-testid="leaderboard-chart-container"
|
|
290
310
|
className={ clsx(
|
|
291
311
|
styles.leaderboardChart,
|
|
292
312
|
{
|
|
313
|
+
[ styles[ 'leaderboardChart--responsive' ] ]: ! propWidth && ! propHeight,
|
|
293
314
|
[ styles[ 'leaderboardChart--loading' ] ]: loading,
|
|
294
|
-
[ styles[ 'leaderboardChart--with-legend' ] ]: showLegend,
|
|
295
|
-
[ styles[ 'leaderboardChart--legend-top' ] ]: showLegend && legendPosition === 'top',
|
|
296
315
|
},
|
|
297
316
|
className
|
|
298
317
|
) }
|
|
299
|
-
|
|
318
|
+
gap={ gap }
|
|
319
|
+
style={ {
|
|
320
|
+
...style,
|
|
321
|
+
width: propWidth || undefined,
|
|
322
|
+
height: propHeight || undefined,
|
|
323
|
+
} }
|
|
300
324
|
>
|
|
301
|
-
{
|
|
302
|
-
|
|
303
|
-
{ __( 'All series are hidden. Click legend items to show data.', 'jetpack-charts' ) }
|
|
304
|
-
</div>
|
|
305
|
-
) : (
|
|
306
|
-
<Grid templateColumns="minmax(0, 1fr) auto" rowGap={ rowGap } columnGap={ columnGap }>
|
|
307
|
-
{ data.map( entry => {
|
|
308
|
-
const colorIndex = Math.sign( entry.delta ) + 1;
|
|
309
|
-
const deltaColor = deltaColors[ colorIndex ];
|
|
310
|
-
|
|
311
|
-
return (
|
|
312
|
-
<Fragment key={ entry.id }>
|
|
313
|
-
<VStack spacing={ labelSpacing }>
|
|
314
|
-
<BarWithLabel
|
|
315
|
-
entry={ entry }
|
|
316
|
-
withComparison={ withComparison }
|
|
317
|
-
withOverlayLabel={ withOverlayLabel }
|
|
318
|
-
primaryColor={ resolvedPrimaryColor }
|
|
319
|
-
secondaryColor={ resolvedSecondaryColor }
|
|
320
|
-
isPrimaryVisible={ isPrimaryVisible }
|
|
321
|
-
isComparisonVisible={ isComparisonVisible }
|
|
322
|
-
animation={ animation && ! loading && ! prefersReducedMotion }
|
|
323
|
-
/>
|
|
324
|
-
</VStack>
|
|
325
|
-
|
|
326
|
-
<div
|
|
327
|
-
className={ clsx( styles.valueContainer, {
|
|
328
|
-
[ styles.overlayLabel ]: withOverlayLabel,
|
|
329
|
-
} ) }
|
|
330
|
-
>
|
|
331
|
-
{ isPrimaryVisible && <Text>{ valueFormatter( entry.currentValue ) }</Text> }
|
|
332
|
-
|
|
333
|
-
{ withComparison && isComparisonVisible && (
|
|
334
|
-
<Text style={ { color: deltaColor } }>{ deltaFormatter( entry.delta ) }</Text>
|
|
335
|
-
) }
|
|
336
|
-
</div>
|
|
337
|
-
</Fragment>
|
|
338
|
-
);
|
|
339
|
-
} ) }
|
|
340
|
-
</Grid>
|
|
341
|
-
) }
|
|
325
|
+
{ legendPosition === 'top' && legendElement }
|
|
326
|
+
{ renderLegendSlot( legendChildren, 'top' ) }
|
|
342
327
|
|
|
343
|
-
{
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
328
|
+
<div className={ styles.leaderboardChart__content }>
|
|
329
|
+
{ allSeriesHidden ? (
|
|
330
|
+
<div className={ styles.emptyState }>
|
|
331
|
+
{ __( 'All series are hidden. Click legend items to show data.', 'jetpack-charts' ) }
|
|
332
|
+
</div>
|
|
333
|
+
) : (
|
|
334
|
+
<Grid templateColumns="minmax(0, 1fr) auto" rowGap={ rowGap } columnGap={ columnGap }>
|
|
335
|
+
{ data.map( entry => {
|
|
336
|
+
const colorIndex = Math.sign( entry.delta ) + 1;
|
|
337
|
+
const deltaColor = deltaColors[ colorIndex ];
|
|
338
|
+
|
|
339
|
+
return (
|
|
340
|
+
<Fragment key={ entry.id }>
|
|
341
|
+
<Stack direction="column" gap={ labelSpacing }>
|
|
342
|
+
<BarWithLabel
|
|
343
|
+
entry={ entry }
|
|
344
|
+
withComparison={ withComparison }
|
|
345
|
+
withOverlayLabel={ withOverlayLabel }
|
|
346
|
+
primaryColor={ resolvedPrimaryColor }
|
|
347
|
+
secondaryColor={ resolvedSecondaryColor }
|
|
348
|
+
isPrimaryVisible={ isPrimaryVisible }
|
|
349
|
+
isComparisonVisible={ isComparisonVisible }
|
|
350
|
+
animation={ animation && ! loading && ! prefersReducedMotion }
|
|
351
|
+
/>
|
|
352
|
+
</Stack>
|
|
353
|
+
|
|
354
|
+
<Stack
|
|
355
|
+
direction="row"
|
|
356
|
+
gap="xs"
|
|
357
|
+
className={ clsx( styles.valueContainer, {
|
|
358
|
+
[ styles.overlayLabel ]: withOverlayLabel,
|
|
359
|
+
} ) }
|
|
360
|
+
>
|
|
361
|
+
{ isPrimaryVisible && <Text>{ valueFormatter( entry.currentValue ) }</Text> }
|
|
362
|
+
|
|
363
|
+
{ withComparison && isComparisonVisible && (
|
|
364
|
+
<Text style={ { color: deltaColor } }>
|
|
365
|
+
{ deltaFormatter( entry.delta ) }
|
|
366
|
+
</Text>
|
|
367
|
+
) }
|
|
368
|
+
</Stack>
|
|
369
|
+
</Fragment>
|
|
370
|
+
);
|
|
371
|
+
} ) }
|
|
372
|
+
</Grid>
|
|
373
|
+
) }
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
{ legendPosition === 'bottom' && legendElement }
|
|
377
|
+
{ renderLegendSlot( legendChildren, 'bottom' ) }
|
|
355
378
|
|
|
356
|
-
{
|
|
357
|
-
|
|
358
|
-
</div>
|
|
379
|
+
{ nonLegendChildren }
|
|
380
|
+
</Stack>
|
|
359
381
|
</SingleChartContext.Provider>
|
|
360
382
|
);
|
|
361
383
|
};
|
|
@@ -2,6 +2,17 @@ import { render, screen } from '@testing-library/react';
|
|
|
2
2
|
import LeaderboardChart from '../leaderboard-chart';
|
|
3
3
|
import type { LeaderboardEntry } from '../../../types';
|
|
4
4
|
|
|
5
|
+
const mockDefaultParentSize = () => ( {
|
|
6
|
+
parentRef: { current: null },
|
|
7
|
+
width: 400,
|
|
8
|
+
height: 300,
|
|
9
|
+
} );
|
|
10
|
+
|
|
11
|
+
// Mock useParentSize so the responsive wrapper returns predictable dimensions in tests
|
|
12
|
+
jest.mock( '@visx/responsive', () => ( {
|
|
13
|
+
useParentSize: jest.fn( () => mockDefaultParentSize() ),
|
|
14
|
+
} ) );
|
|
15
|
+
|
|
5
16
|
const mockData: LeaderboardEntry[] = [
|
|
6
17
|
{
|
|
7
18
|
id: 'direct',
|
|
@@ -40,6 +51,11 @@ const testValueFormatter = ( value: number ) => `${ value }$`;
|
|
|
40
51
|
const testDeltaFormatter = ( value: number ) => `${ value }delta`;
|
|
41
52
|
|
|
42
53
|
describe( 'LeaderboardChart', () => {
|
|
54
|
+
afterEach( () => {
|
|
55
|
+
const { useParentSize } = jest.requireMock( '@visx/responsive' );
|
|
56
|
+
useParentSize.mockImplementation( () => mockDefaultParentSize() );
|
|
57
|
+
} );
|
|
58
|
+
|
|
43
59
|
it( 'renders leaderboard entries', () => {
|
|
44
60
|
render( <LeaderboardChart data={ mockData } /> );
|
|
45
61
|
|
|
@@ -153,9 +169,7 @@ describe( 'LeaderboardChart', () => {
|
|
|
153
169
|
data={ mockData }
|
|
154
170
|
withComparison={ true }
|
|
155
171
|
showLegend={ true }
|
|
156
|
-
|
|
157
|
-
legendShapeWidth={ 10 }
|
|
158
|
-
legendShapeHeight={ 6 }
|
|
172
|
+
legend={ { shape: 'rect', shapeStyles: { width: 10, height: 6 } } }
|
|
159
173
|
/>
|
|
160
174
|
);
|
|
161
175
|
|
|
@@ -204,7 +218,7 @@ describe( 'LeaderboardChart', () => {
|
|
|
204
218
|
it( 'renders LeaderboardChart.Legend as child component', () => {
|
|
205
219
|
render(
|
|
206
220
|
<LeaderboardChart data={ mockData } withComparison={ true }>
|
|
207
|
-
<LeaderboardChart.Legend
|
|
221
|
+
<LeaderboardChart.Legend />
|
|
208
222
|
</LeaderboardChart>
|
|
209
223
|
);
|
|
210
224
|
|
|
@@ -212,8 +226,8 @@ describe( 'LeaderboardChart', () => {
|
|
|
212
226
|
expect( screen.getByText( 'Direct' ) ).toBeInTheDocument();
|
|
213
227
|
expect( screen.getByText( 'Social Media' ) ).toBeInTheDocument();
|
|
214
228
|
|
|
215
|
-
// Composition legend should render
|
|
216
|
-
expect( screen.getAllByTestId( '
|
|
229
|
+
// Composition legend should render
|
|
230
|
+
expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength( 2 );
|
|
217
231
|
expect( screen.getByText( 'Current period' ) ).toBeInTheDocument();
|
|
218
232
|
expect( screen.getByText( 'Previous period' ) ).toBeInTheDocument();
|
|
219
233
|
} );
|
|
@@ -221,15 +235,12 @@ describe( 'LeaderboardChart', () => {
|
|
|
221
235
|
it( 'renders composition legend regardless of showLegend value', () => {
|
|
222
236
|
render(
|
|
223
237
|
<LeaderboardChart data={ mockData } withComparison={ true } showLegend={ false }>
|
|
224
|
-
<LeaderboardChart.Legend
|
|
238
|
+
<LeaderboardChart.Legend />
|
|
225
239
|
</LeaderboardChart>
|
|
226
240
|
);
|
|
227
241
|
|
|
228
|
-
//
|
|
229
|
-
expect( screen.
|
|
230
|
-
|
|
231
|
-
// Composition legend should still render regardless of showLegend value
|
|
232
|
-
expect( screen.getAllByTestId( 'composition-legend-item' ) ).toHaveLength( 2 );
|
|
242
|
+
// Composition legend should render regardless of showLegend value
|
|
243
|
+
expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength( 2 );
|
|
233
244
|
expect( screen.getByText( 'Current period' ) ).toBeInTheDocument();
|
|
234
245
|
expect( screen.getByText( 'Previous period' ) ).toBeInTheDocument();
|
|
235
246
|
} );
|
|
@@ -237,41 +248,36 @@ describe( 'LeaderboardChart', () => {
|
|
|
237
248
|
it( 'supports both built-in and composition legends simultaneously', () => {
|
|
238
249
|
render(
|
|
239
250
|
<LeaderboardChart data={ mockData } withComparison={ true } showLegend={ true }>
|
|
240
|
-
<LeaderboardChart.Legend
|
|
251
|
+
<LeaderboardChart.Legend />
|
|
241
252
|
</LeaderboardChart>
|
|
242
253
|
);
|
|
243
254
|
|
|
244
|
-
//
|
|
245
|
-
expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength(
|
|
246
|
-
|
|
247
|
-
// Composition legend should also render
|
|
248
|
-
expect( screen.getAllByTestId( 'composition-legend-item' ) ).toHaveLength( 2 );
|
|
255
|
+
// Both built-in and composition legends should render (2 items each = 4 total)
|
|
256
|
+
expect( screen.getAllByTestId( 'legend-item' ) ).toHaveLength( 4 );
|
|
249
257
|
|
|
250
258
|
// Should have legend items from both legends
|
|
251
259
|
const currentPeriodItems = screen.getAllByText( 'Current period' );
|
|
252
260
|
const previousPeriodItems = screen.getAllByText( 'Previous period' );
|
|
253
|
-
expect( currentPeriodItems ).toHaveLength( 2 );
|
|
254
|
-
expect( previousPeriodItems ).toHaveLength( 2 );
|
|
261
|
+
expect( currentPeriodItems ).toHaveLength( 2 );
|
|
262
|
+
expect( previousPeriodItems ).toHaveLength( 2 );
|
|
255
263
|
} );
|
|
256
264
|
|
|
257
265
|
it( 'passes props correctly to composition legend', () => {
|
|
258
266
|
render(
|
|
259
267
|
<LeaderboardChart data={ mockData } withComparison={ true }>
|
|
260
|
-
<LeaderboardChart.Legend
|
|
261
|
-
data-testid="composition-legend-item"
|
|
262
|
-
shape="circle"
|
|
263
|
-
shapeWidth={ 12 }
|
|
264
|
-
shapeHeight={ 12 }
|
|
265
|
-
style={ { marginTop: '20px' } }
|
|
266
|
-
/>
|
|
268
|
+
<LeaderboardChart.Legend shape="circle" shapeStyles={ { margin: '4px 8px' } } />
|
|
267
269
|
</LeaderboardChart>
|
|
268
270
|
);
|
|
269
271
|
|
|
270
|
-
const legendItems = screen.getAllByTestId( '
|
|
272
|
+
const legendItems = screen.getAllByTestId( 'legend-item' );
|
|
271
273
|
expect( legendItems ).toHaveLength( 2 );
|
|
272
|
-
|
|
274
|
+
|
|
275
|
+
// Verify custom shape styles are applied within each legend item.
|
|
276
|
+
// Direct DOM access is needed because visx legend shapes lack accessible attributes and we cannot pass a test id to them.
|
|
273
277
|
legendItems.forEach( item => {
|
|
274
|
-
|
|
278
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
279
|
+
const shape = item.querySelector( '.visx-legend-shape' );
|
|
280
|
+
expect( shape ).toHaveStyle( { margin: '4px 8px' } );
|
|
275
281
|
} );
|
|
276
282
|
} );
|
|
277
283
|
|
|
@@ -299,7 +305,7 @@ describe( 'LeaderboardChart', () => {
|
|
|
299
305
|
data={ mockData }
|
|
300
306
|
withComparison={ true }
|
|
301
307
|
showLegend={ true }
|
|
302
|
-
|
|
308
|
+
legend={ { interactive: true } }
|
|
303
309
|
/>
|
|
304
310
|
);
|
|
305
311
|
|
|
@@ -313,7 +319,7 @@ describe( 'LeaderboardChart', () => {
|
|
|
313
319
|
data={ mockData }
|
|
314
320
|
withComparison={ true }
|
|
315
321
|
showLegend={ true }
|
|
316
|
-
|
|
322
|
+
legend={ { interactive: false } }
|
|
317
323
|
/>
|
|
318
324
|
);
|
|
319
325
|
|
|
@@ -328,7 +334,7 @@ describe( 'LeaderboardChart', () => {
|
|
|
328
334
|
data={ mockData }
|
|
329
335
|
withComparison={ true }
|
|
330
336
|
showLegend={ true }
|
|
331
|
-
|
|
337
|
+
legend={ { interactive: true } }
|
|
332
338
|
/>
|
|
333
339
|
);
|
|
334
340
|
|
|
@@ -339,4 +345,26 @@ describe( 'LeaderboardChart', () => {
|
|
|
339
345
|
expect( screen.getByText( '-8%' ) ).toBeInTheDocument();
|
|
340
346
|
} );
|
|
341
347
|
} );
|
|
348
|
+
|
|
349
|
+
describe( 'Responsive wrapper', () => {
|
|
350
|
+
it( 'fills parent container (height:100%) by default', () => {
|
|
351
|
+
render( <LeaderboardChart data={ mockData } /> );
|
|
352
|
+
const wrapper = screen.getByTestId( 'responsive-wrapper' );
|
|
353
|
+
expect( wrapper ).toHaveStyle( { height: '100%' } );
|
|
354
|
+
} );
|
|
355
|
+
|
|
356
|
+
it( 'applies explicit width and height to chart container', () => {
|
|
357
|
+
const { useParentSize } = jest.requireMock( '@visx/responsive' );
|
|
358
|
+
useParentSize.mockReturnValue( {
|
|
359
|
+
parentRef: { current: null },
|
|
360
|
+
width: 0,
|
|
361
|
+
height: 0,
|
|
362
|
+
} );
|
|
363
|
+
|
|
364
|
+
render( <LeaderboardChart data={ mockData } width={ 500 } height={ 240 } /> );
|
|
365
|
+
const chartContainer = screen.getByTestId( 'leaderboard-chart-container' );
|
|
366
|
+
|
|
367
|
+
expect( chartContainer ).toHaveStyle( { width: '500px', height: '240px' } );
|
|
368
|
+
} );
|
|
369
|
+
} );
|
|
342
370
|
} );
|
|
@@ -80,7 +80,6 @@ describe( 'useLeaderboardLegendItems', () => {
|
|
|
80
80
|
expect( result.current ).toHaveLength( 1 );
|
|
81
81
|
expect( result.current[ 0 ] ).toEqual( {
|
|
82
82
|
label: 'Current period',
|
|
83
|
-
value: '',
|
|
84
83
|
color: expect.any( String ),
|
|
85
84
|
} );
|
|
86
85
|
} );
|
|
@@ -102,14 +101,12 @@ describe( 'useLeaderboardLegendItems', () => {
|
|
|
102
101
|
// Current period item
|
|
103
102
|
expect( result.current[ 0 ] ).toEqual( {
|
|
104
103
|
label: 'Current period',
|
|
105
|
-
value: '',
|
|
106
104
|
color: expect.any( String ),
|
|
107
105
|
} );
|
|
108
106
|
|
|
109
107
|
// Previous period item
|
|
110
108
|
expect( result.current[ 1 ] ).toEqual( {
|
|
111
109
|
label: 'Previous period',
|
|
112
|
-
value: '',
|
|
113
110
|
color: expect.any( String ),
|
|
114
111
|
} );
|
|
115
112
|
} );
|
|
@@ -585,7 +582,7 @@ describe( 'useLeaderboardLegendItems', () => {
|
|
|
585
582
|
expect( result.current[ 1 ].label ).toBe( 'Previous period' );
|
|
586
583
|
} );
|
|
587
584
|
|
|
588
|
-
it( 'should
|
|
585
|
+
it( 'should not include value property for legend items', () => {
|
|
589
586
|
const wrapper = createWrapper();
|
|
590
587
|
const { result } = renderHook(
|
|
591
588
|
() =>
|
|
@@ -598,7 +595,7 @@ describe( 'useLeaderboardLegendItems', () => {
|
|
|
598
595
|
);
|
|
599
596
|
|
|
600
597
|
result.current.forEach( item => {
|
|
601
|
-
expect( item
|
|
598
|
+
expect( item ).not.toHaveProperty( 'value' );
|
|
602
599
|
} );
|
|
603
600
|
} );
|
|
604
601
|
|
|
@@ -7,15 +7,12 @@ export interface LeaderboardChartProps
|
|
|
7
7
|
| 'className'
|
|
8
8
|
| 'data'
|
|
9
9
|
| 'showLegend'
|
|
10
|
-
| '
|
|
11
|
-
| 'legendPosition'
|
|
12
|
-
| 'legendAlignment'
|
|
13
|
-
| 'legendShape'
|
|
10
|
+
| 'legend'
|
|
14
11
|
| 'chartId'
|
|
15
12
|
| 'width'
|
|
16
13
|
| 'height'
|
|
17
14
|
| 'size'
|
|
18
|
-
| '
|
|
15
|
+
| 'gap'
|
|
19
16
|
| 'animation'
|
|
20
17
|
> {
|
|
21
18
|
/**
|
|
@@ -60,16 +57,6 @@ export interface LeaderboardChartProps
|
|
|
60
57
|
'--a8c--charts--leaderboard--bar--border-radius'?: string;
|
|
61
58
|
};
|
|
62
59
|
|
|
63
|
-
/**
|
|
64
|
-
* Width of legend shapes in pixels
|
|
65
|
-
*/
|
|
66
|
-
legendShapeWidth?: number;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Height of legend shapes in pixels
|
|
70
|
-
*/
|
|
71
|
-
legendShapeHeight?: number;
|
|
72
|
-
|
|
73
60
|
/**
|
|
74
61
|
* Custom labels for legend items
|
|
75
62
|
*/
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
useChartDataTransform,
|
|
16
16
|
useChartMargin,
|
|
17
17
|
useElementSize,
|
|
18
|
-
useHasLegendChild,
|
|
19
18
|
usePrefersReducedMotion,
|
|
20
19
|
} from '../../hooks';
|
|
21
20
|
import {
|
|
@@ -27,6 +26,7 @@ import {
|
|
|
27
26
|
useGlobalChartsTheme,
|
|
28
27
|
} from '../../providers';
|
|
29
28
|
import { attachSubComponents } from '../../utils';
|
|
29
|
+
import { useChartChildren, renderLegendSlot } from '../private/chart-composition';
|
|
30
30
|
import { DefaultGlyph } from '../private/default-glyph';
|
|
31
31
|
import { SingleChartContext, type SingleChartRef } from '../private/single-chart-context';
|
|
32
32
|
import { withResponsive } from '../private/with-responsive';
|
|
@@ -256,15 +256,9 @@ const LineChartInternal = forwardRef< SingleChartRef, LineChartProps >(
|
|
|
256
256
|
withTooltips = true,
|
|
257
257
|
withTooltipCrosshairs,
|
|
258
258
|
showLegend = false,
|
|
259
|
-
|
|
260
|
-
legendAlignment = 'center',
|
|
261
|
-
legendPosition = 'bottom',
|
|
262
|
-
legendMaxWidth,
|
|
263
|
-
legendTextOverflow = 'wrap',
|
|
264
|
-
legendItemClassName,
|
|
259
|
+
legend = {},
|
|
265
260
|
renderGlyph = defaultRenderGlyph,
|
|
266
261
|
glyphStyle = {},
|
|
267
|
-
legendShape = 'line',
|
|
268
262
|
withLegendGlyph = false,
|
|
269
263
|
withGradientFill = false,
|
|
270
264
|
smoothing = true,
|
|
@@ -272,7 +266,6 @@ const LineChartInternal = forwardRef< SingleChartRef, LineChartProps >(
|
|
|
272
266
|
renderTooltip = renderDefaultTooltip,
|
|
273
267
|
withStartGlyphs = false,
|
|
274
268
|
withEndGlyphs = false,
|
|
275
|
-
legendInteractive = false,
|
|
276
269
|
animation,
|
|
277
270
|
options = {},
|
|
278
271
|
onPointerDown = undefined,
|
|
@@ -285,6 +278,10 @@ const LineChartInternal = forwardRef< SingleChartRef, LineChartProps >(
|
|
|
285
278
|
},
|
|
286
279
|
ref
|
|
287
280
|
) => {
|
|
281
|
+
const legendInteractive = legend.interactive ?? false;
|
|
282
|
+
const legendShape = legend.shape ?? 'line';
|
|
283
|
+
const legendPosition = legend.position ?? 'bottom';
|
|
284
|
+
|
|
288
285
|
const providerTheme = useGlobalChartsTheme();
|
|
289
286
|
const theme = useXYChartTheme( data );
|
|
290
287
|
const chartId = useChartId( providedChartId );
|
|
@@ -294,8 +291,9 @@ const LineChartInternal = forwardRef< SingleChartRef, LineChartProps >(
|
|
|
294
291
|
const [ isNavigating, setIsNavigating ] = useState( false );
|
|
295
292
|
const internalChartRef = useRef< SingleChartRef >( null );
|
|
296
293
|
|
|
297
|
-
//
|
|
298
|
-
const
|
|
294
|
+
// Process children for composition API (Legend, etc.)
|
|
295
|
+
const { legendChildren, nonLegendChildren } = useChartChildren( children, 'LineChart' );
|
|
296
|
+
const hasLegendChild = legendChildren.length > 0;
|
|
299
297
|
|
|
300
298
|
// Use the measured SVG wrapper height, falling back to the passed height if provided.
|
|
301
299
|
// When there's a legend (via prop or composition), we must wait for measurement because
|
|
@@ -454,12 +452,13 @@ const LineChartInternal = forwardRef< SingleChartRef, LineChartProps >(
|
|
|
454
452
|
|
|
455
453
|
const legendElement = showLegend && (
|
|
456
454
|
<Legend
|
|
457
|
-
orientation={
|
|
458
|
-
alignment={
|
|
455
|
+
orientation={ legend.orientation ?? 'horizontal' }
|
|
456
|
+
alignment={ legend.alignment ?? 'center' }
|
|
459
457
|
position={ legendPosition }
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
458
|
+
labelStyles={ legend.labelStyles }
|
|
459
|
+
itemClassName={ legend.itemClassName }
|
|
460
|
+
itemStyles={ legend.itemStyles }
|
|
461
|
+
shapeStyles={ legend.shapeStyles }
|
|
463
462
|
className={ styles[ 'line-chart__legend' ] }
|
|
464
463
|
shape={ legendShape }
|
|
465
464
|
chartId={ chartId }
|
|
@@ -493,6 +492,7 @@ const LineChartInternal = forwardRef< SingleChartRef, LineChartProps >(
|
|
|
493
492
|
} }
|
|
494
493
|
>
|
|
495
494
|
{ legendPosition === 'top' && legendElement }
|
|
495
|
+
{ renderLegendSlot( legendChildren, 'top' ) }
|
|
496
496
|
|
|
497
497
|
<div
|
|
498
498
|
className={ styles[ 'line-chart__svg-wrapper' ] }
|
|
@@ -655,8 +655,9 @@ const LineChartInternal = forwardRef< SingleChartRef, LineChartProps >(
|
|
|
655
655
|
</div>
|
|
656
656
|
|
|
657
657
|
{ legendPosition === 'bottom' && legendElement }
|
|
658
|
+
{ renderLegendSlot( legendChildren, 'bottom' ) }
|
|
658
659
|
|
|
659
|
-
{
|
|
660
|
+
{ nonLegendChildren }
|
|
660
661
|
</Stack>
|
|
661
662
|
</SingleChartContext.Provider>
|
|
662
663
|
);
|