From bedd53266417e4b0a94497b5321c89a16a4e4f1c Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 7 Feb 2025 18:39:34 +0100 Subject: [PATCH 01/12] useSeries docs --- packages/x-charts/src/BarChart/BarPlot.tsx | 2 +- packages/x-charts/src/LineChart/AreaPlot.tsx | 2 +- .../src/LineChart/LineHighlightPlot.tsx | 2 +- packages/x-charts/src/LineChart/LinePlot.tsx | 2 +- packages/x-charts/src/LineChart/MarkPlot.tsx | 2 +- packages/x-charts/src/PieChart/PiePlot.tsx | 2 +- .../x-charts/src/ScatterChart/ScatterPlot.tsx | 2 +- packages/x-charts/src/hooks/index.ts | 12 ++-- packages/x-charts/src/hooks/useAxis.ts | 19 +++-- .../x-charts/src/hooks/useBarSeries.test.ts | 59 +++++++++++++++ packages/x-charts/src/hooks/useBarSeries.ts | 50 +++++++++++++ packages/x-charts/src/hooks/useChartId.ts | 6 +- packages/x-charts/src/hooks/useColorScale.ts | 44 ++++++++---- packages/x-charts/src/hooks/useDrawingArea.ts | 7 ++ .../x-charts/src/hooks/useLineSeries.test.ts | 59 +++++++++++++++ packages/x-charts/src/hooks/useLineSeries.ts | 50 +++++++++++++ .../x-charts/src/hooks/usePieSeries.test.ts | 69 ++++++++++++++++++ packages/x-charts/src/hooks/usePieSeries.ts | 50 +++++++++++++ packages/x-charts/src/hooks/useScale.ts | 32 +++++---- .../src/hooks/useScatterSeries.test.ts | 71 +++++++++++++++++++ .../x-charts/src/hooks/useScatterSeries.ts | 50 +++++++++++++ packages/x-charts/src/hooks/useSeries.ts | 52 -------------- packages/x-charts/src/hooks/useSvgRef.ts | 4 ++ 23 files changed, 550 insertions(+), 98 deletions(-) create mode 100644 packages/x-charts/src/hooks/useBarSeries.test.ts create mode 100644 packages/x-charts/src/hooks/useBarSeries.ts create mode 100644 packages/x-charts/src/hooks/useLineSeries.test.ts create mode 100644 packages/x-charts/src/hooks/useLineSeries.ts create mode 100644 packages/x-charts/src/hooks/usePieSeries.test.ts create mode 100644 packages/x-charts/src/hooks/usePieSeries.ts create mode 100644 packages/x-charts/src/hooks/useScatterSeries.test.ts create mode 100644 packages/x-charts/src/hooks/useScatterSeries.ts diff --git a/packages/x-charts/src/BarChart/BarPlot.tsx b/packages/x-charts/src/BarChart/BarPlot.tsx index 33924df041dba..9938a617fdf1d 100644 --- a/packages/x-charts/src/BarChart/BarPlot.tsx +++ b/packages/x-charts/src/BarChart/BarPlot.tsx @@ -14,7 +14,7 @@ import { BarClipPath } from './BarClipPath'; import { BarLabelItemProps, BarLabelSlotProps, BarLabelSlots } from './BarLabel/BarLabelItem'; import { BarLabelPlot } from './BarLabel/BarLabelPlot'; import { checkScaleErrors } from './checkScaleErrors'; -import { useBarSeries } from '../hooks/useSeries'; +import { useBarSeries } from '../hooks/useBarSeries'; import { SeriesFormatterResult } from '../context/PluginProvider'; import { useSkipAnimation } from '../context/AnimationProvider'; diff --git a/packages/x-charts/src/LineChart/AreaPlot.tsx b/packages/x-charts/src/LineChart/AreaPlot.tsx index 2a4f2d6f32806..4ceaae52a777a 100644 --- a/packages/x-charts/src/LineChart/AreaPlot.tsx +++ b/packages/x-charts/src/LineChart/AreaPlot.tsx @@ -16,7 +16,7 @@ import getCurveFactory from '../internals/getCurve'; import { DEFAULT_X_AXIS_KEY } from '../constants'; import { LineItemIdentifier } from '../models/seriesType/line'; import { useChartGradient } from '../internals/components/ChartsAxesGradients'; -import { useLineSeries } from '../hooks/useSeries'; +import { useLineSeries } from '../hooks/useLineSeries'; import { AxisId } from '../models/axis'; import { useSkipAnimation } from '../context/AnimationProvider'; diff --git a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx index bd37e6e2ec4bf..a120408f9676f 100644 --- a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx +++ b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx @@ -9,7 +9,7 @@ import { LineHighlightElement, LineHighlightElementProps } from './LineHighlight import { getValueToPositionMapper } from '../hooks/useScale'; import { DEFAULT_X_AXIS_KEY } from '../constants'; import getColor from './getColor'; -import { useLineSeries } from '../hooks/useSeries'; +import { useLineSeries } from '../hooks/useLineSeries'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { selectorChartsInteractionXAxis } from '../context/InteractionSelectors'; diff --git a/packages/x-charts/src/LineChart/LinePlot.tsx b/packages/x-charts/src/LineChart/LinePlot.tsx index b0986bee8d677..eded7613805c7 100644 --- a/packages/x-charts/src/LineChart/LinePlot.tsx +++ b/packages/x-charts/src/LineChart/LinePlot.tsx @@ -16,7 +16,7 @@ import getCurveFactory from '../internals/getCurve'; import { DEFAULT_X_AXIS_KEY } from '../constants'; import { LineItemIdentifier } from '../models/seriesType/line'; import { useChartGradient } from '../internals/components/ChartsAxesGradients'; -import { useLineSeries } from '../hooks/useSeries'; +import { useLineSeries } from '../hooks/useLineSeries'; import { AxisId } from '../models/axis'; import { useSkipAnimation } from '../context/AnimationProvider'; diff --git a/packages/x-charts/src/LineChart/MarkPlot.tsx b/packages/x-charts/src/LineChart/MarkPlot.tsx index 7731eba6392fb..bd601f9c613d8 100644 --- a/packages/x-charts/src/LineChart/MarkPlot.tsx +++ b/packages/x-charts/src/LineChart/MarkPlot.tsx @@ -7,7 +7,7 @@ import { useCartesianContext } from '../context/CartesianProvider'; import { useChartId } from '../hooks/useChartId'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { getValueToPositionMapper } from '../hooks/useScale'; -import { useLineSeries } from '../hooks/useSeries'; +import { useLineSeries } from '../hooks/useLineSeries'; import { cleanId } from '../internals/cleanId'; import { LineItemIdentifier } from '../models/seriesType/line'; import { CircleMarkElement } from './CircleMarkElement'; diff --git a/packages/x-charts/src/PieChart/PiePlot.tsx b/packages/x-charts/src/PieChart/PiePlot.tsx index 50190f23472a0..d7e684ce50386 100644 --- a/packages/x-charts/src/PieChart/PiePlot.tsx +++ b/packages/x-charts/src/PieChart/PiePlot.tsx @@ -6,7 +6,7 @@ import { PieArcPlot, PieArcPlotProps, PieArcPlotSlotProps, PieArcPlotSlots } fro import { PieArcLabelPlotSlots, PieArcLabelPlotSlotProps, PieArcLabelPlot } from './PieArcLabelPlot'; import { getPercentageValue } from '../internals/getPercentageValue'; import { getPieCoordinates } from './getPieCoordinates'; -import { usePieSeries } from '../hooks/useSeries'; +import { usePieSeries } from '../hooks/usePieSeries'; import { useSkipAnimation } from '../context/AnimationProvider'; export interface PiePlotSlots extends PieArcPlotSlots, PieArcLabelPlotSlots {} diff --git a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx index 639121a8c79e8..193070613b74d 100644 --- a/packages/x-charts/src/ScatterChart/ScatterPlot.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterPlot.tsx @@ -5,7 +5,7 @@ import { Scatter, ScatterProps } from './Scatter'; import { useCartesianContext } from '../context/CartesianProvider'; import getColor from './getColor'; import { ZAxisContext } from '../context/ZAxisContextProvider'; -import { useScatterSeries } from '../hooks/useSeries'; +import { useScatterSeries } from '../hooks/useScatterSeries'; export interface ScatterPlotSlots { scatter?: React.JSXElementConstructor; diff --git a/packages/x-charts/src/hooks/index.ts b/packages/x-charts/src/hooks/index.ts index 7f6e5dcdbdafe..a413a690e8934 100644 --- a/packages/x-charts/src/hooks/index.ts +++ b/packages/x-charts/src/hooks/index.ts @@ -4,10 +4,8 @@ export * from './useScale'; export * from './useAxis'; export * from './useColorScale'; export * from './useSvgRef'; -export { - useSeries as unstable_useSeries, - usePieSeries as unstable_usePieSeries, - useLineSeries as unstable_useLineSeries, - useBarSeries as unstable_useBarSeries, - useScatterSeries as unstable_useScatterSeries, -} from './useSeries'; +export * from './useSeries'; +export * from './useScatterSeries'; +export * from './usePieSeries'; +export * from './useBarSeries'; +export * from './useLineSeries'; diff --git a/packages/x-charts/src/hooks/useAxis.ts b/packages/x-charts/src/hooks/useAxis.ts index 7f4ac25f6cef4..61104d4ceb982 100644 --- a/packages/x-charts/src/hooks/useAxis.ts +++ b/packages/x-charts/src/hooks/useAxis.ts @@ -1,18 +1,29 @@ 'use client'; import { useCartesianContext } from '../context/CartesianProvider'; +import { AxisId } from '../models/axis'; -export function useXAxis(identifier?: number | string) { +/** + * Get the X axis. + * @param {AxisId | undefined} axisId - If provided returns the x axis with axisId, else returns the values for the default x axis. + * @returns The X axis. + */ +export function useXAxis(axisId?: AxisId) { const { xAxis, xAxisIds } = useCartesianContext(); - const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; + const id = axisId ?? xAxisIds[0]; return xAxis[id]; } -export function useYAxis(identifier?: number | string) { +/** + * Get the Y axis. + * @param {AxisId | undefined} axisId - If provided returns the y axis with axisId, else returns the values for the default y axis. + * @returns The Y axis. + */ +export function useYAxis(axisId?: AxisId) { const { yAxis, yAxisIds } = useCartesianContext(); - const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; + const id = axisId ?? yAxisIds[0]; return yAxis[id]; } diff --git a/packages/x-charts/src/hooks/useBarSeries.test.ts b/packages/x-charts/src/hooks/useBarSeries.test.ts new file mode 100644 index 0000000000000..68845b8e31c6c --- /dev/null +++ b/packages/x-charts/src/hooks/useBarSeries.test.ts @@ -0,0 +1,59 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import { stub, restore } from 'sinon'; +import { useBarSeries } from './useBarSeries'; +import * as series from './useSeries'; +import { SeriesId } from '../models/seriesType/common'; +import { FormattedSeries } from '../context/SeriesProvider'; + +describe('useBarSeries', () => { + const defaultProps = { + valueFormatter: (v: any) => v, + color: 'red', + layout: 'vertical', + type: 'bar', + stackedData: [] as [number, number][], + } as const; + + const mockSeries: FormattedSeries = { + bar: { + series: { + '1': { ...defaultProps, id: '1', data: [1, 2, 3] }, + '2': { ...defaultProps, id: '2', data: [4, 5, 6] }, + }, + seriesOrder: ['1', '2'], + stackingGroups: [], + }, + }; + + beforeEach(() => { + stub(series, 'useSeries').returns(mockSeries); + }); + + afterEach(() => { + restore(); + }); + + it('should return all bar series when no seriesIds are provided', () => { + const { result } = renderHook(() => useBarSeries()); + expect(result.current).to.deep.equal(mockSeries.bar); + }); + + it('should return the specific bar series when a single seriesId is provided', () => { + const { result } = renderHook(() => useBarSeries('1' as SeriesId)); + expect(result.current).to.deep.equal(mockSeries!.bar!.series['1']); + }); + + it('should return the specific bar series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useBarSeries('1' as SeriesId, '2' as SeriesId)); + expect(result.current).to.deep.equal([ + mockSeries!.bar!.series['1'], + mockSeries!.bar!.series['2'], + ]); + }); + + it('should filter out undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useBarSeries('1' as SeriesId, '3' as SeriesId)); + expect(result.current).to.deep.equal([mockSeries!.bar!.series['1']]); + }); +}); diff --git a/packages/x-charts/src/hooks/useBarSeries.ts b/packages/x-charts/src/hooks/useBarSeries.ts new file mode 100644 index 0000000000000..020856eb9edd9 --- /dev/null +++ b/packages/x-charts/src/hooks/useBarSeries.ts @@ -0,0 +1,50 @@ +'use client'; +import * as React from 'react'; +import { FormattedSeries } from '../context/SeriesProvider'; +import { SeriesId } from '../models/seriesType/common'; +import { ChartSeriesDefaultized } from '../models/seriesType/config'; +import { useSeries } from './useSeries'; + +/** + * Get access to the internal state of bar series. + * The returned object contains: + * - series: a mapping from ids to series attributes. + * - seriesOrder: the array of series ids. + * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} barSeries + */ +export function useBarSeries(): FormattedSeries['bar']; +/** + * Get access to the internal state of bar series. + * + * @param {SeriesId} seriesId The id of the series to get. + * @returns {ChartSeriesDefaultized<'bar'> | undefined} barSeries + */ +export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'>; +/** + * Get access to the internal state of bar series. + * + * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. + * @returns {ChartSeriesDefaultized<'bar'>[] | undefined} barSeries + */ +export function useBarSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'bar'>[]; +export function useBarSeries(...seriesIds: SeriesId[]): any { + const series = useSeries(); + + return React.useMemo( + () => { + if (seriesIds.length === 0) { + return series.bar; + } + + if (seriesIds.length === 1) { + return series?.bar?.series[seriesIds[0]]; + } + + return seriesIds.map((id) => series?.bar?.series[id]).filter(Boolean); + }, + // DANGER: Ensure that the dependencies array is correct. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + [series.bar, ...seriesIds], + ); +} diff --git a/packages/x-charts/src/hooks/useChartId.ts b/packages/x-charts/src/hooks/useChartId.ts index 644d0acfaab6a..2c6c16798222a 100644 --- a/packages/x-charts/src/hooks/useChartId.ts +++ b/packages/x-charts/src/hooks/useChartId.ts @@ -2,7 +2,11 @@ import * as React from 'react'; import { DrawingAreaContext } from '../context/DrawingAreaProvider'; -export function useChartId() { +/** + * Get the unique identifier of the chart. + * @returns {string} chartId + */ +export function useChartId(): string { const { chartId } = React.useContext(DrawingAreaContext); return React.useMemo(() => chartId, [chartId]); diff --git a/packages/x-charts/src/hooks/useColorScale.ts b/packages/x-charts/src/hooks/useColorScale.ts index f4284efa7454b..f9e947b17a018 100644 --- a/packages/x-charts/src/hooks/useColorScale.ts +++ b/packages/x-charts/src/hooks/useColorScale.ts @@ -1,35 +1,49 @@ 'use client'; import * as React from 'react'; -import { useCartesianContext } from '../context/CartesianProvider'; -import { AxisScaleComputedConfig, ScaleName } from '../models/axis'; +import { AxisId, AxisScaleComputedConfig, ScaleName } from '../models/axis'; import { ZAxisContext } from '../context/ZAxisContextProvider'; - +import { useXAxis, useYAxis } from './useAxis'; + +/** + * Get the X axis color scale. + * + * @param {AxisId | undefined} axisId - If provided returns color scale for axisId, else returns the values for the default axis. + * @returns {AxisScaleComputedConfig[S]['colorScale'] | undefined} The color scale for the specified X axis, or undefined if not found. + */ export function useXColorScale( - identifier?: number | string, + axisId?: AxisId, ): AxisScaleComputedConfig[S]['colorScale'] | undefined { - const { xAxis, xAxisIds } = useCartesianContext(); - - const id = typeof identifier === 'string' ? identifier : xAxisIds[identifier ?? 0]; + const axis = useXAxis(axisId); - return xAxis[id].colorScale; + return axis.colorScale; } +/** + * Get the Y axis color scale. + * + * @param {AxisId | undefined} axisId - If provided returns color scale for axisId, else returns the values for the default axis. + * @returns {AxisScaleComputedConfig[S]['colorScale'] | undefined} The color scale for the specified Y axis, or undefined if not found. + */ export function useYColorScale( - identifier?: number | string, + axisId?: AxisId, ): AxisScaleComputedConfig[S]['colorScale'] | undefined { - const { yAxis, yAxisIds } = useCartesianContext(); - - const id = typeof identifier === 'string' ? identifier : yAxisIds[identifier ?? 0]; + const axis = useYAxis(axisId); - return yAxis[id].colorScale; + return axis.colorScale; } +/** + * Get the Z axis color scale. + * + * @param {AxisId | undefined} axisId - If provided returns color scale for axisId, else returns the values for the default axis. + * @returns {AxisScaleComputedConfig[S]['colorScale'] | undefined} The color scale for the specified Z axis, or undefined if not found. + */ export function useZColorScale( - identifier?: number | string, + axisId?: AxisId, ): AxisScaleComputedConfig[S]['colorScale'] | undefined { const { zAxis, zAxisIds } = React.useContext(ZAxisContext); - const id = typeof identifier === 'string' ? identifier : zAxisIds[identifier ?? 0]; + const id = axisId ?? zAxisIds[0]; return zAxis[id]?.colorScale; } diff --git a/packages/x-charts/src/hooks/useDrawingArea.ts b/packages/x-charts/src/hooks/useDrawingArea.ts index f45457e907434..21e58cd1550ea 100644 --- a/packages/x-charts/src/hooks/useDrawingArea.ts +++ b/packages/x-charts/src/hooks/useDrawingArea.ts @@ -2,6 +2,13 @@ import * as React from 'react'; import { DrawingAreaContext, DrawingAreaState } from '../context/DrawingAreaProvider'; +/** + * Get the drawing area dimensions and coordinates. The drawing area is the area where the chart is rendered. + * + * It includes the left, top, width, height, bottom, right, and a function to check if a given point is inside the drawing area. + * + * @returns {DrawingAreaState} The drawing area dimensions. + */ export function useDrawingArea(): DrawingAreaState { const { left, top, width, height, bottom, right, isPointInside } = React.useContext(DrawingAreaContext); diff --git a/packages/x-charts/src/hooks/useLineSeries.test.ts b/packages/x-charts/src/hooks/useLineSeries.test.ts new file mode 100644 index 0000000000000..2b7f6085ef645 --- /dev/null +++ b/packages/x-charts/src/hooks/useLineSeries.test.ts @@ -0,0 +1,59 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import { stub, restore } from 'sinon'; +import { useLineSeries } from './useLineSeries'; +import * as series from './useSeries'; +import { SeriesId } from '../models/seriesType/common'; +import { FormattedSeries } from '../context/SeriesProvider'; + +describe('useLineSeries', () => { + const defaultProps = { + valueFormatter: (v: any) => v, + color: 'red', + layout: 'vertical', + type: 'line', + stackedData: [] as [number, number][], + } as const; + + const mockSeries: FormattedSeries = { + line: { + series: { + '1': { ...defaultProps, id: '1', data: [1, 2, 3] }, + '2': { ...defaultProps, id: '2', data: [4, 5, 6] }, + }, + seriesOrder: ['1', '2'], + stackingGroups: [], + }, + }; + + beforeEach(() => { + stub(series, 'useSeries').returns(mockSeries); + }); + + afterEach(() => { + restore(); + }); + + it('should return all line series when no seriesIds are provided', () => { + const { result } = renderHook(() => useLineSeries()); + expect(result.current).to.deep.equal(mockSeries.line); + }); + + it('should return the specific line series when a single seriesId is provided', () => { + const { result } = renderHook(() => useLineSeries('1' as SeriesId)); + expect(result.current).to.deep.equal(mockSeries!.line!.series['1']); + }); + + it('should return the specific line series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useLineSeries('1' as SeriesId, '2' as SeriesId)); + expect(result.current).to.deep.equal([ + mockSeries!.line!.series['1'], + mockSeries!.line!.series['2'], + ]); + }); + + it('should filter out undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useLineSeries('1' as SeriesId, '3' as SeriesId)); + expect(result.current).to.deep.equal([mockSeries!.line!.series['1']]); + }); +}); diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts new file mode 100644 index 0000000000000..a3198ba92f8d5 --- /dev/null +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -0,0 +1,50 @@ +'use client'; +import * as React from 'react'; +import { FormattedSeries } from '../context/SeriesProvider'; +import { SeriesId } from '../models/seriesType/common'; +import { ChartSeriesDefaultized } from '../models/seriesType/config'; +import { useSeries } from './useSeries'; + +/** + * Get access to the internal state of line series. + * The returned object contains: + * - series: a mapping from ids to series attributes. + * - seriesOrder: the array of series ids. + * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} lineSeries + */ +export function useLineSeries(): FormattedSeries['line']; +/** + * Get access to the internal state of line series. + * + * @param {SeriesId} seriesId The id of the series to get. + * @returns {ChartSeriesDefaultized<'line'> | undefined} lineSeries + */ +export function useLineSeries(seriesId: SeriesId): ChartSeriesDefaultized<'line'>; +/** + * Get access to the internal state of line series. + * + * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. + * @returns {ChartSeriesDefaultized<'line'>[] | undefined} lineSeries + */ +export function useLineSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'line'>[]; +export function useLineSeries(...seriesIds: SeriesId[]): any { + const series = useSeries(); + + return React.useMemo( + () => { + if (seriesIds.length === 0) { + return series.line; + } + + if (seriesIds.length === 1) { + return series?.line?.series[seriesIds[0]]; + } + + return seriesIds.map((id) => series?.line?.series[id]).filter(Boolean); + }, + // DANGER: Ensure that the dependencies array is correct. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + [series.line, ...seriesIds], + ); +} diff --git a/packages/x-charts/src/hooks/usePieSeries.test.ts b/packages/x-charts/src/hooks/usePieSeries.test.ts new file mode 100644 index 0000000000000..80dd3bc743bdd --- /dev/null +++ b/packages/x-charts/src/hooks/usePieSeries.test.ts @@ -0,0 +1,69 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import { stub, restore } from 'sinon'; +import { usePieSeries } from './usePieSeries'; +import * as series from './useSeries'; +import { SeriesId } from '../models/seriesType/common'; +import { FormattedSeries } from '../context/SeriesProvider'; + +describe('usePieSeries', () => { + const defaultProps = { + valueFormatter: (v: any) => v, + color: 'red', + layout: 'vertical', + type: 'pie', + stackedData: [] as [number, number][], + } as const; + + const dataExample = { + id: 1, + value: 10, + startAngle: 0, + endAngle: 1, + color: 'red', + formattedValue: '10', + index: 0, + padAngle: 0, + } as const; + + const mockSeries: FormattedSeries = { + pie: { + series: { + '1': { ...defaultProps, id: '1', data: [dataExample] }, + '2': { ...defaultProps, id: '2', data: [dataExample] }, + }, + seriesOrder: ['1', '2'], + }, + }; + + beforeEach(() => { + stub(series, 'useSeries').returns(mockSeries); + }); + + afterEach(() => { + restore(); + }); + + it('should return all pie series when no seriesIds are provided', () => { + const { result } = renderHook(() => usePieSeries()); + expect(result.current).to.deep.equal(mockSeries.pie); + }); + + it('should return the specific pie series when a single seriesId is provided', () => { + const { result } = renderHook(() => usePieSeries('1' as SeriesId)); + expect(result.current).to.deep.equal(mockSeries!.pie!.series['1']); + }); + + it('should return the specific pie series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => usePieSeries('1' as SeriesId, '2' as SeriesId)); + expect(result.current).to.deep.equal([ + mockSeries!.pie!.series['1'], + mockSeries!.pie!.series['2'], + ]); + }); + + it('should filter out undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => usePieSeries('1' as SeriesId, '3' as SeriesId)); + expect(result.current).to.deep.equal([mockSeries!.pie!.series['1']]); + }); +}); diff --git a/packages/x-charts/src/hooks/usePieSeries.ts b/packages/x-charts/src/hooks/usePieSeries.ts new file mode 100644 index 0000000000000..56592a621754b --- /dev/null +++ b/packages/x-charts/src/hooks/usePieSeries.ts @@ -0,0 +1,50 @@ +'use client'; +import * as React from 'react'; +import { FormattedSeries } from '../context/SeriesProvider'; +import { SeriesId } from '../models/seriesType/common'; +import { ChartSeriesDefaultized } from '../models/seriesType/config'; +import { useSeries } from './useSeries'; + +/** + * Get access to the internal state of pie series. + * The returned object contains: + * - series: a mapping from ids to series attributes. + * - seriesOrder: the array of series ids. + * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} pieSeries + */ +export function usePieSeries(): FormattedSeries['pie']; +/** + * Get access to the internal state of pie series. + * + * @param {SeriesId} seriesId The id of the series to get. + * @returns {ChartSeriesDefaultized<'pie'> | undefined} pieSeries + */ +export function usePieSeries(seriesId: SeriesId): ChartSeriesDefaultized<'pie'>; +/** + * Get access to the internal state of pie series. + * + * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. + * @returns {ChartSeriesDefaultized<'pie'>[] | undefined} pieSeries + */ +export function usePieSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'pie'>[]; +export function usePieSeries(...seriesIds: SeriesId[]): any { + const series = useSeries(); + + return React.useMemo( + () => { + if (seriesIds.length === 0) { + return series.pie; + } + + if (seriesIds.length === 1) { + return series?.pie?.series[seriesIds[0]]; + } + + return seriesIds.map((id) => series?.pie?.series[id]).filter(Boolean); + }, + // DANGER: Ensure that the dependencies array is correct. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + [series.pie, ...seriesIds], + ); +} diff --git a/packages/x-charts/src/hooks/useScale.ts b/packages/x-charts/src/hooks/useScale.ts index 6081559d0a685..58caa3c8d53b1 100644 --- a/packages/x-charts/src/hooks/useScale.ts +++ b/packages/x-charts/src/hooks/useScale.ts @@ -1,33 +1,41 @@ 'use client'; import { isBandScale } from '../internals/isBandScale'; -import { AxisScaleConfig, D3Scale, ScaleName } from '../models/axis'; +import { AxisId, AxisScaleConfig, D3Scale, ScaleName } from '../models/axis'; import { useXAxis, useYAxis } from './useAxis'; /** * For a given scale return a function that map value to their position. * Useful when dealing with specific scale such as band. - * @param scale The scale to use - * @returns (value: any) => number + * @param {D3Scale} scale The scale to use + * @returns {(value: any) => number} A function that map value to their position */ -export function getValueToPositionMapper(scale: D3Scale) { +export function getValueToPositionMapper(scale: D3Scale): (value: any) => number { if (isBandScale(scale)) { return (value: any) => (scale(value) ?? 0) + scale.bandwidth() / 2; } return (value: any) => scale(value) as number; } -export function useXScale( - identifier?: number | string, -): AxisScaleConfig[S]['scale'] { - const axis = useXAxis(identifier); +/** + * Get the X scale. + * + * @param {AxisId | undefined} axisId - If provided returns the scale for the x axis with axisId, else returns the values for the default x axis. + * @returns {AxisScaleConfig[S]['scale']} The scale for the specified X axis. + */ +export function useXScale(axisId?: AxisId): AxisScaleConfig[S]['scale'] { + const axis = useXAxis(axisId); return axis.scale; } -export function useYScale( - identifier?: number | string, -): AxisScaleConfig[S]['scale'] { - const axis = useYAxis(identifier); +/** + * Get the Y scale. + * + * @param {AxisId | undefined} axisId - If provided returns the scale for the y axis with axisId, else returns the values for the default y axis. + * @returns {AxisScaleConfig[S]['scale']} The scale for the specified Y axis. + */ +export function useYScale(axisId?: AxisId): AxisScaleConfig[S]['scale'] { + const axis = useYAxis(axisId); return axis.scale; } diff --git a/packages/x-charts/src/hooks/useScatterSeries.test.ts b/packages/x-charts/src/hooks/useScatterSeries.test.ts new file mode 100644 index 0000000000000..4113b4192b955 --- /dev/null +++ b/packages/x-charts/src/hooks/useScatterSeries.test.ts @@ -0,0 +1,71 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import { stub, restore } from 'sinon'; +import { useScatterSeries } from './useScatterSeries'; +import * as series from './useSeries'; +import { SeriesId } from '../models/seriesType/common'; +import { FormattedSeries } from '../context/SeriesProvider'; + +describe('useScatterSeries', () => { + const defaultProps = { + valueFormatter: (v: any) => v, + color: 'red', + layout: 'vertical', + type: 'scatter', + } as const; + + const mockSeries: FormattedSeries = { + scatter: { + series: { + '1': { + ...defaultProps, + id: '1', + data: [ + { id: 1, x: 1, y: 1 }, + { id: 2, x: 2, y: 2 }, + ], + }, + '2': { + ...defaultProps, + id: '2', + data: [ + { id: 3, x: 3, y: 3 }, + { id: 4, x: 4, y: 4 }, + ], + }, + }, + seriesOrder: ['1', '2'], + }, + }; + + beforeEach(() => { + stub(series, 'useSeries').returns(mockSeries); + }); + + afterEach(() => { + restore(); + }); + + it('should return all scatter series when no seriesIds are provided', () => { + const { result } = renderHook(() => useScatterSeries()); + expect(result.current).to.deep.equal(mockSeries.scatter); + }); + + it('should return the specific scatter series when a single seriesId is provided', () => { + const { result } = renderHook(() => useScatterSeries('1' as SeriesId)); + expect(result.current).to.deep.equal(mockSeries!.scatter!.series['1']); + }); + + it('should return the specific scatter series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useScatterSeries('1' as SeriesId, '2' as SeriesId)); + expect(result.current).to.deep.equal([ + mockSeries!.scatter!.series['1'], + mockSeries!.scatter!.series['2'], + ]); + }); + + it('should filter out undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useScatterSeries('1' as SeriesId, '3' as SeriesId)); + expect(result.current).to.deep.equal([mockSeries!.scatter!.series['1']]); + }); +}); diff --git a/packages/x-charts/src/hooks/useScatterSeries.ts b/packages/x-charts/src/hooks/useScatterSeries.ts new file mode 100644 index 0000000000000..538c5f390e356 --- /dev/null +++ b/packages/x-charts/src/hooks/useScatterSeries.ts @@ -0,0 +1,50 @@ +'use client'; +import * as React from 'react'; +import { FormattedSeries } from '../context/SeriesProvider'; +import { SeriesId } from '../models/seriesType/common'; +import { ChartSeriesDefaultized } from '../models/seriesType/config'; +import { useSeries } from './useSeries'; + +/** + * Get access to the internal state of scatter series. + * The returned object contains: + * - series: a mapping from ids to series attributes. + * - seriesOrder: the array of series ids. + * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} scatterSeries + */ +export function useScatterSeries(): FormattedSeries['scatter']; +/** + * Get access to the internal state of scatter series. + * + * @param {SeriesId} seriesId The id of the series to get. + * @returns {ChartSeriesDefaultized<'scatter'> | undefined} scatterSeries + */ +export function useScatterSeries(seriesId: SeriesId): ChartSeriesDefaultized<'scatter'>; +/** + * Get access to the internal state of scatter series. + * + * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. + * @returns {ChartSeriesDefaultized<'scatter'>[] | undefined} scatterSeries + */ +export function useScatterSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'scatter'>[]; +export function useScatterSeries(...seriesIds: SeriesId[]): any { + const series = useSeries(); + + return React.useMemo( + () => { + if (seriesIds.length === 0) { + return series.scatter; + } + + if (seriesIds.length === 1) { + return series?.scatter?.series[seriesIds[0]]; + } + + return seriesIds.map((id) => series?.scatter?.series[id]).filter(Boolean); + }, + // DANGER: Ensure that the dependencies array is correct. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + [series.pie, ...seriesIds], + ); +} diff --git a/packages/x-charts/src/hooks/useSeries.ts b/packages/x-charts/src/hooks/useSeries.ts index 4f68bfa6ef1e2..6a7b6f88cbbe6 100644 --- a/packages/x-charts/src/hooks/useSeries.ts +++ b/packages/x-charts/src/hooks/useSeries.ts @@ -22,55 +22,3 @@ export function useSeries(): FormattedSeries { return data; } - -/** - * Get access to the internal state of pie series. - * The returned object contains: - * - series: a mapping from ids to series attributes. - * - seriesOrder: the array of series ids. - * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} pieSeries - */ -export function usePieSeries(): FormattedSeries['pie'] { - const series = useSeries(); - - return React.useMemo(() => series.pie, [series.pie]); -} - -/** - * Get access to the internal state of line series. - * The returned object contains: - * - series: a mapping from ids to series attributes. - * - seriesOrder: the array of series ids. - * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} lineSeries - */ -export function useLineSeries(): FormattedSeries['line'] { - const series = useSeries(); - - return React.useMemo(() => series.line, [series.line]); -} - -/** - * Get access to the internal state of bar series. - * The returned object contains: - * - series: a mapping from ids to series attributes. - * - seriesOrder: the array of series ids. - * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} barSeries - */ -export function useBarSeries(): FormattedSeries['bar'] { - const series = useSeries(); - - return React.useMemo(() => series.bar, [series.bar]); -} - -/** - * Get access to the internal state of scatter series. - * The returned object contains: - * - series: a mapping from ids to series attributes. - * - seriesOrder: the array of series ids. - * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} scatterSeries - */ -export function useScatterSeries(): FormattedSeries['scatter'] { - const series = useSeries(); - - return React.useMemo(() => series.scatter, [series.scatter]); -} diff --git a/packages/x-charts/src/hooks/useSvgRef.ts b/packages/x-charts/src/hooks/useSvgRef.ts index ef1e3fe842ac0..4500d8b140053 100644 --- a/packages/x-charts/src/hooks/useSvgRef.ts +++ b/packages/x-charts/src/hooks/useSvgRef.ts @@ -2,6 +2,10 @@ import * as React from 'react'; import { SvgRefContext } from '../context/SvgRefProvider'; +/** + * Get the ref for the SVG element. + * @returns The SVG ref. + */ export function useSvgRef(): React.MutableRefObject { const { isInitialized, data } = React.useContext(SvgRefContext); From 7a70ef4c55be8ccb6be4ef3a49b5d5f8c524bf33 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 7 Feb 2025 19:16:59 +0100 Subject: [PATCH 02/12] add heatmap and tests --- .../x-charts-pro/src/Heatmap/HeatmapPlot.tsx | 2 +- .../src/Heatmap/HeatmapTooltip.tsx | 2 +- packages/x-charts-pro/src/hooks/index.ts | 2 +- .../src/hooks/useHeatmapSeries.test.ts | 72 +++++++++++++++++++ .../src/hooks/useHeatmapSeries.ts | 52 ++++++++++++++ packages/x-charts-pro/src/hooks/useSeries.ts | 16 ----- .../ChartsVoronoiHandler.tsx | 2 +- .../x-charts/src/hooks/useBarSeries.test.ts | 4 +- packages/x-charts/src/hooks/useBarSeries.ts | 4 +- .../x-charts/src/hooks/useLineSeries.test.ts | 4 +- packages/x-charts/src/hooks/useLineSeries.ts | 4 +- .../x-charts/src/hooks/usePieSeries.test.ts | 4 +- packages/x-charts/src/hooks/usePieSeries.ts | 4 +- .../src/hooks/useScatterSeries.test.ts | 4 +- .../x-charts/src/hooks/useScatterSeries.ts | 4 +- 15 files changed, 144 insertions(+), 36 deletions(-) create mode 100644 packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts create mode 100644 packages/x-charts-pro/src/hooks/useHeatmapSeries.ts delete mode 100644 packages/x-charts-pro/src/hooks/useSeries.ts diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx index 171ce56b3cffa..daea4f3d8aafc 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapPlot.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { useXScale, useYScale, useZColorScale } from '@mui/x-charts/hooks'; -import { useHeatmapSeries } from '../hooks/useSeries'; +import { useHeatmapSeries } from '../hooks/useHeatmapSeries'; import { HeatmapItem, HeatmapItemProps } from './HeatmapItem'; export interface HeatmapPlotProps extends Pick {} diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapTooltip.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapTooltip.tsx index bce80b58c67ae..fb3fe1f0ae7d2 100644 --- a/packages/x-charts-pro/src/Heatmap/HeatmapTooltip.tsx +++ b/packages/x-charts-pro/src/Heatmap/HeatmapTooltip.tsx @@ -16,7 +16,7 @@ import { } from '@mui/x-charts/ChartsTooltip'; import { useXAxis, useYAxis } from '@mui/x-charts/hooks'; import { getLabel, ChartsLabelMark } from '@mui/x-charts/internals'; -import { useHeatmapSeries } from '../hooks/useSeries'; +import { useHeatmapSeries } from '../hooks/useHeatmapSeries'; export interface HeatmapTooltipProps extends Omit {} diff --git a/packages/x-charts-pro/src/hooks/index.ts b/packages/x-charts-pro/src/hooks/index.ts index f9be207805602..60ff5de53db1b 100644 --- a/packages/x-charts-pro/src/hooks/index.ts +++ b/packages/x-charts-pro/src/hooks/index.ts @@ -1,2 +1,2 @@ -export { useHeatmapSeries } from './useSeries'; +export { useHeatmapSeries } from './useHeatmapSeries'; export * from './zoom'; diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts new file mode 100644 index 0000000000000..39b9f92bbf3c1 --- /dev/null +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts @@ -0,0 +1,72 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import { stub, restore } from 'sinon'; +import type { SeriesId, ProcessedSeries } from '@mui/x-charts/internals'; +import * as series from '@mui/x-charts/hooks/useSeries'; +import { useHeatmapSeries } from './useHeatmapSeries'; + +describe('useHeatmapSeries', () => { + const defaultProps = { + valueFormatter: (v: any) => v, + color: 'red', + layout: 'vertical', + type: 'heatmap', + } as const; + + const mockSeries: ProcessedSeries = { + heatmap: { + series: { + '1': { + ...defaultProps, + id: '1', + data: [ + [0, 0, 10], + [0, 1, 20], + [0, 2, 40], + ], + }, + '2': { + ...defaultProps, + id: '2', + data: [ + [3, 2, 20], + [3, 3, 70], + [3, 4, 90], + ], + }, + }, + seriesOrder: ['1', '2'], + }, + }; + + beforeEach(() => { + stub(series, 'useSeries').returns(mockSeries); + }); + + afterEach(() => { + restore(); + }); + + it('should return all heatmap series when no seriesIds are provided', () => { + const { result } = renderHook(() => useHeatmapSeries()); + expect(result.current).to.deep.equal(mockSeries.heatmap); + }); + + it('should return the specific heatmap series when a single seriesId is provided', () => { + const { result } = renderHook(() => useHeatmapSeries('1' as SeriesId)); + expect(result.current).to.deep.equal(mockSeries!.heatmap!.series['1']); + }); + + it('should return the specific heatmap series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useHeatmapSeries('1' as SeriesId, '2' as SeriesId)); + expect(result.current).to.deep.equal([ + mockSeries!.heatmap!.series['1'], + mockSeries!.heatmap!.series['2'], + ]); + }); + + it('should filter out undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useHeatmapSeries('1' as SeriesId, '3' as SeriesId)); + expect(result.current).to.deep.equal([mockSeries!.heatmap!.series['1']]); + }); +}); diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts new file mode 100644 index 0000000000000..90b534ea39958 --- /dev/null +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts @@ -0,0 +1,52 @@ +'use client'; +import * as React from 'react'; +import { + useSeries, + ProcessedSeries, + SeriesId, + ChartSeriesDefaultized, +} from '@mui/x-charts/internals'; + +/** + * Get access to the internal state of heatmap series. + * The returned object contains: + * - series: a mapping from ids to series attributes. + * - seriesOrder: the array of series ids. + * @returns { series: Record; seriesOrder: SeriesId[]; } | undefined heatmapSeries + */ +export function useHeatmapSeries(): ProcessedSeries['heatmap']; +/** + * Get access to the internal state of heatmap series. + * + * @param {SeriesId} seriesId The id of the series to get. + * @returns {ChartSeriesDefaultized<'heatmap'> | undefined} heatmapSeries + */ +export function useHeatmapSeries(seriesId: SeriesId): ChartSeriesDefaultized<'heatmap'>; +/** + * Get access to the internal state of heatmap series. + * + * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. + * @returns {ChartSeriesDefaultized<'heatmap'>[] | undefined} heatmapSeries + */ +export function useHeatmapSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'heatmap'>[]; +export function useHeatmapSeries(...seriesIds: SeriesId[]): any { + const series = useSeries(); + + return React.useMemo( + () => { + if (seriesIds.length === 0) { + return series.heatmap; + } + + if (seriesIds.length === 1) { + return series?.heatmap?.series[seriesIds[0]]; + } + + return seriesIds.map((id) => series?.heatmap?.series[id]).filter(Boolean); + }, + // DANGER: Ensure that the dependencies array is correct. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + [series.heatmap, ...seriesIds], + ); +} diff --git a/packages/x-charts-pro/src/hooks/useSeries.ts b/packages/x-charts-pro/src/hooks/useSeries.ts deleted file mode 100644 index 6a150b390d983..0000000000000 --- a/packages/x-charts-pro/src/hooks/useSeries.ts +++ /dev/null @@ -1,16 +0,0 @@ -'use client'; -import * as React from 'react'; -import { useSeries, ProcessedSeries } from '@mui/x-charts/internals'; - -/** - * Get access to the internal state of heatmap series. - * The returned object contains: - * - series: a mapping from ids to series attributes. - * - seriesOrder: the array of series ids. - * @returns { series: Record; seriesOrder: SeriesId[]; } | undefined heatmapSeries - */ -export function useHeatmapSeries(): ProcessedSeries['heatmap'] { - const series = useSeries(); - - return React.useMemo(() => series.heatmap, [series.heatmap]); -} diff --git a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx index 1620c8b41b177..2a3740846d018 100644 --- a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx +++ b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx @@ -8,7 +8,7 @@ import { useStore } from '../internals/store/useStore'; import { getSVGPoint } from '../internals/getSVGPoint'; import { ScatterItemIdentifier } from '../models'; import { SeriesId } from '../models/seriesType/common'; -import { useScatterSeries } from '../hooks/useSeries'; +import { useScatterSeries } from '../hooks/useScatterSeries'; import { useChartContext } from '../context/ChartProvider/useChartContext'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { useSvgRef } from '../hooks/useSvgRef'; diff --git a/packages/x-charts/src/hooks/useBarSeries.test.ts b/packages/x-charts/src/hooks/useBarSeries.test.ts index 68845b8e31c6c..5cd1f01c96e9c 100644 --- a/packages/x-charts/src/hooks/useBarSeries.test.ts +++ b/packages/x-charts/src/hooks/useBarSeries.test.ts @@ -4,7 +4,7 @@ import { stub, restore } from 'sinon'; import { useBarSeries } from './useBarSeries'; import * as series from './useSeries'; import { SeriesId } from '../models/seriesType/common'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; describe('useBarSeries', () => { const defaultProps = { @@ -15,7 +15,7 @@ describe('useBarSeries', () => { stackedData: [] as [number, number][], } as const; - const mockSeries: FormattedSeries = { + const mockSeries: ProcessedSeries = { bar: { series: { '1': { ...defaultProps, id: '1', data: [1, 2, 3] }, diff --git a/packages/x-charts/src/hooks/useBarSeries.ts b/packages/x-charts/src/hooks/useBarSeries.ts index 020856eb9edd9..39c8334870865 100644 --- a/packages/x-charts/src/hooks/useBarSeries.ts +++ b/packages/x-charts/src/hooks/useBarSeries.ts @@ -1,6 +1,6 @@ 'use client'; import * as React from 'react'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; import { useSeries } from './useSeries'; @@ -12,7 +12,7 @@ import { useSeries } from './useSeries'; * - seriesOrder: the array of series ids. * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} barSeries */ -export function useBarSeries(): FormattedSeries['bar']; +export function useBarSeries(): ProcessedSeries['bar']; /** * Get access to the internal state of bar series. * diff --git a/packages/x-charts/src/hooks/useLineSeries.test.ts b/packages/x-charts/src/hooks/useLineSeries.test.ts index 2b7f6085ef645..73c3fc20e2c03 100644 --- a/packages/x-charts/src/hooks/useLineSeries.test.ts +++ b/packages/x-charts/src/hooks/useLineSeries.test.ts @@ -4,7 +4,7 @@ import { stub, restore } from 'sinon'; import { useLineSeries } from './useLineSeries'; import * as series from './useSeries'; import { SeriesId } from '../models/seriesType/common'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; describe('useLineSeries', () => { const defaultProps = { @@ -15,7 +15,7 @@ describe('useLineSeries', () => { stackedData: [] as [number, number][], } as const; - const mockSeries: FormattedSeries = { + const mockSeries: ProcessedSeries = { line: { series: { '1': { ...defaultProps, id: '1', data: [1, 2, 3] }, diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts index a3198ba92f8d5..e156bace87bf4 100644 --- a/packages/x-charts/src/hooks/useLineSeries.ts +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -1,6 +1,6 @@ 'use client'; import * as React from 'react'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; import { useSeries } from './useSeries'; @@ -12,7 +12,7 @@ import { useSeries } from './useSeries'; * - seriesOrder: the array of series ids. * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} lineSeries */ -export function useLineSeries(): FormattedSeries['line']; +export function useLineSeries(): ProcessedSeries['line']; /** * Get access to the internal state of line series. * diff --git a/packages/x-charts/src/hooks/usePieSeries.test.ts b/packages/x-charts/src/hooks/usePieSeries.test.ts index 80dd3bc743bdd..523d54337d5ef 100644 --- a/packages/x-charts/src/hooks/usePieSeries.test.ts +++ b/packages/x-charts/src/hooks/usePieSeries.test.ts @@ -4,7 +4,7 @@ import { stub, restore } from 'sinon'; import { usePieSeries } from './usePieSeries'; import * as series from './useSeries'; import { SeriesId } from '../models/seriesType/common'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; describe('usePieSeries', () => { const defaultProps = { @@ -26,7 +26,7 @@ describe('usePieSeries', () => { padAngle: 0, } as const; - const mockSeries: FormattedSeries = { + const mockSeries: ProcessedSeries = { pie: { series: { '1': { ...defaultProps, id: '1', data: [dataExample] }, diff --git a/packages/x-charts/src/hooks/usePieSeries.ts b/packages/x-charts/src/hooks/usePieSeries.ts index 56592a621754b..265ff7c949950 100644 --- a/packages/x-charts/src/hooks/usePieSeries.ts +++ b/packages/x-charts/src/hooks/usePieSeries.ts @@ -1,6 +1,6 @@ 'use client'; import * as React from 'react'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; import { useSeries } from './useSeries'; @@ -12,7 +12,7 @@ import { useSeries } from './useSeries'; * - seriesOrder: the array of series ids. * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} pieSeries */ -export function usePieSeries(): FormattedSeries['pie']; +export function usePieSeries(): ProcessedSeries['pie']; /** * Get access to the internal state of pie series. * diff --git a/packages/x-charts/src/hooks/useScatterSeries.test.ts b/packages/x-charts/src/hooks/useScatterSeries.test.ts index 4113b4192b955..031cb84ba3880 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.test.ts +++ b/packages/x-charts/src/hooks/useScatterSeries.test.ts @@ -4,7 +4,7 @@ import { stub, restore } from 'sinon'; import { useScatterSeries } from './useScatterSeries'; import * as series from './useSeries'; import { SeriesId } from '../models/seriesType/common'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; describe('useScatterSeries', () => { const defaultProps = { @@ -14,7 +14,7 @@ describe('useScatterSeries', () => { type: 'scatter', } as const; - const mockSeries: FormattedSeries = { + const mockSeries: ProcessedSeries = { scatter: { series: { '1': { diff --git a/packages/x-charts/src/hooks/useScatterSeries.ts b/packages/x-charts/src/hooks/useScatterSeries.ts index 538c5f390e356..5915dd40d175a 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.ts +++ b/packages/x-charts/src/hooks/useScatterSeries.ts @@ -1,6 +1,6 @@ 'use client'; import * as React from 'react'; -import { FormattedSeries } from '../context/SeriesProvider'; +import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; import { useSeries } from './useSeries'; @@ -12,7 +12,7 @@ import { useSeries } from './useSeries'; * - seriesOrder: the array of series ids. * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} scatterSeries */ -export function useScatterSeries(): FormattedSeries['scatter']; +export function useScatterSeries(): ProcessedSeries['scatter']; /** * Get access to the internal state of scatter series. * From 247c6f35aee02eca6cf215028db9d45b265be90f Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 7 Feb 2025 19:27:21 +0100 Subject: [PATCH 03/12] fix multiple exports --- packages/x-charts/src/hooks/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/x-charts/src/hooks/index.ts b/packages/x-charts/src/hooks/index.ts index 12d2ccb3fadae..2b60e7ce7b78e 100644 --- a/packages/x-charts/src/hooks/index.ts +++ b/packages/x-charts/src/hooks/index.ts @@ -12,6 +12,5 @@ export * from './useBarSeries'; export * from './useLineSeries'; export * from './useItemHighlighted'; export * from './useItemHighlightedGetter'; -export { useSeries } from './useSeries'; export * from './useLegend'; export { useChartGradientId, useChartGradientIdObjectBound } from './useChartGradientId'; From 10219b3ebd46cab945cd9c40cf1abb4d1313d0df Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 7 Feb 2025 19:41:42 +0100 Subject: [PATCH 04/12] deduplicate behaviour --- .../src/hooks/useHeatmapSeries.ts | 23 ++------------- packages/x-charts/src/hooks/useBarSeries.ts | 23 ++------------- packages/x-charts/src/hooks/useLineSeries.ts | 23 ++------------- packages/x-charts/src/hooks/usePieSeries.ts | 23 ++------------- .../x-charts/src/hooks/useScatterSeries.ts | 23 ++------------- packages/x-charts/src/internals/index.ts | 1 + .../x-charts/src/internals/useSeriesOfType.ts | 29 +++++++++++++++++++ 7 files changed, 40 insertions(+), 105 deletions(-) create mode 100644 packages/x-charts/src/internals/useSeriesOfType.ts diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts index 90b534ea39958..27c74f8bd998c 100644 --- a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts @@ -1,7 +1,6 @@ 'use client'; -import * as React from 'react'; import { - useSeries, + useSeriesOfType, ProcessedSeries, SeriesId, ChartSeriesDefaultized, @@ -30,23 +29,5 @@ export function useHeatmapSeries(seriesId: SeriesId): ChartSeriesDefaultized<'he */ export function useHeatmapSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'heatmap'>[]; export function useHeatmapSeries(...seriesIds: SeriesId[]): any { - const series = useSeries(); - - return React.useMemo( - () => { - if (seriesIds.length === 0) { - return series.heatmap; - } - - if (seriesIds.length === 1) { - return series?.heatmap?.series[seriesIds[0]]; - } - - return seriesIds.map((id) => series?.heatmap?.series[id]).filter(Boolean); - }, - // DANGER: Ensure that the dependencies array is correct. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [series.heatmap, ...seriesIds], - ); + return useSeriesOfType('heatmap', ...seriesIds); } diff --git a/packages/x-charts/src/hooks/useBarSeries.ts b/packages/x-charts/src/hooks/useBarSeries.ts index 39c8334870865..f6b72ad0587ff 100644 --- a/packages/x-charts/src/hooks/useBarSeries.ts +++ b/packages/x-charts/src/hooks/useBarSeries.ts @@ -1,9 +1,8 @@ 'use client'; -import * as React from 'react'; import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeries } from './useSeries'; +import { useSeriesOfType } from '../internals/useSeriesOfType'; /** * Get access to the internal state of bar series. @@ -28,23 +27,5 @@ export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'>; */ export function useBarSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'bar'>[]; export function useBarSeries(...seriesIds: SeriesId[]): any { - const series = useSeries(); - - return React.useMemo( - () => { - if (seriesIds.length === 0) { - return series.bar; - } - - if (seriesIds.length === 1) { - return series?.bar?.series[seriesIds[0]]; - } - - return seriesIds.map((id) => series?.bar?.series[id]).filter(Boolean); - }, - // DANGER: Ensure that the dependencies array is correct. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [series.bar, ...seriesIds], - ); + return useSeriesOfType('bar', ...seriesIds); } diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts index e156bace87bf4..1f9f60d573285 100644 --- a/packages/x-charts/src/hooks/useLineSeries.ts +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -1,9 +1,8 @@ 'use client'; -import * as React from 'react'; import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeries } from './useSeries'; +import { useSeriesOfType } from '../internals/useSeriesOfType'; /** * Get access to the internal state of line series. @@ -28,23 +27,5 @@ export function useLineSeries(seriesId: SeriesId): ChartSeriesDefaultized<'line' */ export function useLineSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'line'>[]; export function useLineSeries(...seriesIds: SeriesId[]): any { - const series = useSeries(); - - return React.useMemo( - () => { - if (seriesIds.length === 0) { - return series.line; - } - - if (seriesIds.length === 1) { - return series?.line?.series[seriesIds[0]]; - } - - return seriesIds.map((id) => series?.line?.series[id]).filter(Boolean); - }, - // DANGER: Ensure that the dependencies array is correct. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [series.line, ...seriesIds], - ); + return useSeriesOfType('line', ...seriesIds); } diff --git a/packages/x-charts/src/hooks/usePieSeries.ts b/packages/x-charts/src/hooks/usePieSeries.ts index 265ff7c949950..5547354d354b8 100644 --- a/packages/x-charts/src/hooks/usePieSeries.ts +++ b/packages/x-charts/src/hooks/usePieSeries.ts @@ -1,9 +1,8 @@ 'use client'; -import * as React from 'react'; import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeries } from './useSeries'; +import { useSeriesOfType } from '../internals/useSeriesOfType'; /** * Get access to the internal state of pie series. @@ -28,23 +27,5 @@ export function usePieSeries(seriesId: SeriesId): ChartSeriesDefaultized<'pie'>; */ export function usePieSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'pie'>[]; export function usePieSeries(...seriesIds: SeriesId[]): any { - const series = useSeries(); - - return React.useMemo( - () => { - if (seriesIds.length === 0) { - return series.pie; - } - - if (seriesIds.length === 1) { - return series?.pie?.series[seriesIds[0]]; - } - - return seriesIds.map((id) => series?.pie?.series[id]).filter(Boolean); - }, - // DANGER: Ensure that the dependencies array is correct. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [series.pie, ...seriesIds], - ); + return useSeriesOfType('pie', ...seriesIds); } diff --git a/packages/x-charts/src/hooks/useScatterSeries.ts b/packages/x-charts/src/hooks/useScatterSeries.ts index 5915dd40d175a..2ab00186fd203 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.ts +++ b/packages/x-charts/src/hooks/useScatterSeries.ts @@ -1,9 +1,8 @@ 'use client'; -import * as React from 'react'; import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeries } from './useSeries'; +import { useSeriesOfType } from '../internals/useSeriesOfType'; /** * Get access to the internal state of scatter series. @@ -28,23 +27,5 @@ export function useScatterSeries(seriesId: SeriesId): ChartSeriesDefaultized<'sc */ export function useScatterSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'scatter'>[]; export function useScatterSeries(...seriesIds: SeriesId[]): any { - const series = useSeries(); - - return React.useMemo( - () => { - if (seriesIds.length === 0) { - return series.scatter; - } - - if (seriesIds.length === 1) { - return series?.scatter?.series[seriesIds[0]]; - } - - return seriesIds.map((id) => series?.scatter?.series[id]).filter(Boolean); - }, - // DANGER: Ensure that the dependencies array is correct. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [series.pie, ...seriesIds], - ); + return useSeriesOfType('scatter', ...seriesIds); } diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index 1b03a08bce6ea..28894728cf4d8 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -12,6 +12,7 @@ export { useLineChartProps } from '../LineChart/useLineChartProps'; export { useBarChartProps } from '../BarChart/useBarChartProps'; export * from '../ChartContainer/useChartContainerProps'; export * from '../ChartDataProvider/useChartDataProviderProps'; +export * from './useSeriesOfType'; // plugins export * from './plugins/corePlugins/useChartId'; diff --git a/packages/x-charts/src/internals/useSeriesOfType.ts b/packages/x-charts/src/internals/useSeriesOfType.ts new file mode 100644 index 0000000000000..382bd0daae952 --- /dev/null +++ b/packages/x-charts/src/internals/useSeriesOfType.ts @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { ChartsSeriesConfig } from '../models/seriesType/config'; +import { SeriesId } from '../models/seriesType/common'; +import { useSeries } from '../hooks'; + +export function useSeriesOfType( + seriesType: T, + ...seriesIds: SeriesId[] +) { + const series = useSeries(); + + return React.useMemo( + () => { + if (seriesIds.length === 0) { + return series[seriesType]; + } + + if (seriesIds.length === 1) { + return series?.[seriesType]?.series[seriesIds[0]]; + } + + return seriesIds.map((id) => series?.[seriesType]?.series[id]).filter(Boolean); + }, + // DANGER: Ensure that the dependencies array is correct. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + [series[seriesType], ...seriesIds], + ); +} From 7a9241fa83972b6084e36e4f16d5bb5086f8eabe Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 7 Feb 2025 19:43:14 +0100 Subject: [PATCH 05/12] fix cycle --- packages/x-charts/src/internals/useSeriesOfType.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-charts/src/internals/useSeriesOfType.ts b/packages/x-charts/src/internals/useSeriesOfType.ts index 382bd0daae952..13d76a8f474ec 100644 --- a/packages/x-charts/src/internals/useSeriesOfType.ts +++ b/packages/x-charts/src/internals/useSeriesOfType.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { ChartsSeriesConfig } from '../models/seriesType/config'; import { SeriesId } from '../models/seriesType/common'; -import { useSeries } from '../hooks'; +import { useSeries } from '../hooks/useSeries'; export function useSeriesOfType( seriesType: T, From bbbcc3ee9af1c5f663e59dd09f27f7fbf75dfb63 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Mon, 10 Feb 2025 15:28:23 +0100 Subject: [PATCH 06/12] naming --- packages/x-charts/src/hooks/useAxis.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/x-charts/src/hooks/useAxis.ts b/packages/x-charts/src/hooks/useAxis.ts index bd2fabd7471af..6ff78f947d68e 100644 --- a/packages/x-charts/src/hooks/useAxis.ts +++ b/packages/x-charts/src/hooks/useAxis.ts @@ -9,14 +9,14 @@ import { useStore } from '../internals/store/useStore'; import { AxisId } from '../models/axis'; /** - * Get all the X axes. + * Get all the x-axes. * * - `xAxis` is an object with the shape `{ [axisId]: axis }`. * - `xAxisIds` is an array of axis IDs. * * If access to a specific X axis is needed, use the `useXAxis` hook instead. * - * @returns `{ xAxis, xAxisIds }` - The X axes and their IDs. + * @returns `{ xAxis, xAxisIds }` - The x-axes and their IDs. */ export function useXAxes() { const store = useStore<[UseChartCartesianAxisSignature]>(); @@ -26,14 +26,14 @@ export function useXAxes() { } /** - * Get all the Y axes. + * Get all the y-axes. * * - `yAxis` is an object with the shape `{ [axisId]: axis }`. * - `yAxisIds` is an array of axis IDs. * * If access to a specific Y axis is needed, use the `useYAxis` hook instead. * - * @returns `{ yAxis, yAxisIds }` - The Y axes and their IDs. + * @returns `{ yAxis, yAxisIds }` - The y-axes and their IDs. */ export function useYAxes() { const store = useStore<[UseChartCartesianAxisSignature]>(); From 63fa80cf4d47fd0125be165771ad82b25a9f125b Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Mon, 10 Feb 2025 19:12:07 +0100 Subject: [PATCH 07/12] fixbehavior and tests to use selectors --- .../src/hooks/useHeatmapSeries.test.ts | 72 ------------------- .../src/hooks/useHeatmapSeries.test.tsx | 64 +++++++++++++++++ .../src/hooks/useHeatmapSeries.ts | 14 ++-- .../x-charts/src/hooks/useBarSeries.test.ts | 59 --------------- .../x-charts/src/hooks/useBarSeries.test.tsx | 54 ++++++++++++++ packages/x-charts/src/hooks/useBarSeries.ts | 12 ++-- .../x-charts/src/hooks/useLineSeries.test.ts | 59 --------------- .../x-charts/src/hooks/useLineSeries.test.tsx | 54 ++++++++++++++ packages/x-charts/src/hooks/useLineSeries.ts | 12 ++-- .../x-charts/src/hooks/usePieSeries.test.ts | 69 ------------------ .../x-charts/src/hooks/usePieSeries.test.tsx | 54 ++++++++++++++ packages/x-charts/src/hooks/usePieSeries.ts | 12 ++-- .../src/hooks/useScatterSeries.test.ts | 71 ------------------ .../src/hooks/useScatterSeries.test.tsx | 60 ++++++++++++++++ .../x-charts/src/hooks/useScatterSeries.ts | 12 ++-- .../internals/createSeriesSelectorOfType.ts | 29 ++++++++ packages/x-charts/src/internals/index.ts | 2 +- .../x-charts/src/internals/useSeriesOfType.ts | 29 -------- 18 files changed, 357 insertions(+), 381 deletions(-) delete mode 100644 packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts create mode 100644 packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx delete mode 100644 packages/x-charts/src/hooks/useBarSeries.test.ts create mode 100644 packages/x-charts/src/hooks/useBarSeries.test.tsx delete mode 100644 packages/x-charts/src/hooks/useLineSeries.test.ts create mode 100644 packages/x-charts/src/hooks/useLineSeries.test.tsx delete mode 100644 packages/x-charts/src/hooks/usePieSeries.test.ts create mode 100644 packages/x-charts/src/hooks/usePieSeries.test.tsx delete mode 100644 packages/x-charts/src/hooks/useScatterSeries.test.ts create mode 100644 packages/x-charts/src/hooks/useScatterSeries.test.tsx create mode 100644 packages/x-charts/src/internals/createSeriesSelectorOfType.ts delete mode 100644 packages/x-charts/src/internals/useSeriesOfType.ts diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts deleted file mode 100644 index 39b9f92bbf3c1..0000000000000 --- a/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { renderHook } from '@mui/internal-test-utils'; -import { expect } from 'chai'; -import { stub, restore } from 'sinon'; -import type { SeriesId, ProcessedSeries } from '@mui/x-charts/internals'; -import * as series from '@mui/x-charts/hooks/useSeries'; -import { useHeatmapSeries } from './useHeatmapSeries'; - -describe('useHeatmapSeries', () => { - const defaultProps = { - valueFormatter: (v: any) => v, - color: 'red', - layout: 'vertical', - type: 'heatmap', - } as const; - - const mockSeries: ProcessedSeries = { - heatmap: { - series: { - '1': { - ...defaultProps, - id: '1', - data: [ - [0, 0, 10], - [0, 1, 20], - [0, 2, 40], - ], - }, - '2': { - ...defaultProps, - id: '2', - data: [ - [3, 2, 20], - [3, 3, 70], - [3, 4, 90], - ], - }, - }, - seriesOrder: ['1', '2'], - }, - }; - - beforeEach(() => { - stub(series, 'useSeries').returns(mockSeries); - }); - - afterEach(() => { - restore(); - }); - - it('should return all heatmap series when no seriesIds are provided', () => { - const { result } = renderHook(() => useHeatmapSeries()); - expect(result.current).to.deep.equal(mockSeries.heatmap); - }); - - it('should return the specific heatmap series when a single seriesId is provided', () => { - const { result } = renderHook(() => useHeatmapSeries('1' as SeriesId)); - expect(result.current).to.deep.equal(mockSeries!.heatmap!.series['1']); - }); - - it('should return the specific heatmap series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useHeatmapSeries('1' as SeriesId, '2' as SeriesId)); - expect(result.current).to.deep.equal([ - mockSeries!.heatmap!.series['1'], - mockSeries!.heatmap!.series['2'], - ]); - }); - - it('should filter out undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useHeatmapSeries('1' as SeriesId, '3' as SeriesId)); - expect(result.current).to.deep.equal([mockSeries!.heatmap!.series['1']]); - }); -}); diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx b/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx new file mode 100644 index 0000000000000..272dbba0b1eca --- /dev/null +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx @@ -0,0 +1,64 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import * as React from 'react'; +import { useHeatmapSeries } from './useHeatmapSeries'; +import { Heatmap } from '../Heatmap'; +import { HeatmapSeriesType } from '../models'; + +describe('useHeatmapSeries', () => { + const mockSeries: HeatmapSeriesType[] = [ + { + type: 'heatmap', + id: '1', + data: [ + [0, 0, 10], + [0, 1, 20], + [0, 2, 40], + ], + }, + { + type: 'heatmap', + id: '2', + data: [ + [3, 2, 20], + [3, 3, 70], + [3, 4, 90], + ], + }, + ]; + + const defaultProps = { + series: mockSeries, + height: 400, + width: 400, + xAxis: [{ data: [1, 2, 3, 4] }], + yAxis: [{ data: ['A', 'B', 'C', 'D', 'E'] }], + }; + + const options: any = { + wrapper: ({ children }: { children: React.ReactElement }) => { + return {children}; + }, + }; + + it('should return all heatmap series when no seriesIds are provided', () => { + const { result } = renderHook(() => useHeatmapSeries(), options); + expect(result.current?.seriesOrder).to.deep.equal(['1', '2']); + expect(Object.keys(result.current?.series ?? {})).to.deep.equal(['1', '2']); + }); + + it('should return the specific heatmap series when a single seriesId is provided', () => { + const { result } = renderHook(() => useHeatmapSeries('1'), options); + expect(result.current?.id).to.deep.equal(mockSeries[0].id); + }); + + it('should return the specific heatmap series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useHeatmapSeries('2', '1'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); + }); + + it('should return undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useHeatmapSeries('1', '3'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); + }); +}); diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts index 27c74f8bd998c..3cccf67df7394 100644 --- a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts @@ -1,17 +1,19 @@ 'use client'; import { - useSeriesOfType, + createSeriesSelectorsOfType, ProcessedSeries, SeriesId, ChartSeriesDefaultized, } from '@mui/x-charts/internals'; +const selectorSeries = createSeriesSelectorsOfType('heatmap'); + /** * Get access to the internal state of heatmap series. * The returned object contains: * - series: a mapping from ids to series attributes. * - seriesOrder: the array of series ids. - * @returns { series: Record; seriesOrder: SeriesId[]; } | undefined heatmapSeries + * @returns {{ series: Record; seriesOrder: SeriesId[]; } | undefined} heatmapSeries */ export function useHeatmapSeries(): ProcessedSeries['heatmap']; /** @@ -20,14 +22,16 @@ export function useHeatmapSeries(): ProcessedSeries['heatmap']; * @param {SeriesId} seriesId The id of the series to get. * @returns {ChartSeriesDefaultized<'heatmap'> | undefined} heatmapSeries */ -export function useHeatmapSeries(seriesId: SeriesId): ChartSeriesDefaultized<'heatmap'>; +export function useHeatmapSeries(seriesId: SeriesId): ChartSeriesDefaultized<'heatmap'> | undefined; /** * Get access to the internal state of heatmap series. * * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {ChartSeriesDefaultized<'heatmap'>[] | undefined} heatmapSeries */ -export function useHeatmapSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'heatmap'>[]; +export function useHeatmapSeries( + ...seriesIds: SeriesId[] +): (ChartSeriesDefaultized<'heatmap'> | undefined)[]; export function useHeatmapSeries(...seriesIds: SeriesId[]): any { - return useSeriesOfType('heatmap', ...seriesIds); + return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useBarSeries.test.ts b/packages/x-charts/src/hooks/useBarSeries.test.ts deleted file mode 100644 index 5cd1f01c96e9c..0000000000000 --- a/packages/x-charts/src/hooks/useBarSeries.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { renderHook } from '@mui/internal-test-utils'; -import { expect } from 'chai'; -import { stub, restore } from 'sinon'; -import { useBarSeries } from './useBarSeries'; -import * as series from './useSeries'; -import { SeriesId } from '../models/seriesType/common'; -import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; - -describe('useBarSeries', () => { - const defaultProps = { - valueFormatter: (v: any) => v, - color: 'red', - layout: 'vertical', - type: 'bar', - stackedData: [] as [number, number][], - } as const; - - const mockSeries: ProcessedSeries = { - bar: { - series: { - '1': { ...defaultProps, id: '1', data: [1, 2, 3] }, - '2': { ...defaultProps, id: '2', data: [4, 5, 6] }, - }, - seriesOrder: ['1', '2'], - stackingGroups: [], - }, - }; - - beforeEach(() => { - stub(series, 'useSeries').returns(mockSeries); - }); - - afterEach(() => { - restore(); - }); - - it('should return all bar series when no seriesIds are provided', () => { - const { result } = renderHook(() => useBarSeries()); - expect(result.current).to.deep.equal(mockSeries.bar); - }); - - it('should return the specific bar series when a single seriesId is provided', () => { - const { result } = renderHook(() => useBarSeries('1' as SeriesId)); - expect(result.current).to.deep.equal(mockSeries!.bar!.series['1']); - }); - - it('should return the specific bar series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useBarSeries('1' as SeriesId, '2' as SeriesId)); - expect(result.current).to.deep.equal([ - mockSeries!.bar!.series['1'], - mockSeries!.bar!.series['2'], - ]); - }); - - it('should filter out undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useBarSeries('1' as SeriesId, '3' as SeriesId)); - expect(result.current).to.deep.equal([mockSeries!.bar!.series['1']]); - }); -}); diff --git a/packages/x-charts/src/hooks/useBarSeries.test.tsx b/packages/x-charts/src/hooks/useBarSeries.test.tsx new file mode 100644 index 0000000000000..5969599ac9c52 --- /dev/null +++ b/packages/x-charts/src/hooks/useBarSeries.test.tsx @@ -0,0 +1,54 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import * as React from 'react'; +import { useBarSeries } from './useBarSeries'; +import { BarSeriesType } from '../models'; +import { BarChart } from '../BarChart'; + +describe('useBarSeries', () => { + const mockSeries: BarSeriesType[] = [ + { + type: 'bar', + id: '1', + data: [1, 2, 3], + }, + { + type: 'bar', + id: '2', + data: [4, 5, 6], + }, + ]; + + const defaultProps = { + series: mockSeries, + height: 400, + width: 400, + }; + + const options: any = { + wrapper: ({ children }: { children: React.ReactElement }) => { + return {children}; + }, + }; + + it('should return all bar series when no seriesIds are provided', () => { + const { result } = renderHook(() => useBarSeries(), options); + expect(result.current?.seriesOrder).to.deep.equal(['1', '2']); + expect(Object.keys(result.current?.series ?? {})).to.deep.equal(['1', '2']); + }); + + it('should return the specific bar series when a single seriesId is provided', () => { + const { result } = renderHook(() => useBarSeries('1'), options); + expect(result.current?.id).to.deep.equal(mockSeries[0].id); + }); + + it('should return the specific bar series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useBarSeries('2', '1'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); + }); + + it('should return undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useBarSeries('1', '3'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); + }); +}); diff --git a/packages/x-charts/src/hooks/useBarSeries.ts b/packages/x-charts/src/hooks/useBarSeries.ts index f6b72ad0587ff..e4ed43c768eff 100644 --- a/packages/x-charts/src/hooks/useBarSeries.ts +++ b/packages/x-charts/src/hooks/useBarSeries.ts @@ -2,7 +2,9 @@ import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeriesOfType } from '../internals/useSeriesOfType'; +import { createSeriesSelectorsOfType } from '../internals/createSeriesSelectorOfType'; + +const selectorSeries = createSeriesSelectorsOfType('bar'); /** * Get access to the internal state of bar series. @@ -18,14 +20,16 @@ export function useBarSeries(): ProcessedSeries['bar']; * @param {SeriesId} seriesId The id of the series to get. * @returns {ChartSeriesDefaultized<'bar'> | undefined} barSeries */ -export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'>; +export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'> | undefined; /** * Get access to the internal state of bar series. * * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {ChartSeriesDefaultized<'bar'>[] | undefined} barSeries */ -export function useBarSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'bar'>[]; +export function useBarSeries( + ...seriesIds: SeriesId[] +): (ChartSeriesDefaultized<'bar'> | undefined)[]; export function useBarSeries(...seriesIds: SeriesId[]): any { - return useSeriesOfType('bar', ...seriesIds); + return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useLineSeries.test.ts b/packages/x-charts/src/hooks/useLineSeries.test.ts deleted file mode 100644 index 73c3fc20e2c03..0000000000000 --- a/packages/x-charts/src/hooks/useLineSeries.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { renderHook } from '@mui/internal-test-utils'; -import { expect } from 'chai'; -import { stub, restore } from 'sinon'; -import { useLineSeries } from './useLineSeries'; -import * as series from './useSeries'; -import { SeriesId } from '../models/seriesType/common'; -import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; - -describe('useLineSeries', () => { - const defaultProps = { - valueFormatter: (v: any) => v, - color: 'red', - layout: 'vertical', - type: 'line', - stackedData: [] as [number, number][], - } as const; - - const mockSeries: ProcessedSeries = { - line: { - series: { - '1': { ...defaultProps, id: '1', data: [1, 2, 3] }, - '2': { ...defaultProps, id: '2', data: [4, 5, 6] }, - }, - seriesOrder: ['1', '2'], - stackingGroups: [], - }, - }; - - beforeEach(() => { - stub(series, 'useSeries').returns(mockSeries); - }); - - afterEach(() => { - restore(); - }); - - it('should return all line series when no seriesIds are provided', () => { - const { result } = renderHook(() => useLineSeries()); - expect(result.current).to.deep.equal(mockSeries.line); - }); - - it('should return the specific line series when a single seriesId is provided', () => { - const { result } = renderHook(() => useLineSeries('1' as SeriesId)); - expect(result.current).to.deep.equal(mockSeries!.line!.series['1']); - }); - - it('should return the specific line series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useLineSeries('1' as SeriesId, '2' as SeriesId)); - expect(result.current).to.deep.equal([ - mockSeries!.line!.series['1'], - mockSeries!.line!.series['2'], - ]); - }); - - it('should filter out undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useLineSeries('1' as SeriesId, '3' as SeriesId)); - expect(result.current).to.deep.equal([mockSeries!.line!.series['1']]); - }); -}); diff --git a/packages/x-charts/src/hooks/useLineSeries.test.tsx b/packages/x-charts/src/hooks/useLineSeries.test.tsx new file mode 100644 index 0000000000000..d9823243b0b8e --- /dev/null +++ b/packages/x-charts/src/hooks/useLineSeries.test.tsx @@ -0,0 +1,54 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import * as React from 'react'; +import { useLineSeries } from './useLineSeries'; +import { LineSeriesType } from '../models'; +import { LineChart } from '../LineChart'; + +describe('useLineSeries', () => { + const mockSeries: LineSeriesType[] = [ + { + type: 'line', + id: '1', + data: [1, 2, 3], + }, + { + type: 'line', + id: '2', + data: [4, 5, 6], + }, + ]; + + const defaultProps = { + series: mockSeries, + height: 400, + width: 400, + }; + + const options: any = { + wrapper: ({ children }: { children: React.ReactElement }) => { + return {children}; + }, + }; + + it('should return all line series when no seriesIds are provided', () => { + const { result } = renderHook(() => useLineSeries(), options); + expect(result.current?.seriesOrder).to.deep.equal(['1', '2']); + expect(Object.keys(result.current?.series ?? {})).to.deep.equal(['1', '2']); + }); + + it('should return the specific line series when a single seriesId is provided', () => { + const { result } = renderHook(() => useLineSeries('1'), options); + expect(result.current?.id).to.deep.equal(mockSeries[0].id); + }); + + it('should return the specific line series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useLineSeries('2', '1'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); + }); + + it('should return undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useLineSeries('1', '3'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); + }); +}); diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts index 1f9f60d573285..535664fa1ebab 100644 --- a/packages/x-charts/src/hooks/useLineSeries.ts +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -2,7 +2,9 @@ import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeriesOfType } from '../internals/useSeriesOfType'; +import { createSeriesSelectorsOfType } from '../internals/createSeriesSelectorOfType'; + +const selectorSeries = createSeriesSelectorsOfType('line'); /** * Get access to the internal state of line series. @@ -18,14 +20,16 @@ export function useLineSeries(): ProcessedSeries['line']; * @param {SeriesId} seriesId The id of the series to get. * @returns {ChartSeriesDefaultized<'line'> | undefined} lineSeries */ -export function useLineSeries(seriesId: SeriesId): ChartSeriesDefaultized<'line'>; +export function useLineSeries(seriesId: SeriesId): ChartSeriesDefaultized<'line'> | undefined; /** * Get access to the internal state of line series. * * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {ChartSeriesDefaultized<'line'>[] | undefined} lineSeries */ -export function useLineSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'line'>[]; +export function useLineSeries( + ...seriesIds: SeriesId[] +): (ChartSeriesDefaultized<'line'> | undefined)[]; export function useLineSeries(...seriesIds: SeriesId[]): any { - return useSeriesOfType('line', ...seriesIds); + return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/usePieSeries.test.ts b/packages/x-charts/src/hooks/usePieSeries.test.ts deleted file mode 100644 index 523d54337d5ef..0000000000000 --- a/packages/x-charts/src/hooks/usePieSeries.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { renderHook } from '@mui/internal-test-utils'; -import { expect } from 'chai'; -import { stub, restore } from 'sinon'; -import { usePieSeries } from './usePieSeries'; -import * as series from './useSeries'; -import { SeriesId } from '../models/seriesType/common'; -import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; - -describe('usePieSeries', () => { - const defaultProps = { - valueFormatter: (v: any) => v, - color: 'red', - layout: 'vertical', - type: 'pie', - stackedData: [] as [number, number][], - } as const; - - const dataExample = { - id: 1, - value: 10, - startAngle: 0, - endAngle: 1, - color: 'red', - formattedValue: '10', - index: 0, - padAngle: 0, - } as const; - - const mockSeries: ProcessedSeries = { - pie: { - series: { - '1': { ...defaultProps, id: '1', data: [dataExample] }, - '2': { ...defaultProps, id: '2', data: [dataExample] }, - }, - seriesOrder: ['1', '2'], - }, - }; - - beforeEach(() => { - stub(series, 'useSeries').returns(mockSeries); - }); - - afterEach(() => { - restore(); - }); - - it('should return all pie series when no seriesIds are provided', () => { - const { result } = renderHook(() => usePieSeries()); - expect(result.current).to.deep.equal(mockSeries.pie); - }); - - it('should return the specific pie series when a single seriesId is provided', () => { - const { result } = renderHook(() => usePieSeries('1' as SeriesId)); - expect(result.current).to.deep.equal(mockSeries!.pie!.series['1']); - }); - - it('should return the specific pie series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => usePieSeries('1' as SeriesId, '2' as SeriesId)); - expect(result.current).to.deep.equal([ - mockSeries!.pie!.series['1'], - mockSeries!.pie!.series['2'], - ]); - }); - - it('should filter out undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => usePieSeries('1' as SeriesId, '3' as SeriesId)); - expect(result.current).to.deep.equal([mockSeries!.pie!.series['1']]); - }); -}); diff --git a/packages/x-charts/src/hooks/usePieSeries.test.tsx b/packages/x-charts/src/hooks/usePieSeries.test.tsx new file mode 100644 index 0000000000000..be0a29993b566 --- /dev/null +++ b/packages/x-charts/src/hooks/usePieSeries.test.tsx @@ -0,0 +1,54 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import * as React from 'react'; +import { usePieSeries } from './usePieSeries'; +import { PieSeriesType } from '../models'; +import { PieChart } from '../PieChart'; + +describe('usePieSeries', () => { + const mockSeries: PieSeriesType[] = [ + { + type: 'pie', + id: '1', + data: [{ value: 1 }], + }, + { + type: 'pie', + id: '2', + data: [{ value: 1 }], + }, + ]; + + const defaultProps = { + series: mockSeries, + height: 400, + width: 400, + }; + + const options: any = { + wrapper: ({ children }: { children: React.ReactElement }) => { + return {children}; + }, + }; + + it('should return all pie series when no seriesIds are provided', () => { + const { result } = renderHook(() => usePieSeries(), options); + expect(result.current?.seriesOrder).to.deep.equal(['1', '2']); + expect(Object.keys(result.current?.series ?? {})).to.deep.equal(['1', '2']); + }); + + it('should return the specific pie series when a single seriesId is provided', () => { + const { result } = renderHook(() => usePieSeries('1'), options); + expect(result.current?.id).to.deep.equal(mockSeries[0].id); + }); + + it('should return the specific pie series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => usePieSeries('2', '1'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); + }); + + it('should return undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => usePieSeries('1', '3'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); + }); +}); diff --git a/packages/x-charts/src/hooks/usePieSeries.ts b/packages/x-charts/src/hooks/usePieSeries.ts index 5547354d354b8..58bf25ecfde48 100644 --- a/packages/x-charts/src/hooks/usePieSeries.ts +++ b/packages/x-charts/src/hooks/usePieSeries.ts @@ -2,7 +2,9 @@ import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeriesOfType } from '../internals/useSeriesOfType'; +import { createSeriesSelectorsOfType } from '../internals/createSeriesSelectorOfType'; + +const selectorSeries = createSeriesSelectorsOfType('pie'); /** * Get access to the internal state of pie series. @@ -18,14 +20,16 @@ export function usePieSeries(): ProcessedSeries['pie']; * @param {SeriesId} seriesId The id of the series to get. * @returns {ChartSeriesDefaultized<'pie'> | undefined} pieSeries */ -export function usePieSeries(seriesId: SeriesId): ChartSeriesDefaultized<'pie'>; +export function usePieSeries(seriesId: SeriesId): ChartSeriesDefaultized<'pie'> | undefined; /** * Get access to the internal state of pie series. * * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {ChartSeriesDefaultized<'pie'>[] | undefined} pieSeries */ -export function usePieSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'pie'>[]; +export function usePieSeries( + ...seriesIds: SeriesId[] +): (ChartSeriesDefaultized<'pie'> | undefined)[]; export function usePieSeries(...seriesIds: SeriesId[]): any { - return useSeriesOfType('pie', ...seriesIds); + return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useScatterSeries.test.ts b/packages/x-charts/src/hooks/useScatterSeries.test.ts deleted file mode 100644 index 031cb84ba3880..0000000000000 --- a/packages/x-charts/src/hooks/useScatterSeries.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { renderHook } from '@mui/internal-test-utils'; -import { expect } from 'chai'; -import { stub, restore } from 'sinon'; -import { useScatterSeries } from './useScatterSeries'; -import * as series from './useSeries'; -import { SeriesId } from '../models/seriesType/common'; -import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; - -describe('useScatterSeries', () => { - const defaultProps = { - valueFormatter: (v: any) => v, - color: 'red', - layout: 'vertical', - type: 'scatter', - } as const; - - const mockSeries: ProcessedSeries = { - scatter: { - series: { - '1': { - ...defaultProps, - id: '1', - data: [ - { id: 1, x: 1, y: 1 }, - { id: 2, x: 2, y: 2 }, - ], - }, - '2': { - ...defaultProps, - id: '2', - data: [ - { id: 3, x: 3, y: 3 }, - { id: 4, x: 4, y: 4 }, - ], - }, - }, - seriesOrder: ['1', '2'], - }, - }; - - beforeEach(() => { - stub(series, 'useSeries').returns(mockSeries); - }); - - afterEach(() => { - restore(); - }); - - it('should return all scatter series when no seriesIds are provided', () => { - const { result } = renderHook(() => useScatterSeries()); - expect(result.current).to.deep.equal(mockSeries.scatter); - }); - - it('should return the specific scatter series when a single seriesId is provided', () => { - const { result } = renderHook(() => useScatterSeries('1' as SeriesId)); - expect(result.current).to.deep.equal(mockSeries!.scatter!.series['1']); - }); - - it('should return the specific scatter series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useScatterSeries('1' as SeriesId, '2' as SeriesId)); - expect(result.current).to.deep.equal([ - mockSeries!.scatter!.series['1'], - mockSeries!.scatter!.series['2'], - ]); - }); - - it('should filter out undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useScatterSeries('1' as SeriesId, '3' as SeriesId)); - expect(result.current).to.deep.equal([mockSeries!.scatter!.series['1']]); - }); -}); diff --git a/packages/x-charts/src/hooks/useScatterSeries.test.tsx b/packages/x-charts/src/hooks/useScatterSeries.test.tsx new file mode 100644 index 0000000000000..69861d216b567 --- /dev/null +++ b/packages/x-charts/src/hooks/useScatterSeries.test.tsx @@ -0,0 +1,60 @@ +import { renderHook } from '@mui/internal-test-utils'; +import { expect } from 'chai'; +import * as React from 'react'; +import { useScatterSeries } from './useScatterSeries'; +import { ScatterSeriesType } from '../models'; +import { ScatterChart } from '../ScatterChart'; + +describe('useScatterSeries', () => { + const mockSeries: ScatterSeriesType[] = [ + { + type: 'scatter', + id: '1', + data: [ + { id: 1, x: 1, y: 1 }, + { id: 2, x: 2, y: 2 }, + ], + }, + { + type: 'scatter', + id: '2', + data: [ + { id: 3, x: 3, y: 3 }, + { id: 4, x: 4, y: 4 }, + ], + }, + ]; + + const defaultProps = { + series: mockSeries, + height: 400, + width: 400, + }; + + const options: any = { + wrapper: ({ children }: { children: React.ReactElement }) => { + return {children}; + }, + }; + + it('should return all scatter series when no seriesIds are provided', () => { + const { result } = renderHook(() => useScatterSeries(), options); + expect(result.current?.seriesOrder).to.deep.equal(['1', '2']); + expect(Object.keys(result.current?.series ?? {})).to.deep.equal(['1', '2']); + }); + + it('should return the specific scatter series when a single seriesId is provided', () => { + const { result } = renderHook(() => useScatterSeries('1'), options); + expect(result.current?.id).to.deep.equal(mockSeries[0].id); + }); + + it('should return the specific scatter series when multiple seriesIds are provided', () => { + const { result } = renderHook(() => useScatterSeries('2', '1'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); + }); + + it('should return undefined series when invalid seriesIds are provided', () => { + const { result } = renderHook(() => useScatterSeries('1', '3'), options); + expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); + }); +}); diff --git a/packages/x-charts/src/hooks/useScatterSeries.ts b/packages/x-charts/src/hooks/useScatterSeries.ts index 2ab00186fd203..297c5a3ba1e5f 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.ts +++ b/packages/x-charts/src/hooks/useScatterSeries.ts @@ -2,7 +2,9 @@ import { ProcessedSeries } from '../internals/plugins/corePlugins/useChartSeries/useChartSeries.types'; import { SeriesId } from '../models/seriesType/common'; import { ChartSeriesDefaultized } from '../models/seriesType/config'; -import { useSeriesOfType } from '../internals/useSeriesOfType'; +import { createSeriesSelectorsOfType } from '../internals/createSeriesSelectorOfType'; + +const selectorSeries = createSeriesSelectorsOfType('scatter'); /** * Get access to the internal state of scatter series. @@ -18,14 +20,16 @@ export function useScatterSeries(): ProcessedSeries['scatter']; * @param {SeriesId} seriesId The id of the series to get. * @returns {ChartSeriesDefaultized<'scatter'> | undefined} scatterSeries */ -export function useScatterSeries(seriesId: SeriesId): ChartSeriesDefaultized<'scatter'>; +export function useScatterSeries(seriesId: SeriesId): ChartSeriesDefaultized<'scatter'> | undefined; /** * Get access to the internal state of scatter series. * * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {ChartSeriesDefaultized<'scatter'>[] | undefined} scatterSeries */ -export function useScatterSeries(...seriesIds: SeriesId[]): ChartSeriesDefaultized<'scatter'>[]; +export function useScatterSeries( + ...seriesIds: SeriesId[] +): (ChartSeriesDefaultized<'scatter'> | undefined)[]; export function useScatterSeries(...seriesIds: SeriesId[]): any { - return useSeriesOfType('scatter', ...seriesIds); + return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/internals/createSeriesSelectorOfType.ts b/packages/x-charts/src/internals/createSeriesSelectorOfType.ts new file mode 100644 index 0000000000000..8442b8acae734 --- /dev/null +++ b/packages/x-charts/src/internals/createSeriesSelectorOfType.ts @@ -0,0 +1,29 @@ +import { ChartsSeriesConfig } from '../models/seriesType/config'; +import { SeriesId } from '../models/seriesType/common'; +import { createSelector } from './plugins/utils/selectors'; +import { selectorChartSeriesProcessed } from './plugins/corePlugins/useChartSeries/useChartSeries.selectors'; +import { useStore } from './store/useStore'; +import { useSelector } from './store/useSelector'; + +export function createSeriesSelectorsOfType(seriesType: T) { + const selectorSeriesWithIds = createSelector( + [selectorChartSeriesProcessed, (_, ids: SeriesId[]) => ids], + (processedSeries, ids) => { + if (ids.length === 0) { + return processedSeries[seriesType]; + } + + if (ids.length === 1) { + return processedSeries[seriesType]?.series?.[ids[0]]; + } + + return ids.map((id) => processedSeries[seriesType]?.series?.[id]); + }, + ); + + return (ids?: SeriesId[]) => { + const store = useStore(); + + return useSelector(store, selectorSeriesWithIds, ids); + }; +} diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index 28894728cf4d8..a984c39b8435d 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -12,7 +12,7 @@ export { useLineChartProps } from '../LineChart/useLineChartProps'; export { useBarChartProps } from '../BarChart/useBarChartProps'; export * from '../ChartContainer/useChartContainerProps'; export * from '../ChartDataProvider/useChartDataProviderProps'; -export * from './useSeriesOfType'; +export * from './createSeriesSelectorOfType'; // plugins export * from './plugins/corePlugins/useChartId'; diff --git a/packages/x-charts/src/internals/useSeriesOfType.ts b/packages/x-charts/src/internals/useSeriesOfType.ts deleted file mode 100644 index 13d76a8f474ec..0000000000000 --- a/packages/x-charts/src/internals/useSeriesOfType.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { ChartsSeriesConfig } from '../models/seriesType/config'; -import { SeriesId } from '../models/seriesType/common'; -import { useSeries } from '../hooks/useSeries'; - -export function useSeriesOfType( - seriesType: T, - ...seriesIds: SeriesId[] -) { - const series = useSeries(); - - return React.useMemo( - () => { - if (seriesIds.length === 0) { - return series[seriesType]; - } - - if (seriesIds.length === 1) { - return series?.[seriesType]?.series[seriesIds[0]]; - } - - return seriesIds.map((id) => series?.[seriesType]?.series[id]).filter(Boolean); - }, - // DANGER: Ensure that the dependencies array is correct. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - [series[seriesType], ...seriesIds], - ); -} From ebb968e7714f0cd350c21d3f3a59450bbe455bc8 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 11 Feb 2025 12:13:00 +0100 Subject: [PATCH 08/12] add fast array compare --- .../fastArrayCompare/fastArrayCompare.test.ts | 35 +++++++++++++++++++ .../src/fastArrayCompare/fastArrayCompare.ts | 32 +++++++++++++++++ .../x-internals/src/fastArrayCompare/index.ts | 1 + 3 files changed, 68 insertions(+) create mode 100644 packages/x-internals/src/fastArrayCompare/fastArrayCompare.test.ts create mode 100644 packages/x-internals/src/fastArrayCompare/fastArrayCompare.ts create mode 100644 packages/x-internals/src/fastArrayCompare/index.ts diff --git a/packages/x-internals/src/fastArrayCompare/fastArrayCompare.test.ts b/packages/x-internals/src/fastArrayCompare/fastArrayCompare.test.ts new file mode 100644 index 0000000000000..ae0ea91046702 --- /dev/null +++ b/packages/x-internals/src/fastArrayCompare/fastArrayCompare.test.ts @@ -0,0 +1,35 @@ +import { expect } from 'chai'; +import { fastArrayCompare } from './fastArrayCompare'; + +describe('fastArrayCompare', () => { + it('should return true if arrays are equal', () => { + expect(fastArrayCompare([1, 2, 3], [1, 2, 3])).to.equal(true); + }); + + it('should return false if arrays are not equal', () => { + expect(fastArrayCompare([1, 2, 3], [1, 2, 4])).to.equal(false); + }); + + it('should return false if arrays have different lengths', () => { + expect(fastArrayCompare([1, 2, 3], [1, 2])).to.equal(false); + }); + + it('should return false if one of the arguments is not an array', () => { + // @ts-expect-error + expect(fastArrayCompare([1, 2, 3], 1)).to.equal(false); + }); + + it('should return false if both arguments are not an array', () => { + // @ts-expect-error + expect(fastArrayCompare(1, 2)).to.equal(false); + }); + + it('should return true if both arguments are the same array', () => { + const arr = [1, 2, 3]; + expect(fastArrayCompare(arr, arr)).to.equal(true); + }); + + it('should return true if both arguments are empty arrays', () => { + expect(fastArrayCompare([], [])).to.equal(true); + }); +}); diff --git a/packages/x-internals/src/fastArrayCompare/fastArrayCompare.ts b/packages/x-internals/src/fastArrayCompare/fastArrayCompare.ts new file mode 100644 index 0000000000000..b82b0729465bd --- /dev/null +++ b/packages/x-internals/src/fastArrayCompare/fastArrayCompare.ts @@ -0,0 +1,32 @@ +/** + * A fast array comparison function that compares two arrays for equality. + * + * Assumes that the arrays are ordered and contain only primitive values. + * + * It is faster than `fastObjectShallowCompare` for arrays. + * + * @returns true if arrays contain the same elements in the same order, false otherwise. + */ +export function fastArrayCompare(a: T, b: T): boolean { + if (a === b) { + return true; + } + + if (!Array.isArray(a) || !Array.isArray(b)) { + return false; + } + + let i = a.length; + if (i !== b.length) { + return false; + } + + // eslint-disable-next-line no-plusplus + while (i--) { + if (a[i] !== b[i]) { + return false; + } + } + + return true; +} diff --git a/packages/x-internals/src/fastArrayCompare/index.ts b/packages/x-internals/src/fastArrayCompare/index.ts new file mode 100644 index 0000000000000..8c93a145fda3b --- /dev/null +++ b/packages/x-internals/src/fastArrayCompare/index.ts @@ -0,0 +1 @@ +export { fastArrayCompare } from './fastArrayCompare'; From 9b84543061ca9f11514e98e832b69155ec1bf3b6 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 11 Feb 2025 12:48:12 +0100 Subject: [PATCH 09/12] Accept array from user --- packages/x-charts-pro/src/hooks/useHeatmapSeries.ts | 4 ++-- packages/x-charts/src/hooks/useBarSeries.ts | 6 ++---- packages/x-charts/src/hooks/useLineSeries.ts | 4 ++-- packages/x-charts/src/hooks/usePieSeries.ts | 6 ++---- packages/x-charts/src/hooks/useScatterSeries.ts | 4 ++-- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts index 3cccf67df7394..c2fc341f30a03 100644 --- a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts @@ -30,8 +30,8 @@ export function useHeatmapSeries(seriesId: SeriesId): ChartSeriesDefaultized<'he * @returns {ChartSeriesDefaultized<'heatmap'>[] | undefined} heatmapSeries */ export function useHeatmapSeries( - ...seriesIds: SeriesId[] + seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'heatmap'> | undefined)[]; -export function useHeatmapSeries(...seriesIds: SeriesId[]): any { +export function useHeatmapSeries(seriesIds?: any): any { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useBarSeries.ts b/packages/x-charts/src/hooks/useBarSeries.ts index e4ed43c768eff..f5489f6ef3f69 100644 --- a/packages/x-charts/src/hooks/useBarSeries.ts +++ b/packages/x-charts/src/hooks/useBarSeries.ts @@ -27,9 +27,7 @@ export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'> * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {ChartSeriesDefaultized<'bar'>[] | undefined} barSeries */ -export function useBarSeries( - ...seriesIds: SeriesId[] -): (ChartSeriesDefaultized<'bar'> | undefined)[]; -export function useBarSeries(...seriesIds: SeriesId[]): any { +export function useBarSeries(seriesIds: SeriesId[]): (ChartSeriesDefaultized<'bar'> | undefined)[]; +export function useBarSeries(seriesIds?: any): any { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts index 535664fa1ebab..a89917158f0cf 100644 --- a/packages/x-charts/src/hooks/useLineSeries.ts +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -28,8 +28,8 @@ export function useLineSeries(seriesId: SeriesId): ChartSeriesDefaultized<'line' * @returns {ChartSeriesDefaultized<'line'>[] | undefined} lineSeries */ export function useLineSeries( - ...seriesIds: SeriesId[] + seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'line'> | undefined)[]; -export function useLineSeries(...seriesIds: SeriesId[]): any { +export function useLineSeries(seriesIds?: any): any { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/usePieSeries.ts b/packages/x-charts/src/hooks/usePieSeries.ts index 58bf25ecfde48..3c251e1d271f9 100644 --- a/packages/x-charts/src/hooks/usePieSeries.ts +++ b/packages/x-charts/src/hooks/usePieSeries.ts @@ -27,9 +27,7 @@ export function usePieSeries(seriesId: SeriesId): ChartSeriesDefaultized<'pie'> * @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. * @returns {ChartSeriesDefaultized<'pie'>[] | undefined} pieSeries */ -export function usePieSeries( - ...seriesIds: SeriesId[] -): (ChartSeriesDefaultized<'pie'> | undefined)[]; -export function usePieSeries(...seriesIds: SeriesId[]): any { +export function usePieSeries(seriesIds: SeriesId[]): (ChartSeriesDefaultized<'pie'> | undefined)[]; +export function usePieSeries(seriesIds?: any): any { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useScatterSeries.ts b/packages/x-charts/src/hooks/useScatterSeries.ts index 297c5a3ba1e5f..dfd7af03b9740 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.ts +++ b/packages/x-charts/src/hooks/useScatterSeries.ts @@ -28,8 +28,8 @@ export function useScatterSeries(seriesId: SeriesId): ChartSeriesDefaultized<'sc * @returns {ChartSeriesDefaultized<'scatter'>[] | undefined} scatterSeries */ export function useScatterSeries( - ...seriesIds: SeriesId[] + seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'scatter'> | undefined)[]; -export function useScatterSeries(...seriesIds: SeriesId[]): any { +export function useScatterSeries(seriesIds?: any): any { return selectorSeries(seriesIds); } From 6320fff106ea4dac6db7de8ecd787ac776f1412f Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 11 Feb 2025 13:31:14 +0100 Subject: [PATCH 10/12] fix test --- packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx | 4 ++-- packages/x-charts/src/hooks/useBarSeries.test.tsx | 4 ++-- packages/x-charts/src/hooks/useLineSeries.test.tsx | 4 ++-- packages/x-charts/src/hooks/usePieSeries.test.tsx | 4 ++-- packages/x-charts/src/hooks/useScatterSeries.test.tsx | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx b/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx index 272dbba0b1eca..b957a16a1d393 100644 --- a/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.test.tsx @@ -53,12 +53,12 @@ describe('useHeatmapSeries', () => { }); it('should return the specific heatmap series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useHeatmapSeries('2', '1'), options); + const { result } = renderHook(() => useHeatmapSeries(['2', '1']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); }); it('should return undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useHeatmapSeries('1', '3'), options); + const { result } = renderHook(() => useHeatmapSeries(['1', '3']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); }); }); diff --git a/packages/x-charts/src/hooks/useBarSeries.test.tsx b/packages/x-charts/src/hooks/useBarSeries.test.tsx index 5969599ac9c52..f567986ca6aac 100644 --- a/packages/x-charts/src/hooks/useBarSeries.test.tsx +++ b/packages/x-charts/src/hooks/useBarSeries.test.tsx @@ -43,12 +43,12 @@ describe('useBarSeries', () => { }); it('should return the specific bar series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useBarSeries('2', '1'), options); + const { result } = renderHook(() => useBarSeries(['2', '1']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); }); it('should return undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useBarSeries('1', '3'), options); + const { result } = renderHook(() => useBarSeries(['1', '3']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); }); }); diff --git a/packages/x-charts/src/hooks/useLineSeries.test.tsx b/packages/x-charts/src/hooks/useLineSeries.test.tsx index d9823243b0b8e..21acb1ac116d7 100644 --- a/packages/x-charts/src/hooks/useLineSeries.test.tsx +++ b/packages/x-charts/src/hooks/useLineSeries.test.tsx @@ -43,12 +43,12 @@ describe('useLineSeries', () => { }); it('should return the specific line series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useLineSeries('2', '1'), options); + const { result } = renderHook(() => useLineSeries(['2', '1']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); }); it('should return undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useLineSeries('1', '3'), options); + const { result } = renderHook(() => useLineSeries(['1', '3']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); }); }); diff --git a/packages/x-charts/src/hooks/usePieSeries.test.tsx b/packages/x-charts/src/hooks/usePieSeries.test.tsx index be0a29993b566..c82979892e1c3 100644 --- a/packages/x-charts/src/hooks/usePieSeries.test.tsx +++ b/packages/x-charts/src/hooks/usePieSeries.test.tsx @@ -43,12 +43,12 @@ describe('usePieSeries', () => { }); it('should return the specific pie series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => usePieSeries('2', '1'), options); + const { result } = renderHook(() => usePieSeries(['2', '1']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); }); it('should return undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => usePieSeries('1', '3'), options); + const { result } = renderHook(() => usePieSeries(['1', '3']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); }); }); diff --git a/packages/x-charts/src/hooks/useScatterSeries.test.tsx b/packages/x-charts/src/hooks/useScatterSeries.test.tsx index 69861d216b567..3bfbd25ee8165 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.test.tsx +++ b/packages/x-charts/src/hooks/useScatterSeries.test.tsx @@ -49,12 +49,12 @@ describe('useScatterSeries', () => { }); it('should return the specific scatter series when multiple seriesIds are provided', () => { - const { result } = renderHook(() => useScatterSeries('2', '1'), options); + const { result } = renderHook(() => useScatterSeries(['2', '1']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[1].id, mockSeries[0].id]); }); it('should return undefined series when invalid seriesIds are provided', () => { - const { result } = renderHook(() => useScatterSeries('1', '3'), options); + const { result } = renderHook(() => useScatterSeries(['1', '3']), options); expect(result.current?.map((v) => v?.id)).to.deep.equal([mockSeries[0].id, undefined]); }); }); From 06cab70ec738ec8d20f52ba4e563f0dc4491ebc0 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 11 Feb 2025 14:11:26 +0100 Subject: [PATCH 11/12] fix ids not being an array --- packages/x-charts-pro/src/hooks/useHeatmapSeries.ts | 2 +- packages/x-charts/src/hooks/useBarSeries.ts | 2 +- packages/x-charts/src/hooks/useLineSeries.ts | 2 +- packages/x-charts/src/hooks/usePieSeries.ts | 2 +- packages/x-charts/src/hooks/useScatterSeries.ts | 2 +- .../x-charts/src/internals/createSeriesSelectorOfType.ts | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts index c2fc341f30a03..a588727bee976 100644 --- a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts @@ -32,6 +32,6 @@ export function useHeatmapSeries(seriesId: SeriesId): ChartSeriesDefaultized<'he export function useHeatmapSeries( seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'heatmap'> | undefined)[]; -export function useHeatmapSeries(seriesIds?: any): any { +export function useHeatmapSeries(seriesIds?: any) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useBarSeries.ts b/packages/x-charts/src/hooks/useBarSeries.ts index f5489f6ef3f69..240f4b41b7e9d 100644 --- a/packages/x-charts/src/hooks/useBarSeries.ts +++ b/packages/x-charts/src/hooks/useBarSeries.ts @@ -28,6 +28,6 @@ export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'> * @returns {ChartSeriesDefaultized<'bar'>[] | undefined} barSeries */ export function useBarSeries(seriesIds: SeriesId[]): (ChartSeriesDefaultized<'bar'> | undefined)[]; -export function useBarSeries(seriesIds?: any): any { +export function useBarSeries(seriesIds?: any) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts index a89917158f0cf..ccf17ecb927b2 100644 --- a/packages/x-charts/src/hooks/useLineSeries.ts +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -30,6 +30,6 @@ export function useLineSeries(seriesId: SeriesId): ChartSeriesDefaultized<'line' export function useLineSeries( seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'line'> | undefined)[]; -export function useLineSeries(seriesIds?: any): any { +export function useLineSeries(seriesIds?: any) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/usePieSeries.ts b/packages/x-charts/src/hooks/usePieSeries.ts index 3c251e1d271f9..3d032314e84d5 100644 --- a/packages/x-charts/src/hooks/usePieSeries.ts +++ b/packages/x-charts/src/hooks/usePieSeries.ts @@ -28,6 +28,6 @@ export function usePieSeries(seriesId: SeriesId): ChartSeriesDefaultized<'pie'> * @returns {ChartSeriesDefaultized<'pie'>[] | undefined} pieSeries */ export function usePieSeries(seriesIds: SeriesId[]): (ChartSeriesDefaultized<'pie'> | undefined)[]; -export function usePieSeries(seriesIds?: any): any { +export function usePieSeries(seriesIds?: any) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useScatterSeries.ts b/packages/x-charts/src/hooks/useScatterSeries.ts index dfd7af03b9740..5d1cce43cda75 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.ts +++ b/packages/x-charts/src/hooks/useScatterSeries.ts @@ -30,6 +30,6 @@ export function useScatterSeries(seriesId: SeriesId): ChartSeriesDefaultized<'sc export function useScatterSeries( seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'scatter'> | undefined)[]; -export function useScatterSeries(seriesIds?: any): any { +export function useScatterSeries(seriesIds?: any) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/internals/createSeriesSelectorOfType.ts b/packages/x-charts/src/internals/createSeriesSelectorOfType.ts index 8442b8acae734..a0b54a8d475c9 100644 --- a/packages/x-charts/src/internals/createSeriesSelectorOfType.ts +++ b/packages/x-charts/src/internals/createSeriesSelectorOfType.ts @@ -7,14 +7,14 @@ import { useSelector } from './store/useSelector'; export function createSeriesSelectorsOfType(seriesType: T) { const selectorSeriesWithIds = createSelector( - [selectorChartSeriesProcessed, (_, ids: SeriesId[]) => ids], + [selectorChartSeriesProcessed, (_, ids?: SeriesId | SeriesId[]) => ids], (processedSeries, ids) => { - if (ids.length === 0) { + if (!ids || (Array.isArray(ids) && ids.length === 0)) { return processedSeries[seriesType]; } - if (ids.length === 1) { - return processedSeries[seriesType]?.series?.[ids[0]]; + if (!Array.isArray(ids)) { + return processedSeries[seriesType]?.series?.[ids]; } return ids.map((id) => processedSeries[seriesType]?.series?.[id]); From 07ae3094283191fc1f98a1a01d26818ab75e0551 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 11 Feb 2025 14:17:25 +0100 Subject: [PATCH 12/12] fix types --- packages/x-charts-pro/src/hooks/useHeatmapSeries.ts | 2 +- packages/x-charts/src/hooks/useBarSeries.ts | 2 +- packages/x-charts/src/hooks/useLineSeries.ts | 2 +- packages/x-charts/src/hooks/usePieSeries.ts | 2 +- packages/x-charts/src/hooks/useScatterSeries.ts | 2 +- packages/x-charts/src/internals/createSeriesSelectorOfType.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts index a588727bee976..01ff32d14b598 100644 --- a/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts +++ b/packages/x-charts-pro/src/hooks/useHeatmapSeries.ts @@ -32,6 +32,6 @@ export function useHeatmapSeries(seriesId: SeriesId): ChartSeriesDefaultized<'he export function useHeatmapSeries( seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'heatmap'> | undefined)[]; -export function useHeatmapSeries(seriesIds?: any) { +export function useHeatmapSeries(seriesIds?: SeriesId | SeriesId[]) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useBarSeries.ts b/packages/x-charts/src/hooks/useBarSeries.ts index 240f4b41b7e9d..cda1d6df429e8 100644 --- a/packages/x-charts/src/hooks/useBarSeries.ts +++ b/packages/x-charts/src/hooks/useBarSeries.ts @@ -28,6 +28,6 @@ export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'> * @returns {ChartSeriesDefaultized<'bar'>[] | undefined} barSeries */ export function useBarSeries(seriesIds: SeriesId[]): (ChartSeriesDefaultized<'bar'> | undefined)[]; -export function useBarSeries(seriesIds?: any) { +export function useBarSeries(seriesIds?: SeriesId | SeriesId[]) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useLineSeries.ts b/packages/x-charts/src/hooks/useLineSeries.ts index ccf17ecb927b2..bcadf79f29c05 100644 --- a/packages/x-charts/src/hooks/useLineSeries.ts +++ b/packages/x-charts/src/hooks/useLineSeries.ts @@ -30,6 +30,6 @@ export function useLineSeries(seriesId: SeriesId): ChartSeriesDefaultized<'line' export function useLineSeries( seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'line'> | undefined)[]; -export function useLineSeries(seriesIds?: any) { +export function useLineSeries(seriesIds?: SeriesId | SeriesId[]) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/usePieSeries.ts b/packages/x-charts/src/hooks/usePieSeries.ts index 3d032314e84d5..16011db4fd9f6 100644 --- a/packages/x-charts/src/hooks/usePieSeries.ts +++ b/packages/x-charts/src/hooks/usePieSeries.ts @@ -28,6 +28,6 @@ export function usePieSeries(seriesId: SeriesId): ChartSeriesDefaultized<'pie'> * @returns {ChartSeriesDefaultized<'pie'>[] | undefined} pieSeries */ export function usePieSeries(seriesIds: SeriesId[]): (ChartSeriesDefaultized<'pie'> | undefined)[]; -export function usePieSeries(seriesIds?: any) { +export function usePieSeries(seriesIds?: SeriesId | SeriesId[]) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/hooks/useScatterSeries.ts b/packages/x-charts/src/hooks/useScatterSeries.ts index 5d1cce43cda75..d41a2c22a4fd8 100644 --- a/packages/x-charts/src/hooks/useScatterSeries.ts +++ b/packages/x-charts/src/hooks/useScatterSeries.ts @@ -30,6 +30,6 @@ export function useScatterSeries(seriesId: SeriesId): ChartSeriesDefaultized<'sc export function useScatterSeries( seriesIds: SeriesId[], ): (ChartSeriesDefaultized<'scatter'> | undefined)[]; -export function useScatterSeries(seriesIds?: any) { +export function useScatterSeries(seriesIds?: SeriesId | SeriesId[]) { return selectorSeries(seriesIds); } diff --git a/packages/x-charts/src/internals/createSeriesSelectorOfType.ts b/packages/x-charts/src/internals/createSeriesSelectorOfType.ts index a0b54a8d475c9..9f49a7fb3e680 100644 --- a/packages/x-charts/src/internals/createSeriesSelectorOfType.ts +++ b/packages/x-charts/src/internals/createSeriesSelectorOfType.ts @@ -21,7 +21,7 @@ export function createSeriesSelectorsOfType( }, ); - return (ids?: SeriesId[]) => { + return (ids?: SeriesId | SeriesId[]) => { const store = useStore(); return useSelector(store, selectorSeriesWithIds, ids);