diff --git a/packages/polaris-viz/src/components/LegendContainer/LegendContainer.tsx b/packages/polaris-viz/src/components/LegendContainer/LegendContainer.tsx index 6f95d4d85..4f6a86f3c 100644 --- a/packages/polaris-viz/src/components/LegendContainer/LegendContainer.tsx +++ b/packages/polaris-viz/src/components/LegendContainer/LegendContainer.tsx @@ -162,11 +162,7 @@ export function LegendContainer({ role="list" style={{...styleMap[direction], ...shouldCenterTiles(position)}} > - {renderLegendContent?.( - colorVisionInteractionMethods, - activeIndex, - legendItemDimensions, - ) ?? ( + {renderLegendContent?.(colorVisionInteractionMethods, activeIndex) ?? ( Boolean(val)) + .filter((dimension) => Boolean(dimension)) .reduce((totalWidth, card, index) => { if (totalWidth + card.width + index * LEGEND_GAP > containerWidth) { lastVisibleIndex = index; diff --git a/packages/polaris-viz/src/components/LineChartRelational/LineChartRelational.scss b/packages/polaris-viz/src/components/LineChartRelational/LineChartRelational.scss deleted file mode 100644 index c4ab89019..000000000 --- a/packages/polaris-viz/src/components/LineChartRelational/LineChartRelational.scss +++ /dev/null @@ -1,3 +0,0 @@ -.Container { - height: 100%; -} diff --git a/packages/polaris-viz/src/components/LineChartRelational/LineChartRelational.tsx b/packages/polaris-viz/src/components/LineChartRelational/LineChartRelational.tsx index 8b20fe88c..0b4263a4f 100644 --- a/packages/polaris-viz/src/components/LineChartRelational/LineChartRelational.tsx +++ b/packages/polaris-viz/src/components/LineChartRelational/LineChartRelational.tsx @@ -5,14 +5,10 @@ import { } from '@shopify/polaris-viz-core'; import {Fragment} from 'react'; -import {useResizeObserver} from '../../hooks'; import type {LineChartProps} from '../LineChart'; import {LineChart} from '../LineChart'; import {RelatedAreas, MissingDataArea, CustomLegend} from './components'; -import styles from './LineChartRelational.scss'; - -const SMALL_SCREEN_WIDTH = 400; export type LineChartRelationalProps = Omit< LineChartProps, @@ -35,13 +31,12 @@ export function LineChartRelational(props: LineChartRelationalProps) { tooltipOptions, xAxisOptions, yAxisOptions, + renderHiddenLegendLabel, } = { ...DEFAULT_CHART_PROPS, ...props, }; - const {setRef, entry} = useResizeObserver(); - const dataWithHiddenRelational = data.map((series) => { return { ...series, @@ -53,57 +48,56 @@ export function LineChartRelational(props: LineChartRelationalProps) { }); const relatedAreasKey = buildRelatedAreasKey(dataWithHiddenRelational); - const hideLegends = entry?.contentRect.width - ? entry.contentRect.width < SMALL_SCREEN_WIDTH - : false; return ( -
- { + { + return ( + + ); + }} + seriesNameFormatter={seriesNameFormatter} + showLegend={showLegend} + skipLinkText={skipLinkText} + slots={{ + chart: (props) => { return ( - + + + + ); - }} - seriesNameFormatter={seriesNameFormatter} - showLegend={showLegend} - skipLinkText={skipLinkText} - slots={{ - chart: (props) => { - return ( - - - - - ); - }, - }} - state={state} - theme={theme} - tooltipOptions={tooltipOptions} - xAxisOptions={xAxisOptions} - yAxisOptions={yAxisOptions} - /> -
+ }, + }} + state={state} + theme={theme} + tooltipOptions={tooltipOptions} + xAxisOptions={xAxisOptions} + yAxisOptions={yAxisOptions} + /> ); } diff --git a/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.scss b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.scss index fc08e746c..0c6ec5590 100644 --- a/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.scss +++ b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.scss @@ -1,8 +1,6 @@ .Container { display: flex; - flex-wrap: wrap; - gap: 12px; + flex-wrap: nowrap; + gap: 10px; list-style: none; - margin: 0; - padding: 0; } diff --git a/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.tsx b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.tsx index 1f17e7fca..63580bcf6 100644 --- a/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.tsx +++ b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/CustomLegend.tsx @@ -4,25 +4,30 @@ import { COLOR_VISION_SINGLE_ITEM, useChartContext, } from '@shopify/polaris-viz-core'; -import {useCallback, useState} from 'react'; +import {useCallback, useRef, useState} from 'react'; import {useOverflowLegend} from '../../../../components/LegendContainer/hooks/useOverflowLegend'; import {HiddenLegendTooltip} from '../../../../components/LegendContainer/components/HiddenLegendTooltip'; -import type {ColorVisionInteractionMethods} from '../../../../types'; +import type { + ColorVisionInteractionMethods, + RenderHiddenLegendLabel, +} from '../../../../types'; import type {LegendItemDimension} from '../../../../components/Legend'; import {LegendItem} from '../../../../components/Legend'; +import {deduplicateByRelatedIndex} from './utilities/deduplicateByRelatedIndex'; import styles from './CustomLegend.scss'; export interface Props extends ColorVisionInteractionMethods { data: DataSeries[]; seriesNameFormatter: LabelFormatter; theme: string; - hideLegends?: boolean; activeIndex: number; - legendItemDimensions: React.RefObject; + renderHiddenLegendLabel?: RenderHiddenLegendLabel; } +const HORIZONTAL_MARGIN = 16; +const LEFT_MARGIN = 12; export function CustomLegend({ data, getColorVisionEventAttrs, @@ -30,11 +35,12 @@ export function CustomLegend({ seriesNameFormatter, theme, activeIndex, - legendItemDimensions, + renderHiddenLegendLabel = (count) => `+${count} more`, }: Props) { const {containerBounds} = useChartContext(); const deduplicatedData = deduplicateByRelatedIndex(data); const [activatorWidth, setActivatorWidth] = useState(0); + const legendItemDimensions = useRef([{width: 0, height: 0}]); const overflowLegendProps = { direction: 'horizontal' as const, @@ -43,8 +49,8 @@ export function CustomLegend({ legendItemDimensions, width: containerBounds.width, activatorWidth, - leftMargin: 16, - horizontalMargin: 16, + leftMargin: LEFT_MARGIN, + horizontalMargin: HORIZONTAL_MARGIN, }; const {displayedData, hiddenData} = useOverflowLegend(overflowLegendProps); @@ -57,22 +63,12 @@ export function CustomLegend({ (series) => series?.metadata?.relatedIndex != null, ); - const percentileIndex = lineSeries.length + 1; - - const hasHiddenItems = hiddenData.length > 0; - - const onDimensionChange = useCallback( - (index, dimensions: LegendItemDimension) => { - if (legendItemDimensions?.current) { - legendItemDimensions.current[index] = dimensions; - } - }, - [legendItemDimensions], + const percentileIndex = data.findIndex( + (series) => series.metadata?.relatedIndex != null, ); const hasHiddenData = displayedData.length < deduplicatedData.length; const visibleSeries = hasHiddenData ? displayedData : lineSeries; - const formattedHiddenData = hiddenData.map((series) => ({ color: series.color!, name: seriesNameFormatter(series?.metadata?.legendLabel ?? series.name), @@ -80,6 +76,15 @@ export function CustomLegend({ lineStyle: series.metadata?.lineStyle, })); + const onDimensionChange = useCallback( + (index, dimensions: LegendItemDimension) => { + if (legendItemDimensions?.current) { + legendItemDimensions.current[index] = dimensions; + } + }, + [legendItemDimensions], + ); + return (
    {visibleSeries.map((series) => { @@ -137,13 +142,13 @@ export function CustomLegend({ )} - {hasHiddenItems && ( + {hasHiddenData && ( @@ -151,14 +156,3 @@ export function CustomLegend({
); } - -const deduplicateByRelatedIndex = (data: any[]) => { - const existingRelatedIndex = new Set(); - return data.filter((item) => { - const relatedIndex = item.metadata?.relatedIndex; - if (!relatedIndex) return true; - if (existingRelatedIndex.has(relatedIndex)) return false; - existingRelatedIndex.add(relatedIndex); - return true; - }); -}; diff --git a/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/tests/CustomLegend.test.tsx b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/tests/CustomLegend.test.tsx index 2c730b090..d6184a7c9 100644 --- a/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/tests/CustomLegend.test.tsx +++ b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/tests/CustomLegend.test.tsx @@ -1,11 +1,20 @@ +/* eslint-disable @shopify/strict-component-boundaries */ import {mount} from '@shopify/react-testing'; import {DEFAULT_THEME_NAME} from '@shopify/polaris-viz-core'; +import {useChartContext} from '@shopify/polaris-viz-core/src/hooks/useChartContext'; import type {Props} from '../CustomLegend'; import {CustomLegend} from '../CustomLegend'; import {LegendItem} from '../../../../Legend'; +import {HiddenLegendTooltip} from '../../../../LegendContainer/components/HiddenLegendTooltip'; + +jest.mock('@shopify/polaris-viz-core/src/hooks/useChartContext'); describe('', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('seriesNameFormatter', () => { it('renders formatted series name', () => { const component = mount( @@ -29,6 +38,29 @@ describe('', () => { }); }); }); + + describe('HiddenLegendTooltip', () => { + it('shows HiddenLegendTooltip when container does not fit all legend items', () => { + (useChartContext as jest.Mock).mockImplementation(() => ({ + containerBounds: {width: 20, height: 250, x: 0, y: 0}, + })); + + const component = mount(); + + expect(component).toContainReactComponent(HiddenLegendTooltip); + expect(component).toContainReactText('+1 more'); + }); + + it('does not show HiddenLegendTooltip when container fits all legend items', () => { + (useChartContext as jest.Mock).mockImplementation(() => ({ + containerBounds: {width: 1200, height: 250, x: 0, y: 0}, + })); + + const component = mount(); + + expect(component).not.toContainReactComponent(HiddenLegendTooltip); + }); + }); }); const MOCK_PROPS: Props = { @@ -48,10 +80,6 @@ const MOCK_PROPS: Props = { legendLabel: '75th - 25th percentile', }, }, - { - name: 'Median', - data: [{value: 238, key: '2020-03-01T12:00:00'}], - }, { name: '25th percentile', data: [{value: 88, key: '2020-03-01T12:00:00'}], @@ -66,5 +94,20 @@ const MOCK_PROPS: Props = { getColorVisionEventAttrs: jest.fn(), getColorVisionStyles: jest.fn(), activeIndex: 0, - legendItemDimensions: {current: []}, + legendItemDimensions: { + current: [ + { + width: 71, + height: 24, + }, + { + width: 66, + height: 24, + }, + { + width: 100, + height: 24, + }, + ], + }, }; diff --git a/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/utilities/deduplicateByRelatedIndex.ts b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/utilities/deduplicateByRelatedIndex.ts new file mode 100644 index 000000000..63a97d0d1 --- /dev/null +++ b/packages/polaris-viz/src/components/LineChartRelational/components/CustomLegend/utilities/deduplicateByRelatedIndex.ts @@ -0,0 +1,10 @@ +export const deduplicateByRelatedIndex = (data: any[]) => { + const existingRelatedIndex = new Set(); + return data.filter((item) => { + const relatedIndex = item.metadata?.relatedIndex; + if (!relatedIndex) return true; + if (existingRelatedIndex.has(relatedIndex)) return false; + existingRelatedIndex.add(relatedIndex); + return true; + }); +}; diff --git a/packages/polaris-viz/src/types.ts b/packages/polaris-viz/src/types.ts index fa647fbd1..dc69b52b3 100644 --- a/packages/polaris-viz/src/types.ts +++ b/packages/polaris-viz/src/types.ts @@ -222,7 +222,6 @@ export interface ColorVisionInteractionMethods { export type RenderLegendContent = ( colorVisionInteractionMethods: ColorVisionInteractionMethods, activeIndex?: number, - legendItemDimensions?: React.RefObject, ) => ReactNode; export type RenderHiddenLegendLabel = (hiddenItemsCount: number) => ReactNode;