From be94cea41a158fead3b01b4ef270c6a49b8d5b16 Mon Sep 17 00:00:00 2001 From: srmukher <120183316+srmukher@users.noreply.github.com> Date: Fri, 27 Dec 2024 14:21:06 +0000 Subject: [PATCH] Adding tests for legend multiselect and updating handlers --- .../HorizontalBarChartWithAxis.base.tsx | 79 +++++++++---------- .../HorizontalBarChartWithAxisRTL.test.tsx | 25 ++++++ packages/react/etc/react.api.md | 44 +++++------ 3 files changed, 84 insertions(+), 64 deletions(-) diff --git a/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.base.tsx b/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.base.tsx index 8a4440a7f3c36..5e3144bfd4300 100644 --- a/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.base.tsx +++ b/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.base.tsx @@ -357,11 +357,7 @@ export class HorizontalBarChartWithAxisBase const { YValueHover, hoverXValue } = this._getCalloutContentForBar(point); if ( - (!this._isLegendSelected() || - (this._isLegendSelected() && - (this._isSpecificLegendTitleSelected(point.legend!) || - this._noLegendsSelected() || - this._isSpecificLegendSelected(point.legend!)))) && + (this.state.isLegendSelected === false || this._isLegendHighlighted(point.legend)) && this._calloutAnchorPoint !== point ) { this._calloutAnchorPoint = point; @@ -402,7 +398,10 @@ export class HorizontalBarChartWithAxisBase refArrayIndexNumber: number, color: string, ): void => { - if (!this._isLegendSelected() || (this._isLegendSelected() && this._isSpecificLegendTitleSelected(point.legend!))) { + if ( + (this.state.isLegendSelected === false || this._isLegendHighlighted(point.legend)) && + this._calloutAnchorPoint !== point + ) { const { YValueHover, hoverXValue } = this._getCalloutContentForBar(point); this._refArray.forEach((obj: IRefArrayData, index: number) => { if (refArrayIndexNumber === index) { @@ -477,9 +476,8 @@ export class HorizontalBarChartWithAxisBase const bars = sortedBars.map((point: IHorizontalBarChartWithAxisDataPoint, index: number) => { let shouldHighlight = true; - if (this._isLegendHovered() || this._isLegendSelected()) { - shouldHighlight = - this._isSpecificLegendTitleSelected(point.legend!) || this._isSpecificLegendSelected(point.legend!); + if (this.state.isLegendHovered || this.state.isLegendSelected) { + shouldHighlight = this._isLegendHighlighted(point.legend); } this._classNames = getClassNames(this.props.styles!, { theme: this.props.theme!, @@ -606,8 +604,8 @@ export class HorizontalBarChartWithAxisBase const { useSingleColor = false } = this.props; const bars = this._points.map((point: IHorizontalBarChartWithAxisDataPoint, index: number) => { let shouldHighlight = true; - if (this._isLegendHovered() || this._isLegendSelected()) { - shouldHighlight = this._isSpecificLegendTitleSelected(point.legend!); + if (this._getHighlightedLegend().length > 0) { + shouldHighlight = this._isLegendHighlighted(point.legend); } this._classNames = getClassNames(this.props.styles!, { theme: this.props.theme!, @@ -779,8 +777,7 @@ export class HorizontalBarChartWithAxisBase focusZonePropsInHoverCard={this.props.focusZonePropsForLegendsInHoverCard} overflowText={this.props.legendsOverflowText} {...this.props.legendProps} - canSelectMultipleLegends={this.props.legendProps?.canSelectMultipleLegends} - onChange={this._onLegendChange} + onChange={this._onLegendSelectionChange.bind(this)} /> ); return legends; @@ -790,49 +787,47 @@ export class HorizontalBarChartWithAxisBase return this.state.isLegendSelected!; }; - private _isSpecificLegendTitleSelected = (legend: string): boolean => { - return this.state.selectedLegendTitle === legend; - }; - - private _isLegendHovered = (): boolean => { - return this.state.isLegendHovered!; - }; - - private _isSpecificLegendSelected = (legend: string): boolean => { - return this.state.selectedLegends.indexOf(legend) > -1; + /** + * This function checks if the given legend is highlighted or not. + * A legend can be highlighted in 2 ways: + * 1. selection: if the user clicks on it + * 2. hovering: if there is no selected legend and the user hovers over it + */ + private _isLegendHighlighted = (legend?: string) => { + return this._getHighlightedLegend().includes(legend!); }; - private _noLegendsSelected = (): boolean => { - return this.state.selectedLegends.length === 0; - }; + private _getHighlightedLegend() { + return this.state.selectedLegends.length > 0 + ? this.state.selectedLegends + : this.state.selectedLegendTitle + ? [this.state.selectedLegendTitle] + : []; + } - private _onLegendChange = ( + private _onLegendSelectionChange( selectedLegends: string[], event: React.MouseEvent, currentLegend?: ILegend, - ) => { - this.setState({ selectedLegends }); - if (this._isLegendSelected()) { - if (this._isSpecificLegendTitleSelected(currentLegend?.title!)) { - this.setState({ - isLegendSelected: false, - selectedLegendTitle: currentLegend?.title!, - }); - } else { - this.setState({ - selectedLegendTitle: currentLegend?.title!, - }); - } + ): void { + if (this.props.legendProps?.canSelectMultipleLegends) { + this.setState({ + selectedLegends, + selectedLegendTitle: currentLegend?.title!, + }); } else { this.setState({ - isLegendSelected: true, + selectedLegends: selectedLegends.slice(-1), selectedLegendTitle: currentLegend?.title!, }); } + this.setState({ + isLegendSelected: selectedLegends.length > 0, + }); if (this.props.legendProps?.onChange) { this.props.legendProps.onChange(selectedLegends, event, currentLegend); } - }; + } private _getAxisData = (yAxisData: IAxisData) => { if (yAxisData && yAxisData.yAxisDomainValues.length) { diff --git a/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxisRTL.test.tsx b/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxisRTL.test.tsx index 6975206a6447a..f19db37b54b68 100644 --- a/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxisRTL.test.tsx +++ b/packages/charts/react-charting/src/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxisRTL.test.tsx @@ -169,6 +169,31 @@ describe('Horizontal bar chart with axis- Subcomponent Legends', () => { expect(legendsAfterClickEvent[3]).toHaveAttribute('aria-selected', 'false'); }, ); + + testWithoutWait( + 'Should select multiple legends on multiple mouse click on legends', + HorizontalBarChartWithAxis, + { data: chartPointsHBCWA, legendProps: { canSelectMultipleLegends: true } }, + container => { + // const legends = screen.getAllByText((content, element) => element!.tagName.toLowerCase() === 'button'); + const legend1 = screen.getByText('Grapes')?.closest('button'); + const legend2 = screen.getByText('Apples')?.closest('button'); + + expect(legend1).toBeDefined(); + expect(legend2).toBeDefined(); + + fireEvent.click(legend1!); + fireEvent.click(legend2!); + const legendsAfterClickEvent = screen.getAllByText( + (content, element) => element!.tagName.toLowerCase() === 'button', + ); + // Assert + expect(legendsAfterClickEvent[0]).toHaveAttribute('aria-selected', 'false'); + expect(legendsAfterClickEvent[1]).toHaveAttribute('aria-selected', 'true'); + expect(legendsAfterClickEvent[2]).toHaveAttribute('aria-selected', 'true'); + expect(legendsAfterClickEvent[3]).toHaveAttribute('aria-selected', 'false'); + }, + ); }); describe('Horizontal bar chart with axis - Subcomponent callout', () => { diff --git a/packages/react/etc/react.api.md b/packages/react/etc/react.api.md index 94b006c369575..2cf141de1c40e 100644 --- a/packages/react/etc/react.api.md +++ b/packages/react/etc/react.api.md @@ -1604,49 +1604,49 @@ export { FabricPerformance } // @public (undocumented) export enum FabricSlots { // (undocumented) - black = 21,// BaseSlots.primaryColor, Shade[Shade.Unshaded]); + black = 21, // (undocumented) - neutralDark = 20,// BaseSlots.primaryColor, Shade[Shade.Shade1]); + neutralDark = 20, // (undocumented) - neutralLight = 11,// BaseSlots.primaryColor, Shade[Shade.Shade2]); + neutralLight = 11, // (undocumented) - neutralLighter = 10,// BaseSlots.primaryColor, Shade[Shade.Shade3]); + neutralLighter = 10, // (undocumented) - neutralLighterAlt = 9,// BaseSlots.primaryColor, Shade[Shade.Shade4]); + neutralLighterAlt = 9, // (undocumented) - neutralPrimary = 19,// BaseSlots.primaryColor, Shade[Shade.Shade5]); + neutralPrimary = 19, // (undocumented) - neutralPrimaryAlt = 18,// BaseSlots.primaryColor, Shade[Shade.Shade6]); + neutralPrimaryAlt = 18, // (undocumented) - neutralQuaternary = 13,// BaseSlots.primaryColor, Shade[Shade.Shade7]); + neutralQuaternary = 13, // (undocumented) - neutralQuaternaryAlt = 12,// BaseSlots.primaryColor, Shade[Shade.Shade8]); + neutralQuaternaryAlt = 12, // (undocumented) - neutralSecondary = 17,// BaseSlots.backgroundColor, Shade[Shade.Shade1]); + neutralSecondary = 17, // (undocumented) - neutralSecondaryAlt = 16,// BaseSlots.backgroundColor, Shade[Shade.Shade2]); + neutralSecondaryAlt = 16, // (undocumented) - neutralTertiary = 15,// BaseSlots.backgroundColor, Shade[Shade.Shade3]); + neutralTertiary = 15, // (undocumented) - neutralTertiaryAlt = 14,// BaseSlots.backgroundColor, Shade[Shade.Shade4]); + neutralTertiaryAlt = 14, // (undocumented) - themeDark = 7,// BaseSlots.backgroundColor, Shade[Shade.Shade5]); + themeDark = 7, // (undocumented) - themeDarkAlt = 6,// BaseSlots.backgroundColor, Shade[Shade.Shade6]); // bg6 or fg2 + themeDarkAlt = 6, // (undocumented) - themeDarker = 8,// BaseSlots.foregroundColor, Shade[Shade.Shade3]); + themeDarker = 8, // (undocumented) - themeLight = 3,// BaseSlots.foregroundColor, Shade[Shade.Shade4]); + themeLight = 3, // (undocumented) - themeLighter = 2,// BaseSlots.foregroundColor, Shade[Shade.Shade5]); + themeLighter = 2, // (undocumented) - themeLighterAlt = 1,// BaseSlots.foregroundColor, Shade[Shade.Shade6]); + themeLighterAlt = 1, // (undocumented) - themePrimary = 0,// BaseSlots.foregroundColor, Shade[Shade.Unshaded]); + themePrimary = 0, // (undocumented) - themeSecondary = 5,// BaseSlots.foregroundColor, Shade[Shade.Shade7]); + themeSecondary = 5, // (undocumented) - themeTertiary = 4,// BaseSlots.foregroundColor, Shade[Shade.Shade8]); + themeTertiary = 4, // (undocumented) white = 22 }